This is the ThingsDB documentation for version v0, click here for the latest version!
An update event is pushed when changes are made to a thing
you are watching.
Nested things need to be watched separately.
The event contains the Thing Id (#
), an event number, and a jobs array containing all the mutations to the thing in the applied order.
{
"#": 3,
"event": 123,
"jobs": [
...mutations
]
}
Each mutation is a map {}
with a single key. This key tells what kind of mutation is applied to the thing. If the thing is actually a collection, you will receive both
changes to the thing, as well as changes to the collection. This way you can also watch for collection mutations such as Type or procedure changes.
Mutation | Target | Description |
---|---|---|
set | thing |
Add a new property. |
del | thing |
Delete a property. |
add | thing |
Add one or more things to a set. |
remove | thing |
Remove one or more things from a set. |
splice | thing |
Delete and/or add items to a list. |
event | thing |
An event is emitted. |
new_type | collection |
A new type is added to the collection. |
set_type | collection |
A type is initialized. |
del_type | collection |
A type is removed from the collection. |
mod_type_add | collection |
A new field is added to an existing type. |
mod_type_del | collection |
A field is removed from an existing type. |
mod_type_mod | collection |
A field is modified on an existing type. |
mod_type_ren | collection |
A field is renamed on an existing type. |
mod_type_wpo | collection |
Wrap-only mode is changed for a type. |
set_enum | collection |
A new enum type is created. |
del_enum | collection |
An enum type is removed from the collection. |
mod_enum_add | collection |
A new member is added to an existing enum. |
mod_enum_def | collection |
The default member is changed for an existing enum. |
mod_enum_del | collection |
A member is removed from an existing enum. |
mod_enum_mod | collection |
A member value is modified on an existing enum. |
mod_enum_ren | collection |
A member name is modified on an existing enum. |
new_procedure | collection |
A new procedure is added to the collection. |
del_procedure | collection |
A procedure is removed from the collection. |
When new things are added via the mutations set, add or splice, Then the mutation will contain the complete thing with all properties. If on the other hand an existing thing is provided, then only the Id (#
) is included.
While most values inside mutation are easy to understand, a instance of a Type might seem a bit strange. For help with parsing such mutations see the set example below, and the mutation format documentation.
// Adds a property `name` with value `"ThingsDB"`.
.name = "ThingsDB";
Mutation result from the above code:
{
"set": {
"name": "ThingsDB"
}
}
Most values like the one above are quite obvious but note that instances of
a certain Type use the type_id
and refer to fields
with the values instead of the property names. For example:
// set_type('Person', {name: 'str'});
.person = Person{name: "Iris"};
The mutation event of creating the Person
above contains an empty key ""
with
an array
of fields. They refer to the fields of the Type with type_id:0
which can be found at key "."
. The Id of the instance is equal to a normal thing
and can be found with key "#"
, so the Id is 5 in the example result below. For more
information on how to parse a Type instance, look at the mutation format documentation.
{
"set": {
"person": {
"": [
"Iris"
],
"#": 5,
".": 0
}
}
}
// Delete property `name`.
// .name = "ThingsDB";
.del("name");
Mutation result from the above code:
{
"del": "name"
}
/*
* Adds the existing things `#11`, `#23` and a new
* thing `#42` to a *set* on property `myset`.
*/
// .myset = set();
.myset.add(#11, #23, {title: 'HG2G'});
Mutation result from the above code:
{
"add": {
"myset": [{
"#": 11
}, {
"#": 23
}, {
"#": 42,
"title": "HG2G"
}]
}
}
/*
* Removes the things `#123` and `#42` are removed
* from a *set* on property `myset`.
*/
// .myset = set(#55, #123, #42);
.myset.remove(#123, #42);
Mutation result from the above code:
{
"remove": {
"myset": [
123,
42
]
}
}
Mutations on a list are always converted to a splice
event. From this it follows that
no matter when using splice, push,
pop or another function to make modifications to a list,
the resulting event contains a splice
mutation.
/*
* Add items `"c"` and `"d"` at position `2`, and
* deletes `0` items to a *list* on property `arr`.
*/
// .arr = ["a", "b"];
.arr.push("c", "d");
Mutation result from the above code: (at position 2, 0 deletions, and 2 new items)
{
"splice": {
"arr": [2 , 0, "c", "d"]
}
}
Events are always triggered using the emit(..) function.
.emit("greet", "Hello", "universe!");
Mutation result from the above code:
{
"event": [
"greet",
"Hello",
"universe!"
]
}
/*
* A new Type named `Person` is added to the collection
* The `type_id` is usually not something you use, except
* for other mutations which refer to `type_id` when creating
* an instance of a Type.
*/
new_type('Person');
Mutation result from the above code:
{
"new_type": {
"created_at": 1581453937,
"name": "Person",
"type_id": 0,
"wrap_only": false
}
}
/*
* Set initial Type field definitions, field `name`
* with definition `str` on type `Person` in this case.
*/
set_type('Person', {name: 'str'});
Mutation result from the above code:
{
"set_type": {
"fields": [
["name", "str"]
],
"methods": {},
"modified_at": 1581455876,
"type_id": 0
}
}
// Delete a Type named `Person`.
// new_type('Person');
del_type('Person');
Mutation result from the above code:
{
"del_type": 0
}
/*
* Add a new field `rating` to type `Book`. If, and only if existing instances
* of the type `Book` exist, the mutation contains an `init` field with
* the given initial value. This value can be used to update earlier loaded
* instances of type `Book` and may be updated with this initial value to stay
* consistent with ThingsDB.
*/
// set_type('Book', {title: 'str'}); .book = Book{title: 'hhgttg'};
mod_type('Book', 'add', 'rating', 'uint', 1);
Mutation result from the above code:
{
"mod_type_add": {
"init": 1,
"modified_at": 1581510638,
"name": "rating",
"spec": "uint",
"type_id": 2
}
}
Instead of adding a new field using a default value, it is possible to use a closure to generate initial values (see mod_type(..add)). In this case the following mutations are pushed to watchers:
mod_type_add
.set
mutation with the new initial value.Delete is always performed using a swap_remove
(the removed value will be replaced with the last value). For example when having the type properties [A, B, C, D]
and then remove B
will result in [A, D, C]
.
// Delete the `rating` field definition of type `Book`.
// set_type('Book', {title: 'str', rating: 'number'});
mod_type('Book', 'del', 'rating');
Mutation result from the above code:
{
"mod_type_del": {
"modified_at": 1581511233,
"name": "rating",
"type_id": 2
}
}
// Change field definition `rating` of type `Book`.
// set_type('Book', {title: 'str', rating: 'uint'});
mod_type('Book', 'mod', 'rating', 'number');
Mutation result from the above code:
{
"mod_type_mod": {
"modified_at": 1581511115,
"name": "rating",
"spec": "number",
"type_id": 2
}
}
Instead of migrating to a less
strict definition, it is possible to use a closure
and migrate to a complete new definition (see mod_type(..mod)). In this case the following mutations are pushed
to watchers:
mod_type_mod
with a any
spec.set
mutation with a new value according the new spec.mod_type_mod
with the required spec.// Rename the `rate` field of type `Book` to `rating`.
// set_type('Book', {title: 'str', rate: 'number'});
mod_type('Book', 'ren', 'rate', 'rating');
Mutation result from the above code:
{
"mod_type_ren": {
"modified_at": 1581511233,
"name": "rate",
"to": "rating",
"type_id": 2
}
}
// Enable wrap-only mode
// set_type('Book', {title: 'str', rate: 'number'});
mod_type('Book', 'wpo', true);
Mutation result from the above code:
{
"mod_type_wpo": {
"modified_at": 1581511233,
"wrap_only": true,
"type_id": 2
}
}
/*
* Create and set initial enumerator.
*/
set_enum('Color', {
RED: '#f00',
GREEN: '#0f0',
BLUE: '#00f'
});
Mutation result from the above code:
{
"set_enum": {
"created_at": 1581455876,
"enum_id": 0,
"name": "Color",
"members": [
["RED", "#f00"],
["GREEN", "#0f0"],
["BLUE", "#00f"]
]
}
}
// Delete a enumerator named `Color`.
del_enum('Color');
Mutation result from the above code:
{
"del_enum": 0
}
// Add a member `BLUE` to enumerator `Color`.
// set_enum('Color', {RED: '#f00', GREEN: '#0f0'});
mod_enum('Color', 'add', 'BLUE', '#00f');
Mutation result from the above code:
{
"mod_type_add": {
"enum_id": 2,
"modified_at": 1581511233,
"name": "BLUE",
"value": "#00f"
}
}
Defaults are always changed using a swap
with the previous default. For example when having the enum values [A, B, C, D]
and then change the default from A
to C
will result in order [C, B, A, D]
.
// Set member `GREEN` as the default member for enumerator `Color`.
// set_enum('Color', {RED: '#f00', GREEN: '#0f0', BLUE: '#00f'});
mod_enum('Color', 'def', 'GREEN');
Mutation result from the above code:
{
"mod_enum_def": {
"enum_id": 2,
"index": 1,
"modified_at": 1581511233
}
}
Delete is always performed using a swap_remove
(the removed value will be replaced with the last value). For example when having the enum members [A, B, C, D]
and then remove B
will result in [A, D, C]
.
// Delete member `GREEN` from enumerator `Color`.
// set_enum('Color', {RED: '#f00', GREEN: '#0f0', BLUE: '#00f'});
mod_enum('Color', 'del', 'GREEN');
Mutation result from the above code:
{
"mod_enum_del": {
"enum_id": 2,
"index": 1,
"modified_at": 1581511233
}
}
// Modify the value of member `BLUE` on enumerator `Color`.
// set_enum('Color', {RED: '#f00', GREEN: '#0f0', BLUE: '#fff'});
mod_enum('Color', 'mod', 'BLUE', '#00f');
Mutation result from the above code:
{
"mod_enum_mod": {
"enum_id": 2,
"index": 2,
"modified_at": 1581511233,
"value": "#00f"
}
}
// Rename member `MOON` to `BLUE` of enumerator `Color`.
// set_enum('Color', {RED: '#f00', GREEN: '#0f0', MOON: '#00f'});
mod_enum('Color', 'ren', 'MOON', 'BLUE');
Mutation result from the above code:
{
"mod_enum_ren": {
"enum_id": 2,
"index": 2,
"modified_at": 1581511233,
"name": "BLUE"
}
}
// A new procedure named `multiply` is added to the collection.
new_procedure('multiply', |a, b| a*b);
Mutation result from the above code:
{
"new_procedure": {
"name": "multiply",
"created_at": 1579601906,
"closure": {
"/": "|a,b|a*b"
}
}
}
// Delete a procedure named `multiply`.
// new_procedure('multiply', |a, b| a*b);
del_procedure('multiply');
Mutation result from the above code:
{
"del_procedure": "multiply"
}