aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/algebra.ml363
-rw-r--r--lib/attribute.ml10
-rw-r--r--lib/conventions.ml15
-rw-r--r--lib/core_functions.ml1
-rw-r--r--lib/dbms_language.ml42
-rw-r--r--lib/dcl/ast.ml6
-rw-r--r--lib/dcl/executor.ml160
-rw-r--r--lib/dcl/parser.ml14
-rw-r--r--lib/dcl/sublanguage.ml8
-rw-r--r--lib/ddl/ast.ml4
-rw-r--r--lib/ddl/executor.ml82
-rw-r--r--lib/ddl/parser.ml7
-rw-r--r--lib/ddl/sublanguage.ml8
-rw-r--r--lib/dml/ast.ml15
-rw-r--r--lib/dml/executor.ml156
-rw-r--r--lib/dml/parser.ml7
-rw-r--r--lib/dml/sublanguage.ml8
-rw-r--r--lib/drl/ast.ml36
-rw-r--r--lib/drl/executor.ml100
-rw-r--r--lib/drl/gate.ml81
-rw-r--r--lib/drl/parser.ml7
-rw-r--r--lib/drl/sublanguage.ml16
-rw-r--r--lib/drl_verified/drl_verified.ml99
-rw-r--r--lib/drl_verified/drl_verified.mli28
-rw-r--r--lib/dune1
-rw-r--r--lib/envelope.ml15
-rw-r--r--lib/generator.ml4
-rw-r--r--lib/hashing.ml37
-rw-r--r--lib/icl/ast.ml14
-rw-r--r--lib/icl/parser.ml7
-rw-r--r--lib/icl/sublanguage.ml8
-rw-r--r--lib/interop.ml3
-rw-r--r--lib/management/branch.ml99
-rw-r--r--lib/management/merge.ml435
-rw-r--r--lib/management/physical.ml135
-rw-r--r--lib/merkle.ml41
-rw-r--r--lib/prelude/catalog.ml135
-rw-r--r--lib/prelude/domains.ml105
-rw-r--r--lib/prelude/standard.ml332
-rw-r--r--lib/relation.ml4
-rw-r--r--lib/schema.ml15
-rw-r--r--lib/scl/executor.ml84
-rw-r--r--lib/scl/sublanguage.ml13
-rw-r--r--lib/session.ml89
-rw-r--r--lib/storable.ml35
-rw-r--r--lib/sublanguage.ml26
-rw-r--r--lib/tuple.ml23
47 files changed, 1483 insertions, 1450 deletions
diff --git a/lib/algebra.ml b/lib/algebra.ml
index a1970bd..30ed1a6 100644
--- a/lib/algebra.ml
+++ b/lib/algebra.ml
@@ -1,39 +1,40 @@
-type error =
- | StorageError of string
- | GeneratorError of string
+type error = StorageError of string | GeneratorError of string
+
+module Make (Storage : Management.Physical.S) = struct
+ module Ops = Manipulation.Make (Storage)
-module Make(Storage : Management.Physical.S) = struct
- module Ops = Manipulation.Make(Storage)
type storage = Storage.t
(* Internal generator utilities *)
let rec list_generator : Tuple.t list -> Generator.t = function
- | [] -> (fun _pos -> Generator.Done)
- | t :: rest -> (fun _pos -> Generator.Value (t, list_generator rest))
+ | [] -> fun _pos -> Generator.Done
+ | t :: rest -> fun _pos -> Generator.Value (t, list_generator rest)
let drain gen =
let rec go gen pos acc =
match gen (Some pos) with
- | Generator.Done -> Ok (List.rev acc)
- | Generator.Error e -> Error (GeneratorError e)
+ | Generator.Done -> Ok (List.rev acc)
+ | Generator.Error e -> Error (GeneratorError e)
| Generator.Value (t, next) -> go next (pos + 1) (t :: acc)
- in go gen 0 []
+ in
+ go gen 0 []
let to_generator (storage : storage) (rel : Relation.t) : Generator.t =
match rel.Relation.generator with
| Some gen -> gen
- | None ->
- (* TODO: Avoid materializing all tuple hashes/tuples at once.
+ | None -> (
+ (* TODO: Avoid materializing all tuple hashes/tuples at once.
Current implementation calls tuple_hashes rel which loads all hashes
into memory, then load_tuples which loads all tuples. This defeats
lazy evaluation and scales badly (fails for billions of tuples).
Replace with paginated tuple_hashes or Merkle streaming to load
hashes/tuples on demand in chunks. *)
- let hashes = Ops.tuple_hashes rel in
- (match Ops.load_tuples storage hashes with
- | Error _ -> (fun _pos -> Generator.Error ("Failed to load: " ^ rel.Relation.name))
- | Ok ts -> list_generator (List.map (fun t -> Tuple.Materialized t) ts))
+ let hashes = Ops.tuple_hashes rel in
+ match Ops.load_tuples storage hashes with
+ | Error _ ->
+ fun _pos -> Generator.Error ("Failed to load: " ^ rel.Relation.name)
+ | Ok ts -> list_generator (List.map (fun t -> Tuple.Materialized t) ts))
let of_generator ~name ~schema ?constraints ?cardinality gen =
let cardinality =
@@ -41,22 +42,24 @@ module Make(Storage : Management.Physical.S) = struct
| Some c -> c
| None -> Conventions.Cardinality.AlephZero
in
- Relation.make
- ~hash:None ~name ~schema ~tree:None ~constraints
- ~cardinality
+ Relation.make ~hash:None ~name ~schema ~tree:None ~constraints ~cardinality
~generator:(Some gen)
~membership_criteria:(fun _ -> true)
~provenance:Relation.Provenance.Undefined
~lineage:(Relation.Lineage.Base "derived")
- let const_relation (pairs : (string * Conventions.AbstractValue.t) list) : Relation.t =
- let attrs = List.fold_left (fun acc (k, v) ->
- Tuple.AttributeMap.add k { Attribute.value = v } acc)
- Tuple.AttributeMap.empty pairs
+ let const_relation (pairs : (string * Conventions.AbstractValue.t) list) :
+ Relation.t =
+ let attrs =
+ List.fold_left
+ (fun acc (k, v) -> Tuple.AttributeMap.add k { Attribute.value = v } acc)
+ Tuple.AttributeMap.empty pairs
+ in
+ let tuple =
+ Tuple.Materialized { Tuple.relation = "const"; attributes = attrs }
in
- let tuple = Tuple.Materialized { Tuple.relation = "const"; attributes = attrs } in
let schema = List.map (fun (k, _) -> (k, "abstract")) pairs in
- of_generator ~name:"const" ~schema (list_generator [tuple])
+ of_generator ~name:"const" ~schema (list_generator [ tuple ])
(* Operators *)
@@ -65,141 +68,181 @@ module Make(Storage : Management.Physical.S) = struct
let lazy_gen =
let rec go g pos =
match g pos with
- | Generator.Done -> Generator.Done
+ | Generator.Done -> Generator.Done
| Generator.Error e -> Generator.Error e
| Generator.Value (t, next) ->
- if predicate t then Generator.Value (t, go next)
- else go next (Option.map ((+) 1) pos)
- in fun pos -> go gen pos
+ if predicate t then Generator.Value (t, go next)
+ else go next (Option.map (( + ) 1) pos)
+ in
+ fun pos -> go gen pos
in
- Ok (of_generator ~name:("σ_" ^ rel.Relation.name) ~schema:rel.Relation.schema
- ?constraints:rel.Relation.constraints lazy_gen)
+ Ok
+ (of_generator
+ ~name:("σ_" ^ rel.Relation.name)
+ ~schema:rel.Relation.schema ?constraints:rel.Relation.constraints
+ lazy_gen)
let project storage (attrs : string list) rel =
let gen = to_generator storage rel in
let project_tuple = function
| Tuple.Materialized t ->
- let attrs' = List.fold_left (fun acc k ->
- match Tuple.AttributeMap.find_opt k t.Tuple.attributes with
- | None -> acc
- | Some v -> Tuple.AttributeMap.add k v acc)
- Tuple.AttributeMap.empty attrs in
- Tuple.Materialized { t with attributes = attrs' }
+ let attrs' =
+ List.fold_left
+ (fun acc k ->
+ match Tuple.AttributeMap.find_opt k t.Tuple.attributes with
+ | None -> acc
+ | Some v -> Tuple.AttributeMap.add k v acc)
+ Tuple.AttributeMap.empty attrs
+ in
+ Tuple.Materialized { t with attributes = attrs' }
| other -> other
in
- let new_schema = List.filter (fun (n, _) -> List.mem n attrs) rel.Relation.schema in
+ let new_schema =
+ List.filter (fun (n, _) -> List.mem n attrs) rel.Relation.schema
+ in
let lazy_gen =
- let rec go g pos = match g pos with
- | Generator.Done -> Generator.Done
+ let rec go g pos =
+ match g pos with
+ | Generator.Done -> Generator.Done
| Generator.Error e -> Generator.Error e
| Generator.Value (t, next) -> Generator.Value (project_tuple t, go next)
- in fun pos -> go gen pos
+ in
+ fun pos -> go gen pos
in
let filtered_constraints =
match rel.Relation.constraints with
| None | Some [] -> None
- | Some cs ->
- let kept =
- List.filter_map
- (fun (name, c) ->
- match Constraint.filter_by_attrs attrs c with
- | Some c' -> Some (name, c')
- | None -> None)
- cs
- in
- (match kept with [] -> None | _ -> Some kept)
+ | Some cs -> (
+ let kept =
+ List.filter_map
+ (fun (name, c) ->
+ match Constraint.filter_by_attrs attrs c with
+ | Some c' -> Some (name, c')
+ | None -> None)
+ cs
+ in
+ match kept with [] -> None | _ -> Some kept)
in
- Ok (of_generator ~name:("π_" ^ rel.Relation.name) ~schema:new_schema
- ?constraints:filtered_constraints lazy_gen)
+ Ok
+ (of_generator
+ ~name:("π_" ^ rel.Relation.name)
+ ~schema:new_schema ?constraints:filtered_constraints lazy_gen)
let rename storage (renames : (string * string) list) rel =
- let rename_key k = match List.assoc_opt k renames with Some k' -> k' | None -> k in
+ let rename_key k =
+ match List.assoc_opt k renames with Some k' -> k' | None -> k
+ in
let rename_tuple = function
| Tuple.Materialized t ->
- let attrs' = Tuple.AttributeMap.fold (fun k v acc ->
- Tuple.AttributeMap.add (rename_key k) v acc)
- t.Tuple.attributes Tuple.AttributeMap.empty in
- Tuple.Materialized { t with attributes = attrs' }
+ let attrs' =
+ Tuple.AttributeMap.fold
+ (fun k v acc -> Tuple.AttributeMap.add (rename_key k) v acc)
+ t.Tuple.attributes Tuple.AttributeMap.empty
+ in
+ Tuple.Materialized { t with attributes = attrs' }
| other -> other
in
let gen = to_generator storage rel in
- let new_schema = List.map (fun (n, d) -> (rename_key n, d)) rel.Relation.schema in
+ let new_schema =
+ List.map (fun (n, d) -> (rename_key n, d)) rel.Relation.schema
+ in
let lazy_gen =
- let rec go g pos = match g pos with
- | Generator.Done -> Generator.Done
+ let rec go g pos =
+ match g pos with
+ | Generator.Done -> Generator.Done
| Generator.Error e -> Generator.Error e
| Generator.Value (t, next) -> Generator.Value (rename_tuple t, go next)
- in fun pos -> go gen pos
+ in
+ fun pos -> go gen pos
in
let renamed_constraints =
match rel.Relation.constraints with
| None | Some [] -> None
| Some cs ->
- Some
- (List.map
- (fun (name, c) -> (name, Constraint.rename_vars renames c))
- cs)
+ Some
+ (List.map
+ (fun (name, c) -> (name, Constraint.rename_vars renames c))
+ cs)
in
- Ok (of_generator ~name:("ρ_" ^ rel.Relation.name) ~schema:new_schema
- ?constraints:renamed_constraints lazy_gen)
+ Ok
+ (of_generator
+ ~name:("ρ_" ^ rel.Relation.name)
+ ~schema:new_schema ?constraints:renamed_constraints lazy_gen)
let equijoin storage (attrs : string list) left right =
let right_gen = to_generator storage right in
match drain right_gen with
| Error e -> Error e
| Ok right_tuples ->
- let left_gen = to_generator storage left in
- let get_vals attr_list = function
- | Tuple.Materialized t ->
- List.map (fun a -> Tuple.AttributeMap.find_opt a t.Tuple.attributes) attr_list
- | _ -> List.map (fun _ -> None) attr_list
- in
- let merge lt rt = match lt, rt with
- | Tuple.Materialized l, Tuple.Materialized r ->
- Tuple.Materialized { l with attributes =
- Tuple.AttributeMap.union (fun _ a _ -> Some a)
- l.Tuple.attributes r.Tuple.attributes }
- | _ -> lt
- in
- let merged_schema =
- left.Relation.schema @
- List.filter (fun (n, _) ->
- not (List.mem n attrs) &&
- not (List.exists (fun (m, _) -> m = n) left.Relation.schema))
- right.Relation.schema
- in
- let join_gen =
- let rec chain_with_cont g cont pos =
- match g pos with
- | Generator.Done -> cont pos
- | Generator.Value (t, next) -> Generator.Value (t, fun p -> chain_with_cont next cont p)
- | Generator.Error e -> Generator.Error e
+ let left_gen = to_generator storage left in
+ let get_vals attr_list = function
+ | Tuple.Materialized t ->
+ List.map
+ (fun a -> Tuple.AttributeMap.find_opt a t.Tuple.attributes)
+ attr_list
+ | _ -> List.map (fun _ -> None) attr_list
in
- let rec from_left lgen lpos =
- fun pos ->
- match lgen (Some lpos) with
- | Generator.Done -> Generator.Done
- | Generator.Error e -> Generator.Error e
- | Generator.Value (lt, next_left) ->
- let lv = get_vals attrs lt in
- let matches = List.filter_map (fun rt ->
- if get_vals attrs rt = lv then Some (merge lt rt) else None) right_tuples in
- (match matches with
- | [] -> from_left next_left (lpos + 1) pos
- | _ ->
- chain_with_cont (list_generator matches)
- (from_left next_left (lpos + 1)) pos)
+ let merge lt rt =
+ match (lt, rt) with
+ | Tuple.Materialized l, Tuple.Materialized r ->
+ Tuple.Materialized
+ {
+ l with
+ attributes =
+ Tuple.AttributeMap.union
+ (fun _ a _ -> Some a)
+ l.Tuple.attributes r.Tuple.attributes;
+ }
+ | _ -> lt
in
- from_left left_gen 0
- in
- let merged_constraints =
- match left.Relation.constraints, right.Relation.constraints with
- | None, None -> None
- | Some cs, None | None, Some cs -> Some cs
- | Some cs1, Some cs2 -> Some (Constraint.merge cs1 cs2)
- in
- let name = "⋈_" ^ left.Relation.name ^ "_" ^ right.Relation.name in
- Ok (of_generator ~name ~schema:merged_schema
+ let merged_schema =
+ left.Relation.schema
+ @ List.filter
+ (fun (n, _) ->
+ (not (List.mem n attrs))
+ && not (List.exists (fun (m, _) -> m = n) left.Relation.schema))
+ right.Relation.schema
+ in
+ let join_gen =
+ let rec chain_with_cont g cont pos =
+ match g pos with
+ | Generator.Done -> cont pos
+ | Generator.Value (t, next) ->
+ Generator.Value (t, fun p -> chain_with_cont next cont p)
+ | Generator.Error e -> Generator.Error e
+ in
+ let rec from_left lgen lpos =
+ fun pos ->
+ match lgen (Some lpos) with
+ | Generator.Done -> Generator.Done
+ | Generator.Error e -> Generator.Error e
+ | Generator.Value (lt, next_left) -> (
+ let lv = get_vals attrs lt in
+ let matches =
+ List.filter_map
+ (fun rt ->
+ if get_vals attrs rt = lv then Some (merge lt rt)
+ else None)
+ right_tuples
+ in
+ match matches with
+ | [] -> from_left next_left (lpos + 1) pos
+ | _ ->
+ chain_with_cont (list_generator matches)
+ (from_left next_left (lpos + 1))
+ pos)
+ in
+ from_left left_gen 0
+ in
+ let merged_constraints =
+ match (left.Relation.constraints, right.Relation.constraints) with
+ | None, None -> None
+ | Some cs, None | None, Some cs -> Some cs
+ | Some cs1, Some cs2 -> Some (Constraint.merge cs1 cs2)
+ in
+ let name = "⋈_" ^ left.Relation.name ^ "_" ^ right.Relation.name in
+ Ok
+ (of_generator ~name ~schema:merged_schema
?constraints:merged_constraints join_gen)
let union storage rel1 rel2 =
@@ -208,47 +251,55 @@ module Make(Storage : Management.Physical.S) = struct
let chain_gen =
let rec go g1 g2 pos =
match g1 pos with
- | Generator.Done -> g2 pos
+ | Generator.Done -> g2 pos
| Generator.Error _ -> g2 pos
| Generator.Value (t, next) -> Generator.Value (t, fun p -> go next g2 p)
- in fun pos -> go gen1 gen2 pos
+ in
+ fun pos -> go gen1 gen2 pos
in
let name = "∪_" ^ rel1.Relation.name ^ "_" ^ rel2.Relation.name in
(* Conservative: drop constraints since they only hold if both inputs agree *)
Ok (of_generator ~name ~schema:rel1.Relation.schema chain_gen)
- let attrs_equal
- (m1 : Attribute.materialized Tuple.AttributeMap.t)
+ let attrs_equal (m1 : Attribute.materialized Tuple.AttributeMap.t)
(m2 : Attribute.materialized Tuple.AttributeMap.t) =
Tuple.AttributeMap.equal
- (fun a b -> Stdlib.(=) a.Attribute.value b.Attribute.value) m1 m2
+ (fun a b -> Stdlib.( = ) a.Attribute.value b.Attribute.value)
+ m1 m2
let diff storage rel1 rel2 =
let right_gen = to_generator storage rel2 in
match drain right_gen with
| Error e -> Error e
| Ok right_tuples ->
- let right_mats = List.filter_map (function
- | Tuple.Materialized t -> Some t | _ -> None) right_tuples in
- let left_gen = to_generator storage rel1 in
- let not_in_right = function
- | Tuple.Materialized t ->
- not (List.exists (fun r ->
- attrs_equal t.Tuple.attributes r.Tuple.attributes) right_mats)
- | _ -> true
- in
- let lazy_gen =
- let rec go g pos =
- match g pos with
- | Generator.Done -> Generator.Done
- | Generator.Error e -> Generator.Error e
- | Generator.Value (t, next) ->
- if not_in_right t then Generator.Value (t, go next)
- else go next (Option.map ((+) 1) pos)
- in fun pos -> go left_gen pos
- in
- let name = "−_" ^ rel1.Relation.name ^ "_" ^ rel2.Relation.name in
- Ok (of_generator ~name ~schema:rel1.Relation.schema
+ let right_mats =
+ List.filter_map
+ (function Tuple.Materialized t -> Some t | _ -> None)
+ right_tuples
+ in
+ let left_gen = to_generator storage rel1 in
+ let not_in_right = function
+ | Tuple.Materialized t ->
+ not
+ (List.exists
+ (fun r -> attrs_equal t.Tuple.attributes r.Tuple.attributes)
+ right_mats)
+ | _ -> true
+ in
+ let lazy_gen =
+ let rec go g pos =
+ match g pos with
+ | Generator.Done -> Generator.Done
+ | Generator.Error e -> Generator.Error e
+ | Generator.Value (t, next) ->
+ if not_in_right t then Generator.Value (t, go next)
+ else go next (Option.map (( + ) 1) pos)
+ in
+ fun pos -> go left_gen pos
+ in
+ let name = "−_" ^ rel1.Relation.name ^ "_" ^ rel2.Relation.name in
+ Ok
+ (of_generator ~name ~schema:rel1.Relation.schema
?constraints:rel1.Relation.constraints lazy_gen)
let take storage n rel =
@@ -256,22 +307,28 @@ module Make(Storage : Management.Physical.S) = struct
let lazy_gen =
let rec go g count pos =
if count = 0 then Generator.Done
- else match g pos with
- | Generator.Done -> Generator.Done
+ else
+ match g pos with
+ | Generator.Done -> Generator.Done
| Generator.Error e -> Generator.Error e
| Generator.Value (t, next) -> Generator.Value (t, go next (count - 1))
- in fun pos -> go gen n pos
+ in
+ fun pos -> go gen n pos
in
- Ok (of_generator ~name:("τ_" ^ rel.Relation.name) ~schema:rel.Relation.schema
- ?constraints:rel.Relation.constraints
- ~cardinality:(Conventions.Cardinality.Finite n) lazy_gen)
+ Ok
+ (of_generator
+ ~name:("τ_" ^ rel.Relation.name)
+ ~schema:rel.Relation.schema ?constraints:rel.Relation.constraints
+ ~cardinality:(Conventions.Cardinality.Finite n) lazy_gen)
let materialize storage rel : (Tuple.materialized list, error) Result.t =
match drain (to_generator storage rel) with
| Error e -> Error e
| Ok tuples ->
- Ok (List.filter_map (function Tuple.Materialized t -> Some t | _ -> None) tuples)
-
+ Ok
+ (List.filter_map
+ (function Tuple.Materialized t -> Some t | _ -> None)
+ tuples)
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/attribute.ml b/lib/attribute.ml
index f3fc0b1..b828d64 100644
--- a/lib/attribute.ml
+++ b/lib/attribute.ml
@@ -1,15 +1,11 @@
type referenced = { value_hash : Conventions.Hash.t } [@@deriving sexp_of]
+type materialized = { value : Conventions.AbstractValue.t } [@@deriving sexp_of]
-type materialized = { value: Conventions.AbstractValue.t } [@@deriving sexp_of]
-
-type t =
- | Referenced of referenced
- | Materialized of materialized
+type t = Referenced of referenced | Materialized of materialized
[@@deriving sexp_of]
let make_referenced ~value =
let value_hash = Conventions.AbstractValue.hash value in
Referenced { value_hash }
-let make_materialized ~value =
- Materialized { value } \ No newline at end of file
+let make_materialized ~value = Materialized { value }
diff --git a/lib/conventions.ml b/lib/conventions.ml
index 60069b0..b6f82a5 100644
--- a/lib/conventions.ml
+++ b/lib/conventions.ml
@@ -1,5 +1,6 @@
module Hash = struct
type t = Interop.Sha256.t
+
let hash_text text = Interop.Sha256.compute_hash (Bytes.of_string text)
let compare = String.compare
let sexp_of_t = Sexplib.Std.sexp_of_string
@@ -7,21 +8,25 @@ end
module Name = struct
type t = string
+
let sexp_of_t = Sexplib.Std.sexp_of_string
end
module Cardinality = struct
type t = Finite of int | ConstrainedFinite | AlephZero | Continuum
+
let sexp_of_t = function
- | Finite n -> Sexplib.Sexp.(List [Atom "Finite"; Atom (string_of_int n)])
+ | Finite n -> Sexplib.Sexp.(List [ Atom "Finite"; Atom (string_of_int n) ])
| ConstrainedFinite -> Sexplib.Sexp.Atom "ConstrainedFinite"
- | AlephZero -> Sexplib.Sexp.Atom "AlephZero"
- | Continuum -> Sexplib.Sexp.Atom "Continuum"
+ | AlephZero -> Sexplib.Sexp.Atom "AlephZero"
+ | Continuum -> Sexplib.Sexp.Atom "Continuum"
end
module AbstractValue = struct
type t = Obj.t
- let hash (elem: t) = Interop.Sha256.compute_hash @@ Marshal.to_bytes elem []
+
+ let hash (elem : t) = Interop.Sha256.compute_hash @@ Marshal.to_bytes elem []
+
let sexp_of_t (v : t) =
let open Sexplib.Sexp in
if Obj.is_int v then Atom (string_of_int (Obj.obj v : int))
@@ -33,4 +38,4 @@ module AbstractValue = struct
if Float.is_nan f || Float.is_infinite f then Atom "nan"
else Atom (string_of_float f)
else Atom "<opaque>"
-end \ No newline at end of file
+end
diff --git a/lib/core_functions.ml b/lib/core_functions.ml
index 39094cc..9cb6213 100644
--- a/lib/core_functions.ml
+++ b/lib/core_functions.ml
@@ -20,5 +20,4 @@ module Functions (F : Ctypes.FOREIGN) = struct
let compute_hash =
Foreign.foreign ~from:libmerklecpp "compute_hash"
(ptr char @-> Ctypes.string @-> returning void)
-
end
diff --git a/lib/dbms_language.ml b/lib/dbms_language.ml
index 8d61aa3..47e5a99 100644
--- a/lib/dbms_language.ml
+++ b/lib/dbms_language.ml
@@ -1,39 +1,37 @@
(** Composable dispatch over sublanguages.
- All commands must use the tagged envelope format: (tag payload)
- where [tag] is the sublanguage name (drl, dml, ddl, icl, dcl, ...).
- Adding a new sublanguage is just extending the list passed to [create]. *)
+ All commands must use the tagged envelope format: (tag payload) where [tag]
+ is the sublanguage name (drl, dml, ddl, icl, dcl, ...). Adding a new
+ sublanguage is just extending the list passed to [create]. *)
module Make (Storage : Management.Physical.S with type error = string) = struct
module type SubS = Sublanguage.S with type storage = Storage.t
type dispatch_error = NoMatch of Sexplib.Sexp.t
-
type dispatch = (module SubS) list
let create (langs : (module SubS) list) : dispatch = langs
- let execute
- (langs : dispatch)
- (storage : Storage.t)
- (db : Management.Database.t)
- (input : string)
- : (Sublanguage.result, dispatch_error) Result.t =
- let no_match s = Error (NoMatch Sexplib.Sexp.(List [Atom "parse-error"; Atom s])) in
+ let execute (langs : dispatch) (storage : Storage.t)
+ (db : Management.Database.t) (input : string) :
+ (Sublanguage.result, dispatch_error) Result.t =
+ let no_match s =
+ Error (NoMatch Sexplib.Sexp.(List [ Atom "parse-error"; Atom s ]))
+ in
match Envelope.parse input with
| Error msg -> no_match msg
- | Ok { tag; payload } ->
- match List.find_opt (fun (module L : SubS) -> L.name = tag) langs with
- | None -> no_match ("unknown sublanguage: " ^ tag)
- | Some (module L) ->
- match L.parse_sexp payload with
- | Error e -> Error (NoMatch (L.sexp_of_error e))
- | Ok ast ->
- match L.execute storage db ast with
- | Ok result -> Ok result
- | Error e -> Error (NoMatch (L.sexp_of_error e))
+ | Ok { tag; payload } -> (
+ match List.find_opt (fun (module L : SubS) -> L.name = tag) langs with
+ | None -> no_match ("unknown sublanguage: " ^ tag)
+ | Some (module L) -> (
+ match L.parse_sexp payload with
+ | Error e -> Error (NoMatch (L.sexp_of_error e))
+ | Ok ast -> (
+ match L.execute storage db ast with
+ | Ok result -> Ok result
+ | Error e -> Error (NoMatch (L.sexp_of_error e)))))
let sexp_of_dispatch_error (NoMatch sexp) = sexp
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/dcl/ast.ml b/lib/dcl/ast.ml
index e1dae13..0b6107f 100644
--- a/lib/dcl/ast.ml
+++ b/lib/dcl/ast.ml
@@ -4,10 +4,10 @@ type merge_strategy = PreferLeft | PreferRight | RevertToAncestor
[@@deriving sexp]
type statement =
- | CreateBranch of { name: string; hash: string option [@sexp.option] }
+ | CreateBranch of { name : string; hash : string option [@sexp.option] }
| Checkout of string
| GetHead
| GetBranchTip of string
- | UpdateBranchTip of { name: string; hash: string }
- | Merge of { left: string; right: string; strategy: merge_strategy }
+ | UpdateBranchTip of { name : string; hash : string }
+ | Merge of { left : string; right : string; strategy : merge_strategy }
[@@deriving sexp]
diff --git a/lib/dcl/executor.ml b/lib/dcl/executor.ml
index cf2cfed..8c2fbdc 100644
--- a/lib/dcl/executor.ml
+++ b/lib/dcl/executor.ml
@@ -1,94 +1,94 @@
module Make (Storage : Management.Physical.S with type error = string) = struct
- module Ops = Manipulation.Make(Storage)
- module Branch = Management.Branch.Make(Storage)
- module MergeOps = Management.Merge.Make(Storage)(Ops)
+ module Ops = Manipulation.Make (Storage)
+ module Branch = Management.Branch.Make (Storage)
+ module MergeOps = Management.Merge.Make (Storage) (Ops)
type error =
- | ParseError of string
+ | ParseError of string
| BranchError of string
- | MergeError of string
+ | MergeError of string
let sexp_of_error e =
let open Sexplib.Sexp in
match e with
- | ParseError s -> List [Atom "parse-error"; Atom s]
- | BranchError s -> List [Atom "branch-error"; Atom s]
- | MergeError s -> List [Atom "merge-error"; Atom s]
+ | ParseError s -> List [ Atom "parse-error"; Atom s ]
+ | BranchError s -> List [ Atom "branch-error"; Atom s ]
+ | MergeError s -> List [ Atom "merge-error"; Atom s ]
- let convert_strategy : Ast.merge_strategy -> Management.Merge.strategy = function
- | Ast.PreferLeft -> Management.Merge.PreferLeft
- | Ast.PreferRight -> Management.Merge.PreferRight
+ let convert_strategy : Ast.merge_strategy -> Management.Merge.strategy =
+ function
+ | Ast.PreferLeft -> Management.Merge.PreferLeft
+ | Ast.PreferRight -> Management.Merge.PreferRight
| Ast.RevertToAncestor -> Management.Merge.RevertToAncestor
- let execute
- (storage : Storage.t)
- (db : Management.Database.t)
- (stmt : Ast.statement)
- : (Management.Database.t * string, error) result =
+ let execute (storage : Storage.t) (db : Management.Database.t)
+ (stmt : Ast.statement) : (Management.Database.t * string, error) result =
match stmt with
-
- | Ast.CreateBranch { name; hash } ->
- let tip = match hash with
- | Some h -> h
- | None -> db.Management.Database.hash
- in
- (match Branch.create storage ~name ~tip with
- | Error e -> Error (BranchError e)
- | Ok () -> Ok (db, "Branch " ^ name ^ " created"))
-
- | Ast.Checkout branch_name ->
- (match Branch.get_tip storage branch_name with
- | Error e -> Error (BranchError e)
- | Ok None -> Error (BranchError ("Branch not found: " ^ branch_name))
- | Ok (Some tip) ->
- (match Branch.checkout storage branch_name with
- | Error e -> Error (BranchError e)
- | Ok () ->
- (match Ops.load_database storage tip with
- | Error e -> Error (BranchError (Manipulation.string_of_error e))
- | Ok None -> Error (BranchError ("No database at hash: " ^ tip))
- | Ok (Some loaded_db) ->
- Ok (loaded_db, "HEAD:" ^ branch_name))))
-
- | Ast.GetHead ->
- (match Branch.get_head storage with
- | Error e -> Error (BranchError e)
- | Ok None -> Ok (db, "HEAD is unset")
- | Ok (Some name) -> Ok (db, "HEAD:" ^ name))
-
- | Ast.GetBranchTip name ->
- (match Branch.get_tip storage name with
- | Error e -> Error (BranchError e)
- | Ok None -> Error (BranchError ("Branch not found: " ^ name))
- | Ok (Some hash) -> Ok (db, "branch:" ^ name ^ "=" ^ hash))
-
- | Ast.UpdateBranchTip { name; hash } ->
- (match Branch.update_tip storage ~name ~tip:hash with
- | Error e -> Error (BranchError e)
- | Ok () -> Ok (db, "Branch " ^ name ^ " updated"))
-
- | Ast.Merge { left; right; strategy } ->
- (match Branch.get_tip storage left, Branch.get_tip storage right with
- | Error e, _ | _, Error e -> Error (BranchError e)
- | Ok None, _ -> Error (BranchError ("Branch not found: " ^ left))
- | _, Ok None -> Error (BranchError ("Branch not found: " ^ right))
- | Ok (Some left_tip), Ok (Some right_tip) ->
- let strat = convert_strategy strategy in
- (match MergeOps.merge ~storage ~strategy:strat ~left_tip ~right_tip with
- | Error e -> Error (MergeError (Manipulation.string_of_error e))
- | Ok (Management.Merge.Failed conflicts) ->
- let msgs = List.map (function
- | Management.Merge.TupleConflict { relation; hash } ->
- "tuple conflict in " ^ relation ^ " (" ^ hash ^ ")"
- | Management.Merge.SchemaConflict r -> "schema conflict in " ^ r
- | Management.Merge.ConstraintConflict r -> "constraint conflict in " ^ r
- ) conflicts in
- Error (MergeError ("Merge failed: " ^ String.concat "; " msgs))
- | Ok (Management.Merge.Clean merged_db) ->
- let _ = Branch.update_tip storage ~name:left
- ~tip:merged_db.Management.Database.hash in
- Ok (merged_db,
- "Merged:" ^ right ^ "→" ^ left)))
+ | Ast.CreateBranch { name; hash } -> (
+ let tip =
+ match hash with Some h -> h | None -> db.Management.Database.hash
+ in
+ match Branch.create storage ~name ~tip with
+ | Error e -> Error (BranchError e)
+ | Ok () -> Ok (db, "Branch " ^ name ^ " created"))
+ | Ast.Checkout branch_name -> (
+ match Branch.get_tip storage branch_name with
+ | Error e -> Error (BranchError e)
+ | Ok None -> Error (BranchError ("Branch not found: " ^ branch_name))
+ | Ok (Some tip) -> (
+ match Branch.checkout storage branch_name with
+ | Error e -> Error (BranchError e)
+ | Ok () -> (
+ match Ops.load_database storage tip with
+ | Error e ->
+ Error (BranchError (Manipulation.string_of_error e))
+ | Ok None -> Error (BranchError ("No database at hash: " ^ tip))
+ | Ok (Some loaded_db) -> Ok (loaded_db, "HEAD:" ^ branch_name)))
+ )
+ | Ast.GetHead -> (
+ match Branch.get_head storage with
+ | Error e -> Error (BranchError e)
+ | Ok None -> Ok (db, "HEAD is unset")
+ | Ok (Some name) -> Ok (db, "HEAD:" ^ name))
+ | Ast.GetBranchTip name -> (
+ match Branch.get_tip storage name with
+ | Error e -> Error (BranchError e)
+ | Ok None -> Error (BranchError ("Branch not found: " ^ name))
+ | Ok (Some hash) -> Ok (db, "branch:" ^ name ^ "=" ^ hash))
+ | Ast.UpdateBranchTip { name; hash } -> (
+ match Branch.update_tip storage ~name ~tip:hash with
+ | Error e -> Error (BranchError e)
+ | Ok () -> Ok (db, "Branch " ^ name ^ " updated"))
+ | Ast.Merge { left; right; strategy } -> (
+ match (Branch.get_tip storage left, Branch.get_tip storage right) with
+ | Error e, _ | _, Error e -> Error (BranchError e)
+ | Ok None, _ -> Error (BranchError ("Branch not found: " ^ left))
+ | _, Ok None -> Error (BranchError ("Branch not found: " ^ right))
+ | Ok (Some left_tip), Ok (Some right_tip) -> (
+ let strat = convert_strategy strategy in
+ match
+ MergeOps.merge ~storage ~strategy:strat ~left_tip ~right_tip
+ with
+ | Error e -> Error (MergeError (Manipulation.string_of_error e))
+ | Ok (Management.Merge.Failed conflicts) ->
+ let msgs =
+ List.map
+ (function
+ | Management.Merge.TupleConflict { relation; hash } ->
+ "tuple conflict in " ^ relation ^ " (" ^ hash ^ ")"
+ | Management.Merge.SchemaConflict r ->
+ "schema conflict in " ^ r
+ | Management.Merge.ConstraintConflict r ->
+ "constraint conflict in " ^ r)
+ conflicts
+ in
+ Error (MergeError ("Merge failed: " ^ String.concat "; " msgs))
+ | Ok (Management.Merge.Clean merged_db) ->
+ let _ =
+ Branch.update_tip storage ~name:left
+ ~tip:merged_db.Management.Database.hash
+ in
+ Ok (merged_db, "Merged:" ^ right ^ "→" ^ left)))
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/dcl/parser.ml b/lib/dcl/parser.ml
index ef64924..79d8fc7 100644
--- a/lib/dcl/parser.ml
+++ b/lib/dcl/parser.ml
@@ -3,16 +3,12 @@ type error = ParseError of string
let of_sexp sexp =
(* ppx_sexp_conv encodes no-argument variants as bare atoms, so
unwrap a single-element list (e.g. (GetHead)) → atom (GetHead). *)
- let sexp = match sexp with
- | Sexplib.Sexp.List [atom] -> atom
- | other -> other
+ let sexp =
+ match sexp with Sexplib.Sexp.List [ atom ] -> atom | other -> other
in
match Ast.statement_of_sexp sexp with
- | stmt -> Ok stmt
+ | stmt -> Ok stmt
| exception exn -> Error (ParseError (Printexc.to_string exn))
-let of_string s =
- of_sexp (Sexplib.Sexp.of_string s)
-
-let to_string stmt =
- Ast.sexp_of_statement stmt |> Sexplib.Sexp.to_string_hum
+let of_string s = of_sexp (Sexplib.Sexp.of_string s)
+let to_string stmt = Ast.sexp_of_statement stmt |> Sexplib.Sexp.to_string_hum
diff --git a/lib/dcl/sublanguage.ml b/lib/dcl/sublanguage.ml
index 112b6ed..c36e2a4 100644
--- a/lib/dcl/sublanguage.ml
+++ b/lib/dcl/sublanguage.ml
@@ -1,9 +1,9 @@
module Make (Storage : Management.Physical.S with type error = string) = struct
- module Exec = Executor.Make(Storage)
+ module Exec = Executor.Make (Storage)
type storage = Storage.t
- type ast = Ast.statement
- type error = Exec.error
+ type ast = Ast.statement
+ type error = Exec.error
let name = "dcl"
@@ -20,4 +20,4 @@ module Make (Storage : Management.Physical.S with type error = string) = struct
let sexp_of_error = Exec.sexp_of_error
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/ddl/ast.ml b/lib/ddl/ast.ml
index 7faee40..ee39edb 100644
--- a/lib/ddl/ast.ml
+++ b/lib/ddl/ast.ml
@@ -9,8 +9,8 @@ type cardinality_spec =
type statement =
| CreateDatabase of string
- | CreateRelation of { name: string; schema: (string * string) list }
+ | CreateRelation of { name : string; schema : (string * string) list }
| RetractRelation of string
| ClearRelation of string
- | RegisterDomain of { name: string; cardinality: cardinality_spec }
+ | RegisterDomain of { name : string; cardinality : cardinality_spec }
[@@deriving sexp]
diff --git a/lib/ddl/executor.ml b/lib/ddl/executor.ml
index fbb2f62..d374ffe 100644
--- a/lib/ddl/executor.ml
+++ b/lib/ddl/executor.ml
@@ -1,68 +1,64 @@
module Make (Storage : Management.Physical.S) = struct
- module Ops = Manipulation.Make(Storage)
+ module Ops = Manipulation.Make (Storage)
type error =
- | ParseError of string
+ | ParseError of string
| ManipulationError of Manipulation.error
- | RelationNotFound of string
+ | RelationNotFound of string
let sexp_of_error e =
let open Sexplib.Sexp in
match e with
- | ParseError s -> List [Atom "parse-error"; Atom s]
+ | ParseError s -> List [ Atom "parse-error"; Atom s ]
| ManipulationError e -> Manipulation.sexp_of_error e
- | RelationNotFound s -> List [Atom "relation-not-found"; Atom s]
+ | RelationNotFound s -> List [ Atom "relation-not-found"; Atom s ]
let ( let* ) = Result.bind
-
let wrap_manip r = Result.map_error (fun e -> ManipulationError e) r
let get_rel db name =
- Ops.get_relation db ~name
- |> Option.to_result ~none:(RelationNotFound name)
+ Ops.get_relation db ~name |> Option.to_result ~none:(RelationNotFound name)
- let convert_cardinality : Ast.cardinality_spec -> Conventions.Cardinality.t = function
- | Ast.Finite n -> Conventions.Cardinality.Finite n
- | Ast.AlephZero -> Conventions.Cardinality.AlephZero
- | Ast.Continuum -> Conventions.Cardinality.Continuum
+ let convert_cardinality : Ast.cardinality_spec -> Conventions.Cardinality.t =
+ function
+ | Ast.Finite n -> Conventions.Cardinality.Finite n
+ | Ast.AlephZero -> Conventions.Cardinality.AlephZero
+ | Ast.Continuum -> Conventions.Cardinality.Continuum
| Ast.ConstrainedFinite -> Conventions.Cardinality.ConstrainedFinite
- let execute
- (storage : Storage.t)
- (db : Management.Database.t)
- (stmt : Ast.statement)
- : (Management.Database.t * string, error) result =
+ let execute (storage : Storage.t) (db : Management.Database.t)
+ (stmt : Ast.statement) : (Management.Database.t * string, error) result =
match stmt with
| Ast.CreateDatabase name ->
- let* db = Ops.create_database storage ~name |> wrap_manip in
- Ok (db, "Database created: " ^ name)
-
+ let* db = Ops.create_database storage ~name |> wrap_manip in
+ Ok (db, "Database created: " ^ name)
| Ast.CreateRelation { name; schema = schema_pairs } ->
- let schema =
- List.fold_left (fun s (attr, dom) -> Schema.add attr dom s) Schema.empty schema_pairs
- in
- let* (db, _) = Ops.create_relation storage db ~name ~schema |> wrap_manip in
- Ok (db, "Relation created: " ^ name)
-
+ let schema =
+ List.fold_left
+ (fun s (attr, dom) -> Schema.add attr dom s)
+ Schema.empty schema_pairs
+ in
+ let* db, _ =
+ Ops.create_relation storage db ~name ~schema |> wrap_manip
+ in
+ Ok (db, "Relation created: " ^ name)
| Ast.RetractRelation name ->
- let* db = Ops.retract_relation storage db ~name |> wrap_manip in
- Ok (db, "Relation retracted: " ^ name)
-
+ let* db = Ops.retract_relation storage db ~name |> wrap_manip in
+ Ok (db, "Relation retracted: " ^ name)
| Ast.ClearRelation name ->
- let* rel = get_rel db name in
- let* (db, _) = Ops.clear_relation storage db rel |> wrap_manip in
- Ok (db, "Relation cleared: " ^ name)
-
+ let* rel = get_rel db name in
+ let* db, _ = Ops.clear_relation storage db rel |> wrap_manip in
+ Ok (db, "Relation cleared: " ^ name)
| Ast.RegisterDomain { name; cardinality } ->
- let domain = Domain.make
- ~name
- ~generator:(fun _ -> Generator.Error "not enumerable via DDL")
- ~membership_criteria:(fun _ -> true)
- ~cardinality:(convert_cardinality cardinality)
- ~compare:Stdlib.compare
- in
- let* db = Ops.register_domain storage db domain |> wrap_manip in
- Ok (db, "Domain registered: " ^ name)
+ let domain =
+ Domain.make ~name
+ ~generator:(fun _ -> Generator.Error "not enumerable via DDL")
+ ~membership_criteria:(fun _ -> true)
+ ~cardinality:(convert_cardinality cardinality)
+ ~compare:Stdlib.compare
+ in
+ let* db = Ops.register_domain storage db domain |> wrap_manip in
+ Ok (db, "Domain registered: " ^ name)
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/ddl/parser.ml b/lib/ddl/parser.ml
index 28f8b6c..5678b47 100644
--- a/lib/ddl/parser.ml
+++ b/lib/ddl/parser.ml
@@ -2,13 +2,12 @@ type error = ParseError of string
let of_sexp sexp =
match Ast.statement_of_sexp sexp with
- | stmt -> Ok stmt
+ | stmt -> Ok stmt
| exception exn -> Error (ParseError (Printexc.to_string exn))
let of_string s =
match Sexplib.Sexp.of_string s |> Ast.statement_of_sexp with
- | stmt -> Ok stmt
+ | stmt -> Ok stmt
| exception exn -> Error (ParseError (Printexc.to_string exn))
-let to_string stmt =
- Ast.sexp_of_statement stmt |> Sexplib.Sexp.to_string_hum
+let to_string stmt = Ast.sexp_of_statement stmt |> Sexplib.Sexp.to_string_hum
diff --git a/lib/ddl/sublanguage.ml b/lib/ddl/sublanguage.ml
index 26a012f..bf40a05 100644
--- a/lib/ddl/sublanguage.ml
+++ b/lib/ddl/sublanguage.ml
@@ -1,9 +1,9 @@
module Make (Storage : Management.Physical.S) = struct
- module Exec = Executor.Make(Storage)
+ module Exec = Executor.Make (Storage)
type storage = Storage.t
- type ast = Ast.statement
- type error = Exec.error
+ type ast = Ast.statement
+ type error = Exec.error
let name = "ddl"
@@ -20,4 +20,4 @@ module Make (Storage : Management.Physical.S) = struct
let sexp_of_error = Exec.sexp_of_error
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/dml/ast.ml b/lib/dml/ast.ml
index 479437a..d8defe6 100644
--- a/lib/dml/ast.ml
+++ b/lib/dml/ast.ml
@@ -1,13 +1,12 @@
open Sexplib.Std
-type attr_value = string * Drl.Ast.value
-[@@deriving sexp]
+type attr_value = string * Drl.Ast.value [@@deriving sexp]
type statement =
- | InsertTuple of { relation: string; attributes: attr_value list }
- | InsertTuples of { relation: string; tuples: attr_value list list }
- | DeleteTuple of { relation: string; attributes: attr_value list }
- | Assign of { target: string; body: Drl.Ast.query }
- | InsertFrom of { target: string; source: Drl.Ast.query }
- | DeleteWhere of { target: string; predicate: Drl.Ast.query }
+ | InsertTuple of { relation : string; attributes : attr_value list }
+ | InsertTuples of { relation : string; tuples : attr_value list list }
+ | DeleteTuple of { relation : string; attributes : attr_value list }
+ | Assign of { target : string; body : Drl.Ast.query }
+ | InsertFrom of { target : string; source : Drl.Ast.query }
+ | DeleteWhere of { target : string; predicate : Drl.Ast.query }
[@@deriving sexp]
diff --git a/lib/dml/executor.ml b/lib/dml/executor.ml
index 7c08a24..08f1a26 100644
--- a/lib/dml/executor.ml
+++ b/lib/dml/executor.ml
@@ -1,117 +1,131 @@
module Make (Storage : Management.Physical.S) = struct
- module Ops = Manipulation.Make(Storage)
- module Alg = Algebra.Make(Storage)
- module DrlExec = Drl.Executor.Make(Storage)
+ module Ops = Manipulation.Make (Storage)
+ module Alg = Algebra.Make (Storage)
+ module DrlExec = Drl.Executor.Make (Storage)
type error =
- | ParseError of string
+ | ParseError of string
| ManipulationError of Manipulation.error
- | RelationNotFound of string
- | AlgebraError of Algebra.error
+ | RelationNotFound of string
+ | AlgebraError of Algebra.error
let sexp_of_error e =
let open Sexplib.Sexp in
match e with
- | ParseError s -> List [Atom "parse-error"; Atom s]
- | ManipulationError e -> Manipulation.sexp_of_error e
- | RelationNotFound s -> List [Atom "relation-not-found"; Atom s]
- | AlgebraError (Algebra.StorageError s) -> List [Atom "storage-error"; Atom s]
- | AlgebraError (Algebra.GeneratorError s) -> List [Atom "generator-error"; Atom s]
+ | ParseError s -> List [ Atom "parse-error"; Atom s ]
+ | ManipulationError e -> Manipulation.sexp_of_error e
+ | RelationNotFound s -> List [ Atom "relation-not-found"; Atom s ]
+ | AlgebraError (Algebra.StorageError s) ->
+ List [ Atom "storage-error"; Atom s ]
+ | AlgebraError (Algebra.GeneratorError s) ->
+ List [ Atom "generator-error"; Atom s ]
let ( let* ) = Result.bind
-
let wrap_manip r = Result.map_error (fun e -> ManipulationError e) r
-
let wrap_alg e = AlgebraError e
let get_rel db name =
match Ops.get_relation db ~name with
| Some r -> Ok r
- | None -> Error (RelationNotFound name)
+ | None -> Error (RelationNotFound name)
- let retarget target (t : Tuple.materialized) = { t with Tuple.relation = target }
+ let retarget target (t : Tuple.materialized) =
+ { t with Tuple.relation = target }
(** Build a materialized tuple from a list of (attr_name, ast_value) pairs *)
- let build_tuple ~relation (attributes : Ast.attr_value list) : Tuple.materialized =
+ let build_tuple ~relation (attributes : Ast.attr_value list) :
+ Tuple.materialized =
let attr_map =
List.fold_left
(fun acc (name, value) ->
Tuple.AttributeMap.add name
{ Attribute.value = Drl.Ast.value_to_abstract value }
acc)
- Tuple.AttributeMap.empty
- attributes
+ Tuple.AttributeMap.empty attributes
in
{ Tuple.relation; attributes = attr_map }
let eval_query storage db query =
match DrlExec.execute storage db query with
| Ok rel -> Ok rel
- | Error (DrlExec.ParseError s) -> Error (ParseError s)
+ | Error (DrlExec.ParseError s) -> Error (ParseError s)
| Error (DrlExec.RelationNotFound s) -> Error (RelationNotFound s)
- | Error (DrlExec.AlgebraError e) -> Error (AlgebraError e)
+ | Error (DrlExec.AlgebraError e) -> Error (AlgebraError e)
let materialize_tuples storage rel =
Result.map_error wrap_alg (Alg.materialize storage rel)
- let execute
- (storage : Storage.t)
- (db : Management.Database.t)
- (stmt : Ast.statement)
- : (Management.Database.t, error) result =
+ let execute (storage : Storage.t) (db : Management.Database.t)
+ (stmt : Ast.statement) : (Management.Database.t, error) result =
match stmt with
| Ast.InsertTuple { relation; attributes } ->
- let* rel = get_rel db relation in
- let tuple = build_tuple ~relation attributes in
- let* (db, _, _) = Ops.create_tuple storage db rel tuple |> wrap_manip in
- Ok db
-
+ let* rel = get_rel db relation in
+ let tuple = build_tuple ~relation attributes in
+ let* db, _, _ = Ops.create_tuple storage db rel tuple |> wrap_manip in
+ Ok db
| Ast.InsertTuples { relation; tuples } ->
- let* rel = get_rel db relation in
- let tuple_list = List.map (build_tuple ~relation) tuples in
- let* (db, _, _) = Ops.create_tuples storage db rel tuple_list |> wrap_manip in
- Ok db
-
+ let* rel = get_rel db relation in
+ let tuple_list = List.map (build_tuple ~relation) tuples in
+ let* db, _, _ =
+ Ops.create_tuples storage db rel tuple_list |> wrap_manip
+ in
+ Ok db
| Ast.DeleteTuple { relation; attributes } ->
- let* rel = get_rel db relation in
- let tuple = build_tuple ~relation attributes in
- let tuple_hash = Hashing.hash_tuple tuple in
- let* (db, _) = Ops.retract_tuple storage db rel ~tuple_hash |> wrap_manip in
- Ok db
-
+ let* rel = get_rel db relation in
+ let tuple = build_tuple ~relation attributes in
+ let tuple_hash = Hashing.hash_tuple tuple in
+ let* db, _ =
+ Ops.retract_tuple storage db rel ~tuple_hash |> wrap_manip
+ in
+ Ok db
| Ast.Assign { target; body } ->
- let* rel = get_rel db target in
- let* result_rel = eval_query storage db body in
- let* tuples = materialize_tuples storage result_rel in
- let* (db, rel) = Ops.clear_relation storage db rel |> wrap_manip in
- let* (db, _, _) = Ops.create_tuples storage db rel (List.map (retarget target) tuples) |> wrap_manip in
- Ok db
-
+ let* rel = get_rel db target in
+ let* result_rel = eval_query storage db body in
+ let* tuples = materialize_tuples storage result_rel in
+ let* db, rel = Ops.clear_relation storage db rel |> wrap_manip in
+ let* db, _, _ =
+ Ops.create_tuples storage db rel (List.map (retarget target) tuples)
+ |> wrap_manip
+ in
+ Ok db
| Ast.InsertFrom { target; source } ->
- let* rel = get_rel db target in
- let* result_rel = eval_query storage db source in
- let* tuples = materialize_tuples storage result_rel in
- let* (db, _, _) = Ops.create_tuples storage db rel (List.map (retarget target) tuples) |> wrap_manip in
- Ok db
-
+ let* rel = get_rel db target in
+ let* result_rel = eval_query storage db source in
+ let* tuples = materialize_tuples storage result_rel in
+ let* db, _, _ =
+ Ops.create_tuples storage db rel (List.map (retarget target) tuples)
+ |> wrap_manip
+ in
+ Ok db
| Ast.DeleteWhere { target; predicate } ->
- let* rel = get_rel db target in
- let* pred_rel = eval_query storage db predicate in
- let common = List.filter_map
- (fun (n, _) -> if List.exists (fun (m, _) -> m = n) pred_rel.Relation.schema
- then Some n else None)
- rel.Relation.schema in
- let* joined = Alg.equijoin storage common rel pred_rel |> Result.map_error wrap_alg in
- let* to_delete = Alg.project storage (List.map fst rel.Relation.schema) joined
- |> Result.map_error wrap_alg in
- let* tuples = materialize_tuples storage to_delete in
- List.fold_left (fun acc t ->
- let* db = acc in
let* rel = get_rel db target in
- let tuple_hash = Hashing.hash_tuple (retarget target t) in
- let* (db, _) = Ops.retract_tuple storage db rel ~tuple_hash |> wrap_manip in
- Ok db)
- (Ok db) tuples
+ let* pred_rel = eval_query storage db predicate in
+ let common =
+ List.filter_map
+ (fun (n, _) ->
+ if List.exists (fun (m, _) -> m = n) pred_rel.Relation.schema then
+ Some n
+ else None)
+ rel.Relation.schema
+ in
+ let* joined =
+ Alg.equijoin storage common rel pred_rel |> Result.map_error wrap_alg
+ in
+ let* to_delete =
+ Alg.project storage (List.map fst rel.Relation.schema) joined
+ |> Result.map_error wrap_alg
+ in
+ let* tuples = materialize_tuples storage to_delete in
+ List.fold_left
+ (fun acc t ->
+ let* db = acc in
+ let* rel = get_rel db target in
+ let tuple_hash = Hashing.hash_tuple (retarget target t) in
+ let* db, _ =
+ Ops.retract_tuple storage db rel ~tuple_hash |> wrap_manip
+ in
+ Ok db)
+ (Ok db) tuples
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/dml/parser.ml b/lib/dml/parser.ml
index 28f8b6c..5678b47 100644
--- a/lib/dml/parser.ml
+++ b/lib/dml/parser.ml
@@ -2,13 +2,12 @@ type error = ParseError of string
let of_sexp sexp =
match Ast.statement_of_sexp sexp with
- | stmt -> Ok stmt
+ | stmt -> Ok stmt
| exception exn -> Error (ParseError (Printexc.to_string exn))
let of_string s =
match Sexplib.Sexp.of_string s |> Ast.statement_of_sexp with
- | stmt -> Ok stmt
+ | stmt -> Ok stmt
| exception exn -> Error (ParseError (Printexc.to_string exn))
-let to_string stmt =
- Ast.sexp_of_statement stmt |> Sexplib.Sexp.to_string_hum
+let to_string stmt = Ast.sexp_of_statement stmt |> Sexplib.Sexp.to_string_hum
diff --git a/lib/dml/sublanguage.ml b/lib/dml/sublanguage.ml
index 29f951e..29b1b77 100644
--- a/lib/dml/sublanguage.ml
+++ b/lib/dml/sublanguage.ml
@@ -1,9 +1,9 @@
module Make (Storage : Management.Physical.S) = struct
- module Exec = Executor.Make(Storage)
+ module Exec = Executor.Make (Storage)
type storage = Storage.t
- type ast = Ast.statement
- type error = Exec.error
+ type ast = Ast.statement
+ type error = Exec.error
let name = "dml"
@@ -20,4 +20,4 @@ module Make (Storage : Management.Physical.S) = struct
let sexp_of_error = Exec.sexp_of_error
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/drl/ast.ml b/lib/drl/ast.ml
index 2beb010..6b191bb 100644
--- a/lib/drl/ast.ml
+++ b/lib/drl/ast.ml
@@ -1,32 +1,28 @@
open Sexplib.Std
(** Literal values for Const nodes *)
-type value =
- | Int of int
- | Float of float
- | Str of string
- | Bool of bool
+type value = Int of int | Float of float | Str of string | Bool of bool
[@@deriving sexp]
(** Convert an AST value to an AbstractValue.t (Obj.t) via Obj.repr *)
let value_to_abstract : value -> Conventions.AbstractValue.t = function
- | Int n -> Obj.repr n
+ | Int n -> Obj.repr n
| Float f -> Obj.repr f
- | Str s -> Obj.repr s
- | Bool b -> Obj.repr b
+ | Str s -> Obj.repr s
+ | Bool b -> Obj.repr b
-type direction = Asc | Desc
-[@@deriving sexp]
+type direction = Asc | Desc [@@deriving sexp]
type query =
- | Base of string (** base relation by name *)
- | Const of (string * value) list (** constant single-tuple relation *)
- | Select of query * query (** σ semijoin: (filter, source) *)
- | Join of string list * query * query (** ⋈ natural equijoin on named attrs *)
- | Cartesian of query * query (** × Cartesian product *)
- | Project of string list * query (** π restrict columns *)
- | Rename of (string * string) list * query (** ρ rename (old,new) pairs *)
- | Union of query * query (** ∪ — compatible schemas assumed *)
- | Diff of query * query (** − *)
- | Take of int * query (** τ *)
+ | Base of string (** base relation by name *)
+ | Const of (string * value) list (** constant single-tuple relation *)
+ | Select of query * query (** σ semijoin: (filter, source) *)
+ | Join of string list * query * query
+ (** ⋈ natural equijoin on named attrs *)
+ | Cartesian of query * query (** × Cartesian product *)
+ | Project of string list * query (** π restrict columns *)
+ | Rename of (string * string) list * query (** ρ rename (old,new) pairs *)
+ | Union of query * query (** ∪ — compatible schemas assumed *)
+ | Diff of query * query (** − *)
+ | Take of int * query (** τ *)
[@@deriving sexp]
diff --git a/lib/drl/executor.ml b/lib/drl/executor.ml
index 322fada..f1732eb 100644
--- a/lib/drl/executor.ml
+++ b/lib/drl/executor.ml
@@ -1,74 +1,74 @@
-module Make(Storage : Management.Physical.S) = struct
- module Alg = Algebra.Make(Storage)
- module Ops = Manipulation.Make(Storage)
+module Make (Storage : Management.Physical.S) = struct
+ module Alg = Algebra.Make (Storage)
+ module Ops = Manipulation.Make (Storage)
type error =
- | ParseError of string
+ | ParseError of string
| RelationNotFound of string
- | AlgebraError of Algebra.error
+ | AlgebraError of Algebra.error
let sexp_of_error e =
let open Sexplib.Sexp in
match e with
- | ParseError s -> List [Atom "parse-error"; Atom s]
- | RelationNotFound s -> List [Atom "relation-not-found"; Atom s]
- | AlgebraError (Algebra.StorageError s) -> List [Atom "storage-error"; Atom s]
- | AlgebraError (Algebra.GeneratorError s) -> List [Atom "generator-error"; Atom s]
+ | ParseError s -> List [ Atom "parse-error"; Atom s ]
+ | RelationNotFound s -> List [ Atom "relation-not-found"; Atom s ]
+ | AlgebraError (Algebra.StorageError s) ->
+ List [ Atom "storage-error"; Atom s ]
+ | AlgebraError (Algebra.GeneratorError s) ->
+ List [ Atom "generator-error"; Atom s ]
let wrap = Result.map_error (fun e -> AlgebraError e)
-
let ast_value_to_abstract = Ast.value_to_abstract
- let rec execute
- (storage : Storage.t)
- (db : Management.Database.t)
- (q : Ast.query)
- : (Relation.t, error) Result.t =
+ let rec execute (storage : Storage.t) (db : Management.Database.t)
+ (q : Ast.query) : (Relation.t, error) Result.t =
let ( >>= ) = Result.bind in
match q with
- | Ast.Base name ->
- (match Ops.get_relation db ~name with
- | None -> Error (RelationNotFound name)
- | Some rel -> Ok rel)
+ | Ast.Base name -> (
+ match Ops.get_relation db ~name with
+ | None -> Error (RelationNotFound name)
+ | Some rel -> Ok rel)
| Ast.Const pairs ->
- Ok (Alg.const_relation
- (List.map (fun (k, v) -> (k, ast_value_to_abstract v)) pairs))
+ Ok
+ (Alg.const_relation
+ (List.map (fun (k, v) -> (k, ast_value_to_abstract v)) pairs))
| Ast.Select (filter_q, source_q) ->
- execute storage db filter_q >>= fun filter ->
- execute storage db source_q >>= fun source ->
- (* semijoin = project(source attrs, equijoin on common attrs) *)
- let common = List.filter_map (fun (n, _) ->
- if List.exists (fun (m, _) -> m = n) filter.Relation.schema
- then Some n else None) source.Relation.schema in
- let source_attrs = List.map fst source.Relation.schema in
- wrap (Alg.equijoin storage common source filter) >>= fun joined ->
- wrap (Alg.project storage source_attrs joined)
+ execute storage db filter_q >>= fun filter ->
+ execute storage db source_q >>= fun source ->
+ (* semijoin = project(source attrs, equijoin on common attrs) *)
+ let common =
+ List.filter_map
+ (fun (n, _) ->
+ if List.exists (fun (m, _) -> m = n) filter.Relation.schema then
+ Some n
+ else None)
+ source.Relation.schema
+ in
+ let source_attrs = List.map fst source.Relation.schema in
+ wrap (Alg.equijoin storage common source filter) >>= fun joined ->
+ wrap (Alg.project storage source_attrs joined)
| Ast.Join (attrs, q1, q2) ->
- execute storage db q1 >>= fun r1 ->
- execute storage db q2 >>= fun r2 ->
- wrap (Alg.equijoin storage attrs r1 r2)
+ execute storage db q1 >>= fun r1 ->
+ execute storage db q2 >>= fun r2 ->
+ wrap (Alg.equijoin storage attrs r1 r2)
| Ast.Project (attrs, q) ->
- execute storage db q >>= fun rel ->
- wrap (Alg.project storage attrs rel)
+ execute storage db q >>= fun rel -> wrap (Alg.project storage attrs rel)
| Ast.Rename (renames, q) ->
- execute storage db q >>= fun rel ->
- wrap (Alg.rename storage renames rel)
+ execute storage db q >>= fun rel ->
+ wrap (Alg.rename storage renames rel)
| Ast.Cartesian (q1, q2) ->
- execute storage db q1 >>= fun r1 ->
- execute storage db q2 >>= fun r2 ->
- (* Cartesian product = join on no attrs *)
- wrap (Alg.equijoin storage [] r1 r2)
+ execute storage db q1 >>= fun r1 ->
+ execute storage db q2 >>= fun r2 ->
+ (* Cartesian product = join on no attrs *)
+ wrap (Alg.equijoin storage [] r1 r2)
| Ast.Union (q1, q2) ->
- execute storage db q1 >>= fun r1 ->
- execute storage db q2 >>= fun r2 ->
- wrap (Alg.union storage r1 r2)
+ execute storage db q1 >>= fun r1 ->
+ execute storage db q2 >>= fun r2 -> wrap (Alg.union storage r1 r2)
| Ast.Diff (q1, q2) ->
- execute storage db q1 >>= fun r1 ->
- execute storage db q2 >>= fun r2 ->
- wrap (Alg.diff storage r1 r2)
+ execute storage db q1 >>= fun r1 ->
+ execute storage db q2 >>= fun r2 -> wrap (Alg.diff storage r1 r2)
| Ast.Take (n, q) ->
- execute storage db q >>= fun rel ->
- wrap (Alg.take storage n rel)
+ execute storage db q >>= fun rel -> wrap (Alg.take storage n rel)
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/drl/gate.ml b/lib/drl/gate.ml
index 222e935..a314bce 100644
--- a/lib/drl/gate.ml
+++ b/lib/drl/gate.ml
@@ -1,8 +1,8 @@
(** Finiteness gate for DRL queries.
- Converts Sakura types to Coq-extracted types and calls the
- verified [predicted_finite] function. Rejects queries whose
- result cannot be statically proven finite. *)
+ Converts Sakura types to Coq-extracted types and calls the verified
+ [predicted_finite] function. Rejects queries whose result cannot be
+ statically proven finite. *)
(* -- string -> char list impedance --------------------------------- *)
@@ -12,71 +12,68 @@ let string_to_chars (s : string) : char list =
(* -- Sakura AST -> extracted AST ----------------------------------- *)
let rec query_of_ast : Ast.query -> Drl_verified.query = function
- | Ast.Base name ->
- Drl_verified.Base (string_to_chars name)
+ | Ast.Base name -> Drl_verified.Base (string_to_chars name)
| Ast.Const pairs ->
- Drl_verified.Const
- (List.map
- (fun (k, v) ->
- (string_to_chars k, value_of_ast_value v))
- pairs)
+ Drl_verified.Const
+ (List.map
+ (fun (k, v) -> (string_to_chars k, value_of_ast_value v))
+ pairs)
| Ast.Select (filter, source) ->
- Drl_verified.Select (query_of_ast filter, query_of_ast source)
+ Drl_verified.Select (query_of_ast filter, query_of_ast source)
| Ast.Join (attrs, q1, q2) ->
- Drl_verified.Join
- (List.map string_to_chars attrs, query_of_ast q1, query_of_ast q2)
+ Drl_verified.Join
+ (List.map string_to_chars attrs, query_of_ast q1, query_of_ast q2)
| Ast.Cartesian (q1, q2) ->
- Drl_verified.Cartesian (query_of_ast q1, query_of_ast q2)
+ Drl_verified.Cartesian (query_of_ast q1, query_of_ast q2)
| Ast.Project (attrs, q) ->
- Drl_verified.Project (List.map string_to_chars attrs, query_of_ast q)
+ Drl_verified.Project (List.map string_to_chars attrs, query_of_ast q)
| Ast.Rename (renames, q) ->
- Drl_verified.Rename
- (List.map
- (fun (o, n) -> (string_to_chars o, string_to_chars n))
- renames,
- query_of_ast q)
- | Ast.Union (q1, q2) ->
- Drl_verified.Union (query_of_ast q1, query_of_ast q2)
- | Ast.Diff (q1, q2) ->
- Drl_verified.Diff (query_of_ast q1, query_of_ast q2)
- | Ast.Take (n, q) ->
- Drl_verified.Take (n, query_of_ast q)
+ Drl_verified.Rename
+ ( List.map (fun (o, n) -> (string_to_chars o, string_to_chars n)) renames,
+ query_of_ast q )
+ | Ast.Union (q1, q2) -> Drl_verified.Union (query_of_ast q1, query_of_ast q2)
+ | Ast.Diff (q1, q2) -> Drl_verified.Diff (query_of_ast q1, query_of_ast q2)
+ | Ast.Take (n, q) -> Drl_verified.Take (n, query_of_ast q)
and value_of_ast_value : Ast.value -> Drl_verified.literal = function
- | Ast.Int n -> Drl_verified.LitInt n
+ | Ast.Int n -> Drl_verified.LitInt n
(* The Coq model has no float literal. This truncation is harmless:
the finiteness gate inspects only relation names and query structure,
never literal values. *)
| Ast.Float f -> Drl_verified.LitInt (int_of_float f)
- | Ast.Str s -> Drl_verified.LitStr (string_to_chars s)
- | Ast.Bool b -> Drl_verified.LitBool b
+ | Ast.Str s -> Drl_verified.LitStr (string_to_chars s)
+ | Ast.Bool b -> Drl_verified.LitBool b
(* -- database snapshot --------------------------------------------- *)
let is_finite (c : Conventions.Cardinality.t) : bool =
match c with
- | Conventions.Cardinality.Finite _ | Conventions.Cardinality.ConstrainedFinite -> true
- | Conventions.Cardinality.AlephZero | Conventions.Cardinality.Continuum -> false
+ | Conventions.Cardinality.Finite _ | Conventions.Cardinality.ConstrainedFinite
+ ->
+ true
+ | Conventions.Cardinality.AlephZero | Conventions.Cardinality.Continuum ->
+ false
let database_snapshot (db : Management.Database.t) : Drl_verified.database =
Management.Database.RelationMap.fold
(fun name (rel : Relation.t) acc ->
- let entry : Drl_verified.relation =
- { rel_name = string_to_chars name;
- rel_finite = is_finite rel.cardinality }
- in
- (string_to_chars name, entry) :: acc)
- db.relations
- []
+ let entry : Drl_verified.relation =
+ {
+ rel_name = string_to_chars name;
+ rel_finite = is_finite rel.cardinality;
+ }
+ in
+ (string_to_chars name, entry) :: acc)
+ db.relations []
(* -- public interface ---------------------------------------------- *)
-let admit (db : Management.Database.t) (ast : Ast.query) : (unit, string) result =
+let admit (db : Management.Database.t) (ast : Ast.query) : (unit, string) result
+ =
let vdb = database_snapshot db in
let vq = query_of_ast ast in
match Drl_verified.predicted_finite vdb vq with
| Some true -> Ok ()
| Some false ->
- Error "query produces potentially infinite result; use Take to bound it"
- | None ->
- Error "referenced relation not found in finiteness check"
+ Error "query produces potentially infinite result; use Take to bound it"
+ | None -> Error "referenced relation not found in finiteness check"
diff --git a/lib/drl/parser.ml b/lib/drl/parser.ml
index 36ce15a..76d4b4e 100644
--- a/lib/drl/parser.ml
+++ b/lib/drl/parser.ml
@@ -2,13 +2,12 @@ type error = ParseError of string
let of_sexp sexp =
match Ast.query_of_sexp sexp with
- | q -> Ok q
+ | q -> Ok q
| exception exn -> Error (ParseError (Printexc.to_string exn))
let of_string s =
match Sexplib.Sexp.of_string s |> Ast.query_of_sexp with
- | q -> Ok q
+ | q -> Ok q
| exception exn -> Error (ParseError (Printexc.to_string exn))
-let to_string q =
- Ast.sexp_of_query q |> Sexplib.Sexp.to_string_hum
+let to_string q = Ast.sexp_of_query q |> Sexplib.Sexp.to_string_hum
diff --git a/lib/drl/sublanguage.ml b/lib/drl/sublanguage.ml
index f57af95..ce69b56 100644
--- a/lib/drl/sublanguage.ml
+++ b/lib/drl/sublanguage.ml
@@ -1,9 +1,9 @@
module Make (Storage : Management.Physical.S) = struct
- module Exec = Executor.Make(Storage)
+ module Exec = Executor.Make (Storage)
type storage = Storage.t
- type ast = Ast.query
- type error = Exec.error
+ type ast = Ast.query
+ type error = Exec.error
let name = "drl"
@@ -15,12 +15,12 @@ module Make (Storage : Management.Physical.S) = struct
let execute storage db ast =
match Gate.admit db ast with
| Error msg -> Error (Exec.ParseError msg)
- | Ok () ->
- match Exec.execute storage db ast with
- | Ok rel -> Ok (Sublanguage.Query rel)
- | Error e -> Error e
+ | Ok () -> (
+ match Exec.execute storage db ast with
+ | Ok rel -> Ok (Sublanguage.Query rel)
+ | Error e -> Error e)
let sexp_of_error = Exec.sexp_of_error
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/drl_verified/drl_verified.ml b/lib/drl_verified/drl_verified.ml
index b5aeaa7..868af2a 100644
--- a/lib/drl_verified/drl_verified.ml
+++ b/lib/drl_verified/drl_verified.ml
@@ -1,76 +1,67 @@
-
(** val eqb : char list -> char list -> bool **)
let rec eqb s1 s2 =
match s1 with
- | [] -> (match s2 with
- | [] -> true
- | _::_ -> false)
- | c1::s1' ->
- (match s2 with
- | [] -> false
- | c2::s2' -> if (=) c1 c2 then eqb s1' s2' else false)
+ | [] -> ( match s2 with [] -> true | _ :: _ -> false)
+ | c1 :: s1' -> (
+ match s2 with
+ | [] -> false
+ | c2 :: s2' -> if c1 = c2 then eqb s1' s2' else false)
type attr_name = char list
-
type relation = { rel_name : char list; rel_finite : bool }
-
type database = (char list * relation) list
(** val db_lookup : char list -> database -> relation option **)
let rec db_lookup name = function
-| [] -> None
-| p :: rest ->
- let (n, r) = p in if eqb name n then Some r else db_lookup name rest
+ | [] -> None
+ | p :: rest ->
+ let n, r = p in
+ if eqb name n then Some r else db_lookup name rest
-type literal =
-| LitInt of int
-| LitStr of char list
-| LitBool of bool
+type literal = LitInt of int | LitStr of char list | LitBool of bool
type query =
-| Base of char list
-| Const of (attr_name * literal) list
-| Select of query * query
-| Join of attr_name list * query * query
-| Cartesian of query * query
-| Project of attr_name list * query
-| Rename of (attr_name * attr_name) list * query
-| Union of query * query
-| Diff of query * query
-| Take of int * query
+ | Base of char list
+ | Const of (attr_name * literal) list
+ | Select of query * query
+ | Join of attr_name list * query * query
+ | Cartesian of query * query
+ | Project of attr_name list * query
+ | Rename of (attr_name * attr_name) list * query
+ | Union of query * query
+ | Diff of query * query
+ | Take of int * query
(** val predicted_finite : database -> query -> bool option **)
let rec predicted_finite db = function
-| Base name ->
- (match db_lookup name db with
- | Some r -> Some r.rel_finite
- | None -> None)
-| Select (_, source) -> predicted_finite db source
-| Join (_, q1, q2) ->
- (match predicted_finite db q1 with
- | Some f1 ->
- (match predicted_finite db q2 with
- | Some f2 -> Some ((&&) f1 f2)
+ | Base name -> (
+ match db_lookup name db with Some r -> Some r.rel_finite | None -> None)
+ | Select (_, source) -> predicted_finite db source
+ | Join (_, q1, q2) -> (
+ match predicted_finite db q1 with
+ | Some f1 -> (
+ match predicted_finite db q2 with
+ | Some f2 -> Some (f1 && f2)
+ | None -> None)
| None -> None)
- | None -> None)
-| Cartesian (q1, q2) ->
- (match predicted_finite db q1 with
- | Some f1 ->
- (match predicted_finite db q2 with
- | Some f2 -> Some ((&&) f1 f2)
+ | Cartesian (q1, q2) -> (
+ match predicted_finite db q1 with
+ | Some f1 -> (
+ match predicted_finite db q2 with
+ | Some f2 -> Some (f1 && f2)
+ | None -> None)
| None -> None)
- | None -> None)
-| Project (_, q0) -> predicted_finite db q0
-| Rename (_, q0) -> predicted_finite db q0
-| Union (q1, q2) ->
- (match predicted_finite db q1 with
- | Some f1 ->
- (match predicted_finite db q2 with
- | Some f2 -> Some ((&&) f1 f2)
+ | Project (_, q0) -> predicted_finite db q0
+ | Rename (_, q0) -> predicted_finite db q0
+ | Union (q1, q2) -> (
+ match predicted_finite db q1 with
+ | Some f1 -> (
+ match predicted_finite db q2 with
+ | Some f2 -> Some (f1 && f2)
+ | None -> None)
| None -> None)
- | None -> None)
-| Diff (q1, _) -> predicted_finite db q1
-| _ -> Some true
+ | Diff (q1, _) -> predicted_finite db q1
+ | _ -> Some true
diff --git a/lib/drl_verified/drl_verified.mli b/lib/drl_verified/drl_verified.mli
index 31acc7a..dac930e 100644
--- a/lib/drl_verified/drl_verified.mli
+++ b/lib/drl_verified/drl_verified.mli
@@ -1,29 +1,23 @@
-
val eqb : char list -> char list -> bool
type attr_name = char list
-
type relation = { rel_name : char list; rel_finite : bool }
-
type database = (char list * relation) list
val db_lookup : char list -> database -> relation option
-type literal =
-| LitInt of int
-| LitStr of char list
-| LitBool of bool
+type literal = LitInt of int | LitStr of char list | LitBool of bool
type query =
-| Base of char list
-| Const of (attr_name * literal) list
-| Select of query * query
-| Join of attr_name list * query * query
-| Cartesian of query * query
-| Project of attr_name list * query
-| Rename of (attr_name * attr_name) list * query
-| Union of query * query
-| Diff of query * query
-| Take of int * query
+ | Base of char list
+ | Const of (attr_name * literal) list
+ | Select of query * query
+ | Join of attr_name list * query * query
+ | Cartesian of query * query
+ | Project of attr_name list * query
+ | Rename of (attr_name * attr_name) list * query
+ | Union of query * query
+ | Diff of query * query
+ | Take of int * query
val predicted_finite : database -> query -> bool option
diff --git a/lib/dune b/lib/dune
index 9b7462c..a6b503d 100644
--- a/lib/dune
+++ b/lib/dune
@@ -1,4 +1,5 @@
(include_subdirs qualified)
+
(library
(name relational_engine)
(libraries
diff --git a/lib/envelope.ml b/lib/envelope.ml
index d8404d9..bed8bc0 100644
--- a/lib/envelope.ml
+++ b/lib/envelope.ml
@@ -1,18 +1,17 @@
(** Envelope parser for tagged S-expressions.
- Parses commands of the form (tag payload...) where the tag selects
- which sublanguage handles the payload. The tag set is open — future
- sublanguages (tcl, ppl, acl) just add new tags. *)
+ Parses commands of the form (tag payload...) where the tag selects which
+ sublanguage handles the payload. The tag set is open — future sublanguages
+ (tcl, ppl, acl) just add new tags. *)
type tagged = { tag : string; payload : Sexplib.Sexp.t }
let parse (input : string) : (tagged, string) Result.t =
match Sexplib.Sexp.of_string input with
| Sexplib.Sexp.List (Sexplib.Sexp.Atom tag :: rest) ->
- let payload = match rest with
- | [single] -> single
- | many -> Sexplib.Sexp.List many
- in
- Ok { tag; payload }
+ let payload =
+ match rest with [ single ] -> single | many -> Sexplib.Sexp.List many
+ in
+ Ok { tag; payload }
| _ -> Error "expected (tag payload...)"
| exception exn -> Error (Printexc.to_string exn)
diff --git a/lib/generator.ml b/lib/generator.ml
index 44f1579..5939ec9 100644
--- a/lib/generator.ml
+++ b/lib/generator.ml
@@ -2,5 +2,5 @@ type result =
| Done
| Value of Tuple.t * (int option -> result)
| Error of string
-
- and t = int option -> result \ No newline at end of file
+
+and t = int option -> result
diff --git a/lib/hashing.ml b/lib/hashing.ml
index 4709ded..9475e46 100644
--- a/lib/hashing.ml
+++ b/lib/hashing.ml
@@ -1,8 +1,8 @@
(** Hash computation for tuples and relations.
This module provides content-addressable hashing for the relational engine.
- All hashes are deterministic - the same content always produces the same hash.
- This enables:
+ All hashes are deterministic - the same content always produces the same
+ hash. This enables:
- Deduplication of tuples
- Merkle tree construction for relations and databases
- Time-travel queries (load any historical state by hash) *)
@@ -16,38 +16,41 @@ let bytes_to_hex bytes =
let hi = c lsr 4 in
let lo = c land 0xf in
Bytes.set hex (i * 2) (Char.chr (if hi < 10 then hi + 48 else hi + 87));
- Bytes.set hex (i * 2 + 1) (Char.chr (if lo < 10 then lo + 48 else lo + 87));
+ Bytes.set hex
+ ((i * 2) + 1)
+ (Char.chr (if lo < 10 then lo + 48 else lo + 87))
done;
Bytes.to_string hex
-(** Compute hash for a tuple.
- The hash is computed from:
+(** Compute hash for a tuple. The hash is computed from:
- The relation name
- - All attribute names and their marshalled values (sorted by name for determinism) *)
+ - All attribute names and their marshalled values (sorted by name for
+ determinism) *)
let hash_tuple (tuple : Tuple.materialized) : Conventions.Hash.t =
let sorted_attrs =
Tuple.AttributeMap.bindings tuple.attributes
|> List.sort (fun (a, _) (b, _) -> String.compare a b)
in
let content =
- List.fold_left (fun acc (name, attr) ->
- (* Marshal the value and hex-encode to avoid null bytes *)
- let value_bytes = Marshal.to_bytes attr.Attribute.value [Marshal.Closures] in
- let value_hex = bytes_to_hex value_bytes in
- acc ^ name ^ ":" ^ value_hex ^ ";"
- ) (tuple.relation ^ "|") sorted_attrs
+ List.fold_left
+ (fun acc (name, attr) ->
+ (* Marshal the value and hex-encode to avoid null bytes *)
+ let value_bytes =
+ Marshal.to_bytes attr.Attribute.value [ Marshal.Closures ]
+ in
+ let value_hex = bytes_to_hex value_bytes in
+ acc ^ name ^ ":" ^ value_hex ^ ";")
+ (tuple.relation ^ "|") sorted_attrs
in
Conventions.Hash.hash_text content
-(** Compute hash for a relation.
- The hash is computed from:
+(** Compute hash for a relation. The hash is computed from:
- The relation name
- The schema (attribute names and types)
- The merkle tree root hash (representing all tuples) *)
let hash_relation ~name ~(schema : Schema.t) ~tree : Conventions.Hash.t =
let schema_str = Schema.to_string schema in
- let tree_hash = match Merkle.root_hash tree with
- | Some h -> h
- | None -> "empty"
+ let tree_hash =
+ match Merkle.root_hash tree with Some h -> h | None -> "empty"
in
Conventions.Hash.hash_text (name ^ "|" ^ schema_str ^ "|" ^ tree_hash)
diff --git a/lib/icl/ast.ml b/lib/icl/ast.ml
index 95e0271..30b0fa7 100644
--- a/lib/icl/ast.ml
+++ b/lib/icl/ast.ml
@@ -6,18 +6,18 @@ type binding_expr =
[@@deriving sexp]
type constraint_body =
- | MemberOf of { target: string; binding: (string * binding_expr) list }
- | Not of { body: constraint_body; universe: string }
+ | MemberOf of { target : string; binding : (string * binding_expr) list }
+ | Not of { body : constraint_body; universe : string }
| And of constraint_body list
| Or of constraint_body list
- | Exists of { variable: string; quantifier: string; body: constraint_body }
- | Forall of { variable: string; quantifier: string; body: constraint_body }
+ | Exists of { variable : string; quantifier : string; body : constraint_body }
+ | Forall of { variable : string; quantifier : string; body : constraint_body }
[@@deriving sexp]
type statement =
| RegisterConstraint of {
- constraint_name: string;
- relation_name: string;
- body: constraint_body;
+ constraint_name : string;
+ relation_name : string;
+ body : constraint_body;
}
[@@deriving sexp]
diff --git a/lib/icl/parser.ml b/lib/icl/parser.ml
index 28f8b6c..5678b47 100644
--- a/lib/icl/parser.ml
+++ b/lib/icl/parser.ml
@@ -2,13 +2,12 @@ type error = ParseError of string
let of_sexp sexp =
match Ast.statement_of_sexp sexp with
- | stmt -> Ok stmt
+ | stmt -> Ok stmt
| exception exn -> Error (ParseError (Printexc.to_string exn))
let of_string s =
match Sexplib.Sexp.of_string s |> Ast.statement_of_sexp with
- | stmt -> Ok stmt
+ | stmt -> Ok stmt
| exception exn -> Error (ParseError (Printexc.to_string exn))
-let to_string stmt =
- Ast.sexp_of_statement stmt |> Sexplib.Sexp.to_string_hum
+let to_string stmt = Ast.sexp_of_statement stmt |> Sexplib.Sexp.to_string_hum
diff --git a/lib/icl/sublanguage.ml b/lib/icl/sublanguage.ml
index 4e74082..56f3e4b 100644
--- a/lib/icl/sublanguage.ml
+++ b/lib/icl/sublanguage.ml
@@ -1,9 +1,9 @@
module Make (Storage : Management.Physical.S) = struct
- module Exec = Executor.Make(Storage)
+ module Exec = Executor.Make (Storage)
type storage = Storage.t
- type ast = Ast.statement
- type error = Exec.error
+ type ast = Ast.statement
+ type error = Exec.error
let name = "icl"
@@ -20,4 +20,4 @@ module Make (Storage : Management.Physical.S) = struct
let sexp_of_error = Exec.sexp_of_error
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/interop.ml b/lib/interop.ml
index ea25e0c..8cbc05c 100644
--- a/lib/interop.ml
+++ b/lib/interop.ml
@@ -2,7 +2,8 @@ open Ctypes
module Sha256 = struct
type t = string
- let compute_hash content: t =
+
+ let compute_hash content : t =
let size_with_null_terminator = C.Types.hash_size + 1 in
let buf = Ctypes.allocate_n char ~count:size_with_null_terminator in
let () = C.Functions.compute_hash buf (Bytes.to_string content) in
diff --git a/lib/management/branch.ml b/lib/management/branch.ml
index 70dfd85..ea15311 100644
--- a/lib/management/branch.ml
+++ b/lib/management/branch.ml
@@ -4,13 +4,8 @@
- "branch_names" → serialized string list (index for enumeration)
- "head" → branch name as raw bytes *)
-type t = {
- name : string;
- tip : Conventions.Hash.t;
-}
-
+type t = { name : string; tip : Conventions.Hash.t }
type head = string
-
type error = string
let branch_key name = "branch:" ^ name
@@ -18,7 +13,6 @@ let head_key = "head"
let names_key = "branch_names"
module Make (Storage : Physical.S with type error = string) = struct
-
let load_names storage =
match Storage.load_raw storage names_key with
| Ok (Some bytes) -> (Marshal.from_bytes bytes 0 : string list)
@@ -31,13 +25,12 @@ module Make (Storage : Physical.S with type error = string) = struct
let create storage ~name ~tip =
let record = { name; tip } in
let bytes = Marshal.to_bytes record [] in
- (match Storage.store_raw storage (branch_key name) bytes with
- | Error e -> Error e
- | Ok () ->
- let names = load_names storage in
- if not (List.mem name names) then
- store_names storage (name :: names);
- Ok ())
+ match Storage.store_raw storage (branch_key name) bytes with
+ | Error e -> Error e
+ | Ok () ->
+ let names = load_names storage in
+ if not (List.mem name names) then store_names storage (name :: names);
+ Ok ()
let checkout storage branch_name =
let bytes = Bytes.of_string branch_name in
@@ -52,27 +45,30 @@ module Make (Storage : Physical.S with type error = string) = struct
let get_tip storage name =
match Storage.load_raw storage (branch_key name) with
| Ok (Some bytes) ->
- let record : t = Marshal.from_bytes bytes 0 in
- Ok (Some record.tip)
+ let record : t = Marshal.from_bytes bytes 0 in
+ Ok (Some record.tip)
| Ok None -> Ok None
| Error e -> Error e
let update_tip storage ~name ~tip =
match Storage.load_raw storage (branch_key name) with
| Ok (Some _) ->
- let record = { name; tip } in
- let bytes = Marshal.to_bytes record [] in
- Storage.store_raw storage (branch_key name) bytes
+ let record = { name; tip } in
+ let bytes = Marshal.to_bytes record [] in
+ Storage.store_raw storage (branch_key name) bytes
| Ok None -> Error ("Branch not found: " ^ name)
| Error e -> Error e
let list storage =
let names = load_names storage in
- let branches = List.filter_map (fun name ->
- match get_tip storage name with
- | Ok (Some tip) -> Some (name, tip)
- | _ -> None
- ) names in
+ let branches =
+ List.filter_map
+ (fun name ->
+ match get_tip storage name with
+ | Ok (Some tip) -> Some (name, tip)
+ | _ -> None)
+ names
+ in
Ok branches
let branch_relation storage : Relation.t =
@@ -83,23 +79,22 @@ module Make (Storage : Physical.S with type error = string) = struct
let rec generator position =
match position with
| None -> Generator.Error "random access not supported for sakura:branch"
- | Some pos ->
- (match list storage with
- | Error _ -> Generator.Done
- | Ok branches ->
- if pos >= List.length branches then Generator.Done
- else
- let (name, tip) = List.nth branches pos in
- let short = String.sub tip 0 (min 8 (String.length tip)) in
- let attributes =
- Tuple.AttributeMap.of_list
- [ ("name", mk name)
- ; ("hash", mk short)
- ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:Prelude.Catalog.branch_rel_name ~attributes
- , generator ))
+ | Some pos -> (
+ match list storage with
+ | Error _ -> Generator.Done
+ | Ok branches ->
+ if pos >= List.length branches then Generator.Done
+ else
+ let name, tip = List.nth branches pos in
+ let short = String.sub tip 0 (min 8 (String.length tip)) in
+ let attributes =
+ Tuple.AttributeMap.of_list
+ [ ("name", mk name); ("hash", mk short) ]
+ in
+ Generator.Value
+ ( Tuple.make_materialized
+ ~relation:Prelude.Catalog.branch_rel_name ~attributes,
+ generator ))
in
Relation.make ~hash:None ~name:Prelude.Catalog.branch_rel_name ~schema
~tree:None ~constraints:None
@@ -115,16 +110,17 @@ module Make (Storage : Physical.S with type error = string) = struct
let generator position =
match position with
| None -> Generator.Error "random access not supported for sakura:head"
- | Some 0 ->
- (match get_head storage with
- | Ok None | Error _ -> Generator.Done
- | Ok (Some branch_name) ->
- let attributes =
- Tuple.AttributeMap.of_list [ ("branch", mk branch_name) ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:Prelude.Catalog.head_rel_name ~attributes
- , fun _ -> Generator.Done ))
+ | Some 0 -> (
+ match get_head storage with
+ | Ok None | Error _ -> Generator.Done
+ | Ok (Some branch_name) ->
+ let attributes =
+ Tuple.AttributeMap.of_list [ ("branch", mk branch_name) ]
+ in
+ Generator.Value
+ ( Tuple.make_materialized
+ ~relation:Prelude.Catalog.head_rel_name ~attributes,
+ fun _ -> Generator.Done ))
| Some _ -> Generator.Done
in
Relation.make ~hash:None ~name:Prelude.Catalog.head_rel_name ~schema
@@ -134,5 +130,4 @@ module Make (Storage : Physical.S with type error = string) = struct
~membership_criteria:(fun _ -> true)
~provenance:(Relation.Provenance.Base Prelude.Catalog.head_rel_name)
~lineage:(Relation.Lineage.Base Prelude.Catalog.head_rel_name)
-
end
diff --git a/lib/management/merge.ml b/lib/management/merge.ml
index e50d0e6..d30545a 100644
--- a/lib/management/merge.ml
+++ b/lib/management/merge.ml
@@ -1,40 +1,37 @@
-(** 3-way merge of two branch tips using their Lowest Common Ancestor.
- Walks the history chain to find it, diffs both sides against it,
- applies merge rules, validates constraints, and persists the result. *)
+(** 3-way merge of two branch tips using their Lowest Common Ancestor. Walks the
+ history chain to find it, diffs both sides against it, applies merge rules,
+ validates constraints, and persists the result. *)
type conflict =
- | TupleConflict of { relation: string; hash: Conventions.Hash.t }
- | SchemaConflict of string
+ | TupleConflict of { relation : string; hash : Conventions.Hash.t }
+ | SchemaConflict of string
| ConstraintConflict of string
type strategy = PreferLeft | PreferRight | RevertToAncestor
-
-type merge_result =
- | Clean of Database.t
- | Failed of conflict list
+type merge_result = Clean of Database.t | Failed of conflict list
(** Module type for the subset of Manipulation.Make we need. *)
module type MANIPULATION = sig
type storage
type error
- val of_string_error : string -> error
- val load_database : storage -> Conventions.Hash.t -> (Database.t option, error) result
+
+ val of_string_error : string -> error
+
+ val load_database :
+ storage -> Conventions.Hash.t -> (Database.t option, error) result
+
val store_database : storage -> Database.t -> (unit, error) result
end
-module StringSet = Set.Make(String)
+module StringSet = Set.Make (String)
(** Walk history to find LCA. First hash in right's ancestry that also appears
in left's ancestry set. *)
let find_lca left_db right_db =
let left_ancestors =
- StringSet.of_list (left_db.Database.hash
- :: left_db.Database.history)
- in
- let right_chain =
- right_db.Database.hash
- :: right_db.Database.history
+ StringSet.of_list (left_db.Database.hash :: left_db.Database.history)
in
+ let right_chain = right_db.Database.hash :: right_db.Database.history in
List.find_opt (fun h -> StringSet.mem h left_ancestors) right_chain
(** Apply a single relation diff to a database, using strategy on conflicts. *)
@@ -42,104 +39,140 @@ let apply_diff db ~strategy ~left_db ~right_db ~(left_diff : Diff.relation_diff)
~(right_diff : Diff.relation_diff option) : Database.t * conflict list =
match left_diff with
| Diff.RelationAdded rel ->
- (* Only left added it; right_diff must be None or same *)
- (Database.add_relation db ~relation:rel, [])
-
- | Diff.RelationRemoved name ->
- (Database.remove_relation db ~name, [])
-
- | Diff.RelationModified { name; added_tuples; removed_tuples; schema_changed } ->
- let conflicts = ref [] in
- (* Determine the merged relation's Merkle tree *)
- let base_rel_opt = Database.get_relation db name in
- (match base_rel_opt with
- | None -> (db, [])
- | Some base_rel ->
- let base_tree = Option.value base_rel.Relation.tree ~default:Merkle.empty in
- (* Handle schema conflict *)
- let (resolved_rel, schema_conflict) =
- if schema_changed then
- match right_diff with
- | Some (Diff.RelationModified { schema_changed = true; _ }) ->
- (* Both changed schema — apply strategy *)
- let winner = match strategy with
- | PreferLeft -> Database.get_relation left_db name
- | PreferRight -> Database.get_relation right_db name
- | RevertToAncestor -> Some base_rel
- in
- (Option.value winner ~default:base_rel, [SchemaConflict name])
- | _ ->
- (* Only left changed schema — take left's relation *)
- let left_rel = Option.value
- (Database.get_relation left_db name) ~default:base_rel in
- (left_rel, [])
- else (base_rel, [])
- in
- conflicts := schema_conflict @ !conflicts;
- (* Apply tuple adds/removes from left *)
- let merged_tree =
- List.fold_left (fun t h -> Merkle.insert h t) base_tree added_tuples
- in
- let merged_tree =
- List.fold_left (fun t h -> Merkle.delete h t) merged_tree removed_tuples
- in
- (* Apply tuple adds/removes from right if disjoint *)
- let merged_tree = match right_diff with
- | Some (Diff.RelationModified
+ (* Only left added it; right_diff must be None or same *)
+ (Database.add_relation db ~relation:rel, [])
+ | Diff.RelationRemoved name -> (Database.remove_relation db ~name, [])
+ | Diff.RelationModified { name; added_tuples; removed_tuples; schema_changed }
+ -> (
+ let conflicts = ref [] in
+ (* Determine the merged relation's Merkle tree *)
+ let base_rel_opt = Database.get_relation db name in
+ match base_rel_opt with
+ | None -> (db, [])
+ | Some base_rel ->
+ let base_tree =
+ Option.value base_rel.Relation.tree ~default:Merkle.empty
+ in
+ (* Handle schema conflict *)
+ let resolved_rel, schema_conflict =
+ if schema_changed then
+ match right_diff with
+ | Some (Diff.RelationModified { schema_changed = true; _ }) ->
+ (* Both changed schema — apply strategy *)
+ let winner =
+ match strategy with
+ | PreferLeft -> Database.get_relation left_db name
+ | PreferRight -> Database.get_relation right_db name
+ | RevertToAncestor -> Some base_rel
+ in
+ ( Option.value winner ~default:base_rel,
+ [ SchemaConflict name ] )
+ | _ ->
+ (* Only left changed schema — take left's relation *)
+ let left_rel =
+ Option.value
+ (Database.get_relation left_db name)
+ ~default:base_rel
+ in
+ (left_rel, [])
+ else (base_rel, [])
+ in
+ conflicts := schema_conflict @ !conflicts;
+ (* Apply tuple adds/removes from left *)
+ let merged_tree =
+ List.fold_left (fun t h -> Merkle.insert h t) base_tree added_tuples
+ in
+ let merged_tree =
+ List.fold_left
+ (fun t h -> Merkle.delete h t)
+ merged_tree removed_tuples
+ in
+ (* Apply tuple adds/removes from right if disjoint *)
+ let merged_tree =
+ match right_diff with
+ | Some
+ (Diff.RelationModified
{ added_tuples = r_add; removed_tuples = r_rem; _ }) ->
- (* Detect tuple conflicts: same hash both added and removed *)
- let left_add = StringSet.of_list added_tuples in
- let left_rem = StringSet.of_list removed_tuples in
- let right_add = StringSet.of_list r_add in
- let right_rem = StringSet.of_list r_rem in
- let conflict_hashes =
- StringSet.inter left_add right_rem
- |> StringSet.union (StringSet.inter left_rem right_add)
- in
- if not (StringSet.is_empty conflict_hashes) then begin
- StringSet.iter (fun h ->
- conflicts := TupleConflict { relation = name; hash = h } :: !conflicts
- ) conflict_hashes;
- (* Resolve conflicting tuples per strategy *)
- match strategy with
- | PreferLeft ->
- (* keep left's merged_tree as-is, ignore conflicting right ops *)
- let safe_add = StringSet.diff right_add conflict_hashes in
- let safe_rem = StringSet.diff right_rem conflict_hashes in
- let t = StringSet.fold (fun h acc -> Merkle.insert h acc) safe_add merged_tree in
- StringSet.fold (fun h acc -> Merkle.delete h acc) safe_rem t
- | PreferRight ->
- (* revert left's conflicting ops, apply right's *)
- let t = StringSet.fold (fun h acc -> Merkle.delete h acc) conflict_hashes merged_tree in
- let t = StringSet.fold (fun h acc -> Merkle.insert h acc) right_add t in
- StringSet.fold (fun h acc -> Merkle.delete h acc) right_rem t
- | RevertToAncestor ->
- (* drop conflicting hashes from merged tree *)
- StringSet.fold (fun h acc -> Merkle.delete h acc) conflict_hashes merged_tree
- end else begin
- (* Disjoint — union both sides *)
- let t = List.fold_left (fun acc h -> Merkle.insert h acc) merged_tree r_add in
- List.fold_left (fun acc h -> Merkle.delete h acc) t r_rem
- end
- | _ -> merged_tree
- in
- let new_hash = Hashing.hash_relation
- ~name:resolved_rel.Relation.name
- ~schema:resolved_rel.Relation.schema
- ~tree:merged_tree
- in
- let updated_rel = { resolved_rel with
- Relation.tree = Some merged_tree;
- hash = Some new_hash;
- } in
- let new_db = Database.update_relation db ~relation:updated_rel in
- (new_db, !conflicts))
+ (* Detect tuple conflicts: same hash both added and removed *)
+ let left_add = StringSet.of_list added_tuples in
+ let left_rem = StringSet.of_list removed_tuples in
+ let right_add = StringSet.of_list r_add in
+ let right_rem = StringSet.of_list r_rem in
+ let conflict_hashes =
+ StringSet.inter left_add right_rem
+ |> StringSet.union (StringSet.inter left_rem right_add)
+ in
+ if not (StringSet.is_empty conflict_hashes) then begin
+ StringSet.iter
+ (fun h ->
+ conflicts :=
+ TupleConflict { relation = name; hash = h }
+ :: !conflicts)
+ conflict_hashes;
+ (* Resolve conflicting tuples per strategy *)
+ match strategy with
+ | PreferLeft ->
+ (* keep left's merged_tree as-is, ignore conflicting right ops *)
+ let safe_add = StringSet.diff right_add conflict_hashes in
+ let safe_rem = StringSet.diff right_rem conflict_hashes in
+ let t =
+ StringSet.fold
+ (fun h acc -> Merkle.insert h acc)
+ safe_add merged_tree
+ in
+ StringSet.fold
+ (fun h acc -> Merkle.delete h acc)
+ safe_rem t
+ | PreferRight ->
+ (* revert left's conflicting ops, apply right's *)
+ let t =
+ StringSet.fold
+ (fun h acc -> Merkle.delete h acc)
+ conflict_hashes merged_tree
+ in
+ let t =
+ StringSet.fold
+ (fun h acc -> Merkle.insert h acc)
+ right_add t
+ in
+ StringSet.fold
+ (fun h acc -> Merkle.delete h acc)
+ right_rem t
+ | RevertToAncestor ->
+ (* drop conflicting hashes from merged tree *)
+ StringSet.fold
+ (fun h acc -> Merkle.delete h acc)
+ conflict_hashes merged_tree
+ end
+ else begin
+ (* Disjoint — union both sides *)
+ let t =
+ List.fold_left
+ (fun acc h -> Merkle.insert h acc)
+ merged_tree r_add
+ in
+ List.fold_left (fun acc h -> Merkle.delete h acc) t r_rem
+ end
+ | _ -> merged_tree
+ in
+ let new_hash =
+ Hashing.hash_relation ~name:resolved_rel.Relation.name
+ ~schema:resolved_rel.Relation.schema ~tree:merged_tree
+ in
+ let updated_rel =
+ {
+ resolved_rel with
+ Relation.tree = Some merged_tree;
+ hash = Some new_hash;
+ }
+ in
+ let new_db = Database.update_relation db ~relation:updated_rel in
+ (new_db, !conflicts))
module Make
(Storage : Physical.S)
- (Manip : MANIPULATION with type storage = Storage.t) =
+ (Manip : MANIPULATION with type storage = Storage.t) =
struct
-
let err s = Error (Manip.of_string_error s)
(* Load both tips, find the lowest common ancestor, compute the diffs,
@@ -151,85 +184,103 @@ struct
match Manip.load_database storage left_tip with
| Error e -> Error e
| Ok None -> err ("Left tip not found: " ^ left_tip)
- | Ok (Some left_db) ->
- match Manip.load_database storage right_tip with
- | Error e -> Error e
- | Ok None -> err ("Right tip not found: " ^ right_tip)
- | Ok (Some right_db) ->
- match find_lca left_db right_db with
- | None -> err "No common ancestor found between branches"
- | Some ancestor_hash ->
- match Manip.load_database storage ancestor_hash with
- | Error e -> Error e
- | Ok None -> err ("Ancestor not found: " ^ ancestor_hash)
- | Ok (Some ancestor_db) ->
- let left_diffs = Diff.diff ~ancestor:ancestor_db ~target:left_db in
- let right_diffs = Diff.diff ~ancestor:ancestor_db ~target:right_db in
- let right_diff_map =
- List.fold_left (fun m d ->
- let key = match d with
- | Diff.RelationAdded r -> r.Relation.name
- | Diff.RelationRemoved n -> n
- | Diff.RelationModified { name; _ } -> name
- in
- Database.RelationMap.add key d m
- ) Database.RelationMap.empty right_diffs
- in
- let (merged_db, all_conflicts) =
- let (db_after_left, left_conflicts) =
- List.fold_left (fun (db, conflicts) left_d ->
- let rel_name = match left_d with
- | Diff.RelationAdded r -> r.Relation.name
- | Diff.RelationRemoved n -> n
- | Diff.RelationModified { name; _ } -> name
- in
- let right_d = Database.RelationMap.find_opt rel_name right_diff_map in
- let (new_db, cs) =
- apply_diff db ~strategy ~left_db ~right_db
- ~left_diff:left_d ~right_diff:right_d
- in
- (new_db, cs @ conflicts)
- ) (ancestor_db, []) left_diffs
- in
- let left_names =
- List.fold_left (fun s d ->
- let n = match d with
- | Diff.RelationAdded r -> r.Relation.name
- | Diff.RelationRemoved n -> n
- | Diff.RelationModified { name; _ } -> name
- in
- StringSet.add n s
- ) StringSet.empty left_diffs
- in
- let right_only = List.filter (fun d ->
- let n = match d with
- | Diff.RelationAdded r -> r.Relation.name
- | Diff.RelationRemoved n -> n
- | Diff.RelationModified { name; _ } -> name
- in
- not (StringSet.mem n left_names)
- ) right_diffs in
- let (db_final, right_conflicts) =
- List.fold_left (fun (db, conflicts) right_d ->
- let (new_db, cs) =
- apply_diff db ~strategy ~left_db ~right_db
- ~left_diff:right_d ~right_diff:None
- in
- (new_db, cs @ conflicts)
- ) (db_after_left, left_conflicts) right_only
- in
- (db_final, right_conflicts)
- in
- let unresolvable = List.filter (function
- | ConstraintConflict _ -> true
- | _ -> false
- ) all_conflicts in
- if unresolvable <> [] then
- Ok (Failed unresolvable)
- else begin
- match Manip.store_database storage merged_db with
- | Error e -> Error e
- | Ok () -> Ok (Clean merged_db)
- end
-
+ | Ok (Some left_db) -> (
+ match Manip.load_database storage right_tip with
+ | Error e -> Error e
+ | Ok None -> err ("Right tip not found: " ^ right_tip)
+ | Ok (Some right_db) -> (
+ match find_lca left_db right_db with
+ | None -> err "No common ancestor found between branches"
+ | Some ancestor_hash -> (
+ match Manip.load_database storage ancestor_hash with
+ | Error e -> Error e
+ | Ok None -> err ("Ancestor not found: " ^ ancestor_hash)
+ | Ok (Some ancestor_db) ->
+ let left_diffs =
+ Diff.diff ~ancestor:ancestor_db ~target:left_db
+ in
+ let right_diffs =
+ Diff.diff ~ancestor:ancestor_db ~target:right_db
+ in
+ let right_diff_map =
+ List.fold_left
+ (fun m d ->
+ let key =
+ match d with
+ | Diff.RelationAdded r -> r.Relation.name
+ | Diff.RelationRemoved n -> n
+ | Diff.RelationModified { name; _ } -> name
+ in
+ Database.RelationMap.add key d m)
+ Database.RelationMap.empty right_diffs
+ in
+ let merged_db, all_conflicts =
+ let db_after_left, left_conflicts =
+ List.fold_left
+ (fun (db, conflicts) left_d ->
+ let rel_name =
+ match left_d with
+ | Diff.RelationAdded r -> r.Relation.name
+ | Diff.RelationRemoved n -> n
+ | Diff.RelationModified { name; _ } -> name
+ in
+ let right_d =
+ Database.RelationMap.find_opt rel_name
+ right_diff_map
+ in
+ let new_db, cs =
+ apply_diff db ~strategy ~left_db ~right_db
+ ~left_diff:left_d ~right_diff:right_d
+ in
+ (new_db, cs @ conflicts))
+ (ancestor_db, []) left_diffs
+ in
+ let left_names =
+ List.fold_left
+ (fun s d ->
+ let n =
+ match d with
+ | Diff.RelationAdded r -> r.Relation.name
+ | Diff.RelationRemoved n -> n
+ | Diff.RelationModified { name; _ } -> name
+ in
+ StringSet.add n s)
+ StringSet.empty left_diffs
+ in
+ let right_only =
+ List.filter
+ (fun d ->
+ let n =
+ match d with
+ | Diff.RelationAdded r -> r.Relation.name
+ | Diff.RelationRemoved n -> n
+ | Diff.RelationModified { name; _ } -> name
+ in
+ not (StringSet.mem n left_names))
+ right_diffs
+ in
+ let db_final, right_conflicts =
+ List.fold_left
+ (fun (db, conflicts) right_d ->
+ let new_db, cs =
+ apply_diff db ~strategy ~left_db ~right_db
+ ~left_diff:right_d ~right_diff:None
+ in
+ (new_db, cs @ conflicts))
+ (db_after_left, left_conflicts)
+ right_only
+ in
+ (db_final, right_conflicts)
+ in
+ let unresolvable =
+ List.filter
+ (function ConstraintConflict _ -> true | _ -> false)
+ all_conflicts
+ in
+ if unresolvable <> [] then Ok (Failed unresolvable)
+ else begin
+ match Manip.store_database storage merged_db with
+ | Error e -> Error e
+ | Ok () -> Ok (Clean merged_db)
+ end)))
end
diff --git a/lib/management/physical.ml b/lib/management/physical.ml
index 6063d79..3fc2cf7 100644
--- a/lib/management/physical.ml
+++ b/lib/management/physical.ml
@@ -1,46 +1,48 @@
(** Physical storage abstraction.
- This module defines a functor-based storage interface that can be backed
- by any key-value store (etcd, Redis, DynamoDB, PostgreSQL, filesystem, etc.).
+ This module defines a functor-based storage interface that can be backed by
+ any key-value store (etcd, Redis, DynamoDB, PostgreSQL, filesystem, etc.).
- All data is content-addressed: keys are hashes, values are serialized objects.
- The storage is append-only - objects are never modified, only new versions
- are written with new hashes. *)
+ All data is content-addressed: keys are hashes, values are serialized
+ objects. The storage is append-only - objects are never modified, only new
+ versions are written with new hashes. *)
(** Backend module signature that any storage driver must implement *)
module type BACKEND = sig
type connection
type error
- (** Connect to the storage backend *)
val connect : unit -> (connection, error) result
+ (** Connect to the storage backend *)
- (** Disconnect from the backend *)
val disconnect : connection -> unit
+ (** Disconnect from the backend *)
- (** Get a value by its hash. Returns None if not found. *)
val get : connection -> Conventions.Hash.t -> (bytes option, error) result
+ (** Get a value by its hash. Returns None if not found. *)
- (** Store a value at its hash *)
val put : connection -> Conventions.Hash.t -> bytes -> (unit, error) result
+ (** Store a value at its hash *)
- (** Check if a hash exists *)
val exists : connection -> Conventions.Hash.t -> (bool, error) result
+ (** Check if a hash exists *)
- (** Begin a transaction *)
val begin_transaction : connection -> (unit, error) result
+ (** Begin a transaction *)
- (** Commit a transaction *)
val commit : connection -> (unit, error) result
+ (** Commit a transaction *)
- (** Rollback a transaction *)
val rollback : connection -> (unit, error) result
+ (** Rollback a transaction *)
+ val get_many :
+ connection -> Conventions.Hash.t list -> (bytes option list, error) result
(** Batch get multiple values *)
- val get_many : connection -> Conventions.Hash.t list -> (bytes option list, error) result
+ val put_many :
+ connection -> (Conventions.Hash.t * bytes) list -> (unit, error) result
(** Batch put multiple values *)
- val put_many : connection -> (Conventions.Hash.t * bytes) list -> (unit, error) result
end
(** Storage operations built on top of a backend *)
@@ -48,29 +50,33 @@ module type S = sig
type t
type error
- (** Create a storage instance from a backend connection *)
val create : unit -> (t, error) result
+ (** Create a storage instance from a backend connection *)
- (** Close the storage *)
val close : t -> unit
+ (** Close the storage *)
+ val store_attribute :
+ t -> Conventions.AbstractValue.t -> (Conventions.Hash.t, error) result
(** Store an attribute value, returns its hash *)
- val store_attribute : t -> Conventions.AbstractValue.t -> (Conventions.Hash.t, error) result
+ val load_attribute :
+ t ->
+ Conventions.Hash.t ->
+ (Conventions.AbstractValue.t option, error) result
(** Load an attribute value by hash *)
- val load_attribute : t -> Conventions.Hash.t -> (Conventions.AbstractValue.t option, error) result
- (** Store raw bytes at a hash *)
val store_raw : t -> Conventions.Hash.t -> bytes -> (unit, error) result
+ (** Store raw bytes at a hash *)
- (** Load raw bytes by hash *)
val load_raw : t -> Conventions.Hash.t -> (bytes option, error) result
+ (** Load raw bytes by hash *)
- (** Check if a hash exists *)
val exists : t -> Conventions.Hash.t -> (bool, error) result
+ (** Check if a hash exists *)
- (** Execute a function within a transaction *)
val with_transaction : t -> (unit -> ('a, error) result) -> ('a, error) result
+ (** Execute a function within a transaction *)
end
(** Functor to create storage operations from a backend *)
@@ -79,15 +85,12 @@ module Make (B : BACKEND) : S with type error = B.error = struct
type error = B.error
let create () = B.connect ()
-
let close = B.disconnect
let store_attribute conn value =
let bytes = Marshal.to_bytes value [] in
let hash = Conventions.AbstractValue.hash value in
- match B.put conn hash bytes with
- | Ok () -> Ok hash
- | Error e -> Error e
+ match B.put conn hash bytes with Ok () -> Ok hash | Error e -> Error e
let load_attribute conn hash =
match B.get conn hash with
@@ -95,27 +98,20 @@ module Make (B : BACKEND) : S with type error = B.error = struct
| Ok None -> Ok None
| Error e -> Error e
- let store_raw conn hash bytes =
- B.put conn hash bytes
-
- let load_raw conn hash =
- B.get conn hash
-
- let exists conn hash =
- B.exists conn hash
+ let store_raw conn hash bytes = B.put conn hash bytes
+ let load_raw conn hash = B.get conn hash
+ let exists conn hash = B.exists conn hash
let with_transaction conn f =
match B.begin_transaction conn with
| Error e -> Error e
- | Ok () ->
- match f () with
- | Ok result ->
- (match B.commit conn with
- | Ok () -> Ok result
- | Error e -> Error e)
- | Error e ->
- let _ = B.rollback conn in
- Error e
+ | Ok () -> (
+ match f () with
+ | Ok result -> (
+ match B.commit conn with Ok () -> Ok result | Error e -> Error e)
+ | Error e ->
+ let _ = B.rollback conn in
+ Error e)
end
(** In-memory backend for testing and development *)
@@ -125,35 +121,34 @@ module MemoryBackend : BACKEND with type error = string = struct
mutable in_transaction : bool;
mutable transaction_buffer : (string * bytes) list;
}
+
type error = string
let connect () =
- Ok {
- data = Hashtbl.create 1024;
- in_transaction = false;
- transaction_buffer = [];
- }
+ Ok
+ {
+ data = Hashtbl.create 1024;
+ in_transaction = false;
+ transaction_buffer = [];
+ }
let disconnect _ = ()
-
- let get conn hash =
- Ok (Hashtbl.find_opt conn.data hash)
+ let get conn hash = Ok (Hashtbl.find_opt conn.data hash)
let put conn hash value =
if conn.in_transaction then begin
conn.transaction_buffer <- (hash, value) :: conn.transaction_buffer;
Ok ()
- end else begin
+ end
+ else begin
Hashtbl.replace conn.data hash value;
Ok ()
end
- let exists conn hash =
- Ok (Hashtbl.mem conn.data hash)
+ let exists conn hash = Ok (Hashtbl.mem conn.data hash)
let begin_transaction conn =
- if conn.in_transaction then
- Error "Already in transaction"
+ if conn.in_transaction then Error "Already in transaction"
else begin
conn.in_transaction <- true;
conn.transaction_buffer <- [];
@@ -161,20 +156,18 @@ module MemoryBackend : BACKEND with type error = string = struct
end
let commit conn =
- if not conn.in_transaction then
- Error "Not in transaction"
+ if not conn.in_transaction then Error "Not in transaction"
else begin
- List.iter (fun (hash, value) ->
- Hashtbl.replace conn.data hash value
- ) conn.transaction_buffer;
+ List.iter
+ (fun (hash, value) -> Hashtbl.replace conn.data hash value)
+ conn.transaction_buffer;
conn.in_transaction <- false;
conn.transaction_buffer <- [];
Ok ()
end
let rollback conn =
- if not conn.in_transaction then
- Error "Not in transaction"
+ if not conn.in_transaction then Error "Not in transaction"
else begin
conn.in_transaction <- false;
conn.transaction_buffer <- [];
@@ -185,14 +178,14 @@ module MemoryBackend : BACKEND with type error = string = struct
Ok (List.map (fun h -> Hashtbl.find_opt conn.data h) hashes)
let put_many conn pairs =
- List.iter (fun (hash, value) ->
- if conn.in_transaction then
- conn.transaction_buffer <- (hash, value) :: conn.transaction_buffer
- else
- Hashtbl.replace conn.data hash value
- ) pairs;
+ List.iter
+ (fun (hash, value) ->
+ if conn.in_transaction then
+ conn.transaction_buffer <- (hash, value) :: conn.transaction_buffer
+ else Hashtbl.replace conn.data hash value)
+ pairs;
Ok ()
end
+module Memory = Make (MemoryBackend)
(** Default in-memory storage for development *)
-module Memory = Make(MemoryBackend)
diff --git a/lib/merkle.ml b/lib/merkle.ml
index ffa7171..6c4be52 100644
--- a/lib/merkle.ml
+++ b/lib/merkle.ml
@@ -2,57 +2,52 @@
This is an opaque interface that can be backed by different implementations:
- A simple hash set (current placeholder)
- - A proper radix/patricia merkle tree (e.g., plebeia when OCaml 5 support arrives)
+ - A proper radix/patricia merkle tree (e.g., plebeia when OCaml 5 support
+ arrives)
- The tree stores hashes as keys (like a set) and computes a root hash
- from all contained elements. *)
+ The tree stores hashes as keys (like a set) and computes a root hash from
+ all contained elements. *)
module type S = sig
type t
- (** The empty tree *)
val empty : t
+ (** The empty tree *)
- (** Check if tree is empty *)
val is_empty : t -> bool
+ (** Check if tree is empty *)
- (** Insert a hash into the tree. Returns a new tree. *)
val insert : Conventions.Hash.t -> t -> t
+ (** Insert a hash into the tree. Returns a new tree. *)
- (** Delete a hash from the tree. Returns a new tree. *)
val delete : Conventions.Hash.t -> t -> t
+ (** Delete a hash from the tree. Returns a new tree. *)
- (** Check if a hash is in the tree *)
val member : Conventions.Hash.t -> t -> bool
+ (** Check if a hash is in the tree *)
- (** Get all hashes in the tree *)
val keys : t -> Conventions.Hash.t list
+ (** Get all hashes in the tree *)
- (** Compute the root hash of the tree. None if empty. *)
val root_hash : t -> Conventions.Hash.t option
+ (** Compute the root hash of the tree. None if empty. *)
- (** Number of elements in the tree *)
val size : t -> int
+ (** Number of elements in the tree *)
end
-(** Simple hash set implementation.
- This is a placeholder until a proper radix-merkle library
- with OCaml 5 support becomes available. *)
+(** Simple hash set implementation. This is a placeholder until a proper
+ radix-merkle library with OCaml 5 support becomes available. *)
module HashSet : S = struct
- module StringSet = Set.Make(String)
+ module StringSet = Set.Make (String)
type t = StringSet.t
let empty = StringSet.empty
-
let is_empty = StringSet.is_empty
-
let insert hash tree = StringSet.add hash tree
-
let delete hash tree = StringSet.remove hash tree
-
let member hash tree = StringSet.mem hash tree
-
let keys tree = StringSet.elements tree
(* TODO: Streaming/pagination for large tuple sets. Currently materializes
entire keyset into memory, which fails for relations with billions of tuples.
@@ -60,10 +55,8 @@ module HashSet : S = struct
to avoid loading all hashes upfront. Consider replacing HashSet with proper
radix-merkle tree (plebeia) for native lazy traversal. *)
-
let root_hash tree =
- if StringSet.is_empty tree then
- None
+ if StringSet.is_empty tree then None
else
(* Compute root hash by hashing sorted concatenation of all hashes *)
let sorted_hashes = StringSet.elements tree in
@@ -73,5 +66,5 @@ module HashSet : S = struct
let size = StringSet.cardinal
end
-(** Default implementation using HashSet *)
include HashSet
+(** Default implementation using HashSet *)
diff --git a/lib/prelude/catalog.ml b/lib/prelude/catalog.ml
index 4a7241a..ce36f1e 100644
--- a/lib/prelude/catalog.ml
+++ b/lib/prelude/catalog.ml
@@ -1,39 +1,35 @@
-(** System catalog helpers.
- Pure definitions — no storage access, no manipulation dependency.
- Consumed by {!Manipulation.Make} to bootstrap and maintain the six
- catalog relations that make the database self-describing. *)
+(** System catalog helpers. Pure definitions — no storage access, no
+ manipulation dependency. Consumed by {!Manipulation.Make} to bootstrap and
+ maintain the six catalog relations that make the database self-describing.
+*)
(* TODO: on_rel_name and timing_rel_name are defined and seeded but never
written to by any executor. They appear to be stubs for trigger/timing
metadata that was never implemented. *)
let catalog_prefix = "sakura:"
-
-let relation_rel_name = catalog_prefix ^ "relation"
-let domain_rel_name = catalog_prefix ^ "domain"
-let attribute_rel_name = catalog_prefix ^ "attribute"
+let relation_rel_name = catalog_prefix ^ "relation"
+let domain_rel_name = catalog_prefix ^ "domain"
+let attribute_rel_name = catalog_prefix ^ "attribute"
let constraint_rel_name = catalog_prefix ^ "constraint"
-let on_rel_name = catalog_prefix ^ "on"
-let timing_rel_name = catalog_prefix ^ "timing"
-let branch_rel_name = catalog_prefix ^ "branch"
-let head_rel_name = catalog_prefix ^ "head"
+let on_rel_name = catalog_prefix ^ "on"
+let timing_rel_name = catalog_prefix ^ "timing"
+let branch_rel_name = catalog_prefix ^ "branch"
+let head_rel_name = catalog_prefix ^ "head"
let catalog_relation_names =
- [ relation_rel_name
- ; domain_rel_name
- ; attribute_rel_name
- ; constraint_rel_name
- ; on_rel_name
- ; timing_rel_name
+ [
+ relation_rel_name;
+ domain_rel_name;
+ attribute_rel_name;
+ constraint_rel_name;
+ on_rel_name;
+ timing_rel_name;
]
let is_catalog_relation name = List.mem name catalog_relation_names
-
-let relation_schema : Schema.t =
- Schema.empty |> Schema.add "name" "string"
-
-let domain_schema : Schema.t =
- Schema.empty |> Schema.add "name" "string"
+let relation_schema : Schema.t = Schema.empty |> Schema.add "name" "string"
+let domain_schema : Schema.t = Schema.empty |> Schema.add "name" "string"
let attribute_schema : Schema.t =
Schema.empty
@@ -42,23 +38,20 @@ let attribute_schema : Schema.t =
|> Schema.add "domain_name" "string"
let constraint_schema : Schema.t =
- Schema.empty
- |> Schema.add "name" "string"
+ Schema.empty |> Schema.add "name" "string"
|> Schema.add "relation_name" "string"
-let on_schema : Schema.t =
- Schema.empty |> Schema.add "event" "string"
-
-let timing_schema : Schema.t =
- Schema.empty |> Schema.add "timing" "string"
+let on_schema : Schema.t = Schema.empty |> Schema.add "event" "string"
+let timing_schema : Schema.t = Schema.empty |> Schema.add "timing" "string"
let catalog_definitions =
- [ (relation_rel_name, relation_schema)
- ; (domain_rel_name, domain_schema)
- ; (attribute_rel_name, attribute_schema)
- ; (constraint_rel_name, constraint_schema)
- ; (on_rel_name, on_schema)
- ; (timing_rel_name, timing_schema)
+ [
+ (relation_rel_name, relation_schema);
+ (domain_rel_name, domain_schema);
+ (attribute_rel_name, attribute_schema);
+ (constraint_rel_name, constraint_schema);
+ (on_rel_name, on_schema);
+ (timing_rel_name, timing_schema);
]
(* TODO: all tuple builders use Obj.magic to coerce string values into
@@ -66,51 +59,59 @@ let catalog_definitions =
should use Obj.repr instead. *)
let build_relation_tuple rel_name : Tuple.materialized =
- { Tuple.relation = relation_rel_name
- ; attributes =
+ {
+ Tuple.relation = relation_rel_name;
+ attributes =
Tuple.AttributeMap.singleton "name"
- { Attribute.value = Obj.magic rel_name }
+ { Attribute.value = Obj.magic rel_name };
}
let build_domain_tuple dom_name : Tuple.materialized =
- { Tuple.relation = domain_rel_name
- ; attributes =
+ {
+ Tuple.relation = domain_rel_name;
+ attributes =
Tuple.AttributeMap.singleton "name"
- { Attribute.value = Obj.magic dom_name }
+ { Attribute.value = Obj.magic dom_name };
}
-let build_attribute_tuples ~relation_name (schema : Schema.t) : Tuple.materialized list =
- List.map (fun (attr_n, dom_n) ->
- { Tuple.relation = attribute_rel_name
- ; attributes =
- Tuple.AttributeMap.of_list
- [ ("relation_name", { Attribute.value = Obj.magic relation_name })
- ; ("attr_name", { Attribute.value = Obj.magic attr_n })
- ; ("domain_name", { Attribute.value = Obj.magic dom_n })
- ]
- }
- ) schema
+let build_attribute_tuples ~relation_name (schema : Schema.t) :
+ Tuple.materialized list =
+ List.map
+ (fun (attr_n, dom_n) ->
+ {
+ Tuple.relation = attribute_rel_name;
+ attributes =
+ Tuple.AttributeMap.of_list
+ [
+ ("relation_name", { Attribute.value = Obj.magic relation_name });
+ ("attr_name", { Attribute.value = Obj.magic attr_n });
+ ("domain_name", { Attribute.value = Obj.magic dom_n });
+ ];
+ })
+ schema
let build_constraint_tuple cname rel_name : Tuple.materialized =
- { Tuple.relation = constraint_rel_name
- ; attributes =
+ {
+ Tuple.relation = constraint_rel_name;
+ attributes =
Tuple.AttributeMap.of_list
- [ ("name", { Attribute.value = Obj.magic cname })
- ; ("relation_name", { Attribute.value = Obj.magic rel_name })
- ]
+ [
+ ("name", { Attribute.value = Obj.magic cname });
+ ("relation_name", { Attribute.value = Obj.magic rel_name });
+ ];
}
let build_on_tuple event : Tuple.materialized =
- { Tuple.relation = on_rel_name
- ; attributes =
- Tuple.AttributeMap.singleton "event"
- { Attribute.value = Obj.magic event }
+ {
+ Tuple.relation = on_rel_name;
+ attributes =
+ Tuple.AttributeMap.singleton "event" { Attribute.value = Obj.magic event };
}
let build_timing_tuple timing : Tuple.materialized =
- { Tuple.relation = timing_rel_name
- ; attributes =
+ {
+ Tuple.relation = timing_rel_name;
+ attributes =
Tuple.AttributeMap.singleton "timing"
- { Attribute.value = Obj.magic timing }
+ { Attribute.value = Obj.magic timing };
}
-
diff --git a/lib/prelude/domains.ml b/lib/prelude/domains.ml
index 29104bb..d892696 100644
--- a/lib/prelude/domains.ml
+++ b/lib/prelude/domains.ml
@@ -1,21 +1,19 @@
-(** Predefined fundamental domains, ported from the Erlang implementation.
- Each domain carries a generator (for enumeration) and membership criteria
- (for validation). Values are stored as {!Conventions.AbstractValue.t} via
+(** Predefined fundamental domains, ported from the Erlang implementation. Each
+ domain carries a generator (for enumeration) and membership criteria (for
+ validation). Values are stored as {!Conventions.AbstractValue.t} via
[Obj.magic], following the same convention as {!Standard}. *)
(** Bijection from natural number to integer: 0→0, 1→1, 2→-1, 3→2, 4→-2, … *)
let nat_to_int n =
- if n = 0 then 0
- else if n mod 2 = 1 then (n + 1) / 2
- else -(n / 2)
+ if n = 0 then 0 else if n mod 2 = 1 then (n + 1) / 2 else -(n / 2)
(** Cantor pairing inverse: given position [n], returns a pair [(a, b)] of
natural numbers such that [a + b] lies on the [n]-th diagonal. *)
let cantor_unpair n =
let w =
- int_of_float (floor ((sqrt (float_of_int (8 * n + 1)) -. 1.) /. 2.))
+ int_of_float (floor ((sqrt (float_of_int ((8 * n) + 1)) -. 1.) /. 2.))
in
- let t = (w * (w + 1)) / 2 in
+ let t = w * (w + 1) / 2 in
let b = n - t in
let a = w - b in
(a, b)
@@ -26,84 +24,84 @@ let integer : Domain.t =
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- let v = nat_to_int n in
- let attributes = Tuple.AttributeMap.of_list [ ("value", Obj.magic v) ] in
- Generator.Value
- (Tuple.make_materialized ~relation:"integer" ~attributes, generator)
+ let v = nat_to_int n in
+ let attributes =
+ Tuple.AttributeMap.of_list [ ("value", Obj.magic v) ]
+ in
+ Generator.Value
+ (Tuple.make_materialized ~relation:"integer" ~attributes, generator)
| None ->
- Generator.Error
- "Cannot produce a randomly enumerated value for the integer domain."
+ Generator.Error
+ "Cannot produce a randomly enumerated value for the integer domain."
in
let membership_criteria : Tuple.t -> bool = function
| Tuple.Materialized _ -> true
| Tuple.NonMaterialized _ -> false
in
Domain.make ~name:"integer" ~generator ~membership_criteria
- ~cardinality:Conventions.Cardinality.AlephZero
- ~compare:(fun a b -> Stdlib.compare (Obj.magic a : int) (Obj.magic b : int))
+ ~cardinality:Conventions.Cardinality.AlephZero ~compare:(fun a b ->
+ Stdlib.compare (Obj.magic a : int) (Obj.magic b : int))
-(** Natural number domain: non-negative integers (0, 1, 2, …).
- Schema: [value: natural]. *)
+(** Natural number domain: non-negative integers (0, 1, 2, …). Schema:
+ [value: natural]. *)
let natural : Domain.t =
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- let attributes = Tuple.AttributeMap.of_list [ ("value", Obj.magic n) ] in
- Generator.Value
- (Tuple.make_materialized ~relation:"natural" ~attributes, generator)
+ let attributes =
+ Tuple.AttributeMap.of_list [ ("value", Obj.magic n) ]
+ in
+ Generator.Value
+ (Tuple.make_materialized ~relation:"natural" ~attributes, generator)
| None ->
- Generator.Error
- "Cannot produce a randomly enumerated value for the natural domain."
+ Generator.Error
+ "Cannot produce a randomly enumerated value for the natural domain."
in
let membership_criteria : Tuple.t -> bool = function
| Tuple.Materialized m -> (
- match Tuple.AttributeMap.find_opt "value" m.attributes with
- | Some attr -> (Obj.magic attr : int) >= 0
- | None -> false)
+ match Tuple.AttributeMap.find_opt "value" m.attributes with
+ | Some attr -> (Obj.magic attr : int) >= 0
+ | None -> false)
| Tuple.NonMaterialized _ -> false
in
Domain.make ~name:"natural" ~generator ~membership_criteria
- ~cardinality:Conventions.Cardinality.AlephZero
- ~compare:(fun a b -> Stdlib.compare (Obj.magic a : int) (Obj.magic b : int))
+ ~cardinality:Conventions.Cardinality.AlephZero ~compare:(fun a b ->
+ Stdlib.compare (Obj.magic a : int) (Obj.magic b : int))
(** Rational number domain: pairs [(numerator, denominator)] where the
- denominator is never zero. The generator enumerates all such pairs via
- Cantor pairing on the integers.
- Schema: [numerator: integer, denominator: integer]. *)
+ denominator is never zero. The generator enumerates all such pairs via
+ Cantor pairing on the integers. Schema:
+ [numerator: integer, denominator: integer]. *)
let rational : Domain.t =
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- let a, b = cantor_unpair n in
- let num = nat_to_int a in
- (* Map b → non-zero integer: 0→1, 1→-1, 2→2, 3→-2, … *)
- let den =
- if b mod 2 = 0 then b / 2 + 1 else -((b + 1) / 2)
- in
- let attributes =
- Tuple.AttributeMap.of_list
- [ ("numerator", Obj.magic num); ("denominator", Obj.magic den) ]
- in
- Generator.Value
- (Tuple.make_materialized ~relation:"rational" ~attributes, generator)
+ let a, b = cantor_unpair n in
+ let num = nat_to_int a in
+ (* Map b → non-zero integer: 0→1, 1→-1, 2→2, 3→-2, … *)
+ let den = if b mod 2 = 0 then (b / 2) + 1 else -((b + 1) / 2) in
+ let attributes =
+ Tuple.AttributeMap.of_list
+ [ ("numerator", Obj.magic num); ("denominator", Obj.magic den) ]
+ in
+ Generator.Value
+ (Tuple.make_materialized ~relation:"rational" ~attributes, generator)
| None ->
- Generator.Error
- "Cannot produce a randomly enumerated value for the rational domain."
+ Generator.Error
+ "Cannot produce a randomly enumerated value for the rational domain."
in
let membership_criteria : Tuple.t -> bool = function
| Tuple.Materialized m -> (
- match Tuple.AttributeMap.find_opt "denominator" m.attributes with
- | Some attr -> (Obj.magic attr : int) <> 0
- | None -> false)
+ match Tuple.AttributeMap.find_opt "denominator" m.attributes with
+ | Some attr -> (Obj.magic attr : int) <> 0
+ | None -> false)
| Tuple.NonMaterialized _ -> false
in
Domain.make ~name:"rational" ~generator ~membership_criteria
- ~cardinality:Conventions.Cardinality.AlephZero
- ~compare:(fun a b ->
+ ~cardinality:Conventions.Cardinality.AlephZero ~compare:(fun a b ->
Stdlib.compare (Obj.magic a : float) (Obj.magic b : float))
-(** String domain: any string value. Not enumerable.
- Schema: [value: string]. *)
+(** String domain: any string value. Not enumerable. Schema: [value: string]. *)
let string : Domain.t =
let generator (_ : int option) : Generator.result =
Generator.Error "Strings are not enumerable."
@@ -113,6 +111,5 @@ let string : Domain.t =
| Tuple.NonMaterialized _ -> false
in
Domain.make ~name:"string" ~generator ~membership_criteria
- ~cardinality:Conventions.Cardinality.AlephZero
- ~compare:(fun a b ->
+ ~cardinality:Conventions.Cardinality.AlephZero ~compare:(fun a b ->
String.compare (Obj.magic a : string) (Obj.magic b : string))
diff --git a/lib/prelude/standard.ml b/lib/prelude/standard.ml
index 68012fc..6bdab0c 100644
--- a/lib/prelude/standard.ml
+++ b/lib/prelude/standard.ml
@@ -7,22 +7,23 @@
let mk v = { Attribute.value = Obj.repr v }
-(** Build a comparison relation over a single domain.
- [pred] receives the result of [Stdlib.compare left right]. *)
+(** Build a comparison relation over a single domain. [pred] receives the result
+ of [Stdlib.compare left right]. *)
let make_comparison ~name ~domain_name ~pred ~cardinality ~generator =
let schema =
- Schema.empty |> Schema.add "left" domain_name
+ Schema.empty
+ |> Schema.add "left" domain_name
|> Schema.add "right" domain_name
in
let membership_criteria : Tuple.t -> bool = function
| Tuple.Materialized m -> (
- match
- ( Tuple.AttributeMap.find_opt "left" m.attributes,
- Tuple.AttributeMap.find_opt "right" m.attributes )
- with
- | Some l, Some r ->
- pred (Stdlib.compare l.Attribute.value r.Attribute.value)
- | _ -> false)
+ match
+ ( Tuple.AttributeMap.find_opt "left" m.attributes,
+ Tuple.AttributeMap.find_opt "right" m.attributes )
+ with
+ | Some l, Some r ->
+ pred (Stdlib.compare l.Attribute.value r.Attribute.value)
+ | _ -> false)
| Tuple.NonMaterialized _ -> false
in
Relation.make ~hash:None ~name ~schema ~tree:None ~constraints:None
@@ -33,38 +34,35 @@ let make_comparison ~name ~domain_name ~pred ~cardinality ~generator =
(** Enumerate pairs (a, b) where a < b using triangular indexing. *)
let pair_of_nat_lt n =
let nf = float_of_int n in
- let r = int_of_float (floor ((1. +. sqrt (1. +. 8. *. nf)) /. 2.)) in
- let t_prev = (r * (r - 1)) / 2 in
+ let r = int_of_float (floor ((1. +. sqrt (1. +. (8. *. nf))) /. 2.)) in
+ let t_prev = r * (r - 1) / 2 in
let left = n - t_prev in
(left, r)
(** Enumerate all pairs (a, b) via Cantor pairing. *)
let cantor_pair_of_nat n =
let w =
- int_of_float (floor ((sqrt (float_of_int (8 * n + 1)) -. 1.) /. 2.))
+ int_of_float (floor ((sqrt (float_of_int ((8 * n) + 1)) -. 1.) /. 2.))
in
- let t = (w * (w + 1)) / 2 in
+ let t = w * (w + 1) / 2 in
let b = n - t in
let a = w - b in
(a, b)
-
let less_than_natural : Relation.t =
let rec generator (position : int option) : Generator.result =
match position with
| Some position ->
- let left, right = pair_of_nat_lt position in
- let attributes : Attribute.materialized Tuple.AttributeMap.t =
- Tuple.AttributeMap.of_list
- [ ("left", mk left); ("right", mk right) ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:"less_than" ~attributes,
- generator )
+ let left, right = pair_of_nat_lt position in
+ let attributes : Attribute.materialized Tuple.AttributeMap.t =
+ Tuple.AttributeMap.of_list [ ("left", mk left); ("right", mk right) ]
+ in
+ Generator.Value
+ (Tuple.make_materialized ~relation:"less_than" ~attributes, generator)
| None ->
- Error
- "Cannot produce a randomly enumerated value for less_than over \
- naturals."
+ Error
+ "Cannot produce a randomly enumerated value for less_than over \
+ naturals."
in
make_comparison ~name:"natural_natural_less_than" ~domain_name:"natural"
~pred:(fun c -> c < 0)
@@ -74,17 +72,16 @@ let less_than_or_equal_natural : Relation.t =
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- let a, b = cantor_pair_of_nat n in
- (* a <= b is always true when a <= b; we enumerate all (a, b) with a <= b *)
- let left = min a b in
- let right = max a b in
- let attributes =
- Tuple.AttributeMap.of_list
- [ ("left", mk left); ("right", mk right) ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:"less_than_or_equal" ~attributes,
- generator )
+ let a, b = cantor_pair_of_nat n in
+ (* a <= b is always true when a <= b; we enumerate all (a, b) with a <= b *)
+ let left = min a b in
+ let right = max a b in
+ let attributes =
+ Tuple.AttributeMap.of_list [ ("left", mk left); ("right", mk right) ]
+ in
+ Generator.Value
+ ( Tuple.make_materialized ~relation:"less_than_or_equal" ~attributes,
+ generator )
| None -> Error "Cannot enumerate less_than_or_equal randomly."
in
make_comparison ~name:"natural_natural_less_than_or_equal"
@@ -96,15 +93,14 @@ let greater_than_natural : Relation.t =
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- let left, right = pair_of_nat_lt n in
- (* Swap: right > left *)
- let attributes =
- Tuple.AttributeMap.of_list
- [ ("left", mk right); ("right", mk left) ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:"greater_than" ~attributes,
- generator )
+ let left, right = pair_of_nat_lt n in
+ (* Swap: right > left *)
+ let attributes =
+ Tuple.AttributeMap.of_list [ ("left", mk right); ("right", mk left) ]
+ in
+ Generator.Value
+ ( Tuple.make_materialized ~relation:"greater_than" ~attributes,
+ generator )
| None -> Error "Cannot enumerate greater_than randomly."
in
make_comparison ~name:"natural_natural_greater_than" ~domain_name:"natural"
@@ -115,16 +111,15 @@ let greater_than_or_equal_natural : Relation.t =
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- let a, b = cantor_pair_of_nat n in
- let left = max a b in
- let right = min a b in
- let attributes =
- Tuple.AttributeMap.of_list
- [ ("left", mk left); ("right", mk right) ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:"greater_than_or_equal" ~attributes,
- generator )
+ let a, b = cantor_pair_of_nat n in
+ let left = max a b in
+ let right = min a b in
+ let attributes =
+ Tuple.AttributeMap.of_list [ ("left", mk left); ("right", mk right) ]
+ in
+ Generator.Value
+ ( Tuple.make_materialized ~relation:"greater_than_or_equal" ~attributes,
+ generator )
| None -> Error "Cannot enumerate greater_than_or_equal randomly."
in
make_comparison ~name:"natural_natural_greater_than_or_equal"
@@ -136,12 +131,11 @@ let equal_natural : Relation.t =
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- let attributes =
- Tuple.AttributeMap.of_list
- [ ("left", mk n); ("right", mk n) ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:"equal" ~attributes, generator )
+ let attributes =
+ Tuple.AttributeMap.of_list [ ("left", mk n); ("right", mk n) ]
+ in
+ Generator.Value
+ (Tuple.make_materialized ~relation:"equal" ~attributes, generator)
| None -> Error "Cannot enumerate equal randomly."
in
make_comparison ~name:"natural_natural_equal" ~domain_name:"natural"
@@ -152,21 +146,19 @@ let not_equal_natural : Relation.t =
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- let a, b = cantor_pair_of_nat n in
- let left, right = if a = b then (a, b + 1) else (a, b) in
- let attributes =
- Tuple.AttributeMap.of_list
- [ ("left", mk left); ("right", mk right) ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:"not_equal" ~attributes, generator )
+ let a, b = cantor_pair_of_nat n in
+ let left, right = if a = b then (a, b + 1) else (a, b) in
+ let attributes =
+ Tuple.AttributeMap.of_list [ ("left", mk left); ("right", mk right) ]
+ in
+ Generator.Value
+ (Tuple.make_materialized ~relation:"not_equal" ~attributes, generator)
| None -> Error "Cannot enumerate not_equal randomly."
in
make_comparison ~name:"natural_natural_not_equal" ~domain_name:"natural"
~pred:(fun c -> c <> 0)
~cardinality:Conventions.Cardinality.AlephZero ~generator
-
let plus_natural : Relation.t =
let schema =
Schema.empty |> Schema.add "a" "natural" |> Schema.add "b" "natural"
@@ -175,175 +167,159 @@ let plus_natural : Relation.t =
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- let a, b = cantor_pair_of_nat n in
- let s = a + b in
- let attributes =
- Tuple.AttributeMap.of_list
- [ ("a", mk a); ("b", mk b); ("sum", mk s) ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:"plus" ~attributes, generator )
+ let a, b = cantor_pair_of_nat n in
+ let s = a + b in
+ let attributes =
+ Tuple.AttributeMap.of_list [ ("a", mk a); ("b", mk b); ("sum", mk s) ]
+ in
+ Generator.Value
+ (Tuple.make_materialized ~relation:"plus" ~attributes, generator)
| None -> Error "Cannot enumerate plus randomly."
in
let membership_criteria : Tuple.t -> bool = function
| Tuple.Materialized m -> (
- match
- ( Tuple.AttributeMap.find_opt "a" m.attributes,
- Tuple.AttributeMap.find_opt "b" m.attributes,
- Tuple.AttributeMap.find_opt "sum" m.attributes )
- with
- | Some a, Some b, Some s ->
- (Obj.magic a.Attribute.value : int)
- + (Obj.magic b.Attribute.value : int)
- = (Obj.magic s.Attribute.value : int)
- | _ -> false)
+ match
+ ( Tuple.AttributeMap.find_opt "a" m.attributes,
+ Tuple.AttributeMap.find_opt "b" m.attributes,
+ Tuple.AttributeMap.find_opt "sum" m.attributes )
+ with
+ | Some a, Some b, Some s ->
+ (Obj.magic a.Attribute.value : int)
+ + (Obj.magic b.Attribute.value : int)
+ = (Obj.magic s.Attribute.value : int)
+ | _ -> false)
| Tuple.NonMaterialized _ -> false
in
Relation.make ~hash:None ~name:"natural_plus" ~schema ~tree:None
- ~constraints:None
- ~cardinality:Conventions.Cardinality.AlephZero
+ ~constraints:None ~cardinality:Conventions.Cardinality.AlephZero
~generator:(Some generator) ~membership_criteria
~provenance:(Relation.Provenance.Base "plus")
~lineage:(Relation.Lineage.Base "plus")
let times_natural : Relation.t =
let schema =
- Schema.empty |> Schema.add "a" "natural"
- |> Schema.add "b" "natural"
+ Schema.empty |> Schema.add "a" "natural" |> Schema.add "b" "natural"
|> Schema.add "product" "natural"
in
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- let a, b = cantor_pair_of_nat n in
- let p = a * b in
- let attributes =
- Tuple.AttributeMap.of_list
- [
- ("a", mk a); ("b", mk b); ("product", mk p);
- ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:"times" ~attributes, generator )
+ let a, b = cantor_pair_of_nat n in
+ let p = a * b in
+ let attributes =
+ Tuple.AttributeMap.of_list
+ [ ("a", mk a); ("b", mk b); ("product", mk p) ]
+ in
+ Generator.Value
+ (Tuple.make_materialized ~relation:"times" ~attributes, generator)
| None -> Error "Cannot enumerate times randomly."
in
let membership_criteria : Tuple.t -> bool = function
| Tuple.Materialized m -> (
- match
- ( Tuple.AttributeMap.find_opt "a" m.attributes,
- Tuple.AttributeMap.find_opt "b" m.attributes,
- Tuple.AttributeMap.find_opt "product" m.attributes )
- with
- | Some a, Some b, Some p ->
- (Obj.magic a.Attribute.value : int)
- * (Obj.magic b.Attribute.value : int)
- = (Obj.magic p.Attribute.value : int)
- | _ -> false)
+ match
+ ( Tuple.AttributeMap.find_opt "a" m.attributes,
+ Tuple.AttributeMap.find_opt "b" m.attributes,
+ Tuple.AttributeMap.find_opt "product" m.attributes )
+ with
+ | Some a, Some b, Some p ->
+ (Obj.magic a.Attribute.value : int)
+ * (Obj.magic b.Attribute.value : int)
+ = (Obj.magic p.Attribute.value : int)
+ | _ -> false)
| Tuple.NonMaterialized _ -> false
in
Relation.make ~hash:None ~name:"natural_times" ~schema ~tree:None
- ~constraints:None
- ~cardinality:Conventions.Cardinality.AlephZero
+ ~constraints:None ~cardinality:Conventions.Cardinality.AlephZero
~generator:(Some generator) ~membership_criteria
~provenance:(Relation.Provenance.Base "times")
~lineage:(Relation.Lineage.Base "times")
let minus_natural : Relation.t =
let schema =
- Schema.empty |> Schema.add "a" "natural"
- |> Schema.add "b" "natural"
+ Schema.empty |> Schema.add "a" "natural" |> Schema.add "b" "natural"
|> Schema.add "difference" "natural"
in
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- (* Enumerate pairs where a >= b, so difference >= 0 *)
- let b, diff = cantor_pair_of_nat n in
- let a = b + diff in
- let attributes =
- Tuple.AttributeMap.of_list
- [
- ("a", mk a);
- ("b", mk b);
- ("difference", mk diff);
- ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:"minus" ~attributes, generator )
+ (* Enumerate pairs where a >= b, so difference >= 0 *)
+ let b, diff = cantor_pair_of_nat n in
+ let a = b + diff in
+ let attributes =
+ Tuple.AttributeMap.of_list
+ [ ("a", mk a); ("b", mk b); ("difference", mk diff) ]
+ in
+ Generator.Value
+ (Tuple.make_materialized ~relation:"minus" ~attributes, generator)
| None -> Error "Cannot enumerate minus randomly."
in
let membership_criteria : Tuple.t -> bool = function
| Tuple.Materialized m -> (
- match
- ( Tuple.AttributeMap.find_opt "a" m.attributes,
- Tuple.AttributeMap.find_opt "b" m.attributes,
- Tuple.AttributeMap.find_opt "difference" m.attributes )
- with
- | Some a, Some b, Some d ->
- let av = (Obj.magic a.Attribute.value : int) in
- let bv = (Obj.magic b.Attribute.value : int) in
- let dv = (Obj.magic d.Attribute.value : int) in
- av - bv = dv && dv >= 0
- | _ -> false)
+ match
+ ( Tuple.AttributeMap.find_opt "a" m.attributes,
+ Tuple.AttributeMap.find_opt "b" m.attributes,
+ Tuple.AttributeMap.find_opt "difference" m.attributes )
+ with
+ | Some a, Some b, Some d ->
+ let av = (Obj.magic a.Attribute.value : int) in
+ let bv = (Obj.magic b.Attribute.value : int) in
+ let dv = (Obj.magic d.Attribute.value : int) in
+ av - bv = dv && dv >= 0
+ | _ -> false)
| Tuple.NonMaterialized _ -> false
in
Relation.make ~hash:None ~name:"natural_minus" ~schema ~tree:None
- ~constraints:None
- ~cardinality:Conventions.Cardinality.AlephZero
+ ~constraints:None ~cardinality:Conventions.Cardinality.AlephZero
~generator:(Some generator) ~membership_criteria
~provenance:(Relation.Provenance.Base "minus")
~lineage:(Relation.Lineage.Base "minus")
let divide_natural : Relation.t =
let schema =
- Schema.empty |> Schema.add "a" "natural"
- |> Schema.add "b" "natural"
+ Schema.empty |> Schema.add "a" "natural" |> Schema.add "b" "natural"
|> Schema.add "quotient" "natural"
|> Schema.add "remainder" "natural"
in
let rec generator (position : int option) : Generator.result =
match position with
| Some n ->
- (* Enumerate (b, q, r) triples where b > 0, then a = b*q + r, 0 <= r < b *)
- (* We use a nested Cantor pairing: n -> (b_idx, qr_idx) -> (q, r) *)
- let b_idx, qr_idx = cantor_pair_of_nat n in
- let b = b_idx + 1 in (* b > 0 *)
- let q, r_raw = cantor_pair_of_nat qr_idx in
- let r = r_raw mod b in
- let a = b * q + r in
- let attributes =
- Tuple.AttributeMap.of_list
- [
- ("a", mk a);
- ("b", mk b);
- ("quotient", mk q);
- ("remainder", mk r);
- ]
- in
- Generator.Value
- ( Tuple.make_materialized ~relation:"divide" ~attributes, generator )
+ (* Enumerate (b, q, r) triples where b > 0, then a = b*q + r, 0 <= r < b *)
+ (* We use a nested Cantor pairing: n -> (b_idx, qr_idx) -> (q, r) *)
+ let b_idx, qr_idx = cantor_pair_of_nat n in
+ let b = b_idx + 1 in
+ (* b > 0 *)
+ let q, r_raw = cantor_pair_of_nat qr_idx in
+ let r = r_raw mod b in
+ let a = (b * q) + r in
+ let attributes =
+ Tuple.AttributeMap.of_list
+ [
+ ("a", mk a); ("b", mk b); ("quotient", mk q); ("remainder", mk r);
+ ]
+ in
+ Generator.Value
+ (Tuple.make_materialized ~relation:"divide" ~attributes, generator)
| None -> Error "Cannot enumerate divide randomly."
in
let membership_criteria : Tuple.t -> bool = function
| Tuple.Materialized m -> (
- match
- ( Tuple.AttributeMap.find_opt "a" m.attributes,
- Tuple.AttributeMap.find_opt "b" m.attributes,
- Tuple.AttributeMap.find_opt "quotient" m.attributes,
- Tuple.AttributeMap.find_opt "remainder" m.attributes )
- with
- | Some a, Some b, Some q, Some r ->
- let av = (Obj.magic a.Attribute.value : int) in
- let bv = (Obj.magic b.Attribute.value : int) in
- let qv = (Obj.magic q.Attribute.value : int) in
- let rv = (Obj.magic r.Attribute.value : int) in
- bv > 0 && av = bv * qv + rv && rv >= 0 && rv < bv
- | _ -> false)
+ match
+ ( Tuple.AttributeMap.find_opt "a" m.attributes,
+ Tuple.AttributeMap.find_opt "b" m.attributes,
+ Tuple.AttributeMap.find_opt "quotient" m.attributes,
+ Tuple.AttributeMap.find_opt "remainder" m.attributes )
+ with
+ | Some a, Some b, Some q, Some r ->
+ let av = (Obj.magic a.Attribute.value : int) in
+ let bv = (Obj.magic b.Attribute.value : int) in
+ let qv = (Obj.magic q.Attribute.value : int) in
+ let rv = (Obj.magic r.Attribute.value : int) in
+ bv > 0 && av = (bv * qv) + rv && rv >= 0 && rv < bv
+ | _ -> false)
| Tuple.NonMaterialized _ -> false
in
Relation.make ~hash:None ~name:"natural_divide" ~schema ~tree:None
- ~constraints:None
- ~cardinality:Conventions.Cardinality.AlephZero
+ ~constraints:None ~cardinality:Conventions.Cardinality.AlephZero
~generator:(Some generator) ~membership_criteria
~provenance:(Relation.Provenance.Base "divide")
~lineage:(Relation.Lineage.Base "divide")
diff --git a/lib/relation.ml b/lib/relation.ml
index 0773c6c..285bcef 100644
--- a/lib/relation.ml
+++ b/lib/relation.ml
@@ -1,5 +1,5 @@
-(** Use the Merkle module for tuple hash storage *)
module Tree = Merkle
+(** Use the Merkle module for tuple hash storage *)
module RelationConstraint = struct
type name = string
@@ -54,4 +54,4 @@ let make ~hash ~name ~schema ~tree ~constraints ~cardinality ~generator
membership_criteria;
provenance;
lineage;
- } \ No newline at end of file
+ }
diff --git a/lib/schema.ml b/lib/schema.ml
index e17f7a5..923284a 100644
--- a/lib/schema.ml
+++ b/lib/schema.ml
@@ -1,7 +1,7 @@
(** Schema: maps attribute names to domain/type names.
- A schema defines the structure of a relation by listing each attribute
- and its associated domain (type). This is used for:
+ A schema defines the structure of a relation by listing each attribute and
+ its associated domain (type). This is used for:
- Hashing relations (schema is part of the relation identity)
- Validation (checking tuple membership)
- Persistence (storing and loading relations with their structure) *)
@@ -9,13 +9,8 @@
type t = (string * string) list
let empty : t = []
-
-let add name domain_name (schema : t) : t =
- (name, domain_name) :: schema
-
-let attributes (schema : t) =
- List.map fst schema
+let add name domain_name (schema : t) : t = (name, domain_name) :: schema
+let attributes (schema : t) = List.map fst schema
let to_string schema =
- List.map (fun (n, t) -> n ^ ":" ^ t) schema
- |> String.concat ","
+ List.map (fun (n, t) -> n ^ ":" ^ t) schema |> String.concat ","
diff --git a/lib/scl/executor.ml b/lib/scl/executor.ml
index 6cb17b8..d48d852 100644
--- a/lib/scl/executor.ml
+++ b/lib/scl/executor.ml
@@ -6,72 +6,68 @@ type cursor_batch = {
has_more : bool;
}
-type exec_result =
- | Batch of cursor_batch
- | Closed of Management.Database.t
+type exec_result = Batch of cursor_batch | Closed of Management.Database.t
let sessions : Session.t option ref = ref None
-
let set_sessions s = sessions := Some s
module Make (Storage : Management.Physical.S) = struct
- module DrlExec = Drl.Executor.Make(Storage)
- module Alg = Algebra.Make(Storage)
+ module DrlExec = Drl.Executor.Make (Storage)
+ module Alg = Algebra.Make (Storage)
type error =
- | ParseError of string
- | QueryError of DrlExec.error
+ | ParseError of string
+ | QueryError of DrlExec.error
| CursorError of string
let sexp_of_error e =
let open Sexplib.Sexp in
match e with
- | ParseError s -> List [Atom "parse-error"; Atom s]
- | QueryError e -> DrlExec.sexp_of_error e
- | CursorError s -> List [Atom "cursor-error"; Atom s]
+ | ParseError s -> List [ Atom "parse-error"; Atom s ]
+ | QueryError e -> DrlExec.sexp_of_error e
+ | CursorError s -> List [ Atom "cursor-error"; Atom s ]
let get_sessions () =
match !sessions with
| Some s -> Ok s
- | None -> Error (CursorError "The session registry has not been initialised; ensure `set_sessions` is called at startup.")
+ | None ->
+ Error
+ (CursorError
+ "The session registry has not been initialised; ensure \
+ `set_sessions` is called at startup.")
let ( let* ) = Result.bind
- let execute
- (storage : Storage.t)
- (db : Management.Database.t)
- (stmt : Ast.statement)
- : (exec_result, error) result =
+ let execute (storage : Storage.t) (db : Management.Database.t)
+ (stmt : Ast.statement) : (exec_result, error) result =
match stmt with
| Ast.Begin { query; limit } ->
- let* reg = get_sessions () in
- let* rel =
- DrlExec.execute storage db query
- |> Result.map_error (fun e -> QueryError e)
- in
- let gen = Alg.to_generator storage rel in
- let query_str = Drl.Parser.to_string query in
- let cur = Session.register reg ~db ~query:query_str ~generator:gen in
- let batch = Option.value ~default:default_batch limit in
- let* (rows, has_more) =
- Session.fetch reg ~id:cur.Session.id ~limit:batch
- |> Result.map_error (fun s -> CursorError s)
- in
- Ok (Batch { cursor_id = cur.Session.id; rows; has_more })
-
+ let* reg = get_sessions () in
+ let* rel =
+ DrlExec.execute storage db query
+ |> Result.map_error (fun e -> QueryError e)
+ in
+ let gen = Alg.to_generator storage rel in
+ let query_str = Drl.Parser.to_string query in
+ let cur = Session.register reg ~db ~query:query_str ~generator:gen in
+ let batch = Option.value ~default:default_batch limit in
+ let* rows, has_more =
+ Session.fetch reg ~id:cur.Session.id ~limit:batch
+ |> Result.map_error (fun s -> CursorError s)
+ in
+ Ok (Batch { cursor_id = cur.Session.id; rows; has_more })
| Ast.Fetch { cursor; limit } ->
- let* reg = get_sessions () in
- let batch = Option.value ~default:default_batch limit in
- let* (rows, has_more) =
- Session.fetch reg ~id:cursor ~limit:batch
- |> Result.map_error (fun s -> CursorError s)
- in
- Ok (Batch { cursor_id = cursor; rows; has_more })
-
+ let* reg = get_sessions () in
+ let batch = Option.value ~default:default_batch limit in
+ let* rows, has_more =
+ Session.fetch reg ~id:cursor ~limit:batch
+ |> Result.map_error (fun s -> CursorError s)
+ in
+ Ok (Batch { cursor_id = cursor; rows; has_more })
| Ast.Close { cursor } ->
- let* reg = get_sessions () in
- Session.close reg ~id:cursor;
- Ok (Closed db)
+ let* reg = get_sessions () in
+ Session.close reg ~id:cursor;
+ Ok (Closed db)
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/scl/sublanguage.ml b/lib/scl/sublanguage.ml
index 7098ced..b39e720 100644
--- a/lib/scl/sublanguage.ml
+++ b/lib/scl/sublanguage.ml
@@ -1,9 +1,9 @@
module Make (Storage : Management.Physical.S) = struct
- module Exec = Executor.Make(Storage)
+ module Exec = Executor.Make (Storage)
type storage = Storage.t
- type ast = Ast.statement
- type error = Exec.error
+ type ast = Ast.statement
+ type error = Exec.error
let name = "scl"
@@ -16,11 +16,10 @@ module Make (Storage : Management.Physical.S) = struct
Exec.execute storage db ast
|> Result.map (function
| Executor.Batch { cursor_id; rows; has_more } ->
- Sublanguage.Cursor { cursor_id; rows; has_more }
- | Executor.Closed db ->
- Sublanguage.Transition (db, "cursor closed"))
+ Sublanguage.Cursor { cursor_id; rows; has_more }
+ | Executor.Closed db -> Sublanguage.Transition (db, "cursor closed"))
let sexp_of_error = Exec.sexp_of_error
end
-module Memory = Make(Management.Physical.Memory)
+module Memory = Make (Management.Physical.Memory)
diff --git a/lib/session.ml b/lib/session.ml
index 272a419..a58d00b 100644
--- a/lib/session.ml
+++ b/lib/session.ml
@@ -1,8 +1,8 @@
(** Cursor registry for streaming tuple consumption.
- Each cursor wraps a [Generator.t] produced by a DRL query and
- tracks the current position so that successive [fetch] calls
- return the next batch of rows without replaying the query. *)
+ Each cursor wraps a [Generator.t] produced by a DRL query and tracks the
+ current position so that successive [fetch] calls return the next batch of
+ rows without replaying the query. *)
type cursor = {
id : string;
@@ -13,70 +13,67 @@ type cursor = {
created_at : float;
}
-type t = {
- tbl : (string, cursor) Hashtbl.t;
- mutable counter : int;
-}
+type t = { tbl : (string, cursor) Hashtbl.t; mutable counter : int }
-let create () : t =
- { tbl = Hashtbl.create 16; counter = 0 }
+let create () : t = { tbl = Hashtbl.create 16; counter = 0 }
let register (reg : t) ~(db : Management.Database.t) ~(query : string)
~(generator : Generator.t) : cursor =
let raw = string_of_int reg.counter ^ query ^ db.Management.Database.hash in
let id = Conventions.Hash.hash_text raw in
reg.counter <- reg.counter + 1;
- let cur = {
- id;
- generator;
- position = 0;
- db_snapshot = db;
- query_sexp = query;
- created_at = Unix.gettimeofday ();
- } in
+ let cur =
+ {
+ id;
+ generator;
+ position = 0;
+ db_snapshot = db;
+ query_sexp = query;
+ created_at = Unix.gettimeofday ();
+ }
+ in
Hashtbl.replace reg.tbl id cur;
cur
-let fetch (reg : t) ~(id : string) ~(limit : int)
- : (Tuple.materialized list * bool, string) result =
+let fetch (reg : t) ~(id : string) ~(limit : int) :
+ (Tuple.materialized list * bool, string) result =
match Hashtbl.find_opt reg.tbl id with
- | None -> Error ("The cursor with identifier `" ^ id ^ "` was not found in the session registry.")
+ | None ->
+ Error
+ ("The cursor with identifier `" ^ id
+ ^ "` was not found in the session registry.")
| Some cur ->
- let rec go gen pos acc count =
- if count >= limit then (List.rev acc, gen, pos, true)
- else
- match gen (Some pos) with
- | Generator.Done -> (List.rev acc, gen, pos, false)
- (* Generator errors are treated as exhaustion: the partial batch is
+ let rec go gen pos acc count =
+ if count >= limit then (List.rev acc, gen, pos, true)
+ else
+ match gen (Some pos) with
+ | Generator.Done -> (List.rev acc, gen, pos, false)
+ (* Generator errors are treated as exhaustion: the partial batch is
returned with has_more = false and the cursor is auto-removed.
The caller receives no indication that the stream terminated
abnormally. When fetch gains a richer return type this arm
should surface the error message instead. *)
- | Generator.Error _ -> (List.rev acc, gen, pos, false)
- | Generator.Value (t, next) ->
- begin match t with
- | Tuple.Materialized m ->
- go next (pos + 1) (m :: acc) (count + 1)
- | Tuple.NonMaterialized _ ->
- go next (pos + 1) acc count
- end
- in
- let (rows, gen', pos', has_more) =
- go cur.generator cur.position [] 0
- in
- cur.generator <- gen';
- cur.position <- pos';
- if not has_more then Hashtbl.remove reg.tbl id;
- Ok (rows, has_more)
+ | Generator.Error _ -> (List.rev acc, gen, pos, false)
+ | Generator.Value (t, next) -> begin
+ match t with
+ | Tuple.Materialized m -> go next (pos + 1) (m :: acc) (count + 1)
+ | Tuple.NonMaterialized _ -> go next (pos + 1) acc count
+ end
+ in
+ let rows, gen', pos', has_more = go cur.generator cur.position [] 0 in
+ cur.generator <- gen';
+ cur.position <- pos';
+ if not has_more then Hashtbl.remove reg.tbl id;
+ Ok (rows, has_more)
-let close (reg : t) ~(id : string) : unit =
- Hashtbl.remove reg.tbl id
+let close (reg : t) ~(id : string) : unit = Hashtbl.remove reg.tbl id
let gc (reg : t) ~(max_age : float) : unit =
let now = Unix.gettimeofday () in
let to_remove =
- Hashtbl.fold (fun k cur acc ->
- if now -. cur.created_at >= max_age then k :: acc else acc)
+ Hashtbl.fold
+ (fun k cur acc ->
+ if now -. cur.created_at >= max_age then k :: acc else acc)
reg.tbl []
in
List.iter (Hashtbl.remove reg.tbl) to_remove
diff --git a/lib/storable.ml b/lib/storable.ml
index 058773c..ec0bce2 100644
--- a/lib/storable.ml
+++ b/lib/storable.ml
@@ -3,7 +3,8 @@
These modules define the wire format for persisting relational engine
objects to storage. Each type has to_bytes/of_bytes for serialization.
- The stored formats capture only the essential data needed for reconstruction:
+ The stored formats capture only the essential data needed for
+ reconstruction:
- Tuple: relation name and attribute hashes
- Relation: name, schema, tuple hashes, cardinality
- Database: name, relation hashes, merkle tree keys, history *)
@@ -12,14 +13,12 @@
module Tuple = struct
type t = {
relation : string;
- attributes : (string * Conventions.Hash.t) list; (* attr_name -> attr_value_hash *)
+ attributes : (string * Conventions.Hash.t) list;
+ (* attr_name -> attr_value_hash *)
}
- let to_bytes (st : t) : bytes =
- Marshal.to_bytes st [Marshal.Closures]
-
- let of_bytes (b : bytes) : t =
- Marshal.from_bytes b 0
+ let to_bytes (st : t) : bytes = Marshal.to_bytes st [ Marshal.Closures ]
+ let of_bytes (b : bytes) : t = Marshal.from_bytes b 0
end
(** Stored relation format for serialization *)
@@ -27,30 +26,26 @@ module Relation = struct
type t = {
name : string;
schema : Schema.t;
- tree_keys : Conventions.Hash.t list; (* Merkle tree contents - tuple hashes *)
+ tree_keys : Conventions.Hash.t list;
+ (* Merkle tree contents - tuple hashes *)
cardinality : Conventions.Cardinality.t;
}
- let to_bytes (sr : t) : bytes =
- Marshal.to_bytes sr [Marshal.Closures]
-
- let of_bytes (b : bytes) : t =
- Marshal.from_bytes b 0
+ let to_bytes (sr : t) : bytes = Marshal.to_bytes sr [ Marshal.Closures ]
+ let of_bytes (b : bytes) : t = Marshal.from_bytes b 0
end
(** Stored database format for serialization *)
module Database = struct
type t = {
name : string;
- relations : (string * Conventions.Hash.t) list; (* name -> relation_hash *)
- tree_keys : Conventions.Hash.t list; (* Merkle tree contents - relation hashes *)
+ relations : (string * Conventions.Hash.t) list; (* name -> relation_hash *)
+ tree_keys : Conventions.Hash.t list;
+ (* Merkle tree contents - relation hashes *)
history : Conventions.Hash.t list;
timestamp : float;
}
- let to_bytes (sd : t) : bytes =
- Marshal.to_bytes sd [Marshal.Closures]
-
- let of_bytes (b : bytes) : t =
- Marshal.from_bytes b 0
+ let to_bytes (sd : t) : bytes = Marshal.to_bytes sd [ Marshal.Closures ]
+ let of_bytes (b : bytes) : t = Marshal.from_bytes b 0
end
diff --git a/lib/sublanguage.ml b/lib/sublanguage.ml
index d92358e..4cfe913 100644
--- a/lib/sublanguage.ml
+++ b/lib/sublanguage.ml
@@ -1,24 +1,24 @@
+type cursor_result = {
+ cursor_id : string;
+ rows : Tuple.materialized list;
+ has_more : bool;
+}
(** Effect classification for sublanguage operations.
Categorically:
- Query: a natural transformation between instance functors (DRL).
Side-effect-free; the database state is unchanged.
- - Transition: a morphism in the category of database states (DDL,
- DML, ICL, DCL, and future TCL). Produces a new state via
- substitution (Harper, PFPL ch. 3-4).
+ - Transition: a morphism in the category of database states (DDL, DML, ICL,
+ DCL, and future TCL). Produces a new state via substitution (Harper, PFPL
+ ch. 3-4).
Future sublanguages:
- - TCL -> Transition (transaction boundaries are state morphisms
- with atomicity constraints)
+ - TCL -> Transition (transaction boundaries are state morphisms with
+ atomicity constraints)
- PPL -> new effect class: potentially non-terminating computation
(Turing-complete; breaks the termination guarantee of DRL)
- ACL -> a functor restriction: narrows the admissible natural
transformations based on authorization context *)
-type cursor_result = {
- cursor_id : string;
- rows : Tuple.materialized list;
- has_more : bool;
-}
type result =
| Query of Relation.t
@@ -29,8 +29,12 @@ module type S = sig
type storage
type ast
type error
+
val name : string
val parse_sexp : Sexplib.Sexp.t -> (ast, error) Result.t
- val execute : storage -> Management.Database.t -> ast -> (result, error) Result.t
+
+ val execute :
+ storage -> Management.Database.t -> ast -> (result, error) Result.t
+
val sexp_of_error : error -> Sexplib.Sexp.t
end
diff --git a/lib/tuple.ml b/lib/tuple.ml
index 11fc508..1ce73b0 100644
--- a/lib/tuple.ml
+++ b/lib/tuple.ml
@@ -1,8 +1,10 @@
module AttributeMap = struct
- include Map.Make(String)
+ include Map.Make (String)
+
let sexp_of_t sexp_of_v m =
Sexplib.Sexp.List
- (List.map (fun (k, v) -> Sexplib.Sexp.List [Sexplib.Sexp.Atom k; sexp_of_v v])
+ (List.map
+ (fun (k, v) -> Sexplib.Sexp.List [ Sexplib.Sexp.Atom k; sexp_of_v v ])
(bindings m))
end
@@ -10,16 +12,17 @@ type non_materialized = {
hash : Conventions.Hash.t;
relation : Conventions.Name.t;
attributes : Attribute.referenced AttributeMap.t;
-} [@@deriving sexp_of]
+}
+[@@deriving sexp_of]
type materialized = {
- relation: Conventions.Name.t;
- attributes: Attribute.materialized AttributeMap.t;
-} [@@deriving sexp_of]
+ relation : Conventions.Name.t;
+ attributes : Attribute.materialized AttributeMap.t;
+}
+[@@deriving sexp_of]
-type t =
- | Materialized of materialized
- | NonMaterialized of non_materialized
+type t = Materialized of materialized | NonMaterialized of non_materialized
[@@deriving sexp_of]
-let make_materialized ~relation ~attributes = Materialized { relation; attributes }
+let make_materialized ~relation ~attributes =
+ Materialized { relation; attributes }