24
Persistent Data Structures in OCaml Anil Madhavapeddy, Imperial College Thomas Gazagnaire, Citrix Systems Inc DEFUN 2009, Edinburgh, UK http://www.flickr.com/photos/stuckincustoms/ 2826117627/

Persistent Data Structures in OCaml

  • Upload
    roscoe

  • View
    67

  • Download
    0

Embed Size (px)

DESCRIPTION

Persistent Data Structures in OCaml. Anil Madhavapeddy , Imperial College Thomas Gazagnaire , Citrix Systems Inc DEFUN 2009, Edinburgh, UK http://www.flickr.com/photos/stuckincustoms/2826117627/. - PowerPoint PPT Presentation

Citation preview

Page 1: Persistent Data Structures in  OCaml

Persistent Data Structuresin OCaml

Anil Madhavapeddy, Imperial College

Thomas Gazagnaire, Citrix Systems Inc

DEFUN 2009, Edinburgh, UK

http://www.flickr.com/photos/stuckincustoms/2826117627/

Page 2: Persistent Data Structures in  OCaml

let sql = “SELECT middle.id, middle.f1_id, middle.f2_id, middle_f2.id, middle_f2.field1, middle_f2.date1, middle_f2.int1, middle_f1.id, middle_f1.field1, middle_f1.date1, middle_f1.int1 FROM middle LEFT JOIN base AS middle_f1 ON (middle_f1.id = middle.f1_id) LEFT JOIN base AS middle_f2 ON (middle_f2.id = middle.f2_id) where id=?” in

let stmt = Sqlite3.prepare sql inSqlite3.bind stmt 1 (Sqlite3.Data.INT (500L));match Sqlite3.step stmt with|Sqlite3.OK -> … AAAAAAAAAAAAAARGGGGH!

Page 3: Persistent Data Structures in  OCaml

type service =| Email of string| Twitter of string| Other of (string * string)and person = { name: string; age: int option; contacts: service list;} with persist ();

Page 4: Persistent Data Structures in  OCaml

type service =| Email of string| Twitter of string| Other of (string * string)and person = { name: string; age: int option; contacts: service list;} with persist ();

Service_OtherINT

Service_Other_1TEXT

Service_Other_2TEXT

Page 5: Persistent Data Structures in  OCaml

type service =| Email of string| Twitter of string| Other of (string * string)and person = { name: string; age: int option; contacts: service list;} with persist ();

Service_OtherINT

Service_Other_1TEXT

Service_Other_2TEXT

ServiceINT

IndexINT

Service_1TEXT

Service_2INT

Page 6: Persistent Data Structures in  OCaml

type service =| Email of string| Twitter of string| Other of (string * string)and person = { name: string; age: int option; contacts: service list;} with persist ();

Service_OtherINT

Service_Other_1TEXT

Service_Other_2TEXT

ServiceINT

IndexINT

Service_1TEXT

Service_2INT

Person_contactsINT

Service_idINT

IndexINT

Page 7: Persistent Data Structures in  OCaml

type service =| Email of string| Twitter of string| Other of (string * string)and person = { name: string; age: int option; contacts: service list;} with persist ();

Service_OtherINT

Service_Other_1TEXT

Service_Other_2TEXT

ServiceINT

IndexINT

Service_1TEXT

Service_2INT

Person_contactsINT

Service_idINT

IndexINT

PersonINT

NameSTRING

AgeINT

Page 8: Persistent Data Structures in  OCaml

type service =| Email of string| Twitter of string| Other of (string * string)and person = { name: string; age: int option; contacts: service;} with persist ();

Page 9: Persistent Data Structures in  OCaml

avsm$ rlwrap ./top_talk

Objective Caml version 3.11.1

open Ormopen Printf;;

# let db = init "talk.db" ;;

val db : Sql_access.state = <abstr>

Page 10: Persistent Data Structures in  OCaml

# let me = person { name="Anil”; age=(Some 31); contact=(Email "[email protected]”) } db ;;

val me : Talk.Orm.person = <obj>

Page 11: Persistent Data Structures in  OCaml

# let tg = person { name="Thomas"; age=None; contact= (Other ("github","samoht") )} db ;;

val tg : Talk.Orm.person = <obj>

Page 12: Persistent Data Structures in  OCaml

# printf "saved: %Lu %Lu\n%!" me#save tg#save ;;

saved: 4 3- : unit = () Object Call

Page 13: Persistent Data Structures in  OCaml

# let print_results hdr = printf “Query: %s\n" hdr; List.iter (fun x -> printf "found: <%s %s : %s>\n%!" x#name (match x#age with |None -> "??" |Some a -> string_of_int a) (match x#contact with |Email e -> e |Twitter t -> t |Other (s,u) -> s^":"^u))

val print_results : string -> < age : int option; contact : Talk.service; name : string; .. > list -> unit = <fun>

Page 14: Persistent Data Structures in  OCaml

# person_get;;- : ?age:[< `Exists of [< `Between of int * int | `Eq of int | `Ge of int | `Geq of int | `Le of int | `Leq of int | `Neq of int ] | `Is_none ] -> ?name:[< `Contains of string | `Eq of string ] -> ?id:[< `Exists of [< `Between of int64 * int64 | `Eq of int64 | `Ge of int64 | `Geq of int64 | `Le of int64 | `Leq of int64 | `Neq of int64 ] | `Is_none ] -> ?fn:(Talk.Orm.person -> bool) -> Sql_access.state -> Talk.Orm.person list= <fun>

Page 15: Persistent Data Structures in  OCaml

# tg#set_age (Some 28);;- : unit = ()# tg#save;;- : int64 = 3L

# print_results "Find >=20" (person_get ~age:(`Exists (`Ge 20)) db);;

Query: Find >=20found: <Anil 31 : [email protected]>found: <Thomas 28 : github:samoht>- : unit = ()

Page 16: Persistent Data Structures in  OCaml

# print_results (person_get ~name:(`Gt 5) db) ;;

File ”talk.ml", line 429, characters 41-48:Error: This expression has type [> `Gt of int ]but an expression was expected of type [< `Contains of string | `Eq of string ]

The second variant type does not allow tag(s) `Gt

Page 17: Persistent Data Structures in  OCaml

# print_results "Find emails" (person_get ~fn:(fun p -> match p#contact with |Email _ -> true |_ -> false) db );;

Query: Find emailsfound: <Anil 31 : [email protected]>- : unit = ()

Page 18: Persistent Data Structures in  OCaml

How it works

• Sqlite3 as a database library • Custom OCaml callback functions in Sqlite3• Camlp4 AST extension

• Experience: used this in the 'LifeDB' project– AJAX / RESTful web servers are mostly mapping

DB queries to/from JSON– with an ORM + json-static, not much left to do!

Page 19: Persistent Data Structures in  OCaml

# method save = let _curobj_id = let stmt = Sqlite3.prepare db.Sql_access.db (match _id with | None -> "INSERT INTO person VALUES(?,?,?,NULL);" | Some _ -> "UPDATE person SET contact=?,age=?,name=? WHERE id=?;") in (Sql_access.db_must_ok db (fun () -> Sqlite3.bind stmt 1 (Sqlite3.Data.TEXT (Sexplib.Sexp.to_string_hum (let sexp_of_contact v = sexp_of_service v in sexp_of_contact _contact)))); Sql_access.db_must_ok db (fun () -> Sqlite3.bind stmt 2 (match _age with | None -> Sqlite3.Data.NULL | Some _age -> Sqlite3.Data.INT (Int64.of_int _age))); Sql_access.db_must_ok db (fun () -> Sqlite3.bind stmt 3 (Sqlite3.Data.TEXT _name)); (match _id with | None -> () | Some _id -> Sql_access.db_must_bind db stmt 4 (Sqlite3.Data.INT _id)); Sql_access.db_must_step db stmt; match _id with | None -> let __id = Sqlite3.last_insert_rowid db.Sql_access.db in (_id <- Some __id; __id) | Some _id -> _id) in _curobj_id

Page 20: Persistent Data Structures in  OCaml

let to_string _loc f = let id = <:expr< $lid:f.f_name$ >> in let pid = <:patt< $lid:f.f_name$ >> in let rec fn = function | <:ctyp@loc< unit >> -> <:expr< "1" >> | <:ctyp@loc< int >> -> <:expr< string_of_int $id$ >> | <:ctyp@loc< int32 >> -> <:expr< Int32.to_string $id$ >> | <:ctyp@loc< int64 >> -> <:expr< Int64.to_string $id$ >> | <:ctyp@loc< float >> -> <:expr< string_of_float $id$ >> | <:ctyp@loc< char >> -> <:expr< String.make 1 $id$ >> | <:ctyp@loc< string >> -> <:expr< $id$ >> | <:ctyp@loc< bool >> -> <:expr< string_of_bool $id$ >> | <:ctyp@loc< option $t$ >> -> <:expr< match $id$ with [ None -> "NULL" |Some $pid$ -> $fn t$ ] >>

Page 21: Persistent Data Structures in  OCaml

Future Directions

Page 22: Persistent Data Structures in  OCaml

Data Migrations

• What happens if we change our schema?– Store schema in database– Structural type comparison on database attach– Tactics for migrations between two schemas

– No manual migrations (A -> B -> C) as other ORMs

Page 23: Persistent Data Structures in  OCaml

Other Languages

• a portable “typed object filesystem”• No SQL in external interface, ever• Generate code for other languages:– Python : objects– F# : records / objects– Haskell: derive?

• Carry your application data with you when new language arrives.

Page 24: Persistent Data Structures in  OCaml

Info

• http://github.com/avsm/ocaml-orm-sqlite– Release soon, announce on ocaml-list– Current release has no camlp4, deprecated

Anil Madhavapeddy: [email protected]://twitter.com/avsm