client_request

model grammar version 89

  1. Request types
    1. Collection query
    2. Acyclic graph tree query
    3. Acyclic graph list query
    4. Mutation
    5. Subscription
    6. Subscription deletion
    7. Command execution
    8. Password mutation
    9. Password reset
  2. Rules

Request types

'type': stategroup (
	'collection query' {
		'context node path': [ on ] component 'id path'
		'collection path': [ from ] component 'collection query path'
		'filters': [ where ] group {
			'todo filter': stategroup (
				'yes' { [ has-todo ]
					'path': component 'conditional path'
				}
				'no' { }
			)
			'property filters': dictionary {
				'path': [ : ] component 'conditional path'
				'property': [ . ] reference
				'type': stategroup (
					'number' {
						'expression': component 'number filter expression'
					}
					'state group' { [ in ]
						'states to include': [ (, ) ] dictionary { [ ? ] }
					}
					'text' {
						'type': stategroup (
							'simple' { [ (, ) ]
								'expression': component 'filter expression'
							}
							'reference' {
								'operator': stategroup (
									'in' { [ in ] }
									'not in' { [ not in ] }
								)
								'references': [ (, ) ] component 'reference filter list'
							}
						)
					}
					'collection' {
						'operator': stategroup (
							'in' { [ in ] }
							'not in' { [ not in ] }
						)
						'keys': [ (, ) ] dictionary { [ [, ] ] }
					}
				)
			}
		}
		'select entries': stategroup (
			'yes' { [ select ]
				'properties': dictionary {
					'path': [ : ] component 'conditional path'
					'type': stategroup (
						'id path' { [ id-path ] }
						'number' { [ number ]
							'expression': [ = ] component 'number expression2'
						}
						'text' { [ text ]
							'expression': [ = ] component 'text expression'
						}
						'file' { [ file ]
							'file': [ = / ] reference
						}
						'state group' { [ stategroup ]
							'state group': [ = . ] reference
						}
					)
				}
				'limit number of entries': [ limit ] integer
			}
			'no' { }
		)
		'aggregates': [ aggregate ] dictionary {
			'type': [ : ] stategroup (
				'state distribution' { [ distribution ]
					'path': component 'conditional path'
					'state group': [ . ] reference
				}
			)
		}
	}
	'acyclic graph tree query' {
		'context node': [ graph ] component 'id path'
		'type': [ select ] stategroup (
			'collection' { [ from ]
				'graph': reference
			}
		)
	}
	'acyclic graph list query' {
		'context node': [ on ] component 'id path'
		'entry points': [ from ] component 'entry point path'
		'graph': [ flatten ] reference
		'query': [ select ] group {
			'collection path': component 'collection path'
			'properties': dictionary {
				'path': [ = ] component 'conditional path'
				'type': stategroup (
					'number' { [ # ]
						'number': reference
					}
					'text' { [ . ]
						'text': reference
					}
					'state group' { [ ? ]
						'state group': reference
					}
				)
			}
		}
	}
	'mutation' {
		'context node': [ update ] component 'id path'
		'update node': component 'update node'
	}
	'subscription' {
		'mutation permissions': stategroup (
			'include' { }
			'ignore' { [ #ignore-mutation-permissions ] }
		)
		'context node': [ subscribe to ] component 'id path'
		'subscribed properties': component 'subscribed properties'
	}
	'subscription deletion' { }
	'command execution' {
		'context node': [ execute ] component 'id path'
		'command': [ : ] reference
		'arguments': [ with ] component 'command arguments'
	}
	'password mutation' { [ change password ]
		'old password': [ from ] text
		'new password': [ to ] text
	}
	'password reset' { [ reset password ]
		'username': [ of ] text
	}
)

Collection query

Queries an hierarchy of collections and produces a select and/or aggregate result the entries that match the filters.

Acyclic graph tree query

Produces a dependency tree showing the dependencies of a node in a predefined ‘graph’. The ‘context node’ is the root of the tree.

Acyclic graph list query

Queries a collection of references and create a flat subgraph of the provided ‘graph’ for each of them. The ‘query’ group defines what data will be queried for each of the entries.

For example, suppose we have this model, specifying Products and Orders:

'Products': collection ['Name']
	'assembly': acyclic-graph
{
	'Name': text
	'Parts': collection ['Product'] {
		'Product': text -> ^ sibling in ('assembly')
		'Price': number positive 'euro'
	}
}
'Orders': collection ['ID'] {
	'ID': text
	'Products': collection ['Product'] {
		'Product': text -> ^ ^ .'Products'
	}
}

And the following query:

on /* root */
from .'Orders'.'Products'>'Product'
flatten 'assembly'
select .'Parts'
	'PP': = #'Price'

Then we get a result of the form:

'Orders': (
	['A'] (
		'Products': (
			subgraph ['1'] = ( // flat subgraph:
				['1'] (
					count = 0
					'Parts' = (
						['1.1'] ( 'PP' = 10 )
						['1.2'] ( 'PP' = 20 )
					)
				) // root of the graph
				['1.1'] ( count = 2 'Parts' = ( ) )
				['1.2'] ( count = 1 'Parts' = ( ) )
			)
		)
	)
	['B'] (
		'Products': (
			['2'] ( ['2'] ( count = 0 'Parts' = ( ) ) )
		)
	)
)

Mutation

Updates specified parts of your data.

Subscription

Subscribes to specific pieces of data. The subscriber will get notifications in case subscribed data are modified.

Subscription deletion

Request unsubscribe, and thus halt notifications for a subscription.

Command execution

Request to execute a command as defined in an application model.

Password mutation

Updates a user’s password.

Password reset

Resets a user’s password.

Rules

'filter expression' {
	'type': stategroup (
		'wildcard' { [ * ] }
		'alternatives' { [ [, ] ]
			'alternatives': dictionary { }
		}
	)
	'has more steps': stategroup (
		'yes' {
			'tail': component 'filter expression'
		}
		'no' { }
	)
}
'number filter expression' {
	'operator': stategroup (
		'range' {
			'greater than': stategroup (
				'yes' { [ > ]
					'criterium': integer
				}
				'no' { }
			)
			'less than': stategroup (
				'yes' { [ < ]
					'criterium': integer
				}
				'no' { }
			)
		}
		'equals' { [ == ]
			'criterium': integer
		}
	)
}
'reference filter list' {
	'referenced node': component 'id path'
	'has alternative': stategroup (
		'yes' {
			'alternative': [ , ] component 'reference filter list'
		}
		'no' { }
	)
}
'id path' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'type': stategroup (
				'collection entry' { [ . ]
					'collection': reference
					'id': [ [, ] ] text
				}
				'group' { [ . ]
					'group': reference
				}
				'state' {
					'state group': [ . ] reference
					'state': [ ? ] reference
				}
			)
			'tail': component 'id path'
		}
	)
}
'conditional child path' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'type': stategroup (
				'group' { [ + ]
					'group': reference
				}
				'state' { [ ? ]
					'state group': reference
					'state': [ | ] reference
				}
			)
			'tail': component 'conditional child path'
		}
	)
}
'collection path' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'head': component 'conditional child path'
			'collection': [ . ] reference
			'tail': component 'collection path'
		}
	)
}
'collection query path' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'head': component 'conditional child path'
			'collection': [ . ] reference
			'type': stategroup (
				'candidates' { [ candidates ]
					'include reference': stategroup (
						'yes' { [ #include-reference ] }
						'no' { }
					)
				}
				'existing entries' { }
			)
			'tail': component 'collection query path'
		}
	)
}
'entry point path' {
	'has steps': stategroup (
		'no' {
			'text': [ > ] reference
		}
		'yes' {
			'head': component 'conditional child path'
			'collection': [ . ] reference
			'tail': component 'entry point path'
		}
	)
}
'plural path' {
	'head': component 'conditional path'
	'has steps': stategroup (
		'no' { }
		'yes' {
			'type': stategroup (
				'union' { [ union ]
					'paths': [ (, ) ] dictionary {
						'plural path': [ -> ] component 'plural path'
					}
				}
				'collection' { [ ., * ]
					'collection': reference
				}
			)
			'tail': component 'plural path'
		}
	)
}
'conditional path' {
	'head': component 'singular path'
	'has steps': stategroup (
		'no' { }
		'yes' {
			'type': stategroup (
				'state' {
					'state group': [ . ] reference
					'state': [ ? ] reference
				}
				'collection entry' {
					'collection': [ . ] reference
					'entry key': [ [, ] ] text
				}
				'link' {
					'text': [ ~> ] reference
				}
			)
			'tail': component 'conditional path'
		}
	)
}
'singular path' {
	'has steps': stategroup (
		'no' { }
		'yes' {
			'type': stategroup (
				'parent' { [ ^ ] }
				'state constraint' { [ .& ]
					'rule': reference
				}
				'property rule' {
					'property': [ . ] reference
					'rule': [ & ] reference
				}
				'reference' {
					'text': [ > ] reference
				}
				'group' {
					'group': [ + ] reference
				}
			)
			'tail': component 'singular path'
		}
	)
}
'aggregate2' {
	'head': component 'singular path'
	'collection': [ . ] reference
	'tail': component 'conditional path'
}
'number aggregate2' {
	'aggregate': component 'aggregate2'
	'property name': [ . ] reference
}
'signed number property2' {
	'sign': stategroup (
		'negative' { [ - ] }
		'positive' { }
	)
	'path': component 'singular path'
	'property name': [ . ] reference
}
'signed number property list' {
	'has element': stategroup (
		'no' { }
		'yes' {
			'signed number property': component 'signed number property2'
			'tail': component 'signed number property list'
		}
	)
}
'number expression2' {
	'type': stategroup (
		'value' {
			'value': integer
		}
		'number property' {
			'signed number property': component 'signed number property2'
		}
		'sum' { [ sum ]
			'number aggregate': component 'number aggregate2'
		}
		'sum list' { [ sum ]
			'numbers': [ (, ) ] component 'signed number property list'
		}
		'remainder' { [ remainder ]
			'number': [ ( ] component 'signed number property2'
			'modulus': [ ,, ) ] component 'signed number property2'
		}
		'product' { [ product ]
			'numbers': [ (, ) ] component 'signed number property list'
		}
		'division' { [ division ]
			'rounding': stategroup (
				'ordinary' { }
				'ceil' { [ ceil ] }
				'floor' { [ floor ] }
			)
			'numerator': [ ( ] component 'signed number property2'
			'denominator': [ ,, ) ] component 'signed number property2'
		}
		'count' { [ count ]
			'aggregate': component 'aggregate2'
		}
		'state based' { [ switch ( ]
			'path': component 'singular path'
			'state group': [ ?, ) ] reference
			'states': [ (, ) ] dictionary { [ | ]
				'value': [ = ] component 'number expression2'
			}
		}
		'maximum' { [ max ]
			'left expression': [ ( ] component 'number expression2'
			'right expression': [ ,, ) ] component 'number expression2'
		}
		'minimum' { [ min ]
			'left expression': [ ( ] component 'number expression2'
			'right expression': [ ,, ) ] component 'number expression2'
		}
	)
}
'singular text expression' {
	'type': stategroup (
		'static' {
			'string': text
		}
		'dynamic' {
			'path': component 'singular path'
			'text': [ . ] reference
		}
	)
}
'singular text expression list' {
	'has element': stategroup (
		'no' { }
		'yes' {
			'singular text expression': component 'singular text expression'
			'tail': component 'singular text expression list'
		}
	)
}
'text expression' {
	'type': stategroup (
		'singular' {
			'expression': component 'singular text expression'
		}
		'concatenation' { [ concat ]
			'parts': [ (, ) ] component 'singular text expression list'
		}
		'join' { [ join ]
			'node collection': component 'plural path'
			'expression': [ (, ) ] component 'text expression'
			'separator': [ with ] text
		}
	)
}
'subscribed properties' { [ (, ) ]
	'properties': dictionary {
		'type': [ : ] stategroup (
			'collection' { [ collection ]
				'subscribe on': stategroup (
					'entries' {
						'key filter': stategroup (
							'no' { }
							'yes' {
								'keys': [ [, ] ] dictionary { }
							}
						)
						'subscribed properties': component 'subscribed properties'
					}
					'updates' { }
				)
			}
			'group' { [ group ]
				'subscribed properties': component 'subscribed properties'
			}
			'number' { [ number ] }
			'state group' { [ stategroup ]
				'states': [ (, ) ] dictionary {
					'subscribed properties': component 'subscribed properties'
				}
			}
			'text' { [ text ]
				'include reference': stategroup (
					'no' { }
					'yes' { [ #include-reference ] }
				)
			}
			'file' { [ file ] }
		)
	}
}
'update node' { [ (, ) ]
	'properties': dictionary {
		'type': [ : ] stategroup (
			'group' { [ group ]
				'update node': component 'update node'
			}
			'number' { [ number ]
				'new value': [ = ] integer
			}
			'state group' { [ stategroup ]
				'state': reference
				'type': stategroup (
					'set' { [ = ]
						'node': component 'initialize node'
					}
					'update' {
						'update node': component 'update node'
					}
				)
			}
			'text' { [ text = ]
				'new value': text
			}
			'file' { [ file = ]
				'new token': text
				'new extension': [ . ] text
			}
			'collection' { [ collection ]
				'entries': [ (, ) ] dictionary {
					'type': stategroup (
						'create' { [ create ]
							'node': component 'initialize node'
						}
						'update' {
							'update node': component 'update node'
						}
						'remove' { [ remove ] }
					)
				}
			}
		)
	}
}
'initialize node' { [ (, ) ]
	'properties': dictionary {
		'type': [ : ] stategroup (
			'group' { [ group ]
				'node': [ = ] component 'initialize node'
			}
			'number' { [ number ]
				'value': [ = ] integer
			}
			'state group' { [ stategroup ]
				'state': [ = ] reference
				'node': component 'initialize node'
			}
			'text' { [ text = ]
				'value': text
			}
			'file' { [ file = ]
				'token': text
				'extension': [ . ] text
			}
			'collection' { [ collection ]
				'entries': [ (, ) ] dictionary {
					'node': component 'initialize node'
				}
			}
		)
	}
}
'command arguments' { [ (, ) ]
	'properties': dictionary {
		'type': [ : ] stategroup (
			'collection' { [ collection = ]
				'entries': [ (, ) ] dictionary {
					'arguments': component 'command arguments'
				}
			}
			'number' { [ number ]
				'value': [ = ] integer
			}
			'text' { [ text = ]
				'text': text
			}
			'file' { [ file = ]
				'token': text
				'extension': [ . ] text
			}
			'state group' { [ stategroup = ]
				'state': reference
				'arguments': component 'command arguments'
			}
			'group' { [ group = ]
				'arguments': component 'command arguments'
			}
		)
	}
}