Skip to content
This repository
tree: d3f31cdaf5
Fetching contributors…

Cannot retrieve contributors at this time

file 218 lines (164 sloc) 6.549 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
WARNING : MOST OF THE FEATURES DESCRIBED BELOW HAVE NOT YET IMPLEMENTED BY DB3

Overview
============
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 : [http://www.mongodb.org/](http://www.mongodb.org/)

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_.

Updating
============
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++}

Querying
============
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
    /dbname/imap[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]


API(s)
============
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 = Db.read(vpath)
    //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 = Db.read(vpath)
    //But you will have a TYPE ERROR if you use specific db3 API
    h = Db3.history(vpath)


Restriction/Todo
============

db3
--------
- dbset are not yet implemeted
- Most of updating and querying operations are not yet implemented

mongo
--------
- Nothing about migration of database schema
Something went wrong with that request. Please try again.