5 Metakit Extension for Jim Tcl
6 =============================
10 The mk extension provides an interface to the Metakit small-footprint
11 embeddable database library (<http://equi4.com/metakit/>). The underlying
12 library is efficient at manipulating not-so-large amounts of data and takes a
13 different approach to composing database operations than common SQL-based
16 Both the Metakit core library and the mk package can be linked either
17 statically or dynamically and loaded using
23 A database (called a "storage" in Metakit terms) may either reside totally in
24 memory or be backed by a file. To open or create a database, call the
25 `storage` command with an optional filename parameter:
27 set db [storage test.mk]
29 The returned handle can be used as a command name to access the database. When
30 you are done, execute the `close` method, that is, run
34 A lost handle won't be found by GC but will be closed when the interpreter
35 exits. Note that by default Metakit will only record changes to the database
36 when you close the handle. Use the `commit` method to record the current
37 state of the database to disk.
41 *Views* in Metakit are what is called "tables" in conventional databases. A view
42 may several typed *properties*, or columns, and contains homogeneous *rows*, or
43 records. New properties may be added to a view as needed; however, new properties
44 are not stored in the database file by default. The structure method specifies
45 the stored properties of a view, creating a new view or restructuring an old one
48 $db structure viewName description
50 The view description must be a list of form `{propName type propName type ...}`.
51 The supported property types include:
54 : A NULL-terminated string, stored as an array of bytes (without any encoding
58 : **Not yet supported by the `mk` extension.**
59 Blob of binary data that may contain embedded NULLs (zero bytes). Stored
60 as-is. This is more efficient than `string` when storing large blocks of
61 data (e.g. images) and will adjust the storage strategy as needed.
64 : An signed integer value occupying a maximum of 32 bits. If all values
65 stored in a column can fit in a smaller range (16, 8, or even 4 or 2 bits),
66 they are packed automatically.
69 : Like `integer`, but is required to fit into 64 bits.
72 : 32-bit and 64-bit IEEE floating-point values respectively.
75 : This type is not usually specified directly; instead, a structure
76 description of a nested view is given. `subview` properties store complete
77 views as their value, creating hierarchical data structures. When retrieved
78 from a view, a value of a subview property is a normal view handle.
80 Without a `description` parameter, the `structure` method returns the current
81 structure of the named view; without any parameters, it returns a dictionary
82 containing structure descriptions of all views stored in the database.
84 After specifying the properties you expect to see in the view, call
86 [$db view $viewName] as viewHandle
88 to obtain a view handle. These handles are also commands, but are
89 garbage-collected and also destroy themselves after a single method call; the
90 `as viewHandle` call assigns the view handle to the specified variable and also
91 tells the view not to destroy itself until all the references to it are gone.
93 View handles may also be made permanent by giving them a global command name,
96 rename [$db view data] .db.data
98 However, such view handles are not managed automatically at all and must be
99 destroyed using the `destroy` method, or by renaming them to `""`.
103 The value of a particular property is obtained using
105 cursor get $cur propName
107 where `$cur` is a string of form `viewHandle!index`. Row indices are zero-based
108 and may also be specified relative to the last row of the view using the
109 `end[+-]integer` notation.
111 A dictionary containing all property name and value pairs can be retrieved by
112 omitting the `propName` argument:
116 Setting property values is also performed either individually, using
118 cursor set $cur propName value ?propName value ...?
120 or via a dictionary with
122 cursor set $cur dictValue
124 In the first form of the command, property names may also be preceded by a
125 -_typeName_ option. In this case, a new property of the specified type will be
126 created if it doesn't already exist; note that this will cause *all* the rows
127 in the view to have the property (but see **A NOTE ON NULL** below).
129 If the row index points after the end of the view, an appropriate number of
130 fresh rows will be inserted first. So, for example, you can use `end+1`
131 to append a new row. (Note that you then have to set it all at once, though.)
133 The total number of rows can be obtained using
137 and set manually with
139 $viewHandle resize newSize
141 For example, you can use `$viewHandle resize 0` to clear a view.
145 New rows may also be inserted at an arbitrary position in a view with
147 cursor insert $cur ?count?
149 This will insert _count_ fresh rows into the view so that _$cur_ points to
150 the first one. The inverse of this operation is
152 cursor remove $cur ?count?
156 The real power of Metakit lies in the way existing views are combined to create
157 new ones to obtain a particular perspective on the stored data. A single
158 operation takes one or more views and possibly additional options and produces a
159 new view, usually tracking notifications to the underlying views and sometimes
160 even supporting modification.
162 Binary operations are left-biased when there are conflicting property values;
163 that is, they always prefer the values from the left view.
165 ### Unary operations ###
168 : Derived view with duplicate rows removed.
170 *view* `sort` *crit ?crit ...?*
171 : Derived view sorted on the specified criteria, in order. A single _crit_
172 is either a property name or a property name preceded by a dash; the latter
173 specifies that the sorting is to be performed in reverse order.
175 ### Binary operations ###
177 The operations taking _set_ arguments require that the given views have no
178 duplicate rows. The `unique` method can be used to ensure this.
180 *view1* `concat` *view2*
181 : Vertical concatenation; that is, all the rows of _view1_ and then all rows
184 *view1* `pair` *view2*
185 : Pairing, or horizontal concatenation: every row in _view1_ is matched with
186 a row with the same index in _view2_; the result has all the properties of
187 _view1_ and all the properties of _view2_.
189 *view1* `product` *view2*
190 : Cartesian product: each row in _view1_ horizontally concatenated with every
193 *set1* `union` *set2*
194 : Set union. Unlike `concat`, this operation removes duplicates from the
195 result. A row is in the result if it is in _set1_ **or** in _set2_.
197 *set1* `intersect` *set2*
198 : Set intersection. A row is in the result if it is in _set1_ **and** in
201 *set1* `different` *set2*
202 : Symmetric difference. A row is in the result if it is in _set1_ **xor** in
203 _set2_, that is, in _set1_ or in _set2_, but not in both.
205 *set1* `minus` *set2*
206 : Set minus. A row is in the result if it is in _set1_ **and not** in _set2_.
208 ### Relational operations ###
210 *view1* `join` *view2* ?`-outer`? *prop ?prop ...?*
211 : Relational join on the specified properties: the rows from _view1_ and
212 _view2_ with all the specified properties equal are concatenated to form a
213 new row. If the `-outer` option is specified, the rows from _view1_ that do
214 not have a corresponding one in _view2_ are also left in the view, with the
215 properties existing only in _view2_ filled with default values.
217 *view* `group` *subviewName prop ?prop ...?*
218 : Groups the rows with all the specified properties equal; moves all the
219 remaining properties into a newly created subview property called
222 *view* `flatten` *subviewProp*
223 : The inverse of `group`.
225 ### Projections and selections ###
227 *view* `project` *prop ?prop ...?*
228 : Projection: a derived view with only the specified properties left.
230 *view* `without` *prop ?prop ...?*
231 : The opposite of `project`: a derived view with the specified properties
234 *view* `range` *start end ?step?*
235 A slice or a segment of _view_: rows at _start_, _start+step_, and so on,
236 until the row number becomes larger than _end_. The usual `end[+-]integer`
237 notation is supported, but the indices don't change if the underlying view
240 **(!) select etc. should go here**
242 ### Search and storage optimization ###
245 : Invokes an optimization designed for storing large amounts of data. _view_
246 must have a single subview property called `_B` with the desired structure
247 inside. This additional level of indirection is used by `blocked` to create
248 a view that looks like a usual one, but can store much more data
249 efficiently. As a result, indexing into the view becomes a bit slower. Once
250 this method is invoked, all access to _view_ must go through the returned
253 *view* `ordered` *prop ?prop ...?*
254 : Does not transform the structure of the view in any way, but signals that
255 the view should be considered ordered on a unique key consisting of the
256 specified properties, enabling some optimizations. Note that duplicate keys
257 are not allowed in an ordered view.
259 **(!) TODO: hash, indexed(?) -- these make no sense until searches are implemented**
263 Because constructs like `[[view op1 ...] op2 ...] op3 ...` tend to be common in
264 programs using Metakit, a shorthand syntax is introduced: such expressions may
265 also be written as `view op1 ... | op2 ... | op3 ...`.
267 Note though that this syntax is not in any way magically wired into the
268 interpreter: it is understood only by the view handles and the two commands that
269 can possibly return a view: `$db view` and `cursor get`. If you want to support
270 this syntax in Tcl procedures, you'll need to do this yourself, or you may want
271 to create a custom view method and have the view handle work out the syntax for
272 you (see **USER-DEFINED METHODS** below).
278 : Creates a copy of view with the same data.
281 : Creates a view with the same structure, but no data.
284 : Specifies that the view should not be destroyed after a single method call.
287 *view* `as` *varName*
288 : In addition to the actions performed by `pin`, assigns the view handle to
289 the variable named varName in the caller's scope.
292 : Returns the names of all properties in the view.
295 : Returns the type of the specified property.
299 Note that Metakit does not have a special `NULL` value like conventional
300 relational databases do. Instead, it defines _default_ property values: `""` for
301 `string` and `binary` types, `0` for all numeric types and a view with no rows
302 for subviews. These defaults are used when a fresh row is inserted and when
303 a new property is added to the view to fill in the missing values.
307 The storage and view handles support custom methods defined in Tcl: to define
308 _methodName_ on every storage or view handle, create a procedure called
309 {`mk.storage` *methodName*} or {`mk.view` *methodName*} respectively. These
310 procedures will receive the handle as the first argument and all the remaining
311 arguments. Remember to `pin` the view handle in view methods if you call more
312 than one method of it!
314 Custom `cursor` subcommands may also be defined by creating a procedure called
315 {`cursor` *methodName*}. These receive all the arguments without any