Fetching contributors…
Cannot retrieve contributors at this time
219 lines (164 sloc) 6.4 KB
Since Opa S4, the compiler handles several database
backends. Depending (for moment) on the '--database' parameter the compiler
generates different database accessors.
Currently, the compiler handles two database backends :
- db3 : Opa database
- mongo : [](
Independently from the database backend, Opa allows :
- Definition of a database schema, made of a set of typed paths
- Generic database paths accessors
- An API that manipulates database paths
But some features can be backend specific. That's why there are also specific API(s)
Databases declaration
type stored = {int x, int y, string v, list(string) lst}
database dbname {
int /i
float /f
string /s
stored /r
list(string) /l
intmap(stored) /imap
stored /set[{x}]
This piece of code declares the database _dbname_ and defines :
- 3 paths containing basic values (/i, /f, /s)
- 1 path containing a record (/r)
- 1 path containing a list of string
- 1 path to an intmap
- 1 path to a database collection of _stored_ record. The key of the declared collection is _x_.
One of the new things available with Opa S4 is the way one can update a
database path. Indeed, previously it was only possible to overwrite a path,
like this :
/path/to/data <- x
With _x_ a value with its type equals to that of _/path/to/data_
Opa S4 defined new and most powerful ways to update a path. An update
operation should be atomic.
Int updating
// Set
/dbname/i <- 42
// Increment
/dbname/i ++
/dbname/i += 10
// Decrement
/dbname/i --
/dbname/i -= 10
// Sure we can go across records
/dbname/r/x ++
Record updating
// Overwrite an entire record
x = {x : 1, y : 2, v : "Hello, world", lst:[]}
/dbname/r <- x
// Update a subset of record fields
/dbname/r <- {x++, y--}
/dbname/r <- {x++, v : "I just want to update z and incr x"}
List updating
// Overwrite an entire list
/dbname/l <- ["Hello", ",", "world", "."]
// Removes first element of a list
/dbname/l pop
// Removes last element of a list
/dbname/l shift
// Append an element
/dbname/l <+ "element"
// Append several elements
/dbname/l <++ ["I", "love", "Opa"]
Database set/map updating
The values stored inside database sets and maps can be updated as we see above.
The difference is how we access to the elements (more details on [querying section](#Querying).
Futhermore updates can operates on several paths.
//Increment the field y of the record stored at position 9 of imap
/dbname/imap[9] <- {y++}
//Increment fields y of records stored with key smaller than 9
/dbname/imap[< 9] <- {y++}
//Increment the field y of record where the field x is equals 9
/dbname/set[x == 9] <- {y++}
//Increment the field y of all records where the field x is smaller than 9
/dbname/set[x < 9] <- {y++}
In the previous section we saw how to update data with Opa S4. Other
novelties concern the way to access to data stored inside collections.
Previously the database collections were intmap and stringmap, and the
way to access to data stored inside database map was :
// Access to the element stored at position 9
But it was impossible to access all the elements within a path, except by
using Db.*_fold_range. But it was just a fold on collection keys
(not on value) and it was not really user friendly.
Opa S4 introduces database sets and a most powerful way to access to
a subset of database collections.
Querying operators
- == expr : equals expr
- != expr : not equals expr
- < expr : lesser than expr
- <= expr : lesser than or equals expr
- > expr : greater than expr
- >= expr : greater than or equals expr
- in expr : in expr where expr is a list
- q1 or q2 : satisfy query q1 or q2
- q1 and q2 : satisfy queries q1 and q2
- not q : doesn't satisfy q
- {f1 q1, f2 q2, ...} : the record field f1 satisfy q1 and field f2 satisfy q2
Querying options
- skip n : where expr should be an expression of type int, skip the first
- limit n : where expr should be an expression of type int, returns maximum n results
- order fld (, fld)+ : where fld specify an order. fld can be <ident> or
+<ident> to specify staticaly fld ident should be sorted by incr, -<ident> by
decr. Or choose dynamicaly by <ident>=<expr> where <expr> should type of {up}
or {down}.
Querying set
k = {x : 9}
stored x = /dbname/set[k] // k should be type of set keys, returns a uniq value
stored x = /dbname/set[x == 10] // Returns a uniq value because {x} is primary key of set
dbset(stored, _) x = /dbname/set[y == 10] // Returns a database set because y is not a primary key
dbset(stored, _) x = /dbname/set[x > 10, y > 0, v in ["foo", "bar"]]
dbset(stored, _) x = /dbname/set[x > 10, y > 0, v in ["foo", "bar"]; skip 10; limit 15; order +x, -y]
it = DbSet.iterator(x); // then use Iter module.
Querying map
//Access to a uniq value (like S3)
stored x = /dbname/imap[9]
//Access to a submap where keys are lesser than 9 and greater than 4
intmap(stored) submap = /dbname/imap[< 9 and > 4]
Some features are available on all backends like read, write, remove, etc
while other feature has available only on one backend (example : path history).
That's why we have commons types (and API stdlib.core.database module Db) :
Db.val_path('a, 'engine)
Db.ref_path('a, 'engine)
Where 'a corresponding to type of value stored, then 'engine depending to the backend.
//Using db3 backend, Db3.val_path is an instance of Db.val_path
Db3.val_path(int) vpath = !/dbname/i
//You can use the common API
x =
//And specific db3 API
h = Db3.history(vpath)
//But if you use mongo backend, DbMongo.val_path is an instance of Db.val_path
DbMongo.val_path(int) vpath = !/dbname/i
//You can use the common API
x =
//But you will have a TYPE ERROR if you use specific db3 API
h = Db3.history(vpath)
- dbset are not yet implemeted
- Most of updating and querying operations are not yet implemented
- Nothing about migration of database schema