-
Notifications
You must be signed in to change notification settings - Fork 125
/
cheat-sheet-db.omd
218 lines (164 loc) · 6.4 KB
/
cheat-sheet-db.omd
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