OGRE - Open Generic Representation.

OGRE is a self-describing data storage. It is open for extensibility, i.e., adding new types of knowledge doesn't break the storage. It also has a well-specified open representation, so that any tool written in any language (or even a human itself) can create, modify and understand the contents (like XML). Ogre provides data persitance and, more importantly, a type safe way of querying and updating the data. The query language is rich enough, and supports joins and boolean constraints

It can be seen as a document NoSQL database engine. As a backing storage Ogre uses S-Expressions, and the structure of a document is close to JSON. In fact it is a restricted subset of JSON, where only scalar values are allowed.

A database, called a "document" (or just "doc") in Ogre parlance, is a set of facts. Each fact is described with a proposition having the following syntax,

(<attribute-name> <v1> <v2> ... <vM> )

where `<attribute-name>`

is a name of a proposition and `<vN>`

is the value of `N`

'th object (or subject) of a proposition. For example,

(student (name Joe) (gpa 3.5))

is a proposition that a student named `Joe`

has a GPA rate `3.5`

. Thus a proposition is a tuple with named fields. All propositions must be well-typed, so the predicate `student`

should be declared before used. The field values maybe stored (and are by default) without the names in the order in which they are specified in the declaration, e.g., the following definition is equivalent to the previous one:

(student Joe 3.5)

Given, that the predicate is declared as:

(declare student (name str) (gpa float))

where the declaration has the following syntax:

declaration ::= ( declare <attribute-name> <field> <field> ... )
field ::= ( <field-name> <field-type> )
field-type ::= int | str | bool | float

Each declaration declare an attribute, that defines a type of the propositions. Unlike the SQL, we denote each tuple type with the word attribute, as under our model each document describes some knowledge (an attribute) about some abstract entity. For example, a document "college.ogre" that contains definitions of attributes named `student`

, `teacher`

, `class`

, `assignments`

is a set of knowledge about a college. Thus an attribute maps to a SQL notion of table (or a relvar). Correspondingly, a column of a table (that is usually referred as an attribute in the relational model), maps to Ogre's field.

`type ('a, 'k) typeinfo constraint 'k = _ -> _`

type information associated with an attribute

`type ('a, 'k) attribute = unit -> ('a, 'k) typeinfo`

a descriptor of an attribute.

Used to construct attribute values, and to query documents. Created with `declare`

function.

Note, that due to a value restriction, an attribute should be defined as a function returning a type information.

`t field`

a descriptor of an attribute field.

Used to construct attributes, and to construct variables that reference particular fields of an attribute.

the type variable `t`

range is `float`

, `int64`

, `string`

or `bool`

.

`attrs query`

constructs a query type.

Created using the `Query`

module. The `attrs`

type variable encodes the types of requested attributes. For example,

`((student -> teacher -> 'a) -> 'a) query`

represents a query for two attributes of type `student`

and `teacher`

correspondingly. It is represented as a continuation, denoting the fact, that the query can be executed later for an arbitrary result.

`type ('f, 'k) scheme constraint 'f = _ -> _ constraint 'k = _ -> _`

type that describes an attribute.

The two type variables describe the constructor and destructor interface. The `'a`

variable, the accessor, describes how an attribute can be constructed. The `'s`

variable, describes how an attribute can be packed in the database. These two types come along and differ only in a return type. The general form of a type variable is `('a -> 'r) -> 'r`

, where `'r`

is the return type (a type of attribute for instance), and `'a`

variable is extended every time a new field is added to a scheme.

`val declare : name:string -> ('f -> 'a, 'k) scheme -> 'f -> ('a, 'k) typeinfo`

`let attr () = declare ~name scheme`

declares an attribute named with `name`

, and having a type described by the `scheme`

.

Due to a value restriction, each attribute should be defined as a thunk (a function).

`module Type : sig ... end`

`module Query : sig ... end`

Domain specific language for constructing queries.

`module type S = sig ... end`

Monadic interface to the document.

`Make(M)`

returns an Ogre monad implementation wrapped in a monad `M`

.

Default implementation of the Orge monad, that is not wrapped into any other monads (in other words, that is wrapped into the identity)

```
include S
with type 'a m = 'a
and type 'a t = 'a Make(Monads.Std.Monad.Ident).t
and type 'a e = doc -> ('a * doc) Core_kernel.Or_error.t
```

`include Monads.Std.Monad.S with type 'a t = 'a Make(Monads.Std.Monad.Ident).t`

`val void : 'a t -> unit t`

`void m`

computes `m`

and discrards the result.

`val sequence : unit t list -> unit t`

`sequence xs`

computes a sequence of computations `xs`

in the left to right order.

`val forever : 'a t -> 'b t`

`forever xs`

creates a computationt that never returns.

Various function combinators lifted into the Kleisli category.

`module Pair : sig ... end`

The pair interface lifted into the monad.

The triple interface lifted into a monad.

`module Lift : sig ... end`

Lifts functions into the monad.

Interacting between monads and language exceptions

Lifts collection interface into the monad.

The Monad.Collection.S interface for lists

The Monad.Collection.S interface for sequences

`include Monads.Std.Monad.Syntax.S with type 'a t := 'a t`

`val (>=>) : ('a -> 'b t) -> ('b -> 'c t) -> 'a -> 'c t`

`f >=> g`

is `fun x -> f x >>= g`

`val (!$) : ('a -> 'b) -> 'a t -> 'b t`

`val (!$$) : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c t`

`val (!$$$) : ('a -> 'b -> 'c -> 'd) -> 'a t -> 'b t -> 'c t -> 'd t`

```
val (!$$$$) :
('a -> 'b -> 'c -> 'd -> 'e) ->
'a t ->
'b t ->
'c t ->
'd t ->
'e t
```

`!$$$$f`

is `Lift.quaternary f`

```
val (!$$$$$) :
('a -> 'b -> 'c -> 'd -> 'e -> 'f) ->
'a t ->
'b t ->
'c t ->
'd t ->
'e t ->
'f t
```

`!$$$$$f`

is `Lift.quinary f`

`include Core_kernel.Monad.S with type 'a t := 'a t`

`val (>>=) : 'a t -> ('a -> 'b t) -> 'b t`

`t >>= f`

returns a computation that sequences the computations represented by two monad elements. The resulting computation first does `t`

to yield a value `v`

, and then runs the computation returned by `f v`

.

`val (>>|) : 'a t -> ('a -> 'b) -> 'b t`

`t >>| f`

is `t >>= (fun a -> return (f a))`

.

`val bind : 'a t -> f:('a -> 'b t) -> 'b t`

`return v`

returns the (trivial) computation that returns v.

`val map : 'a t -> f:('a -> 'b) -> 'b t`

`val join : 'a t t -> 'a t`

`join t`

is `t >>= (fun t' -> t')`

.

`val ignore_m : 'a t -> unit t`

`ignore_m t`

is `map t ~f:(fun _ -> ())`

. `ignore_m`

used to be called `ignore`

, but we decided that was a bad name, because it shadowed the widely used `Caml.ignore`

. Some monads still do `let ignore = ignore_m`

for historical reasons.

`val all : 'a t list -> 'a list t`

`val all_unit : unit t list -> unit t`

Like `all`

, but ensures that every monadic value in the list produces a unit value, all of which are discarded rather than being collected into a list.

`val all_ignore : unit t list -> unit t`

These are convenient to have in scope when programming with a monad:

Monadic operators, see Monad.Syntax.S for more.

`val require : ?that:('a -> bool) -> ('a, _) attribute -> 'a t`

`require a ~that:p`

requires that an attribute `a`

has one and only one value that satisfies a predicate `p`

. It is an error, if there are no such values, or if there are more than one value.

`val request : ?that:('a -> bool) -> ('a, _) attribute -> 'a option t`

`request a ~that:p`

request no more than one value of an attribute `a`

, that satisfies a predicate `p`

. The returned value is wrapped in an option. If there are more than one satisfying value, then it is an error.

`val foreach : ('a -> 'b) query -> f:'a -> 'b seq t`

`foreach query ~f:action`

applies an `action`

for each value of an attributes specified in the query. The `query`

value is built using a domain specific language embedded into OCaml. This language is very similar to SQL, and has join and where clauses, e.g.,

```
let better_than_average_students =
foreach Query.(begin
select
~where:(students.(gpa) > float 3.5)
~join:[
[field classid];
[
field teacher ~from:students;
field id ~from:teachers
]]
(from students $ teachers)
end)
~f:(fun s t -> return (s,t))
```

The type of the `query`

value encodes the type of the function `f`

. A well formed query has a type of form `(t1 -> t2 -> .. -> tm -> 'a t) -> 'a t`

, where `t1`

till `tm`

are types of attributes enumerated in the `from clause`

(in that particular order).

See the `Query`

module documentation for more information about the query EDSL.

`val collect : (('a -> 'a) -> 'b) query -> 'b seq t`

`collect query`

is the same as `foreach query ~f:ident`

`provide attr v1 v2 ... vm`

stores the constituents of an attribute value in the document. An attribute type encodes not only the type of an attribute value, but also a type and the order of the fields. Thus, the `attribute`

itself captures a format of the attribute representation, the same as `format`

is used in printf-like functions. In that sense, the `provide`

function is variadic, where the first argument (the attribute) defines the type and the arity of the function.

`fail error`

aborts an inference process with the specified `error`

.

`failf fmt args... ()`

constructs an error based on the specified format `fmt`

and arguments, terminated by the unit value `()`

. Example:

`failf "the file type %s is unsupported" name ()`

Note: don't forget to terminate a sequence of arguments with an extra unit value. See the corresponding `invalid_argf`

and `failwithf`

function for the reason, why this extra argument is needed.

`eval property document`

makes an inference of a `property`

based on facts stored in a `document`

. If all requirements are satisfied and no errors occurred the inferred result.

For example, given the property `names_of_best_students`

, defined as,

```
let names_of_best_students =
foreach Query.(select (from students)
~where:(students.(gpa) > float 3.8))
~f:(fun s -> return (Student.name s))
```

we can evaluate this property, with

`eval names_of_best_students`

to get a sequence (possibly empty) of all students that have the GPA score greater than 3.8.

`exec op doc`

executes an operation `op`

that, presumably, updates the document `doc`

, returns an updated version.

`run op doc`

runs an operation `op`

that does some inference as well as may update the document. This function is a usual part of a generic state monad interface, and is provided for the consistency. Usually, it is a bad idea, or a notion of a bad style to use this function.