diff --git a/Makefile b/Makefile index b567e8f31e..c3786bc8af 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ BUILD_DIR:=$(ROOT)/_build # The build command and some standard build system flags BUILD=dune build SOURCES=links -DB_SOURCES=links-postgresql,links-sqlite3 +DB_SOURCES=links-postgresql,links-sqlite3,links-mysql # Note: this relies on lazy expansion of `SOURCES'. COMMON_FLAGS=--only-packages $(SOURCES) --build-dir=$(BUILD_DIR) DEV_FLAGS=$(COMMON_FLAGS) --profile=dev diff --git a/core/database.ml b/core/database.ml index 50f17e070b..489109fced 100644 --- a/core/database.ml +++ b/core/database.ml @@ -1,4 +1,3 @@ -open List open CommonTypes open Utility @@ -91,13 +90,10 @@ let execute_insert_returning returning q db = begin match result#status with | `QueryOk -> - let rows = result#get_all_lst in - begin - match rows with - | [[id]] -> Value.box_int (int_of_string id) - | _ -> - raise (runtime_error ("Returned the wrong number of results executing " ^ q)) - end + if result#nfields = 1 && result#ntuples = 1 + then (* returning field has to be of type int *) + Value.box_int (int_of_string (result#getvalue 0 0)) + else raise (runtime_error ("Returned the wrong number of results executing " ^ q)) | `QueryError msg -> raise (runtime_error ("An error occurred executing the query " ^ q ^ ": " ^ msg)) end @@ -149,8 +145,6 @@ let result_signature field_types result = in build rs [] -(* BUG: Lists can be too big for List.map; need to be careful about recursion *) - let execute_select_result (field_types:(string * Types.datatype) list) (query:string) (db: database) = let _ = Debug.print ("Running query: \n" ^ query) in @@ -174,12 +168,3 @@ let execute_select : Value.t = let result,rs = execute_select_result field_types query db in build_result (result,rs) - - -let execute_untyped_select (query:string) (db: database) : Value.t = - let result = (db#exec query) in - (match result#status with - | `QueryOk -> - `List (map (fun row -> `List (map Value.box_string row)) result#get_all_lst) - | `QueryError msg -> - raise (runtime_error ("An error occurred executing the query " ^ query ^ ": " ^ msg))) diff --git a/core/database.mli b/core/database.mli index 58fdc67898..98f6d0e797 100644 --- a/core/database.mli +++ b/core/database.mli @@ -23,7 +23,5 @@ val build_result : Value.dbvalue * (string * (Types.datatype * int)) list -> Val fieldname -> fieldtype. *) val execute_select : (string * Types.datatype) list -> string -> Value.database -> Value.t -val execute_untyped_select : string -> Value.database -> Value.t - val execute_insert_returning : string -> Sql.query -> Value.database -> Value.t diff --git a/core/utility.ml b/core/utility.ml index 7ddbd26b50..4c225eba24 100644 --- a/core/utility.ml +++ b/core/utility.ml @@ -1458,3 +1458,66 @@ struct (sequence xs) >>= fun xs -> Lwt.return (x :: xs) end + + +(* efficient polymorphic buffers *) +(* builds an array of n pages of size m, with some initial dummy value *) +(* allows random access reading/writing and appending at the end *) +module PolyBuffer : sig + type 'a buf + val init : int -> int -> 'a -> 'a buf + val length : 'a buf -> int + val get : 'a buf -> int -> 'a + val set : 'a buf -> int -> 'a -> unit + val append : 'a buf -> 'a -> unit + val to_list : 'a buf -> 'a list +end = +struct + type 'a buf = {mutable numpages: int; + pagesize: int; + default: 'a; + mutable currpage: int; + mutable nextitem: int; + mutable pages:'a + array array} + + let init n m x = {numpages = n; + pagesize = m; + default = x; + currpage = 0; + nextitem = 0; + pages = Array.init n (fun _ -> Array.init m (fun _ -> x)) } + + let length buf = buf.currpage*buf.pagesize + buf.nextitem + + let set buf i x = + if 0 <= i && i < buf.currpage*buf.pagesize + buf.nextitem + then Array.set (Array.get buf.pages (i/buf.pagesize)) (i mod buf.pagesize) x + else raise Not_found + + let get buf i = + if 0 <= i && i < buf.currpage*buf.pagesize + buf.nextitem + then Array.get (Array.get buf.pages (i/buf.pagesize)) (i mod buf.pagesize) + else raise (Invalid_argument "index out of bounds") + + let append buf x = + (* first, check if there is enough space or allocation is needed *) + if (buf.nextitem = buf.pagesize) + then begin + buf.nextitem <- 0; + buf.currpage <- buf.currpage+1; + if (buf.currpage = buf.numpages) + then begin (* need to allocate a new page and copy over *) + buf.numpages <- buf.numpages+1; + let newpages = Array.init buf.numpages (fun i -> + if i < Array.length(buf.pages) + then Array.get buf.pages i + else Array.init buf.pagesize (fun _ -> buf.default)) in + buf.pages <- newpages + end + end; + Array.set (Array.get buf.pages buf.currpage) buf.nextitem x; + buf.nextitem <- buf.nextitem + 1 + + let to_list buf = List.init (length buf) (get buf) +end diff --git a/core/value.ml b/core/value.ml index d81655de5e..f40cae5c2e 100644 --- a/core/value.ml +++ b/core/value.ml @@ -36,34 +36,19 @@ class virtual dbvalue = object (self) method virtual nfields : int method virtual ntuples : int method virtual fname : int -> string - method virtual get_all_lst : string list list method map : 'a. ((int -> string) -> 'a) -> 'a list = fun f -> - let max = self#ntuples in - let rec do_map n acc = - if n < max - then ( - do_map (n+1) (f (self#getvalue n)::acc) - ) - else acc - in do_map 0 [] + List.init (self#ntuples) (fun i -> f (self#getvalue i)) method map_array : 'a. (string array -> 'a) -> 'a list = fun f -> - let max = self#ntuples in - let rec do_map n acc = - if n < max - then ( - do_map (n+1) (f (self#gettuple n)::acc) - ) - else acc - in do_map 0 [] + List.init (self#ntuples) (fun i -> f (self#gettuple i)) method fold_array : 'a. (string array -> 'a -> 'a) -> 'a -> 'a = fun f x -> let max = self#ntuples in let rec do_fold n acc = - if n < max - then ( - do_fold (n+1) (f (self#gettuple n) acc) - ) - else acc - in do_fold 0 x method virtual map : 'a. ((int -> string) -> 'a) -> 'a list + if n < max + then ( + do_fold (n+1) (f (self#gettuple n) acc) + ) + else acc + in do_fold 0 x method virtual getvalue : int -> int -> string method virtual gettuple : int -> string array method virtual error : string diff --git a/core/value.mli b/core/value.mli index 889aeeac2d..ca131f196b 100644 --- a/core/value.mli +++ b/core/value.mli @@ -11,7 +11,6 @@ class virtual dbvalue : object method virtual error : string method virtual fname : int -> string - method virtual get_all_lst : string list list method virtual nfields : int method virtual ntuples : int method map : 'a. ((int -> string) -> 'a) -> 'a list diff --git a/database/mysql-driver/jbuild.unsupported b/database/mysql-driver/dune similarity index 51% rename from database/mysql-driver/jbuild.unsupported rename to database/mysql-driver/dune index e07ad42c8e..c5a4ed0365 100644 --- a/database/mysql-driver/jbuild.unsupported +++ b/database/mysql-driver/dune @@ -1,16 +1,13 @@ -(jbuild_version 1) - (library - ((name links_mysql) + (name links_mysql) (public_name links-mysql) (synopsis "MySQL database backend for Links") - (wrapped false) (optional) (flags (:standard -safe-string -dtypes -w Ae-44-45-60 -g -cclib -lunix -thread)) - (libraries (mysql links)))) + (libraries mysql links.core)) (install - ((section share) - (files (links_mysql_dependencies.json)) - (package links-mysql))) + (section share) + (files links_mysql_dependencies.json) + (package links-mysql)) diff --git a/database/mysql-driver/mysql_database.ml b/database/mysql-driver/mysql_database.ml index 1cd244aeab..13c403e404 100644 --- a/database/mysql-driver/mysql_database.ml +++ b/database/mysql-driver/mysql_database.ml @@ -1,4 +1,6 @@ open Mysql +open Links_core +open Utility let string_of_error_code = function | Aborting_connection -> "Aborting connection" @@ -201,18 +203,23 @@ object method show = pretty_type thing end -let slurp (fn : 'a -> 'b option) (source : 'a) : 'b list = - let rec obtain output = - match fn source with - | None -> output - | Some value -> obtain (value :: output) +let iterUntilNone (fn : unit -> 'b option) (g : 'b -> unit) : unit = + let rec iterate () = + match fn () with + | None -> () + | Some value -> g value; iterate() in - List.rev (obtain []) + iterate () class mysql_result (result : result) db = object inherit Value.dbvalue - val rows = ref None - method status : Value.db_status = + val result_buf = + if size result > Int64.of_int(0) + then let buf = PolyBuffer.init 1 1024 (Array.init 0 (fun _ -> None)) in + iterUntilNone (fun () -> fetch result) (PolyBuffer.append buf); + buf + else PolyBuffer.init 0 1 (Array.init 0 (fun _ -> None)) + method status : Value.db_status = match status db with | StatusOK | StatusEmpty -> `QueryOk | StatusError c -> `QueryError (string_of_error_code c) @@ -222,22 +229,13 @@ class mysql_result (result : result) db = object Int64.to_int(size result) method fname n : string = (Utility.val_of (fetch_field_dir result n)).name - method get_all_lst : string list list = - match !rows with - | None -> - let toList row = - List.map (Utility.from_option "!!NULL!!") (Array.to_list row) in - let r = List.map toList (slurp fetch result) - in - rows := Some r; - r - | Some r -> r method getvalue : int -> int -> string = fun n f -> - to_row result (Int64.of_int n); - Utility.val_of ((Utility.val_of (fetch result)).(f)) + let row = PolyBuffer.get result_buf n in +(* TODO: Handle nulls better *) + Utility.from_option "" (row.(f)) method gettuple : int -> string array = fun n -> - to_row result (Int64.of_int n); - Array.map Utility.val_of (Utility.val_of(fetch result)) + let row = PolyBuffer.get result_buf n in + Array.map (Utility.from_option "") row method error : string = Utility.val_of (errmsg db) end @@ -257,9 +255,12 @@ class mysql_database spec = object(self) "`" ^ Str.global_replace (Str.regexp "`") "``" f ^ "`" method! make_insert_returning_query : string -> Sql.query -> string list = - fun _returning q -> - assert (match q with | Sql.Insert _ -> true | _ -> false); - [self#string_of_query None q; "select last_insert_id()"] + fun returning q -> + match q with + Sql.Insert ins -> + [self#string_of_query q; + Printf.sprintf "select %s from %s where _rowid = last_insert_id()" returning ins.ins_table] + | _ -> assert false method supports_shredding () = false end diff --git a/database/pg-driver/pg_database.ml b/database/pg-driver/pg_database.ml index 5098971161..feb95a1f51 100644 --- a/database/pg-driver/pg_database.ml +++ b/database/pg-driver/pg_database.ml @@ -91,7 +91,7 @@ class pg_dbresult (pgresult:Postgresql.result) = object method nfields : int = original#nfields method ntuples : int = original#ntuples method fname : int -> string = original#fname - method get_all_lst : string list list = pgresult#get_all_lst + (*TODO: better handling of NULLs *) method getvalue : int -> int -> string = pgresult#getvalue method gettuple : int -> string array = pgresult#get_tuple method error : string = original#error diff --git a/database/sqlite3-driver/lite3_database.ml b/database/sqlite3-driver/lite3_database.ml index 7fa88c0db9..bf5970d957 100644 --- a/database/sqlite3-driver/lite3_database.ml +++ b/database/sqlite3-driver/lite3_database.ml @@ -36,6 +36,8 @@ let error_as_string = function | Rc.DONE -> "done" | Rc.UNKNOWN e -> "unknown: "^ string_of_int (Rc.int_of_unknown e) + +(* TODO: Better NULL handling *) let data_to_string data = match data with Data.NONE -> "" @@ -45,36 +47,41 @@ let data_to_string data = | Data.TEXT s | Data.BLOB s -> s ;; + + class lite3_result (stmt: stmt) = object inherit Value.dbvalue - val result_list_and_status = - let rec get_results (results,status) = + + val result_buf_and_status = + let result_buf = PolyBuffer.init 1 1024 [] in + let rec get_results (status) = match status with `QueryOk -> ( match step stmt with Rc.OK|Rc.ROW -> let data = Array.to_list (row_data stmt) in let row = List.map data_to_string data in - get_results (row::results,`QueryOk ) + PolyBuffer.append result_buf row; + get_results `QueryOk | Rc.DONE -> - results,`QueryOk - | e -> results, `QueryError (error_as_string e) + `QueryOk + | e -> `QueryError (error_as_string e) ) - | _ -> (results,status) + | _ -> (status) in - get_results ([],`QueryOk) + (result_buf,get_results (`QueryOk)) - method status : Value.db_status = snd(result_list_and_status) - method nfields : int = column_count stmt - method ntuples : int = List.length (fst result_list_and_status) + method status : Value.db_status = snd(result_buf_and_status) + method nfields : int = column_count stmt + method ntuples : int = PolyBuffer.length (fst result_buf_and_status) method fname n : string = column_name stmt n - method get_all_lst : string list list = fst(result_list_and_status) + (*method get_all_lst : string list list = PolyBuffer.to_list (fst result_buf_and_status)*) method getvalue : int -> int -> string = fun n i -> - List.nth(List.nth (fst(result_list_and_status)) n) i + List.nth(PolyBuffer.get (fst result_buf_and_status) n) i method gettuple : int -> string array = fun n -> - Array.of_list(List.nth (fst(result_list_and_status)) n) + Array.of_list(PolyBuffer.get (fst result_buf_and_status) n) method error : string = - match snd(result_list_and_status) with + match (snd result_buf_and_status) with `QueryError(msg) -> msg | `QueryOk -> "OK" end @@ -115,6 +122,14 @@ class lite3_database file = object(self) | _ -> _supports_shredding <- Some false; false end | _ -> false + method! make_insert_returning_query : string -> Sql.query -> string list = + fun returning q -> + match q with + Sql.Insert ins -> + [self#string_of_query q; + Printf.sprintf "select %s from %s where rowid = last_insert_rowid()" returning ins.ins_table] + | _ -> assert false + end let driver_name = "sqlite3" diff --git a/dune b/dune index c89709ede4..7ae2d48641 100644 --- a/dune +++ b/dune @@ -8,6 +8,7 @@ -warn-error -a ;; Do not treat warnings as errors. -w A-4-42-44-45-48-60-67 ;; Ignores warnings 4, 42, 44, 45, 48, 60, and 67. -g ;; Adds debugging information to the resulting executable / library. + -linkall ))) (release (flags (:standard diff --git a/examples/relational_lenses/config b/examples/relational_lenses/config index ea0bb44ee0..4e1505bc0a 100644 --- a/examples/relational_lenses/config +++ b/examples/relational_lenses/config @@ -1,5 +1,4 @@ database_args=localhost:5432:links:links database_driver=postgresql -relax_query_type_constraint=on shredding=on relational_lenses=on diff --git a/examples/relational_lenses/config.sample b/examples/relational_lenses/config.sample index 0062db4d93..15c9a31208 100644 --- a/examples/relational_lenses/config.sample +++ b/examples/relational_lenses/config.sample @@ -1,5 +1,4 @@ database_args=localhost:5432::links database_driver=postgresql -relax_query_type_constraint=on shredding=on relational_lenses=on diff --git a/links-mysql.opam.unsupported b/links-mysql.opam similarity index 91% rename from links-mysql.opam.unsupported rename to links-mysql.opam index f4652e554b..58f7fd9a26 100644 --- a/links-mysql.opam.unsupported +++ b/links-mysql.opam @@ -1,5 +1,5 @@ opam-version: "2.0" -maintainer: "Jan Stolarek " +maintainer: "James Cheney " authors: "The Links Team " synopsis: "MySQL database driver for the Links Programming Language" description: "MySQL database driver for the Links Programming Language" diff --git a/tests/database/config.mysql b/tests/database/config.mysql new file mode 100644 index 0000000000..35680006c3 --- /dev/null +++ b/tests/database/config.mysql @@ -0,0 +1,4 @@ +database_driver=mysql +database_args=localhost:3306:links:12345 +coerce_null_integers=on +null_integer=-1 diff --git a/tests/database/config.pgsql b/tests/database/config.pgsql new file mode 100644 index 0000000000..31d8377d00 --- /dev/null +++ b/tests/database/config.pgsql @@ -0,0 +1,4 @@ +database_driver=postgresql +database_args=localhost:5432::links +coerce_null_integers=on +null_integer=-1 diff --git a/tests/database/config.sample b/tests/database/config.sample index e987677ceb..31d8377d00 100644 --- a/tests/database/config.sample +++ b/tests/database/config.sample @@ -1,3 +1,4 @@ database_driver=postgresql database_args=localhost:5432::links -show_pre_sugar_typing=off +coerce_null_integers=on +null_integer=-1 diff --git a/tests/database/config.sqlite3 b/tests/database/config.sqlite3 new file mode 100644 index 0000000000..8e9a041999 --- /dev/null +++ b/tests/database/config.sqlite3 @@ -0,0 +1,3 @@ +database_driver=sqlite3 +coerce_null_integers=on +null_integer=-1 diff --git a/tests/database/factorials-large.links b/tests/database/factorials-large.links new file mode 100644 index 0000000000..450ae1243c --- /dev/null +++ b/tests/database/factorials-large.links @@ -0,0 +1,30 @@ +var db = database "links"; +var factorials = table "factorials" with (i : Int, f : Int) from db; + +fun fact (n) { + if (n == 0) {1} + else {if (n == 1) {1} + else {n*fact(n-1)} + } +} + +fun insertL(l) { + delete (x <-- factorials); + for (i <- l) { + insert factorials + values (f, i) + [(i=i,f=fact(i))]; + [] + } +} + +var asdf = insertL([0..511]); + +fun double (l) { + for (x <- l, y <- l) + [(a=1)] +} +# build a result larger than ocaml stack bound +assertEq( + length(query { double(asList(factorials))}), + 262144) \ No newline at end of file diff --git a/tests/database/factorials.links b/tests/database/factorials.links index 892bcd0f52..2264d237cd 100644 --- a/tests/database/factorials.links +++ b/tests/database/factorials.links @@ -30,7 +30,7 @@ fun insertReturningOne() { fun insertReturningTwo() { insert factorials - values (f,i) [(f=2, i=2)] returning i + values (f,i) [(f=2, i=2)] returning f } fun updateTwoThree() { @@ -64,6 +64,15 @@ fun trivialNested2() server { } fun test() { + deleteAll(); + assertEq(lookupFactorials(10), []); + assertEq(insertReturningOne(), 1); + assertEq(lookupFactorials(10), [(f=1,i=1)]); + assertEq(insertReturningTwo(), 2); + assertEq(lookupFactorials(10), [(f=1,i=1),(f=2,i=2)]); + updateTwoThree(); + assertEq(lookupFactorials(10), [(f=1,i=1),(f=3,i=2)]); + deleteAll(); insertOne(); deleteAll(); assertEq(lookupFactorials(10), []); @@ -73,18 +82,9 @@ fun test() { assertEq(lookupFactorials(1), [(f=1,i=1)]); assertEq(query{unwrappedLookup(1)}, [(f=1,i=1)]); insertTwoThree(); - ## The order is wrong. - assertEq(lookupFactorials(3), [(i=3, f=6), (i=2, f=2), (f=1,i=1)]); - deleteAll(); - assertEq(lookupFactorials(10), []); - assertEq(insertReturningOne(), 1); - assertEq(lookupFactorials(10), [(f=1,i=1)]); - assertEq(insertReturningTwo(), 2); - assertEq(lookupFactorials(10), [(f=2,i=2),(f=1,i=1)]); - updateTwoThree(); - assertEq(lookupFactorials(10), [(f=3,i=2),(f=1,i=1)]); - assertEq(trivialNested1(),[(a=0),(a=0)]); - assertEq(trivialNested2(),[(a=0),(a=0)]); + assertEq(lookupFactorials(3), [(i=1, f=1), (i=2, f=2), (f=6,i=3)]); + assertEq(trivialNested1(),[(a=0),(a=0),(a=0)]); + assertEq(trivialNested2(),[(a=0),(a=0),(a=0)]); } test() diff --git a/tests/database/factorials.mysql b/tests/database/factorials.mysql new file mode 100644 index 0000000000..2ce8de83c3 --- /dev/null +++ b/tests/database/factorials.mysql @@ -0,0 +1,7 @@ +DROP TABLE IF EXISTS factorials; + +CREATE TABLE factorials ( + rowid integer PRIMARY KEY AUTO_INCREMENT, + i integer, + f bigint +); diff --git a/tests/database/null.links b/tests/database/null.links new file mode 100644 index 0000000000..45a84fd4d5 --- /dev/null +++ b/tests/database/null.links @@ -0,0 +1,4 @@ +var db = database "links"; +var nulltable = table "nulltable" with (i : Int, f : Int) from db; + +assertEq(query {for (x <-- nulltable) [x]},[(i=1,f= -1)]) diff --git a/tests/database/null.sql b/tests/database/null.sql new file mode 100644 index 0000000000..90bdfa57ca --- /dev/null +++ b/tests/database/null.sql @@ -0,0 +1,9 @@ +DROP TABLE IF EXISTS nulltable; + +CREATE TABLE nulltable ( + i integer, + f bigint +); + + +INSERT INTO nulltable VALUES (1,null); diff --git a/tests/database/testsuite.config b/tests/database/testsuite.config index a7b5edf32d..e31878e7c2 100644 --- a/tests/database/testsuite.config +++ b/tests/database/testsuite.config @@ -1,6 +1,8 @@ factorials +factorials-large empty emptyfun +null unit xpath xpath-reduced diff --git a/tests/database/xpath-reduced.links b/tests/database/xpath-reduced.links index 0783895435..a3e54e8914 100644 --- a/tests/database/xpath-reduced.links +++ b/tests/database/xpath-reduced.links @@ -21,6 +21,7 @@ fun xpath1() { where ( empty(for (t <-- xml) where (x.id == t.parent) [()])) + orderby (x.name) [(name=x.name)] } } @@ -34,12 +35,13 @@ fun xpath2() { query { for (x <-- xml) where ( p(x)) + orderby (x.name) [(name=x.name)] } } fun test() { - assertEq(xpath1(), [(name="f"), (name="e"), (name="c")]); + assertEq(xpath1(), [(name="c"), (name="e"), (name="f")]); assertEq(xpath1(), xpath2()); } diff --git a/tests/database/xpath.links b/tests/database/xpath.links index 5200227c2e..277693f8f7 100644 --- a/tests/database/xpath.links +++ b/tests/database/xpath.links @@ -91,12 +91,13 @@ fun xpath(p) { for (root <-- xml, s <-- xml) where (root.parent == -1 && p(root, s)) + orderby (s.name) [(name=s.name)] } } fun test() { - assertEq(xpath(xp0), [(name="d"), (name="b")]); + assertEq(xpath(xp0), [(name="b"), (name="d")]); } test() diff --git a/tests/relational-lenses/01_cds.links b/tests/relational-lenses/01_cds.links index 55f93ab2cc..8eeec561d5 100644 --- a/tests/relational-lenses/01_cds.links +++ b/tests/relational-lenses/01_cds.links @@ -25,15 +25,15 @@ fun test() { var filtered = lensget filteredLens; assertEq(filtered, [ - (album = "Wish", quantity = 5, rating = 4, track = "Trust"), + (album = "Show", quantity = 3, rating = 3, track = "Lullaby"), (album = "Paris", quantity = 4, rating = 5, track = "Lovesong"), - (album = "Show", quantity = 3, rating = 3, track = "Lullaby") + (album = "Wish", quantity = 5, rating = 4, track = "Trust") ]); # filter out all tracks named "Trust" and change Lullaby's rating to 4. var newTracks = [ - (album = "Show", quantity = 3, rating = 4, track = "Lullaby"), - (album = "Disintegration", quantity = 7, rating = 5, track = "Lovesong") + (album = "Disintegration", quantity = 7, rating = 5, track = "Lovesong"), + (album = "Show", quantity = 3, rating = 4, track = "Lullaby") ]; lensput filteredLens with newTracks; @@ -41,18 +41,17 @@ fun test() { var new = lensget filteredLens; assertEq(new, newTracks); - assertEq(lensget tracksLens, [ - (album = "Show", date = 1989, rating = 4, track = "Lullaby"), - (album = "Galore", date = 1989, rating = 4, track = "Lullaby"), + assertEq(lensget tracksLens, [(album = "Galore", date = 1989, rating = 5, track = "Lovesong"), (album = "Disintegration", date = 1989, rating = 5, track = "Lovesong"), - (album = "Galore", date = 1989, rating = 5, track = "Lovesong") + (album = "Galore", date = 1989, rating = 4, track = "Lullaby"), + (album = "Show", date = 1989, rating = 4, track = "Lullaby") ]); assertEq(lensget albumsLens, [ - (album = "Disintegration", quantity = 7), - (album = "Wish", quantity = 5), - (album = "Paris", quantity = 4), + (album = "Show", quantity = 3), (album = "Galore", quantity = 1), - (album = "Show", quantity = 3) + (album = "Paris", quantity = 4), + (album = "Wish", quantity = 5), + (album = "Disintegration", quantity = 7) ]); lensput filteredLens with filtered; diff --git a/tests/relational-lenses/02_cds.links b/tests/relational-lenses/02_cds.links index a41c7bb8c9..522b7146b6 100644 --- a/tests/relational-lenses/02_cds.links +++ b/tests/relational-lenses/02_cds.links @@ -26,15 +26,15 @@ fun test() { var filtered = lensget filteredLens; assertEq(filtered, [ - (album = "Show", quantity = 3, rating = 3, track = "Lullaby"), + (album = "Paris", quantity = 4, rating = 5, track = "Lovesong"), (album = "Wish", quantity = 5, rating = 4, track = "Trust"), - (album = "Paris", quantity = 4, rating = 5, track = "Lovesong") + (album = "Show", quantity = 3, rating = 3, track = "Lullaby") ]); # filter out all tracks named "Trust" and change Lullaby's rating to 4. var newTracks = [ - (album = "Show", quantity = 3, rating = 4, track = "Lullaby"), - (album = "Disintegration", quantity = 7, rating = 5, track = "Lovesong") + (album = "Disintegration", quantity = 7, rating = 5, track = "Lovesong"), + (album = "Show", quantity = 3, rating = 4, track = "Lullaby") ]; lensput filteredLens with newTracks; @@ -43,17 +43,17 @@ fun test() { assertEq(new, newTracks); assertEq(lensget tracksLens, [ - (album = "Show", date = 1989, rating = 4, track = "Lullaby"), - (album = "Galore", date = 1989, rating = 4, track = "Lullaby"), + (album = "Galore", date = 1989, rating = 5, track = "Lovesong"), (album = "Disintegration", date = 1989, rating = 5, track = "Lovesong"), - (album = "Galore", date = 1989, rating = 5, track = "Lovesong") + (album = "Galore", date = 1989, rating = 4, track = "Lullaby"), + (album = "Show", date = 1989, rating = 4, track = "Lullaby") ]); assertEq(lensget albumsLens, [ - (album = "Disintegration", quantity = 7), - (album = "Wish", quantity = 5), - (album = "Paris", quantity = 4), + (album = "Show", quantity = 3), (album = "Galore", quantity = 1), - (album = "Show", quantity = 3) + (album = "Paris", quantity = 4), + (album = "Wish", quantity = 5), + (album = "Disintegration", quantity = 7) ]); lensput filteredLens with filtered; diff --git a/tests/relational-lenses/03_cds.links b/tests/relational-lenses/03_cds.links index 0703ab3b8c..2b4a396245 100644 --- a/tests/relational-lenses/03_cds.links +++ b/tests/relational-lenses/03_cds.links @@ -21,33 +21,32 @@ fun test() { var old = lensget joinedLens; var newTracks = [ - (album = "Wish", date = 1992, quantity = 5, rating = 4, track = "Trust"), - (track="It's the end of the world as we know it", - rating=5, album="Eponymous", date=1988, quantity=42), - (album = "Show", date = 1989, quantity = 3, rating = 3, track = "Lullaby"), - (album = "Galore", date = 1989, quantity = 1, rating = 3, track = "Lullaby"), + (album = "Galore", date = 1989, quantity = 1, rating = 5, track = "Lovesong"), (album = "Paris", date = 1989, quantity = 4, rating = 5, track = "Lovesong"), - (album = "Galore", date = 1989, quantity = 1, rating = 5, track = "Lovesong") + (album = "Galore", date = 1989, quantity = 1, rating = 3, track = "Lullaby"), + (album = "Show", date = 1989, quantity = 3, rating = 3, track = "Lullaby"), + (album = "Eponymous", date = 1988, quantity = 42, rating = 5, track = "It's the end of the world as we know it"), + (album = "Wish", date = 1992, quantity = 5, rating = 4, track = "Trust") ]; lensput joinedLens with newTracks; assertEq(lensget joinedLens, newTracks); assertEq(lensget albumsLens, [ - (album = "Eponymous", quantity = 42), - (album = "Disintegration", quantity = 7), - (album = "Wish", quantity = 5), - (album = "Paris", quantity = 4), + (album = "Show", quantity = 3), (album = "Galore", quantity = 1), - (album = "Show", quantity = 3) + (album = "Paris", quantity = 4), + (album = "Wish", quantity = 5), + (album = "Disintegration", quantity = 7), + (album = "Eponymous", quantity = 42) ]); assertEq(lensget tracksLens, [ - (album = "Wish", date = 1992, rating = 4, track = "Trust"), - (album = "Eponymous", date = 1988, rating = 5, track = "It's the end of the world as we know it"), - (album = "Show", date = 1989, rating = 3, track = "Lullaby"), - (album = "Galore", date = 1989, rating = 3, track = "Lullaby"), + (album = "Galore", date = 1989, rating = 5, track = "Lovesong"), (album = "Paris", date = 1989, rating = 5, track = "Lovesong"), - (album = "Galore", date = 1989, rating = 5, track = "Lovesong") + (album = "Galore", date = 1989, rating = 3, track = "Lullaby"), + (album = "Show", date = 1989, rating = 3, track = "Lullaby"), + (album = "Eponymous", date = 1988, rating = 5, track = "It's the end of the world as we know it"), + (album = "Wish", date = 1992, rating = 4, track = "Trust") ]); lensput joinedLens with old; diff --git a/tests/relational-lenses/config.sample b/tests/relational-lenses/config.sample index 2264904bdb..9a68801480 100644 --- a/tests/relational-lenses/config.sample +++ b/tests/relational-lenses/config.sample @@ -1,5 +1,4 @@ database_driver=postgresql database_args=localhost:5432::links show_pre_sugar_typing=off -relax_query_type_constraint=on relational_lenses=on