module PostgresExtensionTests open System.IO open BitBadger.Documents open BitBadger.Documents.Postgres open BitBadger.Documents.Tests open Expecto open Npgsql open Types /// Open a connection to the throwaway database let private mkConn (db: ThrowawayPostgresDb) = let conn = new NpgsqlConnection(db.ConnectionString) conn.Open() conn /// Set up a stream writer for a test let private writeStream (stream: Stream) = let writer = new StreamWriter(stream) writer.AutoFlush <- true writer /// Get the text of the given stream let private streamText (stream: Stream) = stream.Position <- 0L use reader = new StreamReader(stream) reader.ReadToEnd() /// Verify a JSON array begins with "[" and ends with "]" let private verifyBeginEnd json = Expect.stringStarts json "[" "The array should have started with `[`" Expect.stringEnds json "]" "The array should have ended with `]`" /// Verify the presence of a document by its ID let private verifyDocById json docId = Expect.stringContains json $"{{\"Id\": \"%s{docId}\"," $"Document `{docId}` not present" /// Verify the presence of a document by its ID let private verifySingleById json docId = verifyBeginEnd json Expect.stringContains json $"{{\"Id\": \"%s{docId}\"," $"Document `{docId}` not present" /// Verify the presence of any of the given document IDs in the given JSON let private verifyAnyById (json: string) (docIds: string list) = match docIds |> List.tryFind (fun it -> json.Contains $"{{\"Id\": \"{it}\"") with | Some _ -> () | None -> let ids = docIds |> String.concat ", " Expect.isTrue false $"Could not find any of IDs {ids} in {json}" /// Verify the JSON for `all` returning data let private verifyAllData json = verifyBeginEnd json [ "one"; "two"; "three"; "four"; "five" ] |> List.iter (verifyDocById json) /// Verify an empty JSON array let private verifyEmpty json = Expect.equal json "[]" "There should be no documents returned" /// Verify an empty JSON document let private verifyNoDoc json = Expect.equal json "{}" "There should be no document returned" /// Verify the JSON for an ordered query let private verifyExpectedOrder (json: string) idFirst idSecond idThird idFourth idFifth = let firstIdx = json.IndexOf $"{{\"Id\": \"%s{idFirst}\"," let secondIdx = json.IndexOf $"{{\"Id\": \"%s{idSecond}\"," verifyBeginEnd json Expect.isGreaterThan secondIdx firstIdx $"`{idSecond}` should have been after `{idFirst}`" match idThird with | Some id3 -> let thirdIdx = json.IndexOf $"{{\"Id\": \"%s{id3}\"," Expect.isGreaterThan thirdIdx secondIdx $"`{id3}` should have been after `{idSecond}`" match idFourth with | Some id4 -> let fourthIdx = json.IndexOf $"{{\"Id\": \"%s{id4}\"," Expect.isGreaterThan fourthIdx thirdIdx $"`{id4}` should have been after `{id3}`" match idFifth with | Some id5 -> let fifthIdx = json.IndexOf $"{{\"Id\": \"%s{id5}\"," Expect.isGreaterThan fifthIdx fourthIdx $"`{id5}` should have been after `{id4}`" | None -> () | None -> () | None -> () /// Integration tests for the F# extensions on the NpgsqlConnection data type let integrationTests = let loadDocs (conn: NpgsqlConnection) = backgroundTask { for doc in testDocuments do do! conn.insert PostgresDb.TableName doc } testList "Postgres.Extensions" [ testList "customList" [ testTask "succeeds when data is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.customList (Query.find PostgresDb.TableName) [] fromData Expect.equal (List.length docs) 5 "There should have been 5 documents returned" } testTask "succeeds when data is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.customList $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath" [ "@path", Sql.string "$.NumValue ? (@ > 100)" ] fromData Expect.isEmpty docs "There should have been no documents returned" } ] testList "customJsonArray" [ testTask "succeeds when data is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.customJsonArray (Query.find PostgresDb.TableName) [] jsonFromData Expect.stringStarts docs "[" "The JSON array should have started with `[`" Expect.hasLength ((string docs).Split "{\"Id\":") 6 "There should have been 5 documents returned" Expect.stringEnds docs "]" "The JSON array should have ended with `[`" } testTask "succeeds when data is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.customJsonArray $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath" [ "@path", Sql.string "$.NumValue ? (@ > 100)" ] jsonFromData Expect.equal docs "[]" "There should have been no documents returned" } ] testList "writeCustomJsonArray" [ testTask "succeeds when data is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeCustomJsonArray (Query.find PostgresDb.TableName) [] writer jsonFromData let docs = streamText stream Expect.stringStarts docs "[" "The JSON array should have started with `[`" Expect.hasLength (docs.Split "{\"Id\":") 6 "There should have been 5 documents returned" Expect.stringEnds docs "]" "The JSON array should have ended with `[`" } testTask "succeeds when data is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeCustomJsonArray $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath" [ "@path", Sql.string "$.NumValue ? (@ > 100)" ] writer jsonFromData Expect.equal (streamText stream) "[]" "There should have been no documents returned" } ] testList "customSingle" [ testTask "succeeds when a row is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.customSingle $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id" [ "@id", Sql.string "one"] fromData Expect.isSome doc "There should have been a document returned" Expect.equal doc.Value.Id "one" "The incorrect document was returned" } testTask "succeeds when a row is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.customSingle $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id" [ "@id", Sql.string "eighty" ] fromData Expect.isNone doc "There should not have been a document returned" } ] testList "customJsonSingle" [ testTask "succeeds when a row is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.customJsonSingle $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id" [ "@id", Sql.string "one"] jsonFromData Expect.stringStarts doc "{" "The document should have started with an open brace" Expect.stringContains doc "\"Id\": \"one\"" "An incorrect document was returned" Expect.stringEnds doc "}" "The document should have ended with a closing brace" } testTask "succeeds when a row is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.customJsonSingle $"SELECT data FROM {PostgresDb.TableName} WHERE data ->> 'Id' = @id" [ "@id", Sql.string "eighty" ] jsonFromData Expect.equal doc "{}" "There should not have been a document returned" } ] testList "customNonQuery" [ testTask "succeeds when operating on data" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.customNonQuery $"DELETE FROM {PostgresDb.TableName}" [] let! remaining = conn.countAll PostgresDb.TableName Expect.equal remaining 0 "There should be no documents remaining in the table" } testTask "succeeds when no data matches where clause" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.customNonQuery $"DELETE FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath" [ "@path", Sql.string "$.NumValue ? (@ > 100)" ] let! remaining = conn.countAll PostgresDb.TableName Expect.equal remaining 5 "There should be 5 documents remaining in the table" } ] testTask "scalar succeeds" { use db = PostgresDb.BuildDb() use conn = mkConn db let! nbr = conn.customScalar "SELECT 5 AS test_value" [] (fun row -> row.int "test_value") Expect.equal nbr 5 "The query should have returned the number 5" } testTask "ensureTable succeeds" { use db = PostgresDb.BuildDb() use conn = mkConn db let tableExists () = conn.customScalar "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'ensured') AS it" [] toExists let keyExists () = conn.customScalar "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_key') AS it" [] toExists let! exists = tableExists () let! alsoExists = keyExists () Expect.isFalse exists "The table should not exist already" Expect.isFalse alsoExists "The key index should not exist already" do! conn.ensureTable "ensured" let! exists' = tableExists () let! alsoExists' = keyExists () Expect.isTrue exists' "The table should now exist" Expect.isTrue alsoExists' "The key index should now exist" } testTask "ensureDocumentIndex succeeds" { use db = PostgresDb.BuildDb() use conn = mkConn db let indexExists () = conn.customScalar "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_document') AS it" [] toExists let! exists = indexExists () Expect.isFalse exists "The index should not exist already" do! conn.ensureTable "ensured" do! conn.ensureDocumentIndex "ensured" Optimized let! exists' = indexExists () Expect.isTrue exists' "The index should now exist" } testTask "ensureFieldIndex succeeds" { use db = PostgresDb.BuildDb() use conn = mkConn db let indexExists () = conn.customScalar "SELECT EXISTS (SELECT 1 FROM pg_class WHERE relname = 'idx_ensured_test') AS it" [] toExists let! exists = indexExists () Expect.isFalse exists "The index should not exist already" do! conn.ensureTable "ensured" do! conn.ensureFieldIndex "ensured" "test" [ "Id"; "Category" ] let! exists' = indexExists () Expect.isTrue exists' "The index should now exist" } testList "insert" [ testTask "succeeds" { use db = PostgresDb.BuildDb() use conn = mkConn db let! before = conn.countAll PostgresDb.TableName Expect.equal before 0 "There should be no documents in the table" let testDoc = { emptyDoc with Id = "turkey"; Sub = Some { Foo = "gobble"; Bar = "gobble" } } do! conn.insert PostgresDb.TableName testDoc let! after = conn.findAll PostgresDb.TableName Expect.equal after [ testDoc ] "There should have been one document inserted" } testTask "fails for duplicate key" { use db = PostgresDb.BuildDb() use conn = mkConn db do! conn.insert PostgresDb.TableName { emptyDoc with Id = "test" } Expect.throws (fun () -> conn.insert PostgresDb.TableName {emptyDoc with Id = "test" } |> Async.AwaitTask |> Async.RunSynchronously) "An exception should have been raised for duplicate document ID insert" } ] testList "save" [ testTask "succeeds when a document is inserted" { use db = PostgresDb.BuildDb() use conn = mkConn db let! before = conn.countAll PostgresDb.TableName Expect.equal before 0 "There should be no documents in the table" let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } } do! conn.save PostgresDb.TableName testDoc let! after = conn.findAll PostgresDb.TableName Expect.equal after [ testDoc ] "There should have been one document inserted" } testTask "succeeds when a document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db let testDoc = { emptyDoc with Id = "test"; Sub = Some { Foo = "a"; Bar = "b" } } do! conn.insert PostgresDb.TableName testDoc let! before = conn.findById PostgresDb.TableName "test" Expect.isSome before "There should have been a document returned" Expect.equal before.Value testDoc "The document is not correct" let upd8Doc = { testDoc with Sub = Some { Foo = "c"; Bar = "d" } } do! conn.save PostgresDb.TableName upd8Doc let! after = conn.findById PostgresDb.TableName "test" Expect.isSome after "There should have been a document returned post-update" Expect.equal after.Value upd8Doc "The updated document is not correct" } ] testTask "countAll succeeds" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! theCount = conn.countAll PostgresDb.TableName Expect.equal theCount 5 "There should have been 5 matching documents" } testTask "countByFields succeeds" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! theCount = conn.countByFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] Expect.equal theCount 2 "There should have been 2 matching documents" } testTask "countByContains succeeds" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! theCount = conn.countByContains PostgresDb.TableName {| Value = "purple" |} Expect.equal theCount 2 "There should have been 2 matching documents" } testTask "countByJsonPath succeeds" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! theCount = conn.countByJsonPath PostgresDb.TableName "$.NumValue ? (@ > 5)" Expect.equal theCount 3 "There should have been 3 matching documents" } testList "existsById" [ testTask "succeeds when a document exists" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! exists = conn.existsById PostgresDb.TableName "three" Expect.isTrue exists "There should have been an existing document" } testTask "succeeds when a document does not exist" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! exists = conn.existsById PostgresDb.TableName "seven" Expect.isFalse exists "There should not have been an existing document" } ] testList "existsByFields" [ testTask "succeeds when documents exist" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! exists = conn.existsByFields PostgresDb.TableName Any [ Field.Exists "Sub" ] Expect.isTrue exists "There should have been existing documents" } testTask "succeeds when documents do not exist" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! exists = conn.existsByFields PostgresDb.TableName Any [ Field.Equal "NumValue" "six" ] Expect.isFalse exists "There should not have been existing documents" } ] testList "existsByContains" [ testTask "succeeds when documents exist" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! exists = conn.existsByContains PostgresDb.TableName {| NumValue = 10 |} Expect.isTrue exists "There should have been existing documents" } testTask "succeeds when no matching documents exist" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! exists = conn.existsByContains PostgresDb.TableName {| Nothing = "none" |} Expect.isFalse exists "There should not have been any existing documents" } ] testList "existsByJsonPath" [ testTask "succeeds when documents exist" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! exists = conn.existsByJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" Expect.isTrue exists "There should have been existing documents" } testTask "succeeds when no matching documents exist" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! exists = conn.existsByJsonPath PostgresDb.TableName "$.NumValue ? (@ > 1000)" Expect.isFalse exists "There should not have been any existing documents" } ] testList "findAll" [ testTask "succeeds when there is data" { use db = PostgresDb.BuildDb() use conn = mkConn db do! conn.insert PostgresDb.TableName { Foo = "one"; Bar = "two" } do! conn.insert PostgresDb.TableName { Foo = "three"; Bar = "four" } do! conn.insert PostgresDb.TableName { Foo = "five"; Bar = "six" } let! results = conn.findAll PostgresDb.TableName Expect.equal results [ { Foo = "one"; Bar = "two" }; { Foo = "three"; Bar = "four" }; { Foo = "five"; Bar = "six" } ] "There should have been 3 documents returned" } testTask "succeeds when there is no data" { use db = PostgresDb.BuildDb() use conn = mkConn db let! results = conn.findAll PostgresDb.TableName Expect.equal results [] "There should have been no documents returned" } ] testList "findAllOrdered" [ testTask "succeeds when ordering numerically" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! results = conn.findAllOrdered PostgresDb.TableName [ Field.Named "n:NumValue" ] Expect.hasLength results 5 "There should have been 5 documents returned" Expect.equal (results |> List.map _.Id |> String.concat "|") "one|three|two|four|five" "The documents were not ordered correctly" } testTask "succeeds when ordering numerically descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! results = conn.findAllOrdered PostgresDb.TableName [ Field.Named "n:NumValue DESC" ] Expect.hasLength results 5 "There should have been 5 documents returned" Expect.equal (results |> List.map _.Id |> String.concat "|") "five|four|two|three|one" "The documents were not ordered correctly" } testTask "succeeds when ordering alphabetically" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! results = conn.findAllOrdered PostgresDb.TableName [ Field.Named "Id DESC" ] Expect.hasLength results 5 "There should have been 5 documents returned" Expect.equal (results |> List.map _.Id |> String.concat "|") "two|three|one|four|five" "The documents were not ordered correctly" } ] testList "findById" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findById PostgresDb.TableName "two" Expect.isSome doc "There should have been a document returned" Expect.equal doc.Value.Id "two" "The incorrect document was returned" } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findById PostgresDb.TableName "three hundred eighty-seven" Expect.isNone doc "There should not have been a document returned" } ] testList "findByFields" [ testTask "succeeds when documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByFields PostgresDb.TableName Any [ Field.Equal "Value" "another" ] Expect.equal (List.length docs) 1 "There should have been one document returned" } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByFields PostgresDb.TableName Any [ Field.Equal "Value" "mauve" ] Expect.isEmpty docs "There should have been no documents returned" } ] testList "findByFieldsOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByFieldsOrdered PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] Expect.hasLength docs 2 "There should have been two documents returned" Expect.equal (docs |> List.map _.Id |> String.concat "|") "five|four" "Documents not ordered correctly" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByFieldsOrdered PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] Expect.hasLength docs 2 "There should have been two documents returned" Expect.equal (docs |> List.map _.Id |> String.concat "|") "four|five" "Documents not ordered correctly" } ] testList "findByContains" [ testTask "succeeds when documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |} Expect.equal (List.length docs) 2 "There should have been two documents returned" } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByContains PostgresDb.TableName {| Value = "mauve" |} Expect.isEmpty docs "There should have been no documents returned" } ] testList "findByContainsOrdered" [ // Id = two, Sub.Bar = blue; Id = four, Sub.Bar = red testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar" ] Expect.hasLength docs 2 "There should have been two documents returned" Expect.equal (docs |> List.map _.Id |> String.concat "|") "two|four" "Documents not ordered correctly" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar DESC" ] Expect.hasLength docs 2 "There should have been two documents returned" Expect.equal (docs |> List.map _.Id |> String.concat "|") "four|two" "Documents not ordered correctly" } ] testList "findByJsonPath" [ testTask "succeeds when documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByJsonPath PostgresDb.TableName "$.NumValue ? (@ < 15)" Expect.equal (List.length docs) 3 "There should have been 3 documents returned" } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)" Expect.isEmpty docs "There should have been no documents returned" } ] testList "findByJsonPathOrdered" [ // Id = one, NumValue = 0; Id = two, NumValue = 10; Id = three, NumValue = 4 testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByJsonPathOrdered PostgresDb.TableName "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue" ] Expect.hasLength docs 3 "There should have been 3 documents returned" Expect.equal (docs |> List.map _.Id |> String.concat "|") "one|three|two" "Documents not ordered correctly" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! docs = conn.findByJsonPathOrdered PostgresDb.TableName "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue DESC" ] Expect.hasLength docs 3 "There should have been 3 documents returned" Expect.equal (docs |> List.map _.Id |> String.concat "|") "two|three|one" "Documents not ordered correctly" } ] testList "findFirstByFields" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByFields PostgresDb.TableName Any [ Field.Equal "Value" "another" ] Expect.isSome doc "There should have been a document returned" Expect.equal doc.Value.Id "two" "The incorrect document was returned" } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] Expect.isSome doc "There should have been a document returned" Expect.contains [ "five"; "four" ] doc.Value.Id "An incorrect document was returned" } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByFields PostgresDb.TableName Any [ Field.Equal "Value" "absent" ] Expect.isNone doc "There should not have been a document returned" } ] testList "findFirstByFieldsOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByFieldsOrdered PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] Expect.isSome doc "There should have been a document returned" Expect.equal "five" doc.Value.Id "An incorrect document was returned" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByFieldsOrdered PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] Expect.isSome doc "There should have been a document returned" Expect.equal "four" doc.Value.Id "An incorrect document was returned" } ] testList "findFirstByContains" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByContains PostgresDb.TableName {| Value = "another" |} Expect.isSome doc "There should have been a document returned" Expect.equal doc.Value.Id "two" "The incorrect document was returned" } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |} Expect.isSome doc "There should have been a document returned" Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned" } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByContains PostgresDb.TableName {| Value = "absent" |} Expect.isNone doc "There should not have been a document returned" } ] testList "findFirstByContainsOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Value" ] Expect.isSome doc "There should have been a document returned" Expect.equal "two" doc.Value.Id "An incorrect document was returned" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Value DESC" ] Expect.isSome doc "There should have been a document returned" Expect.equal "four" doc.Value.Id "An incorrect document was returned" } ] testList "findFirstByJsonPath" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByJsonPath PostgresDb.TableName """$.Value ? (@ == "FIRST!")""" Expect.isSome doc "There should have been a document returned" Expect.equal doc.Value.Id "one" "The incorrect document was returned" } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" Expect.isSome doc "There should have been a document returned" Expect.contains [ "two"; "four" ] doc.Value.Id "An incorrect document was returned" } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByJsonPath PostgresDb.TableName """$.Id ? (@ == "nope")""" Expect.isNone doc "There should not have been a document returned" } ] testList "findFirstByJsonPathOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByJsonPathOrdered PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar" ] Expect.isSome doc "There should have been a document returned" Expect.equal "two" doc.Value.Id "An incorrect document was returned" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! doc = conn.findFirstByJsonPathOrdered PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar DESC" ] Expect.isSome doc "There should have been a document returned" Expect.equal "four" doc.Value.Id "An incorrect document was returned" } ] testList "jsonAll" [ testTask "succeeds when there is data" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonAll PostgresDb.TableName verifyAllData json } testTask "succeeds when there is no data" { use db = PostgresDb.BuildDb() use conn = mkConn db let! json = conn.jsonAll PostgresDb.TableName verifyEmpty json } ] testList "jsonAllOrdered" [ testTask "succeeds when ordering numerically" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonAllOrdered PostgresDb.TableName [ Field.Named "n:NumValue" ] verifyExpectedOrder json "one" "three" (Some "two") (Some "four") (Some "five") } testTask "succeeds when ordering numerically descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonAllOrdered PostgresDb.TableName [ Field.Named "n:NumValue DESC" ] verifyExpectedOrder json "five" "four" (Some "two") (Some "three") (Some "one") } testTask "succeeds when ordering alphabetically" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonAllOrdered PostgresDb.TableName [ Field.Named "Id DESC" ] verifyExpectedOrder json "two" "three" (Some "one") (Some "four") (Some "five") } ] testList "jsonById" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonById PostgresDb.TableName "two" Expect.stringStarts json """{"Id": "two",""" "An incorrect document was returned" Expect.stringEnds json "}" "JSON should have ended with this document" } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonById PostgresDb.TableName "three hundred eighty-seven" verifyNoDoc json } ] testList "jsonByFields" [ testTask "succeeds when documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByFields PostgresDb.TableName All [ Field.In "Value" [ "purple"; "blue" ]; Field.Exists "Sub" ] verifySingleById json "four" } testTask "succeeds when documents are found using IN with numeric field" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByFields PostgresDb.TableName All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ] verifySingleById json "three" } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByFields PostgresDb.TableName All [ Field.Equal "Value" "mauve"; Field.NotEqual "NumValue" 40 ] verifyEmpty json } testTask "succeeds for InArray when matching documents exist" { use db = PostgresDb.BuildDb() use conn = mkConn db do! conn.ensureTable PostgresDb.TableName for doc in ArrayDocument.TestDocuments do do! conn.insert PostgresDb.TableName doc let! json = conn.jsonByFields PostgresDb.TableName All [ Field.InArray "Values" PostgresDb.TableName [ "c" ] ] verifyBeginEnd json verifyDocById json "first" verifyDocById json "second" } testTask "succeeds for InArray when no matching documents exist" { use db = PostgresDb.BuildDb() use conn = mkConn db do! conn.ensureTable PostgresDb.TableName for doc in ArrayDocument.TestDocuments do do! conn.insert PostgresDb.TableName doc let! json = conn.jsonByFields PostgresDb.TableName All [ Field.InArray "Values" PostgresDb.TableName [ "j" ] ] verifyEmpty json } ] testList "jsoByFieldsOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByFieldsOrdered PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] verifyExpectedOrder json "five" "four" None None None } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByFieldsOrdered PostgresDb.TableName All [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] verifyExpectedOrder json "four" "five" None None None } ] testList "jsonByContains" [ testTask "succeeds when documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |} verifyBeginEnd json verifyDocById json "two" verifyDocById json "four" } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByContains PostgresDb.TableName {| Value = "mauve" |} verifyEmpty json } ] testList "jsonByContainsOrdered" [ // Id = two, Sub.Bar = blue; Id = four, Sub.Bar = red testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar" ] verifyExpectedOrder json "two" "four" None None None } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar DESC" ] verifyExpectedOrder json "four" "two" None None None } ] testList "jsonByJsonPath" [ testTask "succeeds when documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByJsonPath PostgresDb.TableName "$.NumValue ? (@ < 15)" verifyBeginEnd json verifyDocById json "one" verifyDocById json "two" verifyDocById json "three" } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)" verifyEmpty json } ] testList "jsonByJsonPathOrdered" [ // Id = one, NumValue = 0; Id = two, NumValue = 10; Id = three, NumValue = 4 testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByJsonPathOrdered PostgresDb.TableName "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue" ] verifyExpectedOrder json "one" "three" (Some "two") None None } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonByJsonPathOrdered PostgresDb.TableName "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue DESC" ] verifyExpectedOrder json "two" "three" (Some "one") None None } ] testList "jsonFirstByFields" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByFields PostgresDb.TableName Any [ Field.Equal "Value" "another" ] verifyDocById json "two" } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] verifyAnyById json [ "five"; "four" ] } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByFields PostgresDb.TableName Any [ Field.Equal "Value" "absent" ] verifyNoDoc json } ] testList "jsonFirstByFieldsOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByFieldsOrdered PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] verifyDocById json "five" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByFieldsOrdered PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] verifyDocById json "four" } ] testList "jsonFirstByContains" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByContains PostgresDb.TableName {| Value = "another" |} verifyDocById json "two" } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByContains PostgresDb.TableName {| Sub = {| Foo = "green" |} |} verifyAnyById json [ "two"; "four" ] } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByContains PostgresDb.TableName {| Value = "absent" |} verifyNoDoc json } ] testList "jsonFirstByContainsOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Value" ] verifyDocById json "two" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByContainsOrdered PostgresDb.TableName {| Sub = {| Foo = "green" |} |} [ Field.Named "Value DESC" ] verifyDocById json "four" } ] testList "jsonFirstByJsonPath" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByJsonPath PostgresDb.TableName """$.Value ? (@ == "FIRST!")""" verifyDocById json "one" } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" verifyAnyById json [ "two"; "four" ] } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByJsonPath PostgresDb.TableName """$.Id ? (@ == "nope")""" verifyNoDoc json } ] testList "jsonFirstByJsonPathOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByJsonPathOrdered PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar" ] verifyDocById json "two" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let! json = conn.jsonFirstByJsonPathOrdered PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar DESC" ] verifyDocById json "four" } ] testList "writeJsonAll" [ testTask "succeeds when there is data" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonAll PostgresDb.TableName writer verifyAllData (streamText stream) } testTask "succeeds when there is no data" { use db = PostgresDb.BuildDb() use conn = mkConn db use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonAll PostgresDb.TableName writer verifyEmpty (streamText stream) } ] testList "writeJsonAllOrdered" [ testTask "succeeds when ordering numerically" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonAllOrdered PostgresDb.TableName writer [ Field.Named "n:NumValue" ] verifyExpectedOrder (streamText stream) "one" "three" (Some "two") (Some "four") (Some "five") } testTask "succeeds when ordering numerically descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonAllOrdered PostgresDb.TableName writer [ Field.Named "n:NumValue DESC" ] verifyExpectedOrder (streamText stream) "five" "four" (Some "two") (Some "three") (Some "one") } testTask "succeeds when ordering alphabetically" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonAllOrdered PostgresDb.TableName writer [ Field.Named "Id DESC" ] verifyExpectedOrder (streamText stream) "two" "three" (Some "one") (Some "four") (Some "five") } ] testList "writeJsonById" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonById PostgresDb.TableName writer "two" let json = streamText stream Expect.stringStarts json """{"Id": "two",""" "An incorrect document was returned" Expect.stringEnds json "}" "JSON should have ended with this document" } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonById PostgresDb.TableName writer "three hundred eighty-seven" verifyNoDoc (streamText stream) } ] testList "writeJsonByFields" [ testTask "succeeds when documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByFields PostgresDb.TableName writer All [ Field.In "Value" [ "purple"; "blue" ]; Field.Exists "Sub" ] verifySingleById (streamText stream) "four" } testTask "succeeds when documents are found using IN with numeric field" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByFields PostgresDb.TableName writer All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ] verifySingleById (streamText stream) "three" } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByFields PostgresDb.TableName writer All [ Field.Equal "Value" "mauve"; Field.NotEqual "NumValue" 40 ] verifyEmpty (streamText stream) } testTask "succeeds for InArray when matching documents exist" { use db = PostgresDb.BuildDb() use conn = mkConn db do! conn.ensureTable PostgresDb.TableName for doc in ArrayDocument.TestDocuments do do! conn.insert PostgresDb.TableName doc use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByFields PostgresDb.TableName writer All [ Field.InArray "Values" PostgresDb.TableName [ "c" ] ] let json = streamText stream verifyBeginEnd json verifyDocById json "first" verifyDocById json "second" } testTask "succeeds for InArray when no matching documents exist" { use db = PostgresDb.BuildDb() use conn = mkConn db do! conn.ensureTable PostgresDb.TableName for doc in ArrayDocument.TestDocuments do do! conn.insert PostgresDb.TableName doc use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByFields PostgresDb.TableName writer All [ Field.InArray "Values" PostgresDb.TableName [ "j" ] ] verifyEmpty (streamText stream) } ] testList "writeJsonByFieldsOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByFieldsOrdered PostgresDb.TableName writer All [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] verifyExpectedOrder (streamText stream) "five" "four" None None None } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByFieldsOrdered PostgresDb.TableName writer All [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] verifyExpectedOrder (streamText stream) "four" "five" None None None } ] testList "writeJsonByContains" [ testTask "succeeds when documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByContains PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} let json = streamText stream verifyBeginEnd json verifyDocById json "two" verifyDocById json "four" } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByContains PostgresDb.TableName writer {| Value = "mauve" |} verifyEmpty (streamText stream) } ] testList "writeJsonByContainsOrdered" [ // Id = two, Sub.Bar = blue; Id = four, Sub.Bar = red testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByContainsOrdered PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar" ] verifyExpectedOrder (streamText stream) "two" "four" None None None } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByContainsOrdered PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar DESC" ] verifyExpectedOrder (streamText stream) "four" "two" None None None } ] testList "writeJsonByJsonPath" [ testTask "succeeds when documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByJsonPath PostgresDb.TableName writer "$.NumValue ? (@ < 15)" let json = streamText stream verifyBeginEnd json verifyDocById json "one" verifyDocById json "two" verifyDocById json "three" } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByJsonPath PostgresDb.TableName writer "$.NumValue ? (@ < 0)" verifyEmpty (streamText stream) } ] testList "writeJsonByJsonPathOrdered" [ // Id = one, NumValue = 0; Id = two, NumValue = 10; Id = three, NumValue = 4 testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByJsonPathOrdered PostgresDb.TableName writer "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue" ] verifyExpectedOrder (streamText stream) "one" "three" (Some "two") None None } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonByJsonPathOrdered PostgresDb.TableName writer "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue DESC" ] verifyExpectedOrder (streamText stream) "two" "three" (Some "one") None None } ] testList "writeJsonFirstByFields" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "another" ] verifyDocById (streamText stream) "two" } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] verifyAnyById (streamText stream) [ "five"; "four" ] } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "absent" ] verifyNoDoc (streamText stream) } ] testList "writeJsonFirstByFieldsOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByFieldsOrdered PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] verifyDocById (streamText stream) "five" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByFieldsOrdered PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] verifyDocById (streamText stream) "four" } ] testList "writeJsonFirstByContains" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByContains PostgresDb.TableName writer {| Value = "another" |} verifyDocById (streamText stream) "two" } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByContains PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} verifyAnyById (streamText stream) [ "two"; "four" ] } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByContains PostgresDb.TableName writer {| Value = "absent" |} verifyNoDoc (streamText stream) } ] testList "writeJsonFirstByContainsOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByContainsOrdered PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Value" ] verifyDocById (streamText stream) "two" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByContainsOrdered PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Value DESC" ] verifyDocById (streamText stream) "four" } ] testList "writeJsonFirstByJsonPath" [ testTask "succeeds when a document is found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByJsonPath PostgresDb.TableName writer """$.Value ? (@ == "FIRST!")""" verifyDocById (streamText stream) "one" } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByJsonPath PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" verifyAnyById (streamText stream) [ "two"; "four" ] } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByJsonPath PostgresDb.TableName writer """$.Id ? (@ == "nope")""" verifyNoDoc (streamText stream) } ] testList "writeJsonFirstByJsonPathOrdered" [ testTask "succeeds when sorting ascending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByJsonPathOrdered PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar" ] verifyDocById (streamText stream) "two" } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn use stream = new MemoryStream() use writer = writeStream stream do! conn.writeJsonFirstByJsonPathOrdered PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar DESC" ] verifyDocById (streamText stream) "four" } ] testList "updateById" [ testTask "succeeds when a document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn let testDoc = { emptyDoc with Id = "one"; Sub = Some { Foo = "blue"; Bar = "red" } } do! conn.updateById PostgresDb.TableName "one" testDoc let! after = conn.findById PostgresDb.TableName "one" Expect.isSome after "There should have been a document returned post-update" Expect.equal after.Value testDoc "The updated document is not correct" } testTask "succeeds when no document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db let! before = conn.countAll PostgresDb.TableName Expect.equal before 0 "There should have been no documents returned" // This not raising an exception is the test do! conn.updateById PostgresDb.TableName "test" { emptyDoc with Id = "x"; Sub = Some { Foo = "blue"; Bar = "red" } } } ] testList "updateByFunc" [ testTask "succeeds when a document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.updateByFunc PostgresDb.TableName _.Id { Id = "one"; Value = "le un"; NumValue = 1; Sub = None } let! after = conn.findById PostgresDb.TableName "one" Expect.isSome after "There should have been a document returned post-update" Expect.equal after.Value { Id = "one"; Value = "le un"; NumValue = 1; Sub = None } "The updated document is not correct" } testTask "succeeds when no document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db let! before = conn.countAll PostgresDb.TableName Expect.equal before 0 "There should have been no documents returned" // This not raising an exception is the test do! conn.updateByFunc PostgresDb.TableName _.Id { Id = "one"; Value = "le un"; NumValue = 1; Sub = None } } ] testList "patchById" [ testTask "succeeds when a document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.patchById PostgresDb.TableName "one" {| NumValue = 44 |} let! after = conn.findById PostgresDb.TableName "one" Expect.isSome after "There should have been a document returned post-update" Expect.equal after.Value.NumValue 44 "The updated document is not correct" } testTask "succeeds when no document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db let! before = conn.countAll PostgresDb.TableName Expect.equal before 0 "There should have been no documents returned" // This not raising an exception is the test do! conn.patchById PostgresDb.TableName "test" {| Foo = "green" |} } ] testList "patchByFields" [ testTask "succeeds when a document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.patchByFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] {| NumValue = 77 |} let! after = conn.countByFields PostgresDb.TableName Any [ Field.Equal "NumValue" "77" ] Expect.equal after 2 "There should have been 2 documents returned" } testTask "succeeds when no document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db let! before = conn.countAll PostgresDb.TableName Expect.equal before 0 "There should have been no documents returned" // This not raising an exception is the test do! conn.patchByFields PostgresDb.TableName Any [ Field.Equal "Value" "burgundy" ] {| Foo = "green" |} } ] testList "patchByContains" [ testTask "succeeds when a document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.patchByContains PostgresDb.TableName {| Value = "purple" |} {| NumValue = 77 |} let! after = conn.countByContains PostgresDb.TableName {| NumValue = 77 |} Expect.equal after 2 "There should have been 2 documents returned" } testTask "succeeds when no document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db let! before = conn.countAll PostgresDb.TableName Expect.equal before 0 "There should have been no documents returned" // This not raising an exception is the test do! conn.patchByContains PostgresDb.TableName {| Value = "burgundy" |} {| Foo = "green" |} } ] testList "patchByJsonPath" [ testTask "succeeds when a document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.patchByJsonPath PostgresDb.TableName "$.NumValue ? (@ > 10)" {| NumValue = 1000 |} let! after = conn.countByJsonPath PostgresDb.TableName "$.NumValue ? (@ > 999)" Expect.equal after 2 "There should have been 2 documents returned" } testTask "succeeds when no document is updated" { use db = PostgresDb.BuildDb() use conn = mkConn db let! before = conn.countAll PostgresDb.TableName Expect.equal before 0 "There should have been no documents returned" // This not raising an exception is the test do! conn.patchByJsonPath PostgresDb.TableName "$.NumValue ? (@ < 0)" {| Foo = "green" |} } ] testList "removeFieldsById" [ testTask "succeeds when multiple fields are removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.removeFieldsById PostgresDb.TableName "two" [ "Sub"; "Value" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ] Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ] Expect.equal noValue 1 "There should be 1 document without Value fields" } testTask "succeeds when a single field is removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.removeFieldsById PostgresDb.TableName "two" [ "Sub" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ] Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ] Expect.equal noValue 0 "There should be no documents without Value fields" } testTask "succeeds when a field is not removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn // This not raising an exception is the test do! conn.removeFieldsById PostgresDb.TableName "two" [ "AFieldThatIsNotThere" ] } testTask "succeeds when no document is matched" { use db = PostgresDb.BuildDb() use conn = mkConn db // This not raising an exception is the test do! conn.removeFieldsById PostgresDb.TableName "two" [ "Value" ] } ] testList "removeFieldsByFields" [ testTask "succeeds when multiple fields are removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.removeFieldsByFields PostgresDb.TableName Any [ Field.Equal "NumValue" "17" ] [ "Sub"; "Value" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ] Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ] Expect.equal noValue 1 "There should be 1 document without Value fields" } testTask "succeeds when a single field is removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.removeFieldsByFields PostgresDb.TableName Any [ Field.Equal "NumValue" "17" ] [ "Sub" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ] Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ] Expect.equal noValue 0 "There should be no documents without Value fields" } testTask "succeeds when a field is not removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn // This not raising an exception is the test do! conn.removeFieldsByFields PostgresDb.TableName Any [ Field.Equal "NumValue" "17" ] [ "Nothing" ] } testTask "succeeds when no document is matched" { use db = PostgresDb.BuildDb() use conn = mkConn db // This not raising an exception is the test do! conn.removeFieldsByFields PostgresDb.TableName Any [ Field.NotEqual "Abracadabra" "apple" ] [ "Value" ] } ] testList "removeFieldsByContains" [ testTask "succeeds when multiple fields are removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.removeFieldsByContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub"; "Value" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ] Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ] Expect.equal noValue 1 "There should be 1 document without Value fields" } testTask "succeeds when a single field is removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.removeFieldsByContains PostgresDb.TableName {| NumValue = 17 |} [ "Sub" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ] Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ] Expect.equal noValue 0 "There should be no documents without Value fields" } testTask "succeeds when a field is not removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn // This not raising an exception is the test do! conn.removeFieldsByContains PostgresDb.TableName {| NumValue = 17 |} [ "Nothing" ] } testTask "succeeds when no document is matched" { use db = PostgresDb.BuildDb() use conn = mkConn db // This not raising an exception is the test do! conn.removeFieldsByContains PostgresDb.TableName {| Abracadabra = "apple" |} [ "Value" ] } ] testList "removeFieldsByJsonPath" [ testTask "succeeds when multiple fields are removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub"; "Value" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ] Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ] Expect.equal noValue 1 "There should be 1 document without Value fields" } testTask "succeeds when a single field is removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Sub" ] let! noSubs = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Sub" ] Expect.equal noSubs 4 "There should now be 4 documents without Sub fields" let! noValue = conn.countByFields PostgresDb.TableName Any [ Field.NotExists "Value" ] Expect.equal noValue 0 "There should be no documents without Value fields" } testTask "succeeds when a field is not removed" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn // This not raising an exception is the test do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.NumValue ? (@ == 17)" [ "Nothing" ] } testTask "succeeds when no document is matched" { use db = PostgresDb.BuildDb() use conn = mkConn db // This not raising an exception is the test do! conn.removeFieldsByJsonPath PostgresDb.TableName "$.Abracadabra ? (@ == \"apple\")" [ "Value" ] } ] testList "deleteById" [ testTask "succeeds when a document is deleted" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.deleteById PostgresDb.TableName "four" let! remaining = conn.countAll PostgresDb.TableName Expect.equal remaining 4 "There should have been 4 documents remaining" } testTask "succeeds when a document is not deleted" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.deleteById PostgresDb.TableName "thirty" let! remaining = conn.countAll PostgresDb.TableName Expect.equal remaining 5 "There should have been 5 documents remaining" } ] testList "deleteByFields" [ testTask "succeeds when documents are deleted" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.deleteByFields PostgresDb.TableName Any [ Field.Equal "Value" "purple" ] let! remaining = conn.countAll PostgresDb.TableName Expect.equal remaining 3 "There should have been 3 documents remaining" } testTask "succeeds when documents are not deleted" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.deleteByFields PostgresDb.TableName Any [ Field.Equal "Value" "crimson" ] let! remaining = conn.countAll PostgresDb.TableName Expect.equal remaining 5 "There should have been 5 documents remaining" } ] testList "deleteByContains" [ testTask "succeeds when documents are deleted" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.deleteByContains PostgresDb.TableName {| Value = "purple" |} let! remaining = conn.countAll PostgresDb.TableName Expect.equal remaining 3 "There should have been 3 documents remaining" } testTask "succeeds when documents are not deleted" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.deleteByContains PostgresDb.TableName {| Value = "crimson" |} let! remaining = conn.countAll PostgresDb.TableName Expect.equal remaining 5 "There should have been 5 documents remaining" } ] testList "deleteByJsonPath" [ testTask "succeeds when documents are deleted" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.deleteByJsonPath PostgresDb.TableName """$.Sub.Foo ? (@ == "green")""" let! remaining = conn.countAll PostgresDb.TableName Expect.equal remaining 3 "There should have been 3 documents remaining" } testTask "succeeds when documents are not deleted" { use db = PostgresDb.BuildDb() use conn = mkConn db do! loadDocs conn do! conn.deleteByJsonPath PostgresDb.TableName "$.NumValue ? (@ > 100)" let! remaining = conn.countAll PostgresDb.TableName Expect.equal remaining 5 "There should have been 5 documents remaining" } ] ] |> testSequenced