EliasDB supports a scripting language called Event Condition Action Language (ECAL) to enable rule based scripting functionality. ECAL provides database trigger functionality for EliasDB.
ECAL was added for the following use-cases:
- Providing a way to manipulate data in response to events
- Enforce certain aspects of a database schema
- Providing back-end logic for web applications using EliasDB
The source of EliasDB comes with a chat example containing a simple ECAL script which adds a timestamp to nodes and a game example which demonstrates a more complex application of ECAL.
These ECAL related config options are available in eliasdb.config.json
:
Configuration Option | Description |
---|---|
EnableECALScripts | Enable ECAL scripting. |
ECALScriptFolder | Scripting folder for ECAL scripts. |
ECALEntryScript | Entry script in the script folder. |
ECALLogFile | File in which the logs should be written (use an empty string for stdout). |
ECALLogLevel | Log level for the printed logs. |
EnableECALDebugServer | Enable debugging and start the ECAL debug server. Note: Activating debugging will slow down the interpreter speed significantly! |
ECALDebugServerHost | Host for the debug server. |
ECALDebugServerPort | Port for the debug server. |
ECALWorkerCount | Number of worker threads in the ECA engine's thread pool. |
If the debug server is enabled in the config file then it is possible to debug ECAL scripts with VSCode. The debugger supports break points and thread state inspection. It is also possible to restart and reload the scripts.
Using the -ecal-console
parameter it is possible to open an interactive console into the server process. If used together with the debug server additional debug commands are available also there. Enter ?
to see the build-in documentation.
The ECAL interpreter in EliasDB receives the following events:
Web Request | ECAL event kind | Event state contents | Description |
---|---|---|---|
/db/api/ | db.web.api |
bodyJSON, bodyString, header, method, path, pathList, query | Any web request to /db/api/... These endpoints are public and never require authentication. |
/db/ecal/ | db.web.ecal |
bodyJSON, bodyString, header, method, path, pathList, query | Any web request to /db/ecal/... These endpoints are considered internal and require authentication if access control is enabled. |
/db/sock/ | db.web.sock |
bodyJSON, bodyString, commID, header, method, path, pathList, query | Any web request to /db/sock/... These endpoints are used to initiate websocket connections. |
- | db.web.sock.data |
commID, data, header, method, path, pathList, query | An existing websocket connection received some JSON object data. If the close attribute of the object is set to true then the websocket connection is closed. |
EliasDB Graph Event | ECAL event kind | Event state contents | Description |
---|---|---|---|
graph.EventNodeCreated | db.node.created |
part, trans, node | A node was created. |
graph.EventNodeUpdated | db.node.updated |
part, trans, node, old_node | A node was updated. |
graph.EventNodeDeleted | db.node.deleted |
part, trans, node | A node was deleted. |
graph.EventEdgeCreated | db.edge.created |
part, trans, edge | An edge was created. |
graph.EventEdgeUpdated | db.edge.updated |
part, trans, edge, old_edge | An edge was updated. |
graph.EventEdgeDeleted | db.edge.deleted |
part, trans, edge | An edge was deleted. |
graph.EventNodeStore | db.node.store |
part, trans, node | A node is about to be stored (always overwriting existing values). |
graph.EventNodeUpdate | db.node.update |
part, trans, node | A node is about to be updated. |
graph.EventNodeDelete | db.node.delete |
part, trans, key, kind | A node is about to be deleted. |
graph.EventEdgeStore | db.edge.store |
part, trans, edge | An edge is about to be stored. |
graph.EventEdgeDelete | db.edge.delete |
part, trans, key, kind | An edge is about to be deleted. |
Note: EliasDB will wait for the event cascade to be finished before performing the actual operation (e.g. inserting a node). If the event handling requires a time consuming operation then a new parallel event cascade can be started using addEvent
with a scope:
EliasDB can receive the following events from the ECAL interpreter:
ECAL event kind | Event state contents | Description |
---|---|---|
db.web.sock.msg | commID, payload, close | The payload is send to a client with an open websocket identified by the commID. |
addEvent("request", "foo.bar.xxx", {
"payload" : 123
}, {
"": true # This scope allows all events
})
The ECAL interpreter in EliasDB supports the following EliasDB specific functions:
Inserts or updates a node in EliasDB.
Parameter | Description |
---|---|
partition | Partition of the node |
nodeMap | Node object as a map with at least a key and a kind attribute |
transaction | Optional a transaction to group a set of changes |
Example:
db.storeNode("main", {
"key" : "foo",
"kind" : "bar",
"data" : 123,
})
Updates a node in EliasDB (only update the given values of the node).
Parameter | Description |
---|---|
partition | Partition of the node |
nodeMap | Node object as a map with at least a key and a kind attribute |
transaction | Optional a transaction to group a set of changes |
Example:
db.updateNode("main", {
"key" : "foo",
"kind" : "bar",
"data" : 123,
})
Removes a node in EliasDB.
Parameter | Description |
---|---|
partition | Partition of the node |
nodeKey | Key attribute of the node to remove |
nodeKind | Kind attribute of the node to remove |
transaction | Optional a transaction to group a set of changes |
Example:
db.removeNode("main", "foo", "bar")
Fetches a node in EliasDB.
Parameter | Description |
---|---|
partition | Partition of the node |
nodeKey | Key attribute of the node to fetch |
nodeKind | Kind attribute of the node to fetch |
Example:
db.fetchNode("main", "foo", "bar")
Inserts or updates an edge in EliasDB.
Parameter | Description |
---|---|
partition | Partition of the edge |
edgeMap | Edge object as a map with at least the main attributes: key, kind, end1cascading, end1key, end1kind, end1role, end2cascading, end2key, end2kind, end2role |
transaction | Optional a transaction to group a set of changes |
Example:
db.storeEdge("main", {
"key": "123",
"kind": "myedges",
"end1cascading": true,
"end1key": "foo",
"end1kind": "bar",
"end1role": "role1",
"end2cascading": false,
"end2key": "key2",
"end2kind": "kind2",
"end2role": "role2",
})
Removes an edge in EliasDB.
Parameter | Description |
---|---|
partition | Partition of the edge |
edgeKey | Key attribute of the edge to remove |
edgeKind | Kind attribute of the edge to remove |
transaction | Optional a transaction to group a set of changes |
Example:
db.removeEdge("main", "123", "myedges")
Fetches an edge in EliasDB.
Parameter | Description |
---|---|
partition | Partition of the edge |
edgeKey | Key attribute of the edge to fetch |
edgeKind | Kind attribute of the edge to fetch |
Example:
db.fetchEdge("main", "123", "myedges")
Traverses an edge in EliasDB from a given node. Returns a list of nodes which were reached and a list of edges which were followed.
Parameter | Description |
---|---|
partition | Partition of the node |
nodeKey | Key attribute of the node to traverse from |
nodeKind | Kind attribute of the node to traverse from |
traversalSpec | Traversal spec |
Example:
[nodes, edges] := db.traverse("main", "foo", "bar", "role1:myedges:role2:kind2")
Creates a new transaction for EliasDB.
Example:
trans := db.newTrans()
Creates a new rolling transaction for EliasDB. A rolling transaction commits after n entries.
Parameter | Description |
---|---|
n | Rolling threshold (number of operations before rolling) |
Example:
trans := db.newRollingTrans(5)
Commits an existing transaction for EliasDB.
Parameter | Description |
---|---|
transaction | Transaction to execute |
Example:
db.commit(trans)
Run an EQL query.
Parameter | Description |
---|---|
partition | Partition to query |
query | Query to execute |
Example:
db.commit("main", "get bar")
Run a GraphQL query.
Parameter | Description |
---|---|
partition | Partition to query |
query | Query to execute |
variables | Map of variables for the query |
operationName | Operation to execute (useful if the query defines more than a single operation) |
Example:
db.graphQL("main", "query myquery($x: string) { bar(key:$x) { data }}", {
"x": "foo",
}, "myquery")
When handling a graph event, notify the GraphManager of EliasDB that no further action is necessary. This creates a special error object and should not be used inside a try
block. When using a try
block this can be used inside an except
or otherwise
block.
Example:
sink mysink
kindmatch [ "db.*.*" ],
{
db.raiseGraphEventHandled()
}
When handling a web event, notify the web API of EliasDB that the web request was handled. This creates a special error object and should not be used inside a try
block. When using a try
block this can be used inside an except
or otherwise
block.
Example:
sink mysink
kindmatch [ "web.*.*" ],
{
db.raiseWebEventHandled({
"status" : 200,
"headers" : {
"Date": "today"
},
"body" : {
"mydata" : [1,2,3]
}
})
}