diff --git a/src/Common/Library.fs b/src/Common/Library.fs index c5668b7..fe55d12 100644 --- a/src/Common/Library.fs +++ b/src/Common/Library.fs @@ -1,6 +1,7 @@ namespace BitBadger.Documents open System.Security.Cryptography +open System.Text /// The types of comparisons available for JSON fields /// @@ -631,3 +632,47 @@ module Query = |> function path -> path + defaultArg direction "") |> String.concat ", " |> function it -> $" ORDER BY {it}" + + +open System.IO.Pipelines + +/// Functions that manipulate PipeWriters +[] +module PipeWriter = + + /// Write a UTF-8 string to this pipe + /// The PipeWriter to which the string should be written + /// The string to be written to the pipe + /// true if the pipe is still open, false if not + [] + let writeString (writer: PipeWriter) (text: string) = backgroundTask { + try + let! writeResult = writer.WriteAsync(Encoding.UTF8.GetBytes text) + let! flushResult = writer.FlushAsync() + return not (writeResult.IsCompleted || flushResult.IsCompleted) + with :? System.ObjectDisposedException -> return false + } + + /// Write an array of strings, abandoning the sequence if the pipe is closed + /// The PipeWriter to which the strings should be written + /// The strings to be written + /// true if the pipe is still open, false if not + [] + let writeStrings writer items = backgroundTask { + let rec writeNext docs idx = backgroundTask { + match items |> Seq.tryItem idx with + | Some item -> + if idx > 0 then + let! _ = writeString writer "," + () + match! writeString writer item with + | true -> return! writeNext docs (idx + 1) + | false -> return false + | None -> return true + } + let! _ = writeString writer "[" + let! isCleanFinish = writeNext items 0 + if isCleanFinish then + let! _ = writeString writer "]" + () + } diff --git a/src/Postgres/Extensions.fs b/src/Postgres/Extensions.fs index da0d24d..ebd9229 100644 --- a/src/Postgres/Extensions.fs +++ b/src/Postgres/Extensions.fs @@ -26,10 +26,10 @@ module Extensions = member conn.customJsonArray query parameters mapFunc = Custom.jsonArray query parameters mapFunc (Sql.existingConnection conn) - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document member conn.writeCustomJsonArray query parameters writer mapFunc = Custom.writeJsonArray query parameters writer mapFunc (Sql.existingConnection conn) @@ -298,9 +298,9 @@ module Extensions = member conn.jsonAll tableName = Json.all tableName (Sql.existingConnection conn) - /// Write all documents in the given table to the given StreamWriter + /// Write all documents in the given table to the given PipeWriter /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written member conn.writeJsonAll tableName writer = Json.writeAll tableName writer (Sql.existingConnection conn) @@ -314,11 +314,11 @@ module Extensions = Json.allOrdered tableName orderFields (Sql.existingConnection conn) /// - /// Write all documents in the given table to the given StreamWriter, ordered by the given fields in the + /// Write all documents in the given table to the given PipeWriter, ordered by the given fields in the /// document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Fields by which the results should be ordered member conn.writeJsonAllOrdered tableName writer orderFields = Json.writeAllOrdered tableName writer orderFields (Sql.existingConnection conn) @@ -330,9 +330,9 @@ module Extensions = member conn.jsonById<'TKey> tableName (docId: 'TKey) = Json.byId tableName docId (Sql.existingConnection conn) - /// Write a JSON document to the given StreamWriter by its ID + /// Write a JSON document to the given PipeWriter by its ID /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The ID of the document to retrieve member conn.writeJsonById<'TKey> tableName writer (docId: 'TKey) = Json.writeById tableName writer docId (Sql.existingConnection conn) @@ -346,11 +346,11 @@ module Extensions = Json.byFields tableName howMatched fields (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, /// etc.) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match member conn.writeJsonByFields tableName writer howMatched fields = @@ -369,11 +369,11 @@ module Extensions = Json.byFieldsOrdered tableName howMatched queryFields orderFields (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, /// etc.) ordered by the given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -388,10 +388,10 @@ module Extensions = Json.byContains tableName criteria (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching a JSON containment query (@>) + /// Write JSON documents to the given PipeWriter matching a JSON containment query (@>) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query member conn.writeJsonByContains tableName writer (criteria: obj) = Json.writeByContains tableName writer criteria (Sql.existingConnection conn) @@ -408,11 +408,11 @@ module Extensions = Json.byContainsOrdered tableName criteria orderFields (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching a JSON containment query (@>) - /// ordered by the given fields in the document + /// Write JSON documents to the given PipeWriter matching a JSON containment query (@>) ordered + /// by the given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query /// Fields by which the results should be ordered member conn.writeJsonByContainsOrdered tableName writer (criteria: obj) orderFields = @@ -426,10 +426,10 @@ module Extensions = Json.byJsonPath tableName jsonPath (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching a JSON Path match query (@?) + /// Write JSON documents to the given PipeWriter matching a JSON Path match query (@?) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match member conn.writeJsonByJsonPath tableName writer jsonPath = Json.writeByJsonPath tableName writer jsonPath (Sql.existingConnection conn) @@ -446,11 +446,11 @@ module Extensions = Json.byJsonPathOrdered tableName jsonPath orderFields (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching a JSON Path match query (@?) ordered - /// by the given fields in the document + /// Write JSON documents to the given PipeWriter matching a JSON Path match query (@?) ordered by + /// the given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match /// Fields by which the results should be ordered member conn.writeJsonByJsonPathOrdered tableName writer jsonPath orderFields = @@ -467,11 +467,11 @@ module Extensions = Json.firstByFields tableName howMatched fields (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match member conn.writeJsonFirstByFields tableName writer howMatched fields = @@ -490,11 +490,11 @@ module Extensions = Json.firstByFieldsOrdered tableName howMatched queryFields orderFields (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -510,11 +510,11 @@ module Extensions = Json.firstByContains tableName criteria (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching a JSON containment query + /// Write the first JSON document to the given PipeWriter matching a JSON containment query /// (@>) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query member conn.writeJsonFirstByContains tableName writer (criteria: obj) = Json.writeFirstByContains tableName writer criteria (Sql.existingConnection conn) @@ -531,11 +531,11 @@ module Extensions = Json.firstByContainsOrdered tableName criteria orderFields (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching a JSON containment query + /// Write the first JSON document to the given PipeWriter matching a JSON containment query /// (@>) ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query /// Fields by which the results should be ordered member conn.writeJsonFirstByContainsOrdered tableName writer (criteria: obj) orderFields = @@ -549,10 +549,10 @@ module Extensions = Json.firstByJsonPath tableName jsonPath (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching a JSON Path match query (@?) + /// Write the first JSON document to the given PipeWriter matching a JSON Path match query (@?) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match member conn.writeJsonFirstByJsonPath tableName writer jsonPath = Json.writeFirstByJsonPath tableName writer jsonPath (Sql.existingConnection conn) @@ -569,11 +569,11 @@ module Extensions = Json.firstByJsonPathOrdered tableName jsonPath orderFields (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching a JSON Path match query (@?) + /// Write the first JSON document to the given PipeWriter matching a JSON Path match query (@?) /// ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match /// Fields by which the results should be ordered member conn.writeJsonFirstByJsonPathOrdered tableName writer jsonPath orderFields = @@ -710,11 +710,11 @@ type NpgsqlConnectionCSharpExtensions = static member inline CustomJsonArray(conn, query, parameters, mapFunc) = Custom.JsonArray(query, parameters, mapFunc, Sql.existingConnection conn) - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The NpgsqlConnection on which to run the query /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document [] static member inline WriteCustomJsonArray(conn, query, parameters, writer, mapFunc) = @@ -1048,10 +1048,10 @@ type NpgsqlConnectionCSharpExtensions = static member inline JsonAll(conn, tableName) = Json.all tableName (Sql.existingConnection conn) - /// Write all documents in the given table to the given StreamWriter + /// Write all documents in the given table to the given PipeWriter /// The NpgsqlConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written [] static member inline WriteJsonAll(conn, tableName, writer) = Json.writeAll tableName writer (Sql.existingConnection conn) @@ -1068,12 +1068,12 @@ type NpgsqlConnectionCSharpExtensions = Json.allOrdered tableName orderFields (Sql.existingConnection conn) /// - /// Write all documents in the given table to the given StreamWriter, ordered by the given fields in the + /// Write all documents in the given table to the given PipeWriter, ordered by the given fields in the /// document /// /// The NpgsqlConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Fields by which the results should be ordered [] static member inline WriteJsonAllOrdered(conn, tableName, writer, orderFields) = @@ -1088,10 +1088,10 @@ type NpgsqlConnectionCSharpExtensions = static member inline JsonById<'TKey>(conn, tableName, docId: 'TKey) = Json.byId tableName docId (Sql.existingConnection conn) - /// Write a JSON document to the given StreamWriter by its ID + /// Write a JSON document to the given PipeWriter by its ID /// The NpgsqlConnection on which to run the query /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The ID of the document to retrieve [] static member inline WriteJsonById<'TKey>(conn, tableName, writer, docId) = @@ -1108,11 +1108,11 @@ type NpgsqlConnectionCSharpExtensions = Json.byFields tableName howMatched fields (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// /// The NpgsqlConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match [] @@ -1134,12 +1134,12 @@ type NpgsqlConnectionCSharpExtensions = Json.byFieldsOrdered tableName howMatched queryFields orderFields (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// ordered by the given fields in the document /// /// The NpgsqlConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -1157,11 +1157,11 @@ type NpgsqlConnectionCSharpExtensions = Json.byContains tableName criteria (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching a JSON containment query (@>) + /// Write JSON documents to the given PipeWriter matching a JSON containment query (@>) /// /// The NpgsqlConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query [] static member inline WriteJsonByContains(conn, tableName, writer, criteria: obj) = @@ -1181,12 +1181,12 @@ type NpgsqlConnectionCSharpExtensions = Json.byContainsOrdered tableName criteria orderFields (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching a JSON containment query (@>) ordered - /// by the given fields in the document + /// Write JSON documents to the given PipeWriter matching a JSON containment query (@>) ordered by + /// the given fields in the document /// /// The NpgsqlConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query /// Fields by which the results should be ordered [] @@ -1203,11 +1203,11 @@ type NpgsqlConnectionCSharpExtensions = Json.byJsonPath tableName jsonPath (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching a JSON Path match query (@?) + /// Write JSON documents to the given PipeWriter matching a JSON Path match query (@?) /// /// The NpgsqlConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match [] static member inline WriteJsonByJsonPath(conn, tableName, writer, jsonPath) = @@ -1226,12 +1226,12 @@ type NpgsqlConnectionCSharpExtensions = Json.byJsonPathOrdered tableName jsonPath orderFields (Sql.existingConnection conn) /// - /// Write JSON documents to the given StreamWriter matching a JSON Path match query (@?) ordered by - /// the given fields in the document + /// Write JSON documents to the given PipeWriter matching a JSON Path match query (@?) ordered by the + /// given fields in the document /// /// The NpgsqlConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match /// Fields by which the results should be ordered [] @@ -1249,12 +1249,12 @@ type NpgsqlConnectionCSharpExtensions = Json.firstByFields tableName howMatched fields (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) /// /// The NpgsqlConnection on which to run the query /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match [] @@ -1276,12 +1276,12 @@ type NpgsqlConnectionCSharpExtensions = Json.firstByFieldsOrdered tableName howMatched queryFields orderFields (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) ordered by the given fields in the document /// /// The NpgsqlConnection on which to run the query /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -1300,11 +1300,11 @@ type NpgsqlConnectionCSharpExtensions = Json.firstByContains tableName criteria (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching a JSON containment query (@>) + /// Write the first JSON document to the given PipeWriter matching a JSON containment query (@>) /// /// The NpgsqlConnection on which to run the query /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query [] static member inline WriteJsonFirstByContains(conn, tableName, writer, criteria: obj) = @@ -1324,12 +1324,12 @@ type NpgsqlConnectionCSharpExtensions = Json.firstByContainsOrdered tableName criteria orderFields (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching a JSON containment query (@>) + /// Write the first JSON document to the given PipeWriter matching a JSON containment query (@>) /// ordered by the given fields in the document /// /// The NpgsqlConnection on which to run the query /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query /// Fields by which the results should be ordered [] @@ -1346,11 +1346,11 @@ type NpgsqlConnectionCSharpExtensions = Json.firstByJsonPath tableName jsonPath (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching a JSON Path match query (@?) + /// Write the first JSON document to the given PipeWriter matching a JSON Path match query (@?) /// /// The NpgsqlConnection on which to run the query /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match [] static member inline WriteJsonFirstByJsonPath(conn, tableName, writer, jsonPath) = @@ -1370,12 +1370,12 @@ type NpgsqlConnectionCSharpExtensions = Json.firstByJsonPathOrdered tableName jsonPath orderFields (Sql.existingConnection conn) /// - /// Write the first JSON document to the given StreamWriter matching a JSON Path match query (@?) + /// Write the first JSON document to the given PipeWriter matching a JSON Path match query (@?) /// ordered by the given fields in the document /// /// The NpgsqlConnection on which to run the query /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match /// Fields by which the results should be ordered [] diff --git a/src/Postgres/Functions.fs b/src/Postgres/Functions.fs index f9f0eae..cf4d9f6 100644 --- a/src/Postgres/Functions.fs +++ b/src/Postgres/Functions.fs @@ -38,19 +38,19 @@ module Custom = let JsonArray(query, parameters, mapFunc) = WithProps.Custom.JsonArray(query, parameters, mapFunc, fromDataSource ()) - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document [] let writeJsonArray query parameters writer mapFunc = WithProps.Custom.writeJsonArray query parameters writer mapFunc (fromDataSource ()) - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document let WriteJsonArray(query, parameters, writer, mapFunc) = WithProps.Custom.WriteJsonArray(query, parameters, writer, mapFunc, fromDataSource ()) @@ -527,9 +527,9 @@ module Json = let all tableName = WithProps.Json.all tableName (fromDataSource ()) - /// Write all documents in the given table to the given StreamWriter + /// Write all documents in the given table to the given PipeWriter /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written [] let writeAll tableName writer = WithProps.Json.writeAll tableName writer (fromDataSource ()) @@ -545,11 +545,11 @@ module Json = WithProps.Json.allOrdered tableName orderFields (fromDataSource ()) /// - /// Write all documents in the given table to the given StreamWriter, ordered by the given fields in the + /// Write all documents in the given table to the given PipeWriter, ordered by the given fields in the /// document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Fields by which the results should be ordered [] let writeAllOrdered tableName writer orderFields = @@ -563,9 +563,9 @@ module Json = let byId<'TKey> tableName (docId: 'TKey) = WithProps.Json.byId tableName docId (fromDataSource ()) - /// Write a JSON document to the given StreamWriter by its ID + /// Write a JSON document to the given PipeWriter by its ID /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The ID of the document to retrieve [] let writeById<'TKey> tableName writer (docId: 'TKey) = @@ -581,10 +581,10 @@ module Json = WithProps.Json.byFields tableName howMatched fields (fromDataSource ()) /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match [] @@ -605,11 +605,11 @@ module Json = WithProps.Json.byFieldsOrdered tableName howMatched queryFields orderFields (fromDataSource ()) /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// ordered by the given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -626,10 +626,10 @@ module Json = WithProps.Json.byContains tableName criteria (fromDataSource ()) /// - /// Write JSON documents to the given StreamWriter matching a JSON containment query (@>) + /// Write JSON documents to the given PipeWriter matching a JSON containment query (@>) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query [] let writeByContains tableName writer (criteria: obj) = @@ -648,11 +648,11 @@ module Json = WithProps.Json.byContainsOrdered tableName criteria orderFields (fromDataSource ()) /// - /// Write JSON documents to the given StreamWriter matching a JSON containment query (@>) ordered - /// by the given fields in the document + /// Write JSON documents to the given PipeWriter matching a JSON containment query (@>) ordered by + /// the given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query /// Fields by which the results should be ordered [] @@ -668,10 +668,10 @@ module Json = WithProps.Json.byJsonPath tableName jsonPath (fromDataSource ()) /// - /// Write JSON documents to the given StreamWriter matching a JSON Path match query (@?) + /// Write JSON documents to the given PipeWriter matching a JSON Path match query (@?) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match [] let writeByJsonPath tableName writer jsonPath = @@ -689,11 +689,11 @@ module Json = WithProps.Json.byJsonPathOrdered tableName jsonPath orderFields (fromDataSource ()) /// - /// Write JSON documents to the given StreamWriter matching a JSON Path match query (@?) ordered by - /// the given fields in the document + /// Write JSON documents to the given PipeWriter matching a JSON Path match query (@?) ordered by the + /// given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match /// Fields by which the results should be ordered [] @@ -710,11 +710,11 @@ module Json = WithProps.Json.firstByFields tableName howMatched fields (fromDataSource ()) /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match [] @@ -735,11 +735,11 @@ module Json = WithProps.Json.firstByFieldsOrdered tableName howMatched queryFields orderFields (fromDataSource ()) /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -756,10 +756,10 @@ module Json = WithProps.Json.firstByContains tableName criteria (fromDataSource ()) /// - /// Write the first JSON document to the given StreamWriter matching a JSON containment query (@>) + /// Write the first JSON document to the given PipeWriter matching a JSON containment query (@>) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query [] let writeFirstByContains tableName writer (criteria: obj) = @@ -778,11 +778,11 @@ module Json = WithProps.Json.firstByContainsOrdered tableName criteria orderFields (fromDataSource ()) /// - /// Write the first JSON document to the given StreamWriter matching a JSON containment query (@>) + /// Write the first JSON document to the given PipeWriter matching a JSON containment query (@>) /// ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query /// Fields by which the results should be ordered [] @@ -798,10 +798,10 @@ module Json = WithProps.Json.firstByJsonPath tableName jsonPath (fromDataSource ()) /// - /// Write the first JSON document to the given StreamWriter matching a JSON Path match query (@?) + /// Write the first JSON document to the given PipeWriter matching a JSON Path match query (@?) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match [] let writeFirstByJsonPath tableName writer jsonPath = @@ -820,11 +820,11 @@ module Json = WithProps.Json.firstByJsonPathOrdered tableName jsonPath orderFields (fromDataSource ()) /// - /// Write the first JSON document to the given StreamWriter matching a JSON Path match query (@?) + /// Write the first JSON document to the given PipeWriter matching a JSON Path match query (@?) /// ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match /// Fields by which the results should be ordered [] diff --git a/src/Postgres/Library.fs b/src/Postgres/Library.fs index 7a5520e..230c7f2 100644 --- a/src/Postgres/Library.fs +++ b/src/Postgres/Library.fs @@ -1,9 +1,5 @@ namespace BitBadger.Documents.Postgres -open System.IO -open System.Text -open System.Threading.Tasks - /// The type of index to generate for the document [] type DocumentIndex = @@ -268,6 +264,8 @@ module Query = Query.statementWhere statement (whereJsonPathMatches "@path") +open System.Text + /// Functions for dealing with results [] module Results = @@ -337,24 +335,16 @@ module Results = let ToJsonArray(mapFunc: System.Func, sqlProps) = toJsonArray mapFunc.Invoke sqlProps - /// Write a JSON array of items for the results of a query to the given StreamWriter - /// The StreamWriter to which results should be written + /// Write a JSON array of items for the results of a query to the given PipeWriter + /// The PipeWriter to which results should be written /// The mapping function to extract JSON from the query's results /// The query from which JSON should be extracted [] - let writeJsonArray (writer: StreamWriter) (mapFunc: RowReader -> string) sqlProps = backgroundTask { - let await (it: Task) = it.ConfigureAwait(false).GetAwaiter().GetResult() - do! writer.WriteAsync "[" - let mutable isFirst = true - do! sqlProps - |> Sql.iterAsync (fun it -> - if isFirst then isFirst <- false else await (writer.WriteAsync ",") - (mapFunc >> writer.WriteAsync >> await) it) - do! writer.WriteAsync "]" - } + let writeJsonArray writer (mapFunc: RowReader -> string) sqlProps = + sqlProps |> Sql.toSeq mapFunc |> PipeWriter.writeStrings writer - /// Write a JSON array of items for the results of a query to the given StreamWriter - /// The StreamWriter to which results should be written + /// Write a JSON array of items for the results of a query to the given PipeWriter + /// The PipeWriter to which results should be written /// The mapping function to extract JSON from the query's results /// The query from which JSON should be extracted let WriteJsonArray(writer, mapFunc: System.Func, sqlProps) = diff --git a/src/Postgres/WithProps.fs b/src/Postgres/WithProps.fs index 2a06c96..16901ff 100644 --- a/src/Postgres/WithProps.fs +++ b/src/Postgres/WithProps.fs @@ -1,7 +1,6 @@ /// Versions of queries that accept SqlProps as the last parameter module BitBadger.Documents.Postgres.WithProps -open System.IO open BitBadger.Documents open Npgsql.FSharp @@ -55,10 +54,10 @@ module Custom = let JsonArray(query, parameters, mapFunc: System.Func, sqlProps) = jsonArray query parameters mapFunc.Invoke sqlProps - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document /// The SqlProps to use to execute the query [] @@ -67,10 +66,10 @@ module Custom = |> Sql.parameters (FSharpList.ofSeq parameters) |> writeJsonArray writer mapFunc - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document /// The SqlProps to use to execute the query let WriteJsonArray(query, parameters, writer, mapFunc: System.Func, sqlProps) = @@ -724,9 +723,9 @@ module Json = let all tableName sqlProps = Custom.jsonArray (Query.find tableName) [] jsonFromData sqlProps - /// Write all documents in the given table to the given StreamWriter + /// Write all documents in the given table to the given PipeWriter /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The SqlProps to use to execute the query [] let writeAll tableName writer sqlProps = @@ -744,11 +743,11 @@ module Json = Custom.jsonArray (Query.find tableName + Query.orderBy orderFields PostgreSQL) [] jsonFromData sqlProps /// - /// Write all documents in the given table to the given StreamWriter, ordered by the given fields in the + /// Write all documents in the given table to the given PipeWriter, ordered by the given fields in the /// document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Fields by which the results should be ordered /// The SqlProps to use to execute the query [] @@ -765,15 +764,16 @@ module Json = let byId<'TKey> tableName (docId: 'TKey) sqlProps = Custom.jsonSingle (Query.byId (Query.find tableName) docId) [ idParam docId ] jsonFromData sqlProps - /// Write a JSON document to the given StreamWriter by its ID + /// Write a JSON document to the given PipeWriter by its ID /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The ID of the document to retrieve /// The SqlProps to use to execute the query [] - let writeById<'TKey> tableName (writer: StreamWriter) (docId: 'TKey) sqlProps = backgroundTask { + let writeById<'TKey> tableName writer (docId: 'TKey) sqlProps = backgroundTask { let! json = byId tableName docId sqlProps - do! writer.WriteAsync json + let! _ = PipeWriter.writeString writer json + () } /// Retrieve JSON documents matching JSON field comparisons (->> =, etc.) @@ -788,10 +788,10 @@ module Json = (Query.byFields (Query.find tableName) howMatched fields) (addFieldParams fields []) jsonFromData sqlProps /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// The SqlProps to use to execute the query @@ -823,11 +823,11 @@ module Json = sqlProps /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// ordered by the given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -852,10 +852,10 @@ module Json = (Query.byContains (Query.find tableName)) [ jsonParam "@criteria" criteria ] jsonFromData sqlProps /// - /// Write JSON documents to the given StreamWriter matching a JSON containment query (@>) + /// Write JSON documents to the given PipeWriter matching a JSON containment query (@>) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query /// The SqlProps to use to execute the query [] @@ -881,11 +881,11 @@ module Json = sqlProps /// - /// Write JSON documents to the given StreamWriter matching a JSON containment query (@>) ordered - /// by the given fields in the document + /// Write JSON documents to the given PipeWriter matching a JSON containment query (@>) ordered by + /// the given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query /// Fields by which the results should be ordered /// The SqlProps to use to execute the query @@ -909,10 +909,10 @@ module Json = (Query.byPathMatch (Query.find tableName)) [ "@path", Sql.string jsonPath ] jsonFromData sqlProps /// - /// Write JSON documents to the given StreamWriter matching a JSON Path match query (@?) + /// Write JSON documents to the given PipeWriter matching a JSON Path match query (@?) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match /// The SqlProps to use to execute the query [] @@ -937,11 +937,11 @@ module Json = sqlProps /// - /// Write JSON documents to the given StreamWriter matching a JSON Path match query (@?) ordered by - /// the given fields in the document + /// Write JSON documents to the given PipeWriter matching a JSON Path match query (@?) ordered by the + /// given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match /// Fields by which the results should be ordered /// The SqlProps to use to execute the query @@ -966,18 +966,19 @@ module Json = (Query.byFields (Query.find tableName) howMatched fields) (addFieldParams fields []) jsonFromData sqlProps /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons - /// (->> =, etc.) + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons(->> =, + /// etc.) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// The SqlProps to use to execute the query [] - let writeFirstByFields tableName (writer: StreamWriter) howMatched fields sqlProps = backgroundTask { + let writeFirstByFields tableName writer howMatched fields sqlProps = backgroundTask { let! json = firstByFields tableName howMatched fields sqlProps - do! writer.WriteAsync json + let! _ = PipeWriter.writeString writer json + () } /// @@ -999,21 +1000,21 @@ module Json = sqlProps /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered /// The SqlProps to use to execute the query [] - let writeFirstByFieldsOrdered tableName (writer: StreamWriter) howMatched queryFields orderFields sqlProps = - backgroundTask { - let! json = firstByFieldsOrdered tableName howMatched queryFields orderFields sqlProps - do! writer.WriteAsync json - } + let writeFirstByFieldsOrdered tableName writer howMatched queryFields orderFields sqlProps = backgroundTask { + let! json = firstByFieldsOrdered tableName howMatched queryFields orderFields sqlProps + let! _ = PipeWriter.writeString writer json + () + } /// Retrieve the first JSON document matching a JSON containment query (@>) /// The table from which a document should be retrieved (may include schema) @@ -1026,16 +1027,17 @@ module Json = (Query.byContains (Query.find tableName)) [ jsonParam "@criteria" criteria ] jsonFromData sqlProps /// - /// Write the first JSON document to the given StreamWriter matching a JSON containment query (@>) + /// Write the first JSON document to the given PipeWriter matching a JSON containment query (@>) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query /// The SqlProps to use to execute the query [] - let writeFirstByContains tableName (writer: StreamWriter) (criteria: obj) sqlProps = backgroundTask { + let writeFirstByContains tableName writer (criteria: obj) sqlProps = backgroundTask { let! json = firstByContains tableName criteria sqlProps - do! writer.WriteAsync json + let! _ = PipeWriter.writeString writer json + () } /// @@ -1056,20 +1058,20 @@ module Json = sqlProps /// - /// Write the first JSON document to the given StreamWriter matching a JSON containment query (@>) + /// Write the first JSON document to the given PipeWriter matching a JSON containment query (@>) /// ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The document to match with the containment query /// Fields by which the results should be ordered /// The SqlProps to use to execute the query [] - let writeFirstByContainsOrdered tableName (writer: StreamWriter) (criteria: obj) orderFields sqlProps = - backgroundTask { - let! json = firstByContainsOrdered tableName criteria orderFields sqlProps - do! writer.WriteAsync json - } + let writeFirstByContainsOrdered tableName writer (criteria: obj) orderFields sqlProps = backgroundTask { + let! json = firstByContainsOrdered tableName criteria orderFields sqlProps + let! _ = PipeWriter.writeString writer json + () + } /// Retrieve the first JSON document matching a JSON Path match query (@?) /// The table from which a document should be retrieved (may include schema) @@ -1082,16 +1084,17 @@ module Json = (Query.byPathMatch (Query.find tableName)) [ "@path", Sql.string jsonPath ] jsonFromData sqlProps /// - /// Write the first JSON document to the given StreamWriter matching a JSON Path match query (@?) + /// Write the first JSON document to the given PipeWriter matching a JSON Path match query (@?) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match /// The SqlProps to use to execute the query [] - let writeFirstByJsonPath tableName (writer: StreamWriter) jsonPath sqlProps = backgroundTask { + let writeFirstByJsonPath tableName writer jsonPath sqlProps = backgroundTask { let! json = firstByJsonPath tableName jsonPath sqlProps - do! writer.WriteAsync json + let! _ = PipeWriter.writeString writer json + () } /// @@ -1112,18 +1115,19 @@ module Json = sqlProps /// - /// Write the first JSON document to the given StreamWriter matching a JSON Path match query (@?) + /// Write the first JSON document to the given PipeWriter matching a JSON Path match query (@?) /// ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The JSON Path expression to match /// Fields by which the results should be ordered /// The SqlProps to use to execute the query [] - let writeFirstByJsonPathOrdered tableName (writer: StreamWriter) jsonPath orderFields sqlProps = backgroundTask { + let writeFirstByJsonPathOrdered tableName writer jsonPath orderFields sqlProps = backgroundTask { let! json = firstByJsonPathOrdered tableName jsonPath orderFields sqlProps - do! writer.WriteAsync json + let! _ = PipeWriter.writeString writer json + () } /// Commands to update documents diff --git a/src/Sqlite/Extensions.fs b/src/Sqlite/Extensions.fs index 30160ae..c6d192d 100644 --- a/src/Sqlite/Extensions.fs +++ b/src/Sqlite/Extensions.fs @@ -25,10 +25,10 @@ module Extensions = member conn.customJsonArray query parameters mapFunc = Custom.jsonArray query parameters mapFunc conn - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document member conn.writeCustomJsonArray query parameters writer mapFunc = Custom.writeJsonArray query parameters writer mapFunc conn @@ -242,46 +242,46 @@ module Extensions = member conn.jsonFirstByFieldsOrdered tableName howMatched queryFields orderFields = Json.firstByFieldsOrdered tableName howMatched queryFields orderFields conn - /// Write all JSON documents in the given table to the given StreamWriter + /// Write all JSON documents in the given table to the given PipeWriter /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written member conn.writeJsonAll tableName writer = Json.writeAll tableName writer conn /// - /// Write all JSON all documents in the given table to the given StreamWriter, ordered by the given - /// fields in the document + /// Write all JSON all documents in the given table to the given PipeWriter, ordered by the given fields + /// in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Fields by which the results should be ordered member conn.writeJsonAllOrdered tableName writer orderFields = Json.writeAllOrdered tableName writer orderFields conn - /// Write a JSON document to the given StreamWriter by its ID + /// Write a JSON document to the given PipeWriter by its ID /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The ID of the document to retrieve member conn.writeJsonById<'TKey> tableName writer (docId: 'TKey) = Json.writeById tableName writer docId conn /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, /// etc.) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match member conn.writeJsonByFields tableName writer howMatched fields = Json.writeByFields tableName writer howMatched fields conn /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, /// etc.) ordered by the given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -289,22 +289,22 @@ module Extensions = Json.writeByFieldsOrdered tableName writer howMatched queryFields orderFields conn /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match member conn.writeJsonFirstByFields tableName writer howMatched fields = Json.writeFirstByFields tableName writer howMatched fields conn /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -399,11 +399,11 @@ type SqliteConnectionCSharpExtensions = static member inline CustomJsonArray(conn, query, parameters, mapFunc) = Custom.JsonArray(query, parameters, mapFunc, conn) - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The SqliteConnection on which to run the query /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document [] static member inline WriteCustomJsonArray(conn, query, parameters, writer, mapFunc) = @@ -668,41 +668,41 @@ type SqliteConnectionCSharpExtensions = static member inline JsonFirstByFieldsOrdered(conn, tableName, howMatched, queryFields, orderFields) = Json.firstByFieldsOrdered tableName howMatched queryFields orderFields conn - /// Write all JSON documents in the given table to the given StreamWriter + /// Write all JSON documents in the given table to the given PipeWriter /// The SqliteConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written [] static member inline WriteJsonAll(conn, tableName, writer) = Json.writeAll tableName writer conn /// - /// Write all JSON all documents in the given table to the given StreamWriter, ordered by the given fields in + /// Write all JSON all documents in the given table to the given PipeWriter, ordered by the given fields in /// the document /// /// The SqliteConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Fields by which the results should be ordered [] static member inline WriteJsonAllOrdered(conn, tableName, writer, orderFields) = Json.writeAllOrdered tableName writer orderFields conn - /// Write a JSON document to the given StreamWriter by its ID + /// Write a JSON document to the given PipeWriter by its ID /// The SqliteConnection on which to run the query /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The ID of the document to retrieve [] static member inline WriteJsonById<'TKey>(conn, tableName, writer, docId: 'TKey) = Json.writeById tableName writer docId conn /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// /// The SqliteConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match [] @@ -710,12 +710,12 @@ type SqliteConnectionCSharpExtensions = Json.writeByFields tableName writer howMatched fields conn /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// ordered by the given fields in the document /// /// The SqliteConnection on which to run the query /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -724,12 +724,12 @@ type SqliteConnectionCSharpExtensions = Json.writeByFieldsOrdered tableName writer howMatched queryFields orderFields conn /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) /// /// The SqliteConnection on which to run the query /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match [] @@ -737,12 +737,12 @@ type SqliteConnectionCSharpExtensions = Json.writeFirstByFields tableName writer howMatched fields conn /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) ordered by the given fields in the document /// /// The SqliteConnection on which to run the query /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered diff --git a/src/Sqlite/Functions.fs b/src/Sqlite/Functions.fs index 2b0ec65..c147f9a 100644 --- a/src/Sqlite/Functions.fs +++ b/src/Sqlite/Functions.fs @@ -44,20 +44,20 @@ module Custom = use conn = Configuration.dbConn () WithConn.Custom.JsonArray(query, parameters, mapFunc, conn) - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document [] let writeJsonArray query parameters writer mapFunc = use conn = Configuration.dbConn () WithConn.Custom.writeJsonArray query parameters writer mapFunc conn - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document let WriteJsonArray(query, parameters, writer, mapFunc) = use conn = Configuration.dbConn () @@ -446,29 +446,29 @@ module Json = use conn = Configuration.dbConn () WithConn.Json.firstByFieldsOrdered tableName howMatched queryFields orderFields conn - /// Write all JSON documents in the given table to the given StreamWriter + /// Write all JSON documents in the given table to the given PipeWriter /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written [] let writeAll tableName writer = use conn = Configuration.dbConn () WithConn.Json.writeAll tableName writer conn /// - /// Write all JSON all documents in the given table to the given StreamWriter, ordered by the given fields in + /// Write all JSON all documents in the given table to the given PipeWriter, ordered by the given fields in /// the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Fields by which the results should be ordered [] let writeAllOrdered tableName writer orderFields = use conn = Configuration.dbConn () WithConn.Json.writeAllOrdered tableName writer orderFields conn - /// Write a JSON document to the given StreamWriter by its ID + /// Write a JSON document to the given PipeWriter by its ID /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The ID of the document to retrieve [] let writeById<'TKey> tableName writer (docId: 'TKey) = @@ -476,10 +476,10 @@ module Json = WithConn.Json.writeById tableName writer docId conn /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match [] @@ -488,11 +488,11 @@ module Json = WithConn.Json.writeByFields tableName writer howMatched fields conn /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// ordered by the given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -502,11 +502,11 @@ module Json = WithConn.Json.writeByFieldsOrdered tableName writer howMatched queryFields orderFields conn /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match [] @@ -515,11 +515,11 @@ module Json = WithConn.Json.writeFirstByFields tableName writer howMatched fields conn /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered diff --git a/src/Sqlite/Library.fs b/src/Sqlite/Library.fs index 8e74554..0b44915 100644 --- a/src/Sqlite/Library.fs +++ b/src/Sqlite/Library.fs @@ -1,8 +1,5 @@ namespace BitBadger.Documents.Sqlite -open System.IO -open System.Text -open BitBadger.Documents open Microsoft.Data.Sqlite /// Configuration for document handling @@ -34,6 +31,8 @@ module Configuration = | None -> invalidOp "Please provide a connection string before attempting data access" +open BitBadger.Documents + /// Query definitions [] module Query = @@ -183,6 +182,8 @@ module Parameters = Seq.empty +open System.Text + /// Helper functions for handling results [] module Results = @@ -294,22 +295,18 @@ module Results = /// The StreamWriter to which results should be written /// The mapping function to extract JSON from the query's results [] - let writeJsonArray (cmd: SqliteCommand) (writer: StreamWriter) (mapFunc: SqliteDataReader -> string) = - backgroundTask { - use! rdr = cmd.ExecuteReaderAsync() - do! writer.WriteAsync "[" - let mutable isFirst = true - while! rdr.ReadAsync() do - if isFirst then isFirst <- false else do! writer.WriteAsync "," - do! writer.WriteAsync(mapFunc rdr) - do! writer.WriteAsync "]" - } + let writeJsonArray (cmd: SqliteCommand) writer (mapFunc: SqliteDataReader -> string) = backgroundTask { + use! rdr = cmd.ExecuteReaderAsync() + return + seq { while rdr.Read() do yield mapFunc rdr } + |> PipeWriter.writeStrings writer + } /// Write a JSON array of items for the results of a query to the given StreamWriter /// The command to execute /// The StreamWriter to which results should be written /// The mapping function to extract JSON from the query's results - let WriteJsonArray (cmd: SqliteCommand) (writer: StreamWriter) (mapFunc: System.Func) = + let WriteJsonArray (cmd: SqliteCommand) writer (mapFunc: System.Func) = writeJsonArray cmd writer mapFunc.Invoke diff --git a/src/Sqlite/WithConn.fs b/src/Sqlite/WithConn.fs index 1006a3f..d0deeb9 100644 --- a/src/Sqlite/WithConn.fs +++ b/src/Sqlite/WithConn.fs @@ -1,7 +1,6 @@ /// Versions of queries that accept a SqliteConnection as the last parameter module BitBadger.Documents.Sqlite.WithConn -open System.IO open BitBadger.Documents open Microsoft.Data.Sqlite @@ -64,10 +63,10 @@ module Custom = let JsonArray(query, parameters, mapFunc: System.Func, conn) = jsonArray query parameters mapFunc.Invoke conn - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document /// The SqliteConnection to use to execute the query [] @@ -82,10 +81,10 @@ module Custom = cmd.Parameters.AddRange parameters writeJsonArray cmd writer mapFunc - /// Execute a query, writing its results to the given StreamWriter + /// Execute a query, writing its results to the given PipeWriter /// The query to retrieve the results /// Parameters to use for the query - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The mapping function to extract the document /// The SqliteConnection to use to execute the query let WriteJsonArray(query, parameters, writer, mapFunc: System.Func, conn) = @@ -554,42 +553,43 @@ module Json = jsonFromData conn - /// Write all JSON documents in the given table to the given StreamWriter + /// Write all JSON documents in the given table to the given PipeWriter /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The SqliteConnection to use to execute the query [] let writeAll tableName writer conn = Custom.writeJsonArray (Query.find tableName) [] writer jsonFromData conn /// - /// Write all JSON all documents in the given table to the given StreamWriter, ordered by the given fields in + /// Write all JSON all documents in the given table to the given PipeWriter, ordered by the given fields in /// the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Fields by which the results should be ordered /// The SqliteConnection to use to execute the query [] let writeAllOrdered tableName writer orderFields conn = Custom.writeJsonArray (Query.find tableName + Query.orderBy orderFields SQLite) [] writer jsonFromData conn - /// Write a JSON document to the given StreamWriter by its ID + /// Write a JSON document to the given PipeWriter by its ID /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// The ID of the document to retrieve /// The SqliteConnection to use to execute the query [] - let writeById<'TKey> tableName (writer: StreamWriter) (docId: 'TKey) conn = backgroundTask { + let writeById<'TKey> tableName writer (docId: 'TKey) conn = backgroundTask { let! json = Custom.jsonSingle (Query.byId (Query.find tableName) docId) [ idParam docId ] jsonFromData conn - do! writer.WriteAsync json + let! _ = PipeWriter.writeString writer json + () } /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// The SqliteConnection to use to execute the query @@ -603,11 +603,11 @@ module Json = conn /// - /// Write JSON documents to the given StreamWriter matching JSON field comparisons (->> =, etc.) + /// Write JSON documents to the given PipeWriter matching JSON field comparisons (->> =, etc.) /// ordered by the given fields in the document /// /// The table from which documents should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered @@ -622,43 +622,44 @@ module Json = conn /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// The SqliteConnection to use to execute the query [] - let writeFirstByFields tableName (writer: StreamWriter) howMatched fields conn = backgroundTask { + let writeFirstByFields tableName writer howMatched fields conn = backgroundTask { let! json = Custom.jsonSingle (Query.byFields (Query.find tableName) howMatched fields) (addFieldParams fields []) jsonFromData conn - do! writer.WriteAsync json + let! _ = PipeWriter.writeString writer json + () } /// - /// Write the first JSON document to the given StreamWriter matching JSON field comparisons + /// Write the first JSON document to the given PipeWriter matching JSON field comparisons /// (->> =, etc.) ordered by the given fields in the document /// /// The table from which a document should be retrieved (may include schema) - /// The StreamWriter to which the results should be written + /// The PipeWriter to which the results should be written /// Whether to match any or all of the field conditions /// The field conditions to match /// Fields by which the results should be ordered /// The SqliteConnection to use to execute the query [] - let writeFirstByFieldsOrdered tableName (writer: StreamWriter) howMatched queryFields orderFields conn = - backgroundTask { - let! json = - Custom.jsonSingle - (Query.byFields (Query.find tableName) howMatched queryFields + Query.orderBy orderFields SQLite) - (addFieldParams queryFields []) - jsonFromData - conn - do! writer.WriteAsync json - } + let writeFirstByFieldsOrdered tableName writer howMatched queryFields orderFields conn = backgroundTask { + let! json = + Custom.jsonSingle + (Query.byFields (Query.find tableName) howMatched queryFields + Query.orderBy orderFields SQLite) + (addFieldParams queryFields []) + jsonFromData + conn + let! _ = PipeWriter.writeString writer json + () + } /// Commands to update documents diff --git a/src/Tests.CSharp/CommonCSharpTests.cs b/src/Tests.CSharp/CommonCSharpTests.cs index 90cbcba..0ed9d67 100644 --- a/src/Tests.CSharp/CommonCSharpTests.cs +++ b/src/Tests.CSharp/CommonCSharpTests.cs @@ -1,3 +1,4 @@ +using System.IO.Pipelines; using Expecto.CSharp; using Expecto; using Microsoft.FSharp.Core; @@ -648,6 +649,114 @@ public static class CommonCSharpTests ]) ]); + private static string StreamText(Stream stream) + { + stream.Position = 0L; + using StreamReader reader = new(stream); + return reader.ReadToEnd(); + } + + /// Unit tests for the PipeWriter module + private static readonly Test PipeWriterTests = TestList("PipeWriterModule", + [ + TestList("WriteString", + [ + TestCase("succeeds when writer is open", async () => + { + await using MemoryStream stream = new(); + var writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true)); + try + { + var result = await PipeWriterModule.WriteString(writer, "abc"); + Expect.isTrue(result, "The write operation should have been successful"); + Expect.equal(StreamText(stream), "abc", "The string was not written correctly"); + } + finally + { + await writer.CompleteAsync(); + } + }), + TestCase("succeeds when writer is completed", async () => + { + await using MemoryStream stream = new(); + var writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true)); + await writer.CompleteAsync(); + + var result = await PipeWriterModule.WriteString(writer, "abc"); + Expect.isFalse(result, "The write operation should have returned false"); + Expect.equal(StreamText(stream), "", "No text should have been written"); + }) + ]), + TestList("WriteStrings", + [ + TestCase("succeeds with no strings", async () => + { + await using MemoryStream stream = new(); + var writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true)); + try + { + await PipeWriterModule.WriteStrings(writer, []); + Expect.equal(StreamText(stream), "[]", "An empty sequence of strings was not written correctly"); + } + finally + { + await writer.CompleteAsync(); + } + }), + TestCase("succeeds with one strings", async () => + { + await using MemoryStream stream = new(); + var writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true)); + try + { + await PipeWriterModule.WriteStrings(writer, ["le-test"]); + Expect.equal(StreamText(stream), "[le-test]", "A sequence of one string was not written correctly"); + } + finally + { + await writer.CompleteAsync(); + } + }), + TestCase("succeeds with many strings", async () => + { + await using MemoryStream stream = new(); + var writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true)); + + try + { + await PipeWriterModule.WriteStrings(writer, ["z", "y", "x", "c", "b", "a"]); + Expect.equal(StreamText(stream), "[z,y,x,c,b,a]", + "A sequence of many strings was not written correctly"); + } + finally + { + await writer.CompleteAsync(); + } + }), + TestCase("succeeds when the writer is completed early", async () => + { + await using MemoryStream stream = new(); + var writer = PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true)); + + await PipeWriterModule.WriteStrings(writer, Items()); + Expect.equal(StreamText(stream), "[a,b,c", "The writing should have stopped when the writer completed"); + return; + + IEnumerable Items() + { + yield return "a"; + yield return "b"; + yield return "c"; + writer.Complete(); + yield return "d"; + yield return "e"; + yield return "f"; + } + }) + ]) + ]); + + /// /// Unit tests /// @@ -660,6 +769,7 @@ public static class CommonCSharpTests ParameterNameTests, AutoIdTests, QueryTests, + PipeWriterTests, TestSequenced(ConfigurationTests) ]); } diff --git a/src/Tests.CSharp/PostgresCSharpExtensionTests.cs b/src/Tests.CSharp/PostgresCSharpExtensionTests.cs index c0398ed..d665106 100644 --- a/src/Tests.CSharp/PostgresCSharpExtensionTests.cs +++ b/src/Tests.CSharp/PostgresCSharpExtensionTests.cs @@ -1,3 +1,4 @@ +using System.IO.Pipelines; using Expecto.CSharp; using Expecto; using BitBadger.Documents.Postgres; @@ -31,12 +32,8 @@ public class PostgresCSharpExtensionTests } /// Set up a stream writer for a test - private static StreamWriter WriteStream(Stream stream) - { - StreamWriter writer = new(stream); - writer.AutoFlush = true; - return writer; - } + private static PipeWriter WriteStream(Stream stream) => + PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true)); /// Get the text of the given stream private static string StreamText(Stream stream) @@ -54,10 +51,8 @@ public class PostgresCSharpExtensionTests } /// Verify the presence of a document by its ID - private static void VerifyDocById(string json, string docId) - { + private static void VerifyDocById(string json, string docId) => Expect.stringContains(json, $"{{\"Id\": \"{docId}\",", $"Document `{docId}` not present"); - } /// Verify the presence of a document by its ID private static void VerifySingleById(string json, string docId) @@ -84,16 +79,12 @@ public class PostgresCSharpExtensionTests } /// Verify an empty JSON array - private static void VerifyEmpty(string json) - { + private static void VerifyEmpty(string json) => Expect.equal(json, "[]", "There should be no documents returned"); - } /// Verify an empty JSON document - private static void VerifyNoDoc(string json) - { + private static void VerifyNoDoc(string json) => Expect.equal(json, "{}", "There should be no document returned"); - } /// Verify the JSON for an ordered query private static void VerifyExpectedOrder(string json, string idFirst, string idSecond, string? idThird = null, @@ -158,9 +149,8 @@ public class PostgresCSharpExtensionTests var docs = await conn.CustomJsonArray(Query.Find(PostgresDb.TableName), Parameters.None, Results.JsonFromData); - Expect.stringStarts(docs, "[", "The JSON array should have started with `[`"); + VerifyBeginEnd(docs); Expect.hasLength(docs.Split("{\"Id\":"), 6, "There should have been 5 documents returned"); - Expect.stringEnds(docs, "]", "The JSON array should have ended with `[`"); }), TestCase("succeeds when data is not found", async () => { @@ -171,7 +161,7 @@ public class PostgresCSharpExtensionTests var docs = await conn.CustomJsonArray( $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath", [Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))], Results.JsonFromData); - Expect.equal(docs, "[]", "There should have been no documents returned"); + VerifyEmpty(docs); }) ]), TestList("WriteJsonArray", @@ -183,14 +173,19 @@ public class PostgresCSharpExtensionTests await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteCustomJsonArray(Query.Find(PostgresDb.TableName), Parameters.None, writer, - Results.JsonFromData); - - var 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 `[`"); + var writer = WriteStream(stream); + try + { + await conn.WriteCustomJsonArray(Query.Find(PostgresDb.TableName), Parameters.None, writer, + Results.JsonFromData); + var docs = StreamText(stream); + VerifyBeginEnd(docs); + Expect.hasLength(docs.Split("{\"Id\":"), 6, "There should have been 5 documents returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when data is not found", async () => { @@ -199,12 +194,18 @@ public class PostgresCSharpExtensionTests await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteCustomJsonArray( - $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath", - [Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))], writer, Results.JsonFromData); - - Expect.equal(StreamText(stream), "[]", "There should have been no documents returned"); + var writer = WriteStream(stream); + try + { + await conn.WriteCustomJsonArray( + $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath", + [Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))], writer, Results.JsonFromData); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("CustomSingle", @@ -1331,18 +1332,32 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonAll(PostgresDb.TableName, writer); - VerifyAllData(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonAll(PostgresDb.TableName, writer); + VerifyAllData(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when there is no data", async () => { await using var db = PostgresDb.BuildDb(); await using var conn = MkConn(db); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonAll(PostgresDb.TableName, writer); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonAll(PostgresDb.TableName, writer); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonAllOrdered", @@ -1353,9 +1368,16 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonAllOrdered(PostgresDb.TableName, writer, [Field.Named("n:NumValue")]); - VerifyExpectedOrder(StreamText(stream), "one", "three", "two", "four", "five"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonAllOrdered(PostgresDb.TableName, writer, [Field.Named("n:NumValue")]); + VerifyExpectedOrder(StreamText(stream), "one", "three", "two", "four", "five"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when ordering numerically descending", async () => { @@ -1363,9 +1385,16 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonAllOrdered(PostgresDb.TableName, writer, [Field.Named("n:NumValue DESC")]); - VerifyExpectedOrder(StreamText(stream), "five", "four", "two", "three", "one"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonAllOrdered(PostgresDb.TableName, writer, [Field.Named("n:NumValue DESC")]); + VerifyExpectedOrder(StreamText(stream), "five", "four", "two", "three", "one"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when ordering alphabetically", async () => { @@ -1373,9 +1402,16 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonAllOrdered(PostgresDb.TableName, writer, [Field.Named("Id DESC")]); - VerifyExpectedOrder(StreamText(stream), "two", "three", "one", "four", "five"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonAllOrdered(PostgresDb.TableName, writer, [Field.Named("Id DESC")]); + VerifyExpectedOrder(StreamText(stream), "two", "three", "one", "four", "five"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonById", @@ -1387,11 +1423,18 @@ public class PostgresCSharpExtensionTests await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonById(PostgresDb.TableName, writer, "two"); - var json = StreamText(stream); - Expect.stringStarts(json, """{"Id": "two",""", "An incorrect document was returned"); - Expect.stringEnds(json, "}", "JSON should have ended with this document"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonById(PostgresDb.TableName, writer, "two"); + var json = StreamText(stream); + Expect.stringStarts(json, """{"Id": "two",""", "An incorrect document was returned"); + Expect.stringEnds(json, "}", "JSON should have ended with this document"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { @@ -1399,9 +1442,16 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonById(PostgresDb.TableName, writer, "three hundred eighty-seven"); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonById(PostgresDb.TableName, writer, "three hundred eighty-seven"); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonByFields", @@ -1412,10 +1462,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFields(PostgresDb.TableName, writer, FieldMatch.All, - [Field.In("Value", ["purple", "blue"]), Field.Exists("Sub")]); - VerifySingleById(StreamText(stream), "four"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFields(PostgresDb.TableName, writer, FieldMatch.All, + [Field.In("Value", ["purple", "blue"]), Field.Exists("Sub")]); + VerifySingleById(StreamText(stream), "four"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are found using IN with numeric field", async() => { @@ -1423,10 +1480,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFields(PostgresDb.TableName, writer, FieldMatch.All, - [Field.In("NumValue", [2, 4, 6, 8])]); - VerifySingleById(StreamText(stream), "three"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFields(PostgresDb.TableName, writer, FieldMatch.All, + [Field.In("NumValue", [2, 4, 6, 8])]); + VerifySingleById(StreamText(stream), "three"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are not found", async () => { @@ -1434,10 +1498,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFields(PostgresDb.TableName, writer, FieldMatch.All, - [Field.Equal("Value", "mauve"), Field.NotEqual("NumValue", 40)]); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFields(PostgresDb.TableName, writer, FieldMatch.All, + [Field.Equal("Value", "mauve"), Field.NotEqual("NumValue", 40)]); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds for InArray when matching documents exist", async () => { @@ -1447,13 +1518,20 @@ public class PostgresCSharpExtensionTests foreach (var doc in ArrayDocument.TestDocuments) await conn.Insert(PostgresDb.TableName, doc); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFields(PostgresDb.TableName, writer, FieldMatch.All, - [Field.InArray("Values", PostgresDb.TableName, ["c"])]); - var json = StreamText(stream); - VerifyBeginEnd(json); - VerifyDocById(json, "first"); - VerifyDocById(json, "second"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFields(PostgresDb.TableName, writer, FieldMatch.All, + [Field.InArray("Values", PostgresDb.TableName, ["c"])]); + var json = StreamText(stream); + VerifyBeginEnd(json); + VerifyDocById(json, "first"); + VerifyDocById(json, "second"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds for InArray when no matching documents exist", async () => { @@ -1463,10 +1541,17 @@ public class PostgresCSharpExtensionTests foreach (var doc in ArrayDocument.TestDocuments) await conn.Insert(PostgresDb.TableName, doc); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFields(PostgresDb.TableName, writer, FieldMatch.All, - [Field.InArray("Values", PostgresDb.TableName, ["j"])]); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFields(PostgresDb.TableName, writer, FieldMatch.All, + [Field.InArray("Values", PostgresDb.TableName, ["j"])]); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonByFieldsOrdered", @@ -1477,10 +1562,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.All, - [Field.Equal("Value", "purple")], [Field.Named("Id")]); - VerifyExpectedOrder(StreamText(stream), "five", "four"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.All, + [Field.Equal("Value", "purple")], [Field.Named("Id")]); + VerifyExpectedOrder(StreamText(stream), "five", "four"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { @@ -1488,10 +1580,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.All, - [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]); - VerifyExpectedOrder(StreamText(stream), "four", "five"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.All, + [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]); + VerifyExpectedOrder(StreamText(stream), "four", "five"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonByContains", @@ -1503,12 +1602,19 @@ public class PostgresCSharpExtensionTests await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByContains(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }); - var json = StreamText(stream); - VerifyBeginEnd(json); - VerifyDocById(json, "two"); - VerifyDocById(json, "four"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByContains(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }); + var json = StreamText(stream); + VerifyBeginEnd(json); + VerifyDocById(json, "two"); + VerifyDocById(json, "four"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are not found", async () => { @@ -1516,9 +1622,16 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByContains(PostgresDb.TableName, writer, new { Value = "mauve" }); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByContains(PostgresDb.TableName, writer, new { Value = "mauve" }); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonByContainsOrdered", @@ -1530,10 +1643,18 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByContainsOrdered(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }, - [Field.Named("Sub.Bar")]); - VerifyExpectedOrder(StreamText(stream), "two", "four"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByContainsOrdered(PostgresDb.TableName, writer, + new { Sub = new { Foo = "green" } }, + [Field.Named("Sub.Bar")]); + VerifyExpectedOrder(StreamText(stream), "two", "four"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { @@ -1541,10 +1662,18 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByContainsOrdered(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }, - [Field.Named("Sub.Bar DESC")]); - VerifyExpectedOrder(StreamText(stream), "four", "two"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByContainsOrdered(PostgresDb.TableName, writer, + new { Sub = new { Foo = "green" } }, + [Field.Named("Sub.Bar DESC")]); + VerifyExpectedOrder(StreamText(stream), "four", "two"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonByJsonPath", @@ -1556,13 +1685,20 @@ public class PostgresCSharpExtensionTests await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByJsonPath(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)"); - var json = StreamText(stream); - VerifyBeginEnd(json); - VerifyDocById(json, "one"); - VerifyDocById(json, "two"); - VerifyDocById(json, "three"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByJsonPath(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)"); + var json = StreamText(stream); + VerifyBeginEnd(json); + VerifyDocById(json, "one"); + VerifyDocById(json, "two"); + VerifyDocById(json, "three"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are not found", async () => { @@ -1570,9 +1706,16 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByJsonPath(PostgresDb.TableName, writer, "$.NumValue ? (@ < 0)"); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByJsonPath(PostgresDb.TableName, writer, "$.NumValue ? (@ < 0)"); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonByJsonPathOrdered", @@ -1584,10 +1727,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByJsonPathOrdered(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)", - [Field.Named("n:NumValue")]); - VerifyExpectedOrder(StreamText(stream), "one", "three", "two"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByJsonPathOrdered(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)", + [Field.Named("n:NumValue")]); + VerifyExpectedOrder(StreamText(stream), "one", "three", "two"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { @@ -1595,10 +1745,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByJsonPathOrdered(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)", - [Field.Named("n:NumValue DESC")]); - VerifyExpectedOrder(StreamText(stream), "two", "three", "one"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByJsonPathOrdered(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)", + [Field.Named("n:NumValue DESC")]); + VerifyExpectedOrder(StreamText(stream), "two", "three", "one"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonFirstByFields", @@ -1609,10 +1766,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "another")]); - VerifyDocById(StreamText(stream), "two"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "another")]); + VerifyDocById(StreamText(stream), "two"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when multiple documents are found", async () => { @@ -1620,10 +1784,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "purple")]); - VerifyAnyById(StreamText(stream), ["five", "four"]); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "purple")]); + VerifyAnyById(StreamText(stream), ["five", "four"]); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { @@ -1631,10 +1802,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "absent")]); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "absent")]); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonFirstByFieldsOrdered", @@ -1645,10 +1823,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "purple")], [Field.Named("Id")]); - VerifyDocById(StreamText(stream), "five"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "purple")], [Field.Named("Id")]); + VerifyDocById(StreamText(stream), "five"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { @@ -1656,10 +1841,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]); - VerifyDocById(StreamText(stream), "four"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]); + VerifyDocById(StreamText(stream), "four"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonFirstByContains", @@ -1670,9 +1862,16 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByContains(PostgresDb.TableName, writer, new { Value = "another" }); - VerifyDocById(StreamText(stream), "two"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByContains(PostgresDb.TableName, writer, new { Value = "another" }); + VerifyDocById(StreamText(stream), "two"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when multiple documents are found", async () => { @@ -1680,9 +1879,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByContains(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }); - VerifyAnyById(StreamText(stream), ["two", "four"]); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByContains(PostgresDb.TableName, writer, + new { Sub = new { Foo = "green" } }); + VerifyAnyById(StreamText(stream), ["two", "four"]); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { @@ -1690,9 +1897,16 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByContains(PostgresDb.TableName, writer, new { Value = "absent" }); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByContains(PostgresDb.TableName, writer, new { Value = "absent" }); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonFirstByContainsOrdered", @@ -1703,10 +1917,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByContainsOrdered(PostgresDb.TableName, writer, - new { Sub = new { Foo = "green" } }, [Field.Named("Value")]); - VerifyDocById(StreamText(stream), "two"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByContainsOrdered(PostgresDb.TableName, writer, + new { Sub = new { Foo = "green" } }, [Field.Named("Value")]); + VerifyDocById(StreamText(stream), "two"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { @@ -1714,10 +1935,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByContainsOrdered(PostgresDb.TableName, writer, - new { Sub = new { Foo = "green" } }, [Field.Named("Value DESC")]); - VerifyDocById(StreamText(stream), "four"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByContainsOrdered(PostgresDb.TableName, writer, + new { Sub = new { Foo = "green" } }, [Field.Named("Value DESC")]); + VerifyDocById(StreamText(stream), "four"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonFirstByJsonPath", @@ -1728,9 +1956,16 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByJsonPath(PostgresDb.TableName, writer, """$.Value ? (@ == "FIRST!")"""); - VerifyDocById(StreamText(stream), "one"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByJsonPath(PostgresDb.TableName, writer, """$.Value ? (@ == "FIRST!")"""); + VerifyDocById(StreamText(stream), "one"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when multiple documents are found", async () => { @@ -1738,9 +1973,16 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByJsonPath(PostgresDb.TableName, writer, """$.Sub.Foo ? (@ == "green")"""); - VerifyAnyById(StreamText(stream), ["two", "four"]); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByJsonPath(PostgresDb.TableName, writer, """$.Sub.Foo ? (@ == "green")"""); + VerifyAnyById(StreamText(stream), ["two", "four"]); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { @@ -1748,9 +1990,16 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByJsonPath(PostgresDb.TableName, writer, """$.Id ? (@ == "nope")"""); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByJsonPath(PostgresDb.TableName, writer, """$.Id ? (@ == "nope")"""); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonFirstByJsonPathOrdered", @@ -1761,10 +2010,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByJsonPathOrdered(PostgresDb.TableName, writer, - """$.Sub.Foo ? (@ == "green")""", [Field.Named("Sub.Bar")]); - VerifyDocById(StreamText(stream), "two"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByJsonPathOrdered(PostgresDb.TableName, writer, + """$.Sub.Foo ? (@ == "green")""", [Field.Named("Sub.Bar")]); + VerifyDocById(StreamText(stream), "two"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { @@ -1772,10 +2028,17 @@ public class PostgresCSharpExtensionTests await using var conn = MkConn(db); await LoadDocs(conn); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByJsonPathOrdered(PostgresDb.TableName, writer, - """$.Sub.Foo ? (@ == "green")""", [Field.Named("Sub.Bar DESC")]); - VerifyDocById(StreamText(stream), "four"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByJsonPathOrdered(PostgresDb.TableName, writer, + """$.Sub.Foo ? (@ == "green")""", [Field.Named("Sub.Bar DESC")]); + VerifyDocById(StreamText(stream), "four"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("UpdateById", diff --git a/src/Tests.CSharp/PostgresCSharpTests.cs b/src/Tests.CSharp/PostgresCSharpTests.cs index b0b3393..da3a991 100644 --- a/src/Tests.CSharp/PostgresCSharpTests.cs +++ b/src/Tests.CSharp/PostgresCSharpTests.cs @@ -1,3 +1,4 @@ +using System.IO.Pipelines; using Expecto.CSharp; using Expecto; using BitBadger.Documents.Postgres; @@ -329,12 +330,8 @@ public static class PostgresCSharpTests } /// Set up a stream writer for a test - private static StreamWriter WriteStream(Stream stream) - { - StreamWriter writer = new(stream); - writer.AutoFlush = true; - return writer; - } + private static PipeWriter WriteStream(Stream stream) => + PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true)); /// Get the text of the given stream private static string StreamText(Stream stream) @@ -352,10 +349,8 @@ public static class PostgresCSharpTests } /// Verify the presence of a document by its ID - private static void VerifyDocById(string json, string docId) - { + private static void VerifyDocById(string json, string docId) => Expect.stringContains(json, $"{{\"Id\": \"{docId}\",", $"Document `{docId}` not present"); - } /// Verify the presence of a document by its ID private static void VerifySingleById(string json, string docId) @@ -382,16 +377,12 @@ public static class PostgresCSharpTests } /// Verify an empty JSON array - private static void VerifyEmpty(string json) - { + private static void VerifyEmpty(string json) => Expect.equal(json, "[]", "There should be no documents returned"); - } /// Verify an empty JSON document - private static void VerifyNoDoc(string json) - { + private static void VerifyNoDoc(string json) => Expect.equal(json, "{}", "There should be no document returned"); - } /// /// Integration tests for the Configuration module of the PostgreSQL library @@ -486,14 +477,20 @@ public static class PostgresCSharpTests await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Custom.WriteJsonArray(Query.Find(PostgresDb.TableName), Parameters.None, writer, - Results.JsonFromData); - - var 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 `[`"); + var writer = WriteStream(stream); + try + { + await Custom.WriteJsonArray(Query.Find(PostgresDb.TableName), Parameters.None, writer, + Results.JsonFromData); + var 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 `[`"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when data is not found", async () => { @@ -501,11 +498,18 @@ public static class PostgresCSharpTests await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Custom.WriteJsonArray($"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath", - [Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))], writer, Results.JsonFromData); - - Expect.equal(StreamText(stream), "[]", "There should have been no documents returned"); + var writer = WriteStream(stream); + try + { + await Custom.WriteJsonArray( + $"SELECT data FROM {PostgresDb.TableName} WHERE data @? @path::jsonpath", + [Tuple.Create("@path", Sql.@string("$.NumValue ? (@ > 100)"))], writer, Results.JsonFromData); + Expect.equal(StreamText(stream), "[]", "There should have been no documents returned"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("Single", @@ -1714,17 +1718,31 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteAll(PostgresDb.TableName, writer); - VerifyAllData(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteAll(PostgresDb.TableName, writer); + VerifyAllData(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when there is no data", async () => { await using var db = PostgresDb.BuildDb(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteAll(PostgresDb.TableName, writer); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteAll(PostgresDb.TableName, writer); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteAllOrdered", @@ -1734,27 +1752,48 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteAllOrdered(PostgresDb.TableName, writer, [Field.Named("n:NumValue")]); - VerifyExpectedOrder(StreamText(stream), "one", "three", "two", "four", "five"); + var writer = WriteStream(stream); + try + { + await Json.WriteAllOrdered(PostgresDb.TableName, writer, [Field.Named("n:NumValue")]); + VerifyExpectedOrder(StreamText(stream), "one", "three", "two", "four", "five"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when ordering numerically descending", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteAllOrdered(PostgresDb.TableName, writer, [Field.Named("n:NumValue DESC")]); - VerifyExpectedOrder(StreamText(stream), "five", "four", "two", "three", "one"); + var writer = WriteStream(stream); + try + { + await Json.WriteAllOrdered(PostgresDb.TableName, writer, [Field.Named("n:NumValue DESC")]); + VerifyExpectedOrder(StreamText(stream), "five", "four", "two", "three", "one"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when ordering alphabetically", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteAllOrdered(PostgresDb.TableName, writer, [Field.Named("Id DESC")]); - VerifyExpectedOrder(StreamText(stream), "two", "three", "one", "four", "five"); + var writer = WriteStream(stream); + try + { + await Json.WriteAllOrdered(PostgresDb.TableName, writer, [Field.Named("Id DESC")]); + VerifyExpectedOrder(StreamText(stream), "two", "three", "one", "four", "five"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteById", @@ -1765,20 +1804,34 @@ public static class PostgresCSharpTests await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteById(PostgresDb.TableName, writer, "two"); - var json = StreamText(stream); - Expect.stringStarts(json, """{"Id": "two",""", "An incorrect document was returned"); - Expect.stringEnds(json, "}", "JSON should have ended with this document"); + var writer = WriteStream(stream); + try + { + await Json.WriteById(PostgresDb.TableName, writer, "two"); + var json = StreamText(stream); + Expect.stringStarts(json, """{"Id": "two",""", "An incorrect document was returned"); + Expect.stringEnds(json, "}", "JSON should have ended with this document"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteById(PostgresDb.TableName, writer, "three hundred eighty-seven"); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteById(PostgresDb.TableName, writer, "three hundred eighty-seven"); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteByFields", @@ -1788,30 +1841,51 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFields(PostgresDb.TableName, writer, FieldMatch.All, - [Field.In("Value", ["purple", "blue"]), Field.Exists("Sub")]); - VerifySingleById(StreamText(stream), "four"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFields(PostgresDb.TableName, writer, FieldMatch.All, + [Field.In("Value", ["purple", "blue"]), Field.Exists("Sub")]); + VerifySingleById(StreamText(stream), "four"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are found using IN with numeric field", async() => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFields(PostgresDb.TableName, writer, FieldMatch.All, - [Field.In("NumValue", [2, 4, 6, 8])]); - VerifySingleById(StreamText(stream), "three"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFields(PostgresDb.TableName, writer, FieldMatch.All, + [Field.In("NumValue", [2, 4, 6, 8])]); + VerifySingleById(StreamText(stream), "three"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are not found", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFields(PostgresDb.TableName, writer, FieldMatch.All, - [Field.Equal("Value", "mauve"), Field.NotEqual("NumValue", 40)]); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteByFields(PostgresDb.TableName, writer, FieldMatch.All, + [Field.Equal("Value", "mauve"), Field.NotEqual("NumValue", 40)]); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds for InArray when matching documents exist", async () => { @@ -1820,13 +1894,20 @@ public static class PostgresCSharpTests foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(PostgresDb.TableName, doc); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFields(PostgresDb.TableName, writer, FieldMatch.All, - [Field.InArray("Values", PostgresDb.TableName, ["c"])]); - var json = StreamText(stream); - VerifyBeginEnd(json); - VerifyDocById(json, "first"); - VerifyDocById(json, "second"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFields(PostgresDb.TableName, writer, FieldMatch.All, + [Field.InArray("Values", PostgresDb.TableName, ["c"])]); + var json = StreamText(stream); + VerifyBeginEnd(json); + VerifyDocById(json, "first"); + VerifyDocById(json, "second"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds for InArray when no matching documents exist", async () => { @@ -1834,10 +1915,17 @@ public static class PostgresCSharpTests await Definition.EnsureTable(PostgresDb.TableName); foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(PostgresDb.TableName, doc); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFields(PostgresDb.TableName, writer, FieldMatch.All, - [Field.InArray("Values", PostgresDb.TableName, ["j"])]); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteByFields(PostgresDb.TableName, writer, FieldMatch.All, + [Field.InArray("Values", PostgresDb.TableName, ["j"])]); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteByFieldsOrdered", @@ -1847,20 +1935,34 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.All, - [Field.Equal("Value", "purple")], [Field.Named("Id")]); - VerifyExpectedOrder(StreamText(stream), "five", "four"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.All, + [Field.Equal("Value", "purple")], [Field.Named("Id")]); + VerifyExpectedOrder(StreamText(stream), "five", "four"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.All, - [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]); - VerifyExpectedOrder(StreamText(stream), "four", "five"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.All, + [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]); + VerifyExpectedOrder(StreamText(stream), "four", "five"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteByContains", @@ -1871,21 +1973,35 @@ public static class PostgresCSharpTests await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByContains(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }); - var json = StreamText(stream); - VerifyBeginEnd(json); - VerifyDocById(json, "two"); - VerifyDocById(json, "four"); + var writer = WriteStream(stream); + try + { + await Json.WriteByContains(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }); + var json = StreamText(stream); + VerifyBeginEnd(json); + VerifyDocById(json, "two"); + VerifyDocById(json, "four"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are not found", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByContains(PostgresDb.TableName, writer, new { Value = "mauve" }); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteByContains(PostgresDb.TableName, writer, new { Value = "mauve" }); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteByContainsOrdered", @@ -1896,20 +2012,34 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByContainsOrdered(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }, - [Field.Named("Sub.Bar")]); - VerifyExpectedOrder(StreamText(stream), "two", "four"); + var writer = WriteStream(stream); + try + { + await Json.WriteByContainsOrdered(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }, + [Field.Named("Sub.Bar")]); + VerifyExpectedOrder(StreamText(stream), "two", "four"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByContainsOrdered(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }, - [Field.Named("Sub.Bar DESC")]); - VerifyExpectedOrder(StreamText(stream), "four", "two"); + var writer = WriteStream(stream); + try + { + await Json.WriteByContainsOrdered(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }, + [Field.Named("Sub.Bar DESC")]); + VerifyExpectedOrder(StreamText(stream), "four", "two"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteByJsonPath", @@ -1920,22 +2050,36 @@ public static class PostgresCSharpTests await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByJsonPath(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)"); - var json = StreamText(stream); - VerifyBeginEnd(json); - VerifyDocById(json, "one"); - VerifyDocById(json, "two"); - VerifyDocById(json, "three"); + var writer = WriteStream(stream); + try + { + await Json.WriteByJsonPath(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)"); + var json = StreamText(stream); + VerifyBeginEnd(json); + VerifyDocById(json, "one"); + VerifyDocById(json, "two"); + VerifyDocById(json, "three"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are not found", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByJsonPath(PostgresDb.TableName, writer, "$.NumValue ? (@ < 0)"); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteByJsonPath(PostgresDb.TableName, writer, "$.NumValue ? (@ < 0)"); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteByJsonPathOrdered", @@ -1946,20 +2090,34 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByJsonPathOrdered(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)", - [Field.Named("n:NumValue")]); - VerifyExpectedOrder(StreamText(stream), "one", "three", "two"); + var writer = WriteStream(stream); + try + { + await Json.WriteByJsonPathOrdered(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)", + [Field.Named("n:NumValue")]); + VerifyExpectedOrder(StreamText(stream), "one", "three", "two"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByJsonPathOrdered(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)", - [Field.Named("n:NumValue DESC")]); - VerifyExpectedOrder(StreamText(stream), "two", "three", "one"); + var writer = WriteStream(stream); + try + { + await Json.WriteByJsonPathOrdered(PostgresDb.TableName, writer, "$.NumValue ? (@ < 15)", + [Field.Named("n:NumValue DESC")]); + VerifyExpectedOrder(StreamText(stream), "two", "three", "one"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteFirstByFields", @@ -1969,30 +2127,51 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "another")]); - VerifyDocById(StreamText(stream), "two"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "another")]); + VerifyDocById(StreamText(stream), "two"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when multiple documents are found", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "purple")]); - VerifyAnyById(StreamText(stream), ["five", "four"]); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "purple")]); + VerifyAnyById(StreamText(stream), ["five", "four"]); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "absent")]); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByFields(PostgresDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "absent")]); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteFirstByFieldsOrdered", @@ -2002,20 +2181,34 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "purple")], [Field.Named("Id")]); - VerifyDocById(StreamText(stream), "five"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "purple")], [Field.Named("Id")]); + VerifyDocById(StreamText(stream), "five"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]); - VerifyDocById(StreamText(stream), "four"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByFieldsOrdered(PostgresDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "purple")], [Field.Named("Id DESC")]); + VerifyDocById(StreamText(stream), "four"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteFirstByContains", @@ -2025,27 +2218,48 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByContains(PostgresDb.TableName, writer, new { Value = "another" }); - VerifyDocById(StreamText(stream), "two"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByContains(PostgresDb.TableName, writer, new { Value = "another" }); + VerifyDocById(StreamText(stream), "two"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when multiple documents are found", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByContains(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }); - VerifyAnyById(StreamText(stream), ["two", "four"]); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByContains(PostgresDb.TableName, writer, new { Sub = new { Foo = "green" } }); + VerifyAnyById(StreamText(stream), ["two", "four"]); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByContains(PostgresDb.TableName, writer, new { Value = "absent" }); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByContains(PostgresDb.TableName, writer, new { Value = "absent" }); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteFirstByContainsOrdered", @@ -2055,20 +2269,34 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByContainsOrdered(PostgresDb.TableName, writer, - new { Sub = new { Foo = "green" } }, [Field.Named("Value")]); - VerifyDocById(StreamText(stream), "two"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByContainsOrdered(PostgresDb.TableName, writer, + new { Sub = new { Foo = "green" } }, [Field.Named("Value")]); + VerifyDocById(StreamText(stream), "two"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByContainsOrdered(PostgresDb.TableName, writer, - new { Sub = new { Foo = "green" } }, [Field.Named("Value DESC")]); - VerifyDocById(StreamText(stream), "four"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByContainsOrdered(PostgresDb.TableName, writer, + new { Sub = new { Foo = "green" } }, [Field.Named("Value DESC")]); + VerifyDocById(StreamText(stream), "four"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteFirstByJsonPath", @@ -2078,27 +2306,48 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByJsonPath(PostgresDb.TableName, writer, """$.Value ? (@ == "FIRST!")"""); - VerifyDocById(StreamText(stream), "one"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByJsonPath(PostgresDb.TableName, writer, """$.Value ? (@ == "FIRST!")"""); + VerifyDocById(StreamText(stream), "one"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when multiple documents are found", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByJsonPath(PostgresDb.TableName, writer, """$.Sub.Foo ? (@ == "green")"""); - VerifyAnyById(StreamText(stream), ["two", "four"]); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByJsonPath(PostgresDb.TableName, writer, """$.Sub.Foo ? (@ == "green")"""); + VerifyAnyById(StreamText(stream), ["two", "four"]); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByJsonPath(PostgresDb.TableName, writer, """$.Id ? (@ == "nope")"""); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByJsonPath(PostgresDb.TableName, writer, """$.Id ? (@ == "nope")"""); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteFirstByJsonPathOrdered", @@ -2108,20 +2357,36 @@ public static class PostgresCSharpTests await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByJsonPathOrdered(PostgresDb.TableName, writer, """$.Sub.Foo ? (@ == "green")""", - [Field.Named("Sub.Bar")]); - VerifyDocById(StreamText(stream), "two"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByJsonPathOrdered(PostgresDb.TableName, writer, + """$.Sub.Foo ? (@ == "green")""", + [Field.Named("Sub.Bar")]); + VerifyDocById(StreamText(stream), "two"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { await using var db = PostgresDb.BuildDb(); await LoadDocs(); await using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByJsonPathOrdered(PostgresDb.TableName, writer, """$.Sub.Foo ? (@ == "green")""", - [Field.Named("Sub.Bar DESC")]); - VerifyDocById(StreamText(stream), "four"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByJsonPathOrdered(PostgresDb.TableName, writer, + """$.Sub.Foo ? (@ == "green")""", + [Field.Named("Sub.Bar DESC")]); + VerifyDocById(StreamText(stream), "four"); + } + finally + { + await writer.CompleteAsync(); + } }) ]) ]); diff --git a/src/Tests.CSharp/SqliteCSharpExtensionTests.cs b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs index 6842b2b..e47aedc 100644 --- a/src/Tests.CSharp/SqliteCSharpExtensionTests.cs +++ b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs @@ -1,3 +1,4 @@ +using System.IO.Pipelines; using Expecto.CSharp; using Expecto; using BitBadger.Documents.Sqlite; @@ -25,24 +26,16 @@ public static class SqliteCSharpExtensionTests } /// Verify an empty JSON array - private static void VerifyEmpty(string json) - { + private static void VerifyEmpty(string json) => Expect.equal(json, "[]", "There should be no documents returned"); - } /// Verify an empty JSON document - private static void VerifyNoDoc(string json) - { + private static void VerifyNoDoc(string json) => Expect.equal(json, "{}", "There should be no document returned"); - } /// Set up a stream writer for a test - private static StreamWriter WriteStream(Stream stream) - { - StreamWriter writer = new(stream); - writer.AutoFlush = true; - return writer; - } + private static PipeWriter WriteStream(Stream stream) => + PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true)); /// Get the text of the given stream private static string StreamText(Stream stream) @@ -127,16 +120,22 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteCustomJsonArray(Query.Find(SqliteDb.TableName), [], writer, Results.JsonFromData); - - var json = StreamText(stream); - VerifyBeginEnd(json); - Expect.stringContains(json, JsonDocument.One, "Document ID `one` should have been found"); - Expect.stringContains(json, JsonDocument.Two,"Document ID `two` should have been found"); - Expect.stringContains(json, JsonDocument.Three, "Document ID `three` should have been found"); - Expect.stringContains(json, JsonDocument.Four, "Document ID `four` should have been found"); - Expect.stringContains(json, JsonDocument.Five, "Document ID `five` should have been found"); + var writer = WriteStream(stream); + try + { + await conn.WriteCustomJsonArray(Query.Find(SqliteDb.TableName), [], writer, Results.JsonFromData); + var json = StreamText(stream); + VerifyBeginEnd(json); + Expect.stringContains(json, JsonDocument.One, "Document ID `one` should have been found"); + Expect.stringContains(json, JsonDocument.Two, "Document ID `two` should have been found"); + Expect.stringContains(json, JsonDocument.Three, "Document ID `three` should have been found"); + Expect.stringContains(json, JsonDocument.Four, "Document ID `four` should have been found"); + Expect.stringContains(json, JsonDocument.Five, "Document ID `five` should have been found"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when data is not found", async () => { @@ -145,12 +144,18 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteCustomJsonArray( - $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value", - [new SqliteParameter("@value", 100)], writer, Results.JsonFromData); - - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteCustomJsonArray( + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value", + [new SqliteParameter("@value", 100)], writer, Results.JsonFromData); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("CustomSingle", @@ -828,13 +833,21 @@ public static class SqliteCSharpExtensionTests await conn.Insert(SqliteDb.TableName, new SubDocument { Foo = "five", Bar = "six" }); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonAll(SqliteDb.TableName, writer); - var json = StreamText(stream); - VerifyBeginEnd(json); - Expect.stringContains(json, """{"Foo":"one","Bar":"two"}""", "The first document was not found"); - Expect.stringContains(json, """{"Foo":"three","Bar":"four"}""", "The second document was not found"); - Expect.stringContains(json, """{"Foo":"five","Bar":"six"}""", "The third document was not found"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonAll(SqliteDb.TableName, writer); + var json = StreamText(stream); + VerifyBeginEnd(json); + Expect.stringContains(json, """{"Foo":"one","Bar":"two"}""", "The first document was not found"); + Expect.stringContains(json, """{"Foo":"three","Bar":"four"}""", + "The second document was not found"); + Expect.stringContains(json, """{"Foo":"five","Bar":"six"}""", "The third document was not found"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when there is no data", async () => { @@ -842,9 +855,16 @@ public static class SqliteCSharpExtensionTests await using var conn = Sqlite.Configuration.DbConn(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonAll(SqliteDb.TableName, writer); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonAll(SqliteDb.TableName, writer); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonAllOrdered", @@ -856,11 +876,18 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonAllOrdered(SqliteDb.TableName, writer, [Field.Named("n:NumValue")]); - Expect.equal(StreamText(stream), - $"[{JsonDocument.One},{JsonDocument.Three},{JsonDocument.Two},{JsonDocument.Four},{JsonDocument.Five}]", - "The documents were not ordered correctly"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonAllOrdered(SqliteDb.TableName, writer, [Field.Named("n:NumValue")]); + Expect.equal(StreamText(stream), + $"[{JsonDocument.One},{JsonDocument.Three},{JsonDocument.Two},{JsonDocument.Four},{JsonDocument.Five}]", + "The documents were not ordered correctly"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when ordering numerically descending", async () => { @@ -869,11 +896,18 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonAllOrdered(SqliteDb.TableName, writer, [Field.Named("n:NumValue DESC")]); - Expect.equal(StreamText(stream), - $"[{JsonDocument.Five},{JsonDocument.Four},{JsonDocument.Two},{JsonDocument.Three},{JsonDocument.One}]", - "The documents were not ordered correctly"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonAllOrdered(SqliteDb.TableName, writer, [Field.Named("n:NumValue DESC")]); + Expect.equal(StreamText(stream), + $"[{JsonDocument.Five},{JsonDocument.Four},{JsonDocument.Two},{JsonDocument.Three},{JsonDocument.One}]", + "The documents were not ordered correctly"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when ordering alphabetically", async () => { @@ -882,11 +916,18 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonAllOrdered(SqliteDb.TableName, writer, [Field.Named("Id DESC")]); - Expect.equal(StreamText(stream), - $"[{JsonDocument.Two},{JsonDocument.Three},{JsonDocument.One},{JsonDocument.Four},{JsonDocument.Five}]", - "The documents were not ordered correctly"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonAllOrdered(SqliteDb.TableName, writer, [Field.Named("Id DESC")]); + Expect.equal(StreamText(stream), + $"[{JsonDocument.Two},{JsonDocument.Three},{JsonDocument.One},{JsonDocument.Four},{JsonDocument.Five}]", + "The documents were not ordered correctly"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonById", @@ -898,9 +939,16 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonById(SqliteDb.TableName, writer, "two"); - Expect.equal(StreamText(stream), JsonDocument.Two, "The incorrect document was returned"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonById(SqliteDb.TableName, writer, "two"); + Expect.equal(StreamText(stream), JsonDocument.Two, "The incorrect document was returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { @@ -909,9 +957,16 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonById(SqliteDb.TableName, writer, "three hundred eighty-seven"); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonById(SqliteDb.TableName, writer, "three hundred eighty-seven"); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonByFields", @@ -923,13 +978,20 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFields(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Greater("NumValue", 15)]); - var json = StreamText(stream); - VerifyBeginEnd(json); - Expect.stringContains(json, JsonDocument.Four, "Document `four` should have been returned"); - Expect.stringContains(json, JsonDocument.Five, "Document `five` should have been returned"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFields(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Greater("NumValue", 15)]); + var json = StreamText(stream); + VerifyBeginEnd(json); + Expect.stringContains(json, JsonDocument.Four, "Document `four` should have been returned"); + Expect.stringContains(json, JsonDocument.Five, "Document `five` should have been returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are found using IN with numeric field", async () => { @@ -938,11 +1000,18 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFields(SqliteDb.TableName, writer, FieldMatch.All, - [Field.In("NumValue", [2, 4, 6, 8])]); - Expect.equal(StreamText(stream), $"[{JsonDocument.Three}]", - "There should have been one document returned"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFields(SqliteDb.TableName, writer, FieldMatch.All, + [Field.In("NumValue", [2, 4, 6, 8])]); + Expect.equal(StreamText(stream), $"[{JsonDocument.Three}]", + "There should have been one document returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are not found", async () => { @@ -951,10 +1020,17 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFields(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Greater("NumValue", 100)]); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFields(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Greater("NumValue", 100)]); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds for InArray when matching documents exist", async () => { @@ -964,15 +1040,22 @@ public static class SqliteCSharpExtensionTests foreach (var doc in ArrayDocument.TestDocuments) await conn.Insert(SqliteDb.TableName, doc); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFields(SqliteDb.TableName, writer, FieldMatch.All, - [Field.InArray("Values", SqliteDb.TableName, ["c"])]); - var json = StreamText(stream); - VerifyBeginEnd(json); - Expect.stringContains(json, """{"Id":"first","Values":["a","b","c"]}""", - "Document `first` should have been returned"); - Expect.stringContains(json, """{"Id":"second","Values":["c","d","e"]}""", - "Document `second` should have been returned"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFields(SqliteDb.TableName, writer, FieldMatch.All, + [Field.InArray("Values", SqliteDb.TableName, ["c"])]); + var json = StreamText(stream); + VerifyBeginEnd(json); + Expect.stringContains(json, """{"Id":"first","Values":["a","b","c"]}""", + "Document `first` should have been returned"); + Expect.stringContains(json, """{"Id":"second","Values":["c","d","e"]}""", + "Document `second` should have been returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds for InArray when no matching documents exist", async () => { @@ -982,10 +1065,17 @@ public static class SqliteCSharpExtensionTests foreach (var doc in ArrayDocument.TestDocuments) await conn.Insert(SqliteDb.TableName, doc); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFields(SqliteDb.TableName, writer, FieldMatch.All, - [Field.InArray("Values", SqliteDb.TableName, ["j"])]); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFields(SqliteDb.TableName, writer, FieldMatch.All, + [Field.InArray("Values", SqliteDb.TableName, ["j"])]); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonByFieldsOrdered", @@ -997,11 +1087,18 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Greater("NumValue", 15)], [Field.Named("Id")]); - Expect.equal(StreamText(stream), $"[{JsonDocument.Five},{JsonDocument.Four}]", - "Incorrect documents were returned"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Greater("NumValue", 15)], [Field.Named("Id")]); + Expect.equal(StreamText(stream), $"[{JsonDocument.Five},{JsonDocument.Four}]", + "Incorrect documents were returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { @@ -1010,11 +1107,18 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Greater("NumValue", 15)], [Field.Named("Id DESC")]); - Expect.equal(StreamText(stream), $"[{JsonDocument.Four},{JsonDocument.Five}]", - "Incorrect documents were returned"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Greater("NumValue", 15)], [Field.Named("Id DESC")]); + Expect.equal(StreamText(stream), $"[{JsonDocument.Four},{JsonDocument.Five}]", + "Incorrect documents were returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting case-sensitively", async () => { @@ -1023,11 +1127,18 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.All, - [Field.LessOrEqual("NumValue", 10)], [Field.Named("Value")]); - Expect.equal(StreamText(stream), $"[{JsonDocument.Three},{JsonDocument.One},{JsonDocument.Two}]", - "Documents not ordered correctly"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.All, + [Field.LessOrEqual("NumValue", 10)], [Field.Named("Value")]); + Expect.equal(StreamText(stream), $"[{JsonDocument.Three},{JsonDocument.One},{JsonDocument.Two}]", + "Documents not ordered correctly"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting case-insensitively", async () => { @@ -1036,11 +1147,18 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.All, - [Field.LessOrEqual("NumValue", 10)], [Field.Named("i:Value")]); - Expect.equal(StreamText(stream), $"[{JsonDocument.Three},{JsonDocument.Two},{JsonDocument.One}]", - "Documents not ordered correctly"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.All, + [Field.LessOrEqual("NumValue", 10)], [Field.Named("i:Value")]); + Expect.equal(StreamText(stream), $"[{JsonDocument.Three},{JsonDocument.Two},{JsonDocument.One}]", + "Documents not ordered correctly"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonFirstByFields", @@ -1052,10 +1170,17 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "another")]); - Expect.equal(StreamText(stream), JsonDocument.Two, "The incorrect document was returned"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "another")]); + Expect.equal(StreamText(stream), JsonDocument.Two, "The incorrect document was returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when multiple documents are found", async () => { @@ -1064,12 +1189,19 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Sub.Foo", "green")]); - var json = StreamText(stream); - Expect.notEqual(json, "{}", "There should have been a document returned"); - VerifyAny(json, [JsonDocument.Two, JsonDocument.Four]); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Sub.Foo", "green")]); + var json = StreamText(stream); + Expect.notEqual(json, "{}", "There should have been a document returned"); + VerifyAny(json, [JsonDocument.Two, JsonDocument.Four]); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { @@ -1078,10 +1210,17 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "absent")]); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "absent")]); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteJsonFirstByFieldsOrdered", @@ -1093,10 +1232,17 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar")]); - Expect.equal(StreamText(stream), JsonDocument.Two, "An incorrect document was returned"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar")]); + Expect.equal(StreamText(stream), JsonDocument.Two, "An incorrect document was returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { @@ -1105,10 +1251,17 @@ public static class SqliteCSharpExtensionTests await LoadDocs(conn); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await conn.WriteJsonFirstByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar DESC")]); - Expect.equal(StreamText(stream), JsonDocument.Four, "An incorrect document was returned"); + var writer = WriteStream(stream); + try + { + await conn.WriteJsonFirstByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar DESC")]); + Expect.equal(StreamText(stream), JsonDocument.Four, "An incorrect document was returned"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("UpdateById", diff --git a/src/Tests.CSharp/SqliteCSharpTests.cs b/src/Tests.CSharp/SqliteCSharpTests.cs index 5c89aab..c1e10d8 100644 --- a/src/Tests.CSharp/SqliteCSharpTests.cs +++ b/src/Tests.CSharp/SqliteCSharpTests.cs @@ -1,4 +1,5 @@ -using Expecto.CSharp; +using System.IO.Pipelines; +using Expecto.CSharp; using Expecto; using Microsoft.FSharp.Core; using BitBadger.Documents.Sqlite; @@ -178,24 +179,16 @@ public static class SqliteCSharpTests } /// Verify an empty JSON array - private static void VerifyEmpty(string json) - { + private static void VerifyEmpty(string json) => Expect.equal(json, "[]", "There should be no documents returned"); - } /// Verify an empty JSON document - private static void VerifyNoDoc(string json) - { + private static void VerifyNoDoc(string json) => Expect.equal(json, "{}", "There should be no document returned"); - } /// Set up a stream writer for a test - private static StreamWriter WriteStream(Stream stream) - { - StreamWriter writer = new(stream); - writer.AutoFlush = true; - return writer; - } + private static PipeWriter WriteStream(Stream stream) => + PipeWriter.Create(stream, new StreamPipeWriterOptions(leaveOpen: true)); /// Get the text of the given stream private static string StreamText(Stream stream) @@ -274,16 +267,22 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Custom.WriteJsonArray(Query.Find(SqliteDb.TableName), [], writer, Results.JsonFromData); - - var json = StreamText(stream); - VerifyBeginEnd(json); - Expect.stringContains(json, JsonDocument.One, "Document ID `one` should have been found"); - Expect.stringContains(json, JsonDocument.Two,"Document ID `two` should have been found"); - Expect.stringContains(json, JsonDocument.Three, "Document ID `three` should have been found"); - Expect.stringContains(json, JsonDocument.Four, "Document ID `four` should have been found"); - Expect.stringContains(json, JsonDocument.Five, "Document ID `five` should have been found"); + var writer = WriteStream(stream); + try + { + await Custom.WriteJsonArray(Query.Find(SqliteDb.TableName), [], writer, Results.JsonFromData); + var json = StreamText(stream); + VerifyBeginEnd(json); + Expect.stringContains(json, JsonDocument.One, "Document ID `one` should have been found"); + Expect.stringContains(json, JsonDocument.Two, "Document ID `two` should have been found"); + Expect.stringContains(json, JsonDocument.Three, "Document ID `three` should have been found"); + Expect.stringContains(json, JsonDocument.Four, "Document ID `four` should have been found"); + Expect.stringContains(json, JsonDocument.Five, "Document ID `five` should have been found"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when data is not found", async () => { @@ -291,12 +290,18 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Custom.WriteJsonArray( - $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value", - [new SqliteParameter("@value", 100)], writer, Results.JsonFromData); - - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Custom.WriteJsonArray( + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value", + [new SqliteParameter("@value", 100)], writer, Results.JsonFromData); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("Single", @@ -1096,22 +1101,37 @@ public static class SqliteCSharpTests await Document.Insert(SqliteDb.TableName, new SubDocument { Foo = "five", Bar = "six" }); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteAll(SqliteDb.TableName, writer); - var json = StreamText(stream); - VerifyBeginEnd(json); - Expect.stringContains(json, """{"Foo":"one","Bar":"two"}""", "The first document was not found"); - Expect.stringContains(json, """{"Foo":"three","Bar":"four"}""", "The second document was not found"); - Expect.stringContains(json, """{"Foo":"five","Bar":"six"}""", "The third document was not found"); + var writer = WriteStream(stream); + try + { + await Json.WriteAll(SqliteDb.TableName, writer); + var json = StreamText(stream); + VerifyBeginEnd(json); + Expect.stringContains(json, """{"Foo":"one","Bar":"two"}""", "The first document was not found"); + Expect.stringContains(json, """{"Foo":"three","Bar":"four"}""", + "The second document was not found"); + Expect.stringContains(json, """{"Foo":"five","Bar":"six"}""", "The third document was not found"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when there is no data", async () => { await using var db = await SqliteDb.BuildDb(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteAll(SqliteDb.TableName, writer); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteAll(SqliteDb.TableName, writer); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteAllOrdered", @@ -1122,11 +1142,18 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteAllOrdered(SqliteDb.TableName, writer, [Field.Named("n:NumValue")]); - Expect.equal(StreamText(stream), - $"[{JsonDocument.One},{JsonDocument.Three},{JsonDocument.Two},{JsonDocument.Four},{JsonDocument.Five}]", - "The documents were not ordered correctly"); + var writer = WriteStream(stream); + try + { + await Json.WriteAllOrdered(SqliteDb.TableName, writer, [Field.Named("n:NumValue")]); + Expect.equal(StreamText(stream), + $"[{JsonDocument.One},{JsonDocument.Three},{JsonDocument.Two},{JsonDocument.Four},{JsonDocument.Five}]", + "The documents were not ordered correctly"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when ordering numerically descending", async () => { @@ -1134,11 +1161,18 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteAllOrdered(SqliteDb.TableName, writer, [Field.Named("n:NumValue DESC")]); - Expect.equal(StreamText(stream), - $"[{JsonDocument.Five},{JsonDocument.Four},{JsonDocument.Two},{JsonDocument.Three},{JsonDocument.One}]", - "The documents were not ordered correctly"); + var writer = WriteStream(stream); + try + { + await Json.WriteAllOrdered(SqliteDb.TableName, writer, [Field.Named("n:NumValue DESC")]); + Expect.equal(StreamText(stream), + $"[{JsonDocument.Five},{JsonDocument.Four},{JsonDocument.Two},{JsonDocument.Three},{JsonDocument.One}]", + "The documents were not ordered correctly"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when ordering alphabetically", async () => { @@ -1146,11 +1180,18 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteAllOrdered(SqliteDb.TableName, writer, [Field.Named("Id DESC")]); - Expect.equal(StreamText(stream), - $"[{JsonDocument.Two},{JsonDocument.Three},{JsonDocument.One},{JsonDocument.Four},{JsonDocument.Five}]", - "The documents were not ordered correctly"); + var writer = WriteStream(stream); + try + { + await Json.WriteAllOrdered(SqliteDb.TableName, writer, [Field.Named("Id DESC")]); + Expect.equal(StreamText(stream), + $"[{JsonDocument.Two},{JsonDocument.Three},{JsonDocument.One},{JsonDocument.Four},{JsonDocument.Five}]", + "The documents were not ordered correctly"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteById", @@ -1161,9 +1202,16 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteById(SqliteDb.TableName, writer, "two"); - Expect.equal(StreamText(stream), JsonDocument.Two, "The incorrect document was returned"); + var writer = WriteStream(stream); + try + { + await Json.WriteById(SqliteDb.TableName, writer, "two"); + Expect.equal(StreamText(stream), JsonDocument.Two, "The incorrect document was returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { @@ -1171,9 +1219,16 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteById(SqliteDb.TableName, writer, "three hundred eighty-seven"); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteById(SqliteDb.TableName, writer, "three hundred eighty-seven"); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteByFields", @@ -1184,12 +1239,20 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFields(SqliteDb.TableName, writer, FieldMatch.Any, [Field.Greater("NumValue", 15)]); - var json = StreamText(stream); - VerifyBeginEnd(json); - Expect.stringContains(json, JsonDocument.Four, "Document `four` should have been returned"); - Expect.stringContains(json, JsonDocument.Five, "Document `five` should have been returned"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFields(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Greater("NumValue", 15)]); + var json = StreamText(stream); + VerifyBeginEnd(json); + Expect.stringContains(json, JsonDocument.Four, "Document `four` should have been returned"); + Expect.stringContains(json, JsonDocument.Five, "Document `five` should have been returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are found using IN with numeric field", async () => { @@ -1197,11 +1260,18 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFields(SqliteDb.TableName, writer, FieldMatch.All, - [Field.In("NumValue", [2, 4, 6, 8])]); - Expect.equal(StreamText(stream), $"[{JsonDocument.Three}]", - "There should have been one document returned"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFields(SqliteDb.TableName, writer, FieldMatch.All, + [Field.In("NumValue", [2, 4, 6, 8])]); + Expect.equal(StreamText(stream), $"[{JsonDocument.Three}]", + "There should have been one document returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when documents are not found", async () => { @@ -1209,9 +1279,17 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFields(SqliteDb.TableName, writer, FieldMatch.Any, [Field.Greater("NumValue", 100)]); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteByFields(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Greater("NumValue", 100)]); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds for InArray when matching documents exist", async () => { @@ -1220,15 +1298,22 @@ public static class SqliteCSharpTests foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(SqliteDb.TableName, doc); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFields(SqliteDb.TableName, writer, FieldMatch.All, - [Field.InArray("Values", SqliteDb.TableName, ["c"])]); - var json = StreamText(stream); - VerifyBeginEnd(json); - Expect.stringContains(json, """{"Id":"first","Values":["a","b","c"]}""", - "Document `first` should have been returned"); - Expect.stringContains(json, """{"Id":"second","Values":["c","d","e"]}""", - "Document `second` should have been returned"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFields(SqliteDb.TableName, writer, FieldMatch.All, + [Field.InArray("Values", SqliteDb.TableName, ["c"])]); + var json = StreamText(stream); + VerifyBeginEnd(json); + Expect.stringContains(json, """{"Id":"first","Values":["a","b","c"]}""", + "Document `first` should have been returned"); + Expect.stringContains(json, """{"Id":"second","Values":["c","d","e"]}""", + "Document `second` should have been returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds for InArray when no matching documents exist", async () => { @@ -1237,10 +1322,17 @@ public static class SqliteCSharpTests foreach (var doc in ArrayDocument.TestDocuments) await Document.Insert(SqliteDb.TableName, doc); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFields(SqliteDb.TableName, writer, FieldMatch.All, - [Field.InArray("Values", SqliteDb.TableName, ["j"])]); - VerifyEmpty(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteByFields(SqliteDb.TableName, writer, FieldMatch.All, + [Field.InArray("Values", SqliteDb.TableName, ["j"])]); + VerifyEmpty(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteByFieldsOrdered", @@ -1251,11 +1343,18 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Greater("NumValue", 15)], [Field.Named("Id")]); - Expect.equal(StreamText(stream), $"[{JsonDocument.Five},{JsonDocument.Four}]", - "Incorrect documents were returned"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Greater("NumValue", 15)], [Field.Named("Id")]); + Expect.equal(StreamText(stream), $"[{JsonDocument.Five},{JsonDocument.Four}]", + "Incorrect documents were returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { @@ -1263,11 +1362,18 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Greater("NumValue", 15)], [Field.Named("Id DESC")]); - Expect.equal(StreamText(stream), $"[{JsonDocument.Four},{JsonDocument.Five}]", - "Incorrect documents were returned"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Greater("NumValue", 15)], [Field.Named("Id DESC")]); + Expect.equal(StreamText(stream), $"[{JsonDocument.Four},{JsonDocument.Five}]", + "Incorrect documents were returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting case-sensitively", async () => { @@ -1275,11 +1381,18 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.All, - [Field.LessOrEqual("NumValue", 10)], [Field.Named("Value")]); - Expect.equal(StreamText(stream), $"[{JsonDocument.Three},{JsonDocument.One},{JsonDocument.Two}]", - "Documents not ordered correctly"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.All, + [Field.LessOrEqual("NumValue", 10)], [Field.Named("Value")]); + Expect.equal(StreamText(stream), $"[{JsonDocument.Three},{JsonDocument.One},{JsonDocument.Two}]", + "Documents not ordered correctly"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting case-insensitively", async () => { @@ -1287,11 +1400,18 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.All, - [Field.LessOrEqual("NumValue", 10)], [Field.Named("i:Value")]); - Expect.equal(StreamText(stream), $"[{JsonDocument.Three},{JsonDocument.Two},{JsonDocument.One}]", - "Documents not ordered correctly"); + var writer = WriteStream(stream); + try + { + await Json.WriteByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.All, + [Field.LessOrEqual("NumValue", 10)], [Field.Named("i:Value")]); + Expect.equal(StreamText(stream), $"[{JsonDocument.Three},{JsonDocument.Two},{JsonDocument.One}]", + "Documents not ordered correctly"); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteFirstByFields", @@ -1302,10 +1422,17 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "another")]); - Expect.equal(StreamText(stream), JsonDocument.Two, "The incorrect document was returned"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "another")]); + Expect.equal(StreamText(stream), JsonDocument.Two, "The incorrect document was returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when multiple documents are found", async () => { @@ -1313,12 +1440,19 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Sub.Foo", "green")]); - var json = StreamText(stream); - Expect.notEqual(json, "{}", "There should have been a document returned"); - VerifyAny(json, [JsonDocument.Two, JsonDocument.Four]); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Sub.Foo", "green")]); + var json = StreamText(stream); + Expect.notEqual(json, "{}", "There should have been a document returned"); + VerifyAny(json, [JsonDocument.Two, JsonDocument.Four]); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when a document is not found", async () => { @@ -1326,10 +1460,17 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Value", "absent")]); - VerifyNoDoc(StreamText(stream)); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByFields(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Value", "absent")]); + VerifyNoDoc(StreamText(stream)); + } + finally + { + await writer.CompleteAsync(); + } }) ]), TestList("WriteFirstByFieldsOrdered", @@ -1340,10 +1481,17 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar")]); - Expect.equal(StreamText(stream), JsonDocument.Two, "An incorrect document was returned"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar")]); + Expect.equal(StreamText(stream), JsonDocument.Two, "An incorrect document was returned"); + } + finally + { + await writer.CompleteAsync(); + } }), TestCase("succeeds when sorting descending", async () => { @@ -1351,10 +1499,17 @@ public static class SqliteCSharpTests await LoadDocs(); using MemoryStream stream = new(); - await using var writer = WriteStream(stream); - await Json.WriteFirstByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, - [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar DESC")]); - Expect.equal(StreamText(stream), JsonDocument.Four, "An incorrect document was returned"); + var writer = WriteStream(stream); + try + { + await Json.WriteFirstByFieldsOrdered(SqliteDb.TableName, writer, FieldMatch.Any, + [Field.Equal("Sub.Foo", "green")], [Field.Named("Sub.Bar DESC")]); + Expect.equal(StreamText(stream), JsonDocument.Four, "An incorrect document was returned"); + } + finally + { + await writer.CompleteAsync(); + } }) ]) ]); diff --git a/src/Tests/CommonTests.fs b/src/Tests/CommonTests.fs index 98f6fe8..40aeb8e 100644 --- a/src/Tests/CommonTests.fs +++ b/src/Tests/CommonTests.fs @@ -1,5 +1,7 @@ module CommonTests +open System.IO +open System.IO.Pipelines open BitBadger.Documents open Expecto @@ -484,6 +486,81 @@ let queryTests = testList "Query" [ ] ] +let private streamText (stream: Stream) = + stream.Position <- 0L + use reader = new StreamReader(stream) + reader.ReadToEnd() + +/// Unit tests for the PipeWriter module +let pipeWriterTests = testList "Extensions.PipeWriter" [ + testList "writeString" [ + testTask "succeeds when writer is open" { + use stream = new MemoryStream() + let writer = PipeWriter.Create(stream, StreamPipeWriterOptions(leaveOpen = true)) + try + let! result = PipeWriter.writeString writer "abc" + Expect.isTrue result "The write operation should have been successful" + Expect.equal (streamText stream) "abc" "The string was not written correctly" + finally + writer.Complete() + } + testTask "succeeds when writer is completed" { + use stream = new MemoryStream() + let writer = PipeWriter.Create(stream, StreamPipeWriterOptions(leaveOpen = true)) + do! writer.CompleteAsync() + + let! result = PipeWriter.writeString writer "abc" + Expect.isFalse result "The write operation should have returned false" + Expect.equal (streamText stream) "" "No text should have been written" + } + ] + testList "writeStrings" [ + testTask "succeeds with no strings" { + use stream = new MemoryStream() + let writer = PipeWriter.Create(stream, StreamPipeWriterOptions(leaveOpen = true)) + try + do! PipeWriter.writeStrings writer [] + Expect.equal (streamText stream) "[]" "An empty sequence of strings was not written correctly" + finally + writer.Complete() + } + testTask "succeeds with one strings" { + use stream = new MemoryStream() + let writer = PipeWriter.Create(stream, StreamPipeWriterOptions(leaveOpen = true)) + try + do! PipeWriter.writeStrings writer [ "le-test" ] + Expect.equal (streamText stream) "[le-test]" "A sequence of one string was not written correctly" + finally + writer.Complete() + } + testTask "succeeds with many strings" { + use stream = new MemoryStream() + let writer = PipeWriter.Create(stream, StreamPipeWriterOptions(leaveOpen = true)) + try + do! PipeWriter.writeStrings writer [ "z"; "y"; "x"; "c"; "b"; "a" ] + Expect.equal (streamText stream) "[z,y,x,c,b,a]" "A sequence of many strings was not written correctly" + finally + writer.Complete() + } + testTask "succeeds when the writer is completed early" { + use stream = new MemoryStream() + let writer = PipeWriter.Create(stream, StreamPipeWriterOptions(leaveOpen = true)) + let items = seq { + "a" + "b" + "c" + writer.Complete() + "d" + "e" + "f" + } + + do! PipeWriter.writeStrings writer items + Expect.equal (streamText stream) "[a,b,c" "The writing should have stopped when the writer completed" + } + ] +] + /// Tests which do not hit the database let all = testList "Common" [ comparisonTests @@ -492,5 +569,6 @@ let all = testList "Common" [ parameterNameTests autoIdTests queryTests + pipeWriterTests testSequenced configurationTests ] diff --git a/src/Tests/PostgresExtensionTests.fs b/src/Tests/PostgresExtensionTests.fs index df675c1..d780072 100644 --- a/src/Tests/PostgresExtensionTests.fs +++ b/src/Tests/PostgresExtensionTests.fs @@ -1,6 +1,7 @@ module PostgresExtensionTests open System.IO +open System.IO.Pipelines open BitBadger.Documents open BitBadger.Documents.Postgres open BitBadger.Documents.Tests @@ -16,9 +17,7 @@ let private mkConn (db: ThrowawayPostgresDb) = /// Set up a stream writer for a test let private writeStream (stream: Stream) = - let writer = new StreamWriter(stream) - writer.AutoFlush <- true - writer + PipeWriter.Create(stream, StreamPipeWriterOptions(leaveOpen = true)) /// Get the text of the given stream let private streamText (stream: Stream) = @@ -142,13 +141,15 @@ let integrationTests = 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 `[`" + let writer = writeStream stream + try + 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 `[`" + finally + writer.Complete() } testTask "succeeds when data is not found" { use db = PostgresDb.BuildDb() @@ -156,14 +157,16 @@ let integrationTests = 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" + let writer = writeStream stream + try + 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" + finally + writer.Complete() } ] testList "customSingle" [ @@ -1170,17 +1173,23 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonAll PostgresDb.TableName writer - verifyAllData (streamText stream) + let writer = writeStream stream + try + do! conn.writeJsonAll PostgresDb.TableName writer + verifyAllData (streamText stream) + finally + writer.Complete() } 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) + let writer = writeStream stream + try + do! conn.writeJsonAll PostgresDb.TableName writer + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeJsonAllOrdered" [ @@ -1190,9 +1199,12 @@ let integrationTests = 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") + let writer = writeStream stream + try + do! conn.writeJsonAllOrdered PostgresDb.TableName writer [ Field.Named "n:NumValue" ] + verifyExpectedOrder (streamText stream) "one" "three" (Some "two") (Some "four") (Some "five") + finally + writer.Complete() } testTask "succeeds when ordering numerically descending" { use db = PostgresDb.BuildDb() @@ -1200,9 +1212,12 @@ let integrationTests = 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") + let writer = writeStream stream + try + do! conn.writeJsonAllOrdered PostgresDb.TableName writer [ Field.Named "n:NumValue DESC" ] + verifyExpectedOrder (streamText stream) "five" "four" (Some "two") (Some "three") (Some "one") + finally + writer.Complete() } testTask "succeeds when ordering alphabetically" { use db = PostgresDb.BuildDb() @@ -1210,9 +1225,12 @@ let integrationTests = 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") + let writer = writeStream stream + try + do! conn.writeJsonAllOrdered PostgresDb.TableName writer [ Field.Named "Id DESC" ] + verifyExpectedOrder (streamText stream) "two" "three" (Some "one") (Some "four") (Some "five") + finally + writer.Complete() } ] testList "writeJsonById" [ @@ -1222,11 +1240,14 @@ let integrationTests = 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" + let writer = writeStream stream + try + 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" + finally + writer.Complete() } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() @@ -1234,9 +1255,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonById PostgresDb.TableName writer "three hundred eighty-seven" - verifyNoDoc (streamText stream) + let writer = writeStream stream + try + do! conn.writeJsonById PostgresDb.TableName writer "three hundred eighty-seven" + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeJsonByFields" [ @@ -1246,10 +1270,16 @@ let integrationTests = 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" + let writer = writeStream stream + try + do! conn.writeJsonByFields + PostgresDb.TableName + writer + All + [ Field.In "Value" [ "purple"; "blue" ]; Field.Exists "Sub" ] + verifySingleById (streamText stream) "four" + finally + writer.Complete() } testTask "succeeds when documents are found using IN with numeric field" { use db = PostgresDb.BuildDb() @@ -1257,9 +1287,12 @@ let integrationTests = 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" + let writer = writeStream stream + try + do! conn.writeJsonByFields PostgresDb.TableName writer All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ] + verifySingleById (streamText stream) "three" + finally + writer.Complete() } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() @@ -1267,10 +1300,16 @@ let integrationTests = 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) + let writer = writeStream stream + try + do! conn.writeJsonByFields + PostgresDb.TableName + writer + All + [ Field.Equal "Value" "mauve"; Field.NotEqual "NumValue" 40 ] + verifyEmpty (streamText stream) + finally + writer.Complete() } testTask "succeeds for InArray when matching documents exist" { use db = PostgresDb.BuildDb() @@ -1279,13 +1318,16 @@ let integrationTests = 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" + let writer = writeStream stream + try + 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" + finally + writer.Complete() } testTask "succeeds for InArray when no matching documents exist" { use db = PostgresDb.BuildDb() @@ -1294,10 +1336,13 @@ let integrationTests = 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) + let writer = writeStream stream + try + do! conn.writeJsonByFields + PostgresDb.TableName writer All [ Field.InArray "Values" PostgresDb.TableName [ "j" ] ] + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeJsonByFieldsOrdered" [ @@ -1307,10 +1352,13 @@ let integrationTests = 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 + let writer = writeStream stream + try + do! conn.writeJsonByFieldsOrdered + PostgresDb.TableName writer All [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] + verifyExpectedOrder (streamText stream) "five" "four" None None None + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() @@ -1318,10 +1366,13 @@ let integrationTests = 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 + let writer = writeStream stream + try + do! conn.writeJsonByFieldsOrdered + PostgresDb.TableName writer All [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] + verifyExpectedOrder (streamText stream) "four" "five" None None None + finally + writer.Complete() } ] testList "writeJsonByContains" [ @@ -1331,12 +1382,15 @@ let integrationTests = 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" + let writer = writeStream stream + try + do! conn.writeJsonByContains PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} + let json = streamText stream + verifyBeginEnd json + verifyDocById json "two" + verifyDocById json "four" + finally + writer.Complete() } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() @@ -1344,9 +1398,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonByContains PostgresDb.TableName writer {| Value = "mauve" |} - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! conn.writeJsonByContains PostgresDb.TableName writer {| Value = "mauve" |} + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeJsonByContainsOrdered" [ @@ -1357,10 +1414,13 @@ let integrationTests = 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 + let writer = writeStream stream + try + do! conn.writeJsonByContainsOrdered + PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar" ] + verifyExpectedOrder (streamText stream) "two" "four" None None None + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() @@ -1368,10 +1428,13 @@ let integrationTests = 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 + let writer = writeStream stream + try + do! conn.writeJsonByContainsOrdered + PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar DESC" ] + verifyExpectedOrder (streamText stream) "four" "two" None None None + finally + writer.Complete() } ] testList "writeJsonByJsonPath" [ @@ -1381,13 +1444,16 @@ let integrationTests = 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" + let writer = writeStream stream + try + do! conn.writeJsonByJsonPath PostgresDb.TableName writer "$.NumValue ? (@ < 15)" + let json = streamText stream + verifyBeginEnd json + verifyDocById json "one" + verifyDocById json "two" + verifyDocById json "three" + finally + writer.Complete() } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() @@ -1395,9 +1461,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonByJsonPath PostgresDb.TableName writer "$.NumValue ? (@ < 0)" - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! conn.writeJsonByJsonPath PostgresDb.TableName writer "$.NumValue ? (@ < 0)" + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeJsonByJsonPathOrdered" [ @@ -1408,10 +1477,13 @@ let integrationTests = 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 + let writer = writeStream stream + try + do! conn.writeJsonByJsonPathOrdered + PostgresDb.TableName writer "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue" ] + verifyExpectedOrder (streamText stream) "one" "three" (Some "two") None None + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() @@ -1419,10 +1491,13 @@ let integrationTests = 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 + let writer = writeStream stream + try + do! conn.writeJsonByJsonPathOrdered + PostgresDb.TableName writer "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue DESC" ] + verifyExpectedOrder (streamText stream) "two" "three" (Some "one") None None + finally + writer.Complete() } ] testList "writeJsonFirstByFields" [ @@ -1432,9 +1507,12 @@ let integrationTests = 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" + let writer = writeStream stream + try + do! conn.writeJsonFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "another" ] + verifyDocById (streamText stream) "two" + finally + writer.Complete() } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() @@ -1442,9 +1520,12 @@ let integrationTests = 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" ] + let writer = writeStream stream + try + do! conn.writeJsonFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] + verifyAnyById (streamText stream) [ "five"; "four" ] + finally + writer.Complete() } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() @@ -1452,9 +1533,12 @@ let integrationTests = 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) + let writer = writeStream stream + try + do! conn.writeJsonFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "absent" ] + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeJsonFirstByFieldsOrdered" [ @@ -1464,10 +1548,13 @@ let integrationTests = 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" + let writer = writeStream stream + try + do! conn.writeJsonFirstByFieldsOrdered + PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] + verifyDocById (streamText stream) "five" + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() @@ -1475,10 +1562,13 @@ let integrationTests = 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" + let writer = writeStream stream + try + do! conn.writeJsonFirstByFieldsOrdered + PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] + verifyDocById (streamText stream) "four" + finally + writer.Complete() } ] testList "writeJsonFirstByContains" [ @@ -1488,9 +1578,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonFirstByContains PostgresDb.TableName writer {| Value = "another" |} - verifyDocById (streamText stream) "two" + let writer = writeStream stream + try + do! conn.writeJsonFirstByContains PostgresDb.TableName writer {| Value = "another" |} + verifyDocById (streamText stream) "two" + finally + writer.Complete() } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() @@ -1498,9 +1591,12 @@ let integrationTests = 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" ] + let writer = writeStream stream + try + do! conn.writeJsonFirstByContains PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} + verifyAnyById (streamText stream) [ "two"; "four" ] + finally + writer.Complete() } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() @@ -1508,9 +1604,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonFirstByContains PostgresDb.TableName writer {| Value = "absent" |} - verifyNoDoc (streamText stream) + let writer = writeStream stream + try + do! conn.writeJsonFirstByContains PostgresDb.TableName writer {| Value = "absent" |} + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeJsonFirstByContainsOrdered" [ @@ -1520,10 +1619,13 @@ let integrationTests = 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" + let writer = writeStream stream + try + do! conn.writeJsonFirstByContainsOrdered + PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Value" ] + verifyDocById (streamText stream) "two" + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() @@ -1531,10 +1633,13 @@ let integrationTests = 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" + let writer = writeStream stream + try + do! conn.writeJsonFirstByContainsOrdered + PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Value DESC" ] + verifyDocById (streamText stream) "four" + finally + writer.Complete() } ] testList "writeJsonFirstByJsonPath" [ @@ -1544,9 +1649,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonFirstByJsonPath PostgresDb.TableName writer """$.Value ? (@ == "FIRST!")""" - verifyDocById (streamText stream) "one" + let writer = writeStream stream + try + do! conn.writeJsonFirstByJsonPath PostgresDb.TableName writer """$.Value ? (@ == "FIRST!")""" + verifyDocById (streamText stream) "one" + finally + writer.Complete() } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() @@ -1554,9 +1662,12 @@ let integrationTests = 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" ] + let writer = writeStream stream + try + do! conn.writeJsonFirstByJsonPath PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" + verifyAnyById (streamText stream) [ "two"; "four" ] + finally + writer.Complete() } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() @@ -1564,9 +1675,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonFirstByJsonPath PostgresDb.TableName writer """$.Id ? (@ == "nope")""" - verifyNoDoc (streamText stream) + let writer = writeStream stream + try + do! conn.writeJsonFirstByJsonPath PostgresDb.TableName writer """$.Id ? (@ == "nope")""" + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeJsonFirstByJsonPathOrdered" [ @@ -1576,10 +1690,13 @@ let integrationTests = 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" + let writer = writeStream stream + try + do! conn.writeJsonFirstByJsonPathOrdered + PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar" ] + verifyDocById (streamText stream) "two" + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() @@ -1587,10 +1704,13 @@ let integrationTests = 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" + let writer = writeStream stream + try + do! conn.writeJsonFirstByJsonPathOrdered + PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar DESC" ] + verifyDocById (streamText stream) "four" + finally + writer.Complete() } ] testList "updateById" [ diff --git a/src/Tests/PostgresTests.fs b/src/Tests/PostgresTests.fs index d166cbf..8fd4e73 100644 --- a/src/Tests/PostgresTests.fs +++ b/src/Tests/PostgresTests.fs @@ -1,6 +1,7 @@ module PostgresTests open System.IO +open System.IO.Pipelines open Expecto open BitBadger.Documents open BitBadger.Documents.Postgres @@ -278,9 +279,7 @@ let loadDocs () = backgroundTask { /// Set up a stream writer for a test let writeStream (stream: Stream) = - let writer = new StreamWriter(stream) - writer.AutoFlush <- true - writer + PipeWriter.Create(stream, StreamPipeWriterOptions(leaveOpen = true)) /// Get the text of the given stream let streamText (stream: Stream) = @@ -339,7 +338,7 @@ let customTests = testList "Custom" [ let! docs = Custom.jsonArray (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 `[`" + Expect.stringEnds docs "]" "The JSON array should have ended with `]`" } testTask "succeeds when data is not found" { use db = PostgresDb.BuildDb() @@ -359,27 +358,32 @@ let customTests = testList "Custom" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Custom.writeJsonArray (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 `[`" + let writer = writeStream stream + + try + do! Custom.writeJsonArray (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 `]`" + finally + writer.Complete() } testTask "succeeds when data is not found" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Custom.writeJsonArray - $"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" + let writer = writeStream stream + try + do! Custom.writeJsonArray + $"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" + finally + writer.Complete() } ] testList "single" [ @@ -1457,16 +1461,22 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeAll PostgresDb.TableName writer - verifyAllData (streamText stream) + let writer = writeStream stream + try + do! Json.writeAll PostgresDb.TableName writer + verifyAllData (streamText stream) + finally + writer.Complete() } testTask "succeeds when there is no data" { use db = PostgresDb.BuildDb() use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeAll PostgresDb.TableName writer - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! Json.writeAll PostgresDb.TableName writer + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeAllOrdered" [ @@ -1475,27 +1485,36 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeAllOrdered PostgresDb.TableName writer [ Field.Named "n:NumValue" ] - verifyExpectedOrder (streamText stream) "one" "three" (Some "two") (Some "four") (Some "five") + let writer = writeStream stream + try + do! Json.writeAllOrdered PostgresDb.TableName writer [ Field.Named "n:NumValue" ] + verifyExpectedOrder (streamText stream) "one" "three" (Some "two") (Some "four") (Some "five") + finally + writer.Complete() } testTask "succeeds when ordering numerically descending" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeAllOrdered PostgresDb.TableName writer [ Field.Named "n:NumValue DESC" ] - verifyExpectedOrder (streamText stream) "five" "four" (Some "two") (Some "three") (Some "one") + let writer = writeStream stream + try + do! Json.writeAllOrdered PostgresDb.TableName writer [ Field.Named "n:NumValue DESC" ] + verifyExpectedOrder (streamText stream) "five" "four" (Some "two") (Some "three") (Some "one") + finally + writer.Complete() } testTask "succeeds when ordering alphabetically" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeAllOrdered PostgresDb.TableName writer [ Field.Named "Id DESC" ] - verifyExpectedOrder (streamText stream) "two" "three" (Some "one") (Some "four") (Some "five") + let writer = writeStream stream + try + do! Json.writeAllOrdered PostgresDb.TableName writer [ Field.Named "Id DESC" ] + verifyExpectedOrder (streamText stream) "two" "three" (Some "one") (Some "four") (Some "five") + finally + writer.Complete() } ] testList "writeById" [ @@ -1504,20 +1523,26 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeById 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" + let writer = writeStream stream + try + do! Json.writeById 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" + finally + writer.Complete() } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeById PostgresDb.TableName writer "three hundred eighty-seven" - verifyNoDoc (streamText stream) + let writer = writeStream stream + try + do! Json.writeById PostgresDb.TableName writer "three hundred eighty-seven" + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeByFields" [ @@ -1526,29 +1551,38 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFields - PostgresDb.TableName writer All [ Field.In "Value" [ "purple"; "blue" ]; Field.Exists "Sub" ] - verifySingleById (streamText stream) "four" + let writer = writeStream stream + try + do! Json.writeByFields + PostgresDb.TableName writer All [ Field.In "Value" [ "purple"; "blue" ]; Field.Exists "Sub" ] + verifySingleById (streamText stream) "four" + finally + writer.Complete() } testTask "succeeds when documents are found using IN with numeric field" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFields PostgresDb.TableName writer All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ] - verifySingleById (streamText stream) "three" + let writer = writeStream stream + try + do! Json.writeByFields PostgresDb.TableName writer All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ] + verifySingleById (streamText stream) "three" + finally + writer.Complete() } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFields - PostgresDb.TableName writer All [ Field.Equal "Value" "mauve"; Field.NotEqual "NumValue" 40 ] - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! Json.writeByFields + PostgresDb.TableName writer All [ Field.Equal "Value" "mauve"; Field.NotEqual "NumValue" 40 ] + verifyEmpty (streamText stream) + finally + writer.Complete() } testTask "succeeds for InArray when matching documents exist" { use db = PostgresDb.BuildDb() @@ -1556,13 +1590,16 @@ let jsonTests = testList "Json" [ for doc in ArrayDocument.TestDocuments do do! insert PostgresDb.TableName doc use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFields - PostgresDb.TableName writer All [ Field.InArray "Values" PostgresDb.TableName [ "c" ] ] - let json = streamText stream - verifyBeginEnd json - verifyDocById json "first" - verifyDocById json "second" + let writer = writeStream stream + try + do! Json.writeByFields + PostgresDb.TableName writer All [ Field.InArray "Values" PostgresDb.TableName [ "c" ] ] + let json = streamText stream + verifyBeginEnd json + verifyDocById json "first" + verifyDocById json "second" + finally + writer.Complete() } testTask "succeeds for InArray when no matching documents exist" { use db = PostgresDb.BuildDb() @@ -1570,10 +1607,13 @@ let jsonTests = testList "Json" [ for doc in ArrayDocument.TestDocuments do do! insert PostgresDb.TableName doc use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFields - PostgresDb.TableName writer All [ Field.InArray "Values" PostgresDb.TableName [ "j" ] ] - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! Json.writeByFields + PostgresDb.TableName writer All [ Field.InArray "Values" PostgresDb.TableName [ "j" ] ] + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeByFieldsOrdered" [ @@ -1582,20 +1622,26 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFieldsOrdered - PostgresDb.TableName writer All [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] - verifyExpectedOrder (streamText stream) "five" "four" None None None + let writer = writeStream stream + try + do! Json.writeByFieldsOrdered + PostgresDb.TableName writer All [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] + verifyExpectedOrder (streamText stream) "five" "four" None None None + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFieldsOrdered - PostgresDb.TableName writer All [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] - verifyExpectedOrder (streamText stream) "four" "five" None None None + let writer = writeStream stream + try + do! Json.writeByFieldsOrdered + PostgresDb.TableName writer All [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] + verifyExpectedOrder (streamText stream) "four" "five" None None None + finally + writer.Complete() } ] testList "writeByContains" [ @@ -1604,21 +1650,27 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByContains PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} - let json = streamText stream - verifyBeginEnd json - verifyDocById json "two" - verifyDocById json "four" + let writer = writeStream stream + try + do! Json.writeByContains PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} + let json = streamText stream + verifyBeginEnd json + verifyDocById json "two" + verifyDocById json "four" + finally + writer.Complete() } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByContains PostgresDb.TableName writer {| Value = "mauve" |} - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! Json.writeByContains PostgresDb.TableName writer {| Value = "mauve" |} + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeByContainsOrdered" [ @@ -1628,20 +1680,26 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByContainsOrdered - PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar" ] - verifyExpectedOrder (streamText stream) "two" "four" None None None + let writer = writeStream stream + try + do! Json.writeByContainsOrdered + PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar" ] + verifyExpectedOrder (streamText stream) "two" "four" None None None + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByContainsOrdered - PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar DESC" ] - verifyExpectedOrder (streamText stream) "four" "two" None None None + let writer = writeStream stream + try + do! Json.writeByContainsOrdered + PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Sub.Bar DESC" ] + verifyExpectedOrder (streamText stream) "four" "two" None None None + finally + writer.Complete() } ] testList "writeByJsonPath" [ @@ -1650,22 +1708,28 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByJsonPath PostgresDb.TableName writer "$.NumValue ? (@ < 15)" - let json = streamText stream - verifyBeginEnd json - verifyDocById json "one" - verifyDocById json "two" - verifyDocById json "three" + let writer = writeStream stream + try + do! Json.writeByJsonPath PostgresDb.TableName writer "$.NumValue ? (@ < 15)" + let json = streamText stream + verifyBeginEnd json + verifyDocById json "one" + verifyDocById json "two" + verifyDocById json "three" + finally + writer.Complete() } testTask "succeeds when documents are not found" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByJsonPath PostgresDb.TableName writer "$.NumValue ? (@ < 0)" - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! Json.writeByJsonPath PostgresDb.TableName writer "$.NumValue ? (@ < 0)" + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeByJsonPathOrdered" [ @@ -1675,20 +1739,26 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByJsonPathOrdered - PostgresDb.TableName writer "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue" ] - verifyExpectedOrder (streamText stream) "one" "three" (Some "two") None None + let writer = writeStream stream + try + do! Json.writeByJsonPathOrdered + PostgresDb.TableName writer "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue" ] + verifyExpectedOrder (streamText stream) "one" "three" (Some "two") None None + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByJsonPathOrdered - PostgresDb.TableName writer "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue DESC" ] - verifyExpectedOrder (streamText stream) "two" "three" (Some "one") None None + let writer = writeStream stream + try + do! Json.writeByJsonPathOrdered + PostgresDb.TableName writer "$.NumValue ? (@ < 15)" [ Field.Named "n:NumValue DESC" ] + verifyExpectedOrder (streamText stream) "two" "three" (Some "one") None None + finally + writer.Complete() } ] testList "writeFirstByFields" [ @@ -1697,27 +1767,36 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "another" ] - verifyDocById (streamText stream) "two" + let writer = writeStream stream + try + do! Json.writeFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "another" ] + verifyDocById (streamText stream) "two" + finally + writer.Complete() } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] - verifyAnyById (streamText stream) [ "five"; "four" ] + let writer = writeStream stream + try + do! Json.writeFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] + verifyAnyById (streamText stream) [ "five"; "four" ] + finally + writer.Complete() } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "absent" ] - verifyNoDoc (streamText stream) + let writer = writeStream stream + try + do! Json.writeFirstByFields PostgresDb.TableName writer Any [ Field.Equal "Value" "absent" ] + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeFirstByFieldsOrdered" [ @@ -1726,20 +1805,26 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByFieldsOrdered - PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] - verifyDocById (streamText stream) "five" + let writer = writeStream stream + try + do! Json.writeFirstByFieldsOrdered + PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id" ] + verifyDocById (streamText stream) "five" + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByFieldsOrdered - PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] - verifyDocById (streamText stream) "four" + let writer = writeStream stream + try + do! Json.writeFirstByFieldsOrdered + PostgresDb.TableName writer Any [ Field.Equal "Value" "purple" ] [ Field.Named "Id DESC" ] + verifyDocById (streamText stream) "four" + finally + writer.Complete() } ] testList "writeFirstByContains" [ @@ -1748,27 +1833,36 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByContains PostgresDb.TableName writer {| Value = "another" |} - verifyDocById (streamText stream) "two" + let writer = writeStream stream + try + do! Json.writeFirstByContains PostgresDb.TableName writer {| Value = "another" |} + verifyDocById (streamText stream) "two" + finally + writer.Complete() } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByContains PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} - verifyAnyById (streamText stream) [ "two"; "four" ] + let writer = writeStream stream + try + do! Json.writeFirstByContains PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} + verifyAnyById (streamText stream) [ "two"; "four" ] + finally + writer.Complete() } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByContains PostgresDb.TableName writer {| Value = "absent" |} - verifyNoDoc (streamText stream) + let writer = writeStream stream + try + do! Json.writeFirstByContains PostgresDb.TableName writer {| Value = "absent" |} + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeFirstByContainsOrdered" [ @@ -1777,20 +1871,26 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByContainsOrdered - PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Value" ] - verifyDocById (streamText stream) "two" + let writer = writeStream stream + try + do! Json.writeFirstByContainsOrdered + PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Value" ] + verifyDocById (streamText stream) "two" + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByContainsOrdered - PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Value DESC" ] - verifyDocById (streamText stream) "four" + let writer = writeStream stream + try + do! Json.writeFirstByContainsOrdered + PostgresDb.TableName writer {| Sub = {| Foo = "green" |} |} [ Field.Named "Value DESC" ] + verifyDocById (streamText stream) "four" + finally + writer.Complete() } ] testList "writeFirstByJsonPath" [ @@ -1799,27 +1899,36 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByJsonPath PostgresDb.TableName writer """$.Value ? (@ == "FIRST!")""" - verifyDocById (streamText stream) "one" + let writer = writeStream stream + try + do! Json.writeFirstByJsonPath PostgresDb.TableName writer """$.Value ? (@ == "FIRST!")""" + verifyDocById (streamText stream) "one" + finally + writer.Complete() } testTask "succeeds when multiple documents are found" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByJsonPath PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" - verifyAnyById (streamText stream) [ "two"; "four" ] + let writer = writeStream stream + try + do! Json.writeFirstByJsonPath PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" + verifyAnyById (streamText stream) [ "two"; "four" ] + finally + writer.Complete() } testTask "succeeds when a document is not found" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByJsonPath PostgresDb.TableName writer """$.Id ? (@ == "nope")""" - verifyNoDoc (streamText stream) + let writer = writeStream stream + try + do! Json.writeFirstByJsonPath PostgresDb.TableName writer """$.Id ? (@ == "nope")""" + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeFirstByJsonPathOrdered" [ @@ -1828,20 +1937,26 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByJsonPathOrdered - PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar" ] - verifyDocById (streamText stream) "two" + let writer = writeStream stream + try + do! Json.writeFirstByJsonPathOrdered + PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar" ] + verifyDocById (streamText stream) "two" + finally + writer.Complete() } testTask "succeeds when sorting descending" { use db = PostgresDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByJsonPathOrdered - PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar DESC" ] - verifyDocById (streamText stream) "four" + let writer = writeStream stream + try + do! Json.writeFirstByJsonPathOrdered + PostgresDb.TableName writer """$.Sub.Foo ? (@ == "green")""" [ Field.Named "Sub.Bar DESC" ] + verifyDocById (streamText stream) "four" + finally + writer.Complete() } ] ] diff --git a/src/Tests/SqliteExtensionTests.fs b/src/Tests/SqliteExtensionTests.fs index 44dca44..87f74d2 100644 --- a/src/Tests/SqliteExtensionTests.fs +++ b/src/Tests/SqliteExtensionTests.fs @@ -1,6 +1,7 @@ module SqliteExtensionTests open System.IO +open System.IO.Pipelines open System.Text.Json open BitBadger.Documents open BitBadger.Documents.Sqlite @@ -17,9 +18,7 @@ let integrationTests = /// Set up a stream writer for a test let writeStream (stream: Stream) = - let writer = new StreamWriter(stream) - writer.AutoFlush <- true - writer + PipeWriter.Create(stream, StreamPipeWriterOptions(leaveOpen = true)) /// Get the text of the given stream let streamText (stream: Stream) = @@ -600,21 +599,27 @@ let integrationTests = do! conn.insert SqliteDb.TableName { Foo = "five"; Bar = "six" } use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonAll SqliteDb.TableName writer - let json = streamText stream - verifyBeginEnd json - Expect.stringContains json """{"Foo":"one","Bar":"two"}""" "The first document was not found" - Expect.stringContains json """{"Foo":"three","Bar":"four"}""" "The second document was not found" - Expect.stringContains json """{"Foo":"five","Bar":"six"}""" "The third document was not found" + let writer = writeStream stream + try + do! conn.writeJsonAll SqliteDb.TableName writer + let json = streamText stream + verifyBeginEnd json + Expect.stringContains json """{"Foo":"one","Bar":"two"}""" "The first document was not found" + Expect.stringContains json """{"Foo":"three","Bar":"four"}""" "The second document was not found" + Expect.stringContains json """{"Foo":"five","Bar":"six"}""" "The third document was not found" + finally + writer.Complete() } testTask "succeeds when there is no data" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonAll SqliteDb.TableName writer - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! conn.writeJsonAll SqliteDb.TableName writer + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeJsonAllOrdered" [ @@ -624,12 +629,15 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonAllOrdered SqliteDb.TableName writer [ Field.Named "n:NumValue" ] - Expect.equal - (streamText stream) - $"[{JsonDocument.one},{JsonDocument.three},{JsonDocument.two},{JsonDocument.four},{JsonDocument.five}]" - "The documents were not ordered correctly" + let writer = writeStream stream + try + do! conn.writeJsonAllOrdered SqliteDb.TableName writer [ Field.Named "n:NumValue" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.one},{JsonDocument.three},{JsonDocument.two},{JsonDocument.four},{JsonDocument.five}]" + "The documents were not ordered correctly" + finally + writer.Complete() } testTask "succeeds when ordering numerically descending" { use! db = SqliteDb.BuildDb() @@ -637,12 +645,15 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonAllOrdered SqliteDb.TableName writer [ Field.Named "n:NumValue DESC" ] - Expect.equal - (streamText stream) - $"[{JsonDocument.five},{JsonDocument.four},{JsonDocument.two},{JsonDocument.three},{JsonDocument.one}]" - "The documents were not ordered correctly" + let writer = writeStream stream + try + do! conn.writeJsonAllOrdered SqliteDb.TableName writer [ Field.Named "n:NumValue DESC" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.five},{JsonDocument.four},{JsonDocument.two},{JsonDocument.three},{JsonDocument.one}]" + "The documents were not ordered correctly" + finally + writer.Complete() } testTask "succeeds when ordering alphabetically" { use! db = SqliteDb.BuildDb() @@ -650,12 +661,15 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonAllOrdered SqliteDb.TableName writer [ Field.Named "Id DESC" ] - Expect.equal - (streamText stream) - $"[{JsonDocument.two},{JsonDocument.three},{JsonDocument.one},{JsonDocument.four},{JsonDocument.five}]" - "The documents were not ordered correctly" + let writer = writeStream stream + try + do! conn.writeJsonAllOrdered SqliteDb.TableName writer [ Field.Named "Id DESC" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.two},{JsonDocument.three},{JsonDocument.one},{JsonDocument.four},{JsonDocument.five}]" + "The documents were not ordered correctly" + finally + writer.Complete() } ] testList "writeJsonById" [ @@ -665,9 +679,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonById SqliteDb.TableName writer "two" - Expect.equal (streamText stream) JsonDocument.two "The incorrect document was returned" + let writer = writeStream stream + try + do! conn.writeJsonById SqliteDb.TableName writer "two" + Expect.equal (streamText stream) JsonDocument.two "The incorrect document was returned" + finally + writer.Complete() } testTask "succeeds when a document is not found" { use! db = SqliteDb.BuildDb() @@ -675,9 +692,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonById SqliteDb.TableName writer "three hundred eighty-seven" - verifyNoDoc (streamText stream) + let writer = writeStream stream + try + do! conn.writeJsonById SqliteDb.TableName writer "three hundred eighty-seven" + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeJsonByFields" [ @@ -687,12 +707,15 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonByFields SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] - let json = streamText stream - verifyBeginEnd json - Expect.stringContains json JsonDocument.four "Document `four` should have been returned" - Expect.stringContains json JsonDocument.five "Document `five` should have been returned" + let writer = writeStream stream + try + do! conn.writeJsonByFields SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] + let json = streamText stream + verifyBeginEnd json + Expect.stringContains json JsonDocument.four "Document `four` should have been returned" + Expect.stringContains json JsonDocument.five "Document `five` should have been returned" + finally + writer.Complete() } testTask "succeeds when documents are found using IN with numeric field" { use! db = SqliteDb.BuildDb() @@ -700,9 +723,13 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonByFields SqliteDb.TableName writer All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ] - Expect.equal (streamText stream) $"[{JsonDocument.three}]" "There should have been one document returned" + let writer = writeStream stream + try + do! conn.writeJsonByFields SqliteDb.TableName writer All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ] + Expect.equal + (streamText stream) $"[{JsonDocument.three}]" "There should have been one document returned" + finally + writer.Complete() } testTask "succeeds when documents are not found" { use! db = SqliteDb.BuildDb() @@ -710,9 +737,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonByFields SqliteDb.TableName writer Any [ Field.Greater "NumValue" 100 ] - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! conn.writeJsonByFields SqliteDb.TableName writer Any [ Field.Greater "NumValue" 100 ] + verifyEmpty (streamText stream) + finally + writer.Complete() } testTask "succeeds for InArray when matching documents exist" { use! db = SqliteDb.BuildDb() @@ -721,15 +751,18 @@ let integrationTests = for doc in ArrayDocument.TestDocuments do do! conn.insert SqliteDb.TableName doc use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonByFields - SqliteDb.TableName writer All [ Field.InArray "Values" SqliteDb.TableName [ "c" ] ] - let json = streamText stream - verifyBeginEnd json - Expect.stringContains - json """{"Id":"first","Values":["a","b","c"]}""" "Document `first` should have been returned" - Expect.stringContains - json """{"Id":"second","Values":["c","d","e"]}""" "Document `second` should have been returned" + let writer = writeStream stream + try + do! conn.writeJsonByFields + SqliteDb.TableName writer All [ Field.InArray "Values" SqliteDb.TableName [ "c" ] ] + let json = streamText stream + verifyBeginEnd json + Expect.stringContains + json """{"Id":"first","Values":["a","b","c"]}""" "Document `first` should have been returned" + Expect.stringContains + json """{"Id":"second","Values":["c","d","e"]}""" "Document `second` should have been returned" + finally + writer.Complete() } testTask "succeeds for InArray when no matching documents exist" { use! db = SqliteDb.BuildDb() @@ -738,10 +771,13 @@ let integrationTests = for doc in ArrayDocument.TestDocuments do do! conn.insert SqliteDb.TableName doc use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonByFields - SqliteDb.TableName writer All [ Field.InArray "Values" SqliteDb.TableName [ "j" ] ] - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! conn.writeJsonByFields + SqliteDb.TableName writer All [ Field.InArray "Values" SqliteDb.TableName [ "j" ] ] + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeJsonByFieldsOrdered" [ @@ -751,11 +787,16 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonByFieldsOrdered - SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id" ] - Expect.equal - (streamText stream) $"[{JsonDocument.five},{JsonDocument.four}]" "Incorrect documents were returned" + let writer = writeStream stream + try + do! conn.writeJsonByFieldsOrdered + SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.five},{JsonDocument.four}]" + "Incorrect documents were returned" + finally + writer.Complete() } testTask "succeeds when sorting descending" { use! db = SqliteDb.BuildDb() @@ -763,11 +804,16 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonByFieldsOrdered - SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id DESC" ] - Expect.equal - (streamText stream) $"[{JsonDocument.four},{JsonDocument.five}]" "Incorrect documents were returned" + let writer = writeStream stream + try + do! conn.writeJsonByFieldsOrdered + SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id DESC" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.four},{JsonDocument.five}]" + "Incorrect documents were returned" + finally + writer.Complete() } testTask "succeeds when sorting case-sensitively" { use! db = SqliteDb.BuildDb() @@ -775,13 +821,16 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonByFieldsOrdered - SqliteDb.TableName writer All [ Field.LessOrEqual "NumValue" 10 ] [ Field.Named "Value" ] - Expect.equal - (streamText stream) - $"[{JsonDocument.three},{JsonDocument.one},{JsonDocument.two}]" - "Documents not ordered correctly" + let writer = writeStream stream + try + do! conn.writeJsonByFieldsOrdered + SqliteDb.TableName writer All [ Field.LessOrEqual "NumValue" 10 ] [ Field.Named "Value" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.three},{JsonDocument.one},{JsonDocument.two}]" + "Documents not ordered correctly" + finally + writer.Complete() } testTask "succeeds when sorting case-insensitively" { use! db = SqliteDb.BuildDb() @@ -789,13 +838,16 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonByFieldsOrdered - SqliteDb.TableName writer All [ Field.LessOrEqual "NumValue" 10 ] [ Field.Named "i:Value" ] - Expect.equal - (streamText stream) - $"[{JsonDocument.three},{JsonDocument.two},{JsonDocument.one}]" - "Documents not ordered correctly" + let writer = writeStream stream + try + do! conn.writeJsonByFieldsOrdered + SqliteDb.TableName writer All [ Field.LessOrEqual "NumValue" 10 ] [ Field.Named "i:Value" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.three},{JsonDocument.two},{JsonDocument.one}]" + "Documents not ordered correctly" + finally + writer.Complete() } ] testList "writeJsonFirstByFields" [ @@ -805,9 +857,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Value" "another" ] - Expect.equal (streamText stream) JsonDocument.two "The incorrect document was returned" + let writer = writeStream stream + try + do! conn.writeJsonFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Value" "another" ] + Expect.equal (streamText stream) JsonDocument.two "The incorrect document was returned" + finally + writer.Complete() } testTask "succeeds when multiple documents are found" { use! db = SqliteDb.BuildDb() @@ -815,11 +870,14 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Sub.Foo" "green" ] - let json = streamText stream - Expect.notEqual json "{}" "There should have been a document returned" - verifyAny json [ JsonDocument.two; JsonDocument.four ] + let writer = writeStream stream + try + do! conn.writeJsonFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Sub.Foo" "green" ] + let json = streamText stream + Expect.notEqual json "{}" "There should have been a document returned" + verifyAny json [ JsonDocument.two; JsonDocument.four ] + finally + writer.Complete() } testTask "succeeds when a document is not found" { use! db = SqliteDb.BuildDb() @@ -827,9 +885,12 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Value" "absent" ] - verifyNoDoc (streamText stream) + let writer = writeStream stream + try + do! conn.writeJsonFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Value" "absent" ] + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeJsonFirstByFieldsOrdered" [ @@ -839,10 +900,13 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonFirstByFieldsOrdered - SqliteDb.TableName writer Any [ Field.Equal "Sub.Foo" "green" ] [ Field.Named "Sub.Bar" ] - Expect.equal (streamText stream) JsonDocument.two "An incorrect document was returned" + let writer = writeStream stream + try + do! conn.writeJsonFirstByFieldsOrdered + SqliteDb.TableName writer Any [ Field.Equal "Sub.Foo" "green" ] [ Field.Named "Sub.Bar" ] + Expect.equal (streamText stream) JsonDocument.two "An incorrect document was returned" + finally + writer.Complete() } testTask "succeeds when sorting descending" { use! db = SqliteDb.BuildDb() @@ -850,10 +914,17 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeJsonFirstByFieldsOrdered - SqliteDb.TableName writer Any [ Field.Equal "Sub.Foo" "green" ] [ Field.Named "Sub.Bar DESC" ] - Expect.equal (streamText stream) JsonDocument.four "An incorrect document was returned" + let writer = writeStream stream + try + do! conn.writeJsonFirstByFieldsOrdered + SqliteDb.TableName + writer + Any + [ Field.Equal "Sub.Foo" "green" ] + [ Field.Named "Sub.Bar DESC" ] + Expect.equal (streamText stream) JsonDocument.four "An incorrect document was returned" + finally + writer.Complete() } ] testList "updateById" [ @@ -1113,17 +1184,19 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeCustomJsonArray (Query.find SqliteDb.TableName) [] writer jsonFromData - - let json = streamText stream - Expect.stringStarts json "[" "The JSON array should have started with `[`" - Expect.stringContains json JsonDocument.one "Document ID `one` should have been found" - Expect.stringContains json JsonDocument.two "Document ID `two` should have been found" - Expect.stringContains json JsonDocument.three "Document ID `three` should have been found" - Expect.stringContains json JsonDocument.four "Document ID `four` should have been found" - Expect.stringContains json JsonDocument.five "Document ID `five` should have been found" - Expect.stringEnds json "]" "The JSON array should have ended with `[`" + let writer = writeStream stream + try + do! conn.writeCustomJsonArray (Query.find SqliteDb.TableName) [] writer jsonFromData + let json = streamText stream + Expect.stringStarts json "[" "The JSON array should have started with `[`" + Expect.stringContains json JsonDocument.one "Document ID `one` should have been found" + Expect.stringContains json JsonDocument.two "Document ID `two` should have been found" + Expect.stringContains json JsonDocument.three "Document ID `three` should have been found" + Expect.stringContains json JsonDocument.four "Document ID `four` should have been found" + Expect.stringContains json JsonDocument.five "Document ID `five` should have been found" + Expect.stringEnds json "]" "The JSON array should have ended with `]`" + finally + writer.Complete() } testTask "succeeds when data is not found" { use! db = SqliteDb.BuildDb() @@ -1131,14 +1204,16 @@ let integrationTests = do! loadDocs conn use stream = new MemoryStream() - use writer = writeStream stream - do! conn.writeCustomJsonArray - $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value" - [ SqliteParameter("@value", 100) ] - writer - jsonFromData - - Expect.equal (streamText stream) "[]" "There should have been no documents returned" + let writer = writeStream stream + try + do! conn.writeCustomJsonArray + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value" + [ SqliteParameter("@value", 100) ] + writer + jsonFromData + Expect.equal (streamText stream) "[]" "There should have been no documents returned" + finally + writer.Complete() } ] testList "customSingle" [ diff --git a/src/Tests/SqliteTests.fs b/src/Tests/SqliteTests.fs index 15e5d1d..cd81442 100644 --- a/src/Tests/SqliteTests.fs +++ b/src/Tests/SqliteTests.fs @@ -1,6 +1,7 @@ module SqliteTests open System.IO +open System.IO.Pipelines open System.Text.Json open BitBadger.Documents open BitBadger.Documents.Sqlite @@ -138,9 +139,7 @@ let loadDocs () = backgroundTask { /// Set up a stream writer for a test let writeStream (stream: Stream) = - let writer = new StreamWriter(stream) - writer.AutoFlush <- true - writer + PipeWriter.Create(stream, StreamPipeWriterOptions(leaveOpen = true)) /// Get the text of the given stream let streamText (stream: Stream) = @@ -217,31 +216,35 @@ let customTests = testList "Custom" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Custom.writeJsonArray (Query.find SqliteDb.TableName) [] writer jsonFromData - - let json = streamText stream - Expect.stringStarts json "[" "The JSON array should have started with `[`" - Expect.stringContains json JsonDocument.one "Document ID `one` should have been found" - Expect.stringContains json JsonDocument.two "Document ID `two` should have been found" - Expect.stringContains json JsonDocument.three "Document ID `three` should have been found" - Expect.stringContains json JsonDocument.four "Document ID `four` should have been found" - Expect.stringContains json JsonDocument.five "Document ID `five` should have been found" - Expect.stringEnds json "]" "The JSON array should have ended with `[`" + let writer = writeStream stream + try + do! Custom.writeJsonArray (Query.find SqliteDb.TableName) [] writer jsonFromData + let json = streamText stream + Expect.stringStarts json "[" "The JSON array should have started with `[`" + Expect.stringContains json JsonDocument.one "Document ID `one` should have been found" + Expect.stringContains json JsonDocument.two "Document ID `two` should have been found" + Expect.stringContains json JsonDocument.three "Document ID `three` should have been found" + Expect.stringContains json JsonDocument.four "Document ID `four` should have been found" + Expect.stringContains json JsonDocument.five "Document ID `five` should have been found" + Expect.stringEnds json "]" "The JSON array should have ended with `[`" + finally + writer.Complete() } testTask "succeeds when data is not found" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Custom.writeJsonArray - $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value" - [ SqliteParameter("@value", 100) ] - writer - jsonFromData - - Expect.equal (streamText stream) "[]" "There should have been no documents returned" + let writer = writeStream stream + try + do! Custom.writeJsonArray + $"SELECT data FROM {SqliteDb.TableName} WHERE data ->> 'NumValue' > @value" + [ SqliteParameter("@value", 100) ] + writer + jsonFromData + Expect.equal (streamText stream) "[]" "There should have been no documents returned" + finally + writer.Complete() } ] testList "single" [ @@ -975,20 +978,26 @@ let jsonTests = testList "Json" [ do! insert SqliteDb.TableName { Foo = "five"; Bar = "six" } use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeAll SqliteDb.TableName writer - let json = streamText stream - verifyBeginEnd json - Expect.stringContains json """{"Foo":"one","Bar":"two"}""" "The first document was not found" - Expect.stringContains json """{"Foo":"three","Bar":"four"}""" "The second document was not found" - Expect.stringContains json """{"Foo":"five","Bar":"six"}""" "The third document was not found" + let writer = writeStream stream + try + do! Json.writeAll SqliteDb.TableName writer + let json = streamText stream + verifyBeginEnd json + Expect.stringContains json """{"Foo":"one","Bar":"two"}""" "The first document was not found" + Expect.stringContains json """{"Foo":"three","Bar":"four"}""" "The second document was not found" + Expect.stringContains json """{"Foo":"five","Bar":"six"}""" "The third document was not found" + finally + writer.Complete() } testTask "succeeds when there is no data" { use! db = SqliteDb.BuildDb() use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeAll SqliteDb.TableName writer - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! Json.writeAll SqliteDb.TableName writer + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeAllOrdered" [ @@ -997,36 +1006,45 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeAllOrdered SqliteDb.TableName writer [ Field.Named "n:NumValue" ] - Expect.equal - (streamText stream) - $"[{JsonDocument.one},{JsonDocument.three},{JsonDocument.two},{JsonDocument.four},{JsonDocument.five}]" - "The documents were not ordered correctly" + let writer = writeStream stream + try + do! Json.writeAllOrdered SqliteDb.TableName writer [ Field.Named "n:NumValue" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.one},{JsonDocument.three},{JsonDocument.two},{JsonDocument.four},{JsonDocument.five}]" + "The documents were not ordered correctly" + finally + writer.Complete() } testTask "succeeds when ordering numerically descending" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeAllOrdered SqliteDb.TableName writer [ Field.Named "n:NumValue DESC" ] - Expect.equal - (streamText stream) - $"[{JsonDocument.five},{JsonDocument.four},{JsonDocument.two},{JsonDocument.three},{JsonDocument.one}]" - "The documents were not ordered correctly" + let writer = writeStream stream + try + do! Json.writeAllOrdered SqliteDb.TableName writer [ Field.Named "n:NumValue DESC" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.five},{JsonDocument.four},{JsonDocument.two},{JsonDocument.three},{JsonDocument.one}]" + "The documents were not ordered correctly" + finally + writer.Complete() } testTask "succeeds when ordering alphabetically" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeAllOrdered SqliteDb.TableName writer [ Field.Named "Id DESC" ] - Expect.equal - (streamText stream) - $"[{JsonDocument.two},{JsonDocument.three},{JsonDocument.one},{JsonDocument.four},{JsonDocument.five}]" - "The documents were not ordered correctly" + let writer = writeStream stream + try + do! Json.writeAllOrdered SqliteDb.TableName writer [ Field.Named "Id DESC" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.two},{JsonDocument.three},{JsonDocument.one},{JsonDocument.four},{JsonDocument.five}]" + "The documents were not ordered correctly" + finally + writer.Complete() } ] testList "writeById" [ @@ -1035,18 +1053,24 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeById SqliteDb.TableName writer "two" - Expect.equal (streamText stream) JsonDocument.two "The incorrect document was returned" + let writer = writeStream stream + try + do! Json.writeById SqliteDb.TableName writer "two" + Expect.equal (streamText stream) JsonDocument.two "The incorrect document was returned" + finally + writer.Complete() } testTask "succeeds when a document is not found" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeById SqliteDb.TableName writer "three hundred eighty-seven" - verifyNoDoc (streamText stream) + let writer = writeStream stream + try + do! Json.writeById SqliteDb.TableName writer "three hundred eighty-seven" + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeByFields" [ @@ -1055,30 +1079,40 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFields SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] - let json = streamText stream - verifyBeginEnd json - Expect.stringContains json JsonDocument.four "Document `four` should have been returned" - Expect.stringContains json JsonDocument.five "Document `five` should have been returned" + let writer = writeStream stream + try + do! Json.writeByFields SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] + let json = streamText stream + verifyBeginEnd json + Expect.stringContains json JsonDocument.four "Document `four` should have been returned" + Expect.stringContains json JsonDocument.five "Document `five` should have been returned" + finally + writer.Complete() } testTask "succeeds when documents are found using IN with numeric field" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFields SqliteDb.TableName writer All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ] - Expect.equal (streamText stream) $"[{JsonDocument.three}]" "There should have been one document returned" + let writer = writeStream stream + try + do! Json.writeByFields SqliteDb.TableName writer All [ Field.In "NumValue" [ 2; 4; 6; 8 ] ] + Expect.equal + (streamText stream) $"[{JsonDocument.three}]" "There should have been one document returned" + finally + writer.Complete() } testTask "succeeds when documents are not found" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFields SqliteDb.TableName writer Any [ Field.Greater "NumValue" 100 ] - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! Json.writeByFields SqliteDb.TableName writer Any [ Field.Greater "NumValue" 100 ] + verifyEmpty (streamText stream) + finally + writer.Complete() } testTask "succeeds for InArray when matching documents exist" { use! db = SqliteDb.BuildDb() @@ -1086,14 +1120,18 @@ let jsonTests = testList "Json" [ for doc in ArrayDocument.TestDocuments do do! insert SqliteDb.TableName doc use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFields SqliteDb.TableName writer All [ Field.InArray "Values" SqliteDb.TableName [ "c" ] ] - let json = streamText stream - verifyBeginEnd json - Expect.stringContains - json """{"Id":"first","Values":["a","b","c"]}""" "Document `first` should have been returned" - Expect.stringContains - json """{"Id":"second","Values":["c","d","e"]}""" "Document `second` should have been returned" + let writer = writeStream stream + try + do! Json.writeByFields + SqliteDb.TableName writer All [ Field.InArray "Values" SqliteDb.TableName [ "c" ] ] + let json = streamText stream + verifyBeginEnd json + Expect.stringContains + json """{"Id":"first","Values":["a","b","c"]}""" "Document `first` should have been returned" + Expect.stringContains + json """{"Id":"second","Values":["c","d","e"]}""" "Document `second` should have been returned" + finally + writer.Complete() } testTask "succeeds for InArray when no matching documents exist" { use! db = SqliteDb.BuildDb() @@ -1101,9 +1139,13 @@ let jsonTests = testList "Json" [ for doc in ArrayDocument.TestDocuments do do! insert SqliteDb.TableName doc use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFields SqliteDb.TableName writer All [ Field.InArray "Values" SqliteDb.TableName [ "j" ] ] - verifyEmpty (streamText stream) + let writer = writeStream stream + try + do! Json.writeByFields + SqliteDb.TableName writer All [ Field.InArray "Values" SqliteDb.TableName [ "j" ] ] + verifyEmpty (streamText stream) + finally + writer.Complete() } ] testList "writeByFieldsOrdered" [ @@ -1112,48 +1154,60 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFieldsOrdered - SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id" ] - Expect.equal - (streamText stream) $"[{JsonDocument.five},{JsonDocument.four}]" "Incorrect documents were returned" + let writer = writeStream stream + try + do! Json.writeByFieldsOrdered + SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id" ] + Expect.equal + (streamText stream) $"[{JsonDocument.five},{JsonDocument.four}]" "Incorrect documents were returned" + finally + writer.Complete() } testTask "succeeds when sorting descending" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFieldsOrdered - SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id DESC" ] - Expect.equal - (streamText stream) $"[{JsonDocument.four},{JsonDocument.five}]" "Incorrect documents were returned" + let writer = writeStream stream + try + do! Json.writeByFieldsOrdered + SqliteDb.TableName writer Any [ Field.Greater "NumValue" 15 ] [ Field.Named "Id DESC" ] + Expect.equal + (streamText stream) $"[{JsonDocument.four},{JsonDocument.five}]" "Incorrect documents were returned" + finally + writer.Complete() } testTask "succeeds when sorting case-sensitively" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFieldsOrdered - SqliteDb.TableName writer All [ Field.LessOrEqual "NumValue" 10 ] [ Field.Named "Value" ] - Expect.equal - (streamText stream) - $"[{JsonDocument.three},{JsonDocument.one},{JsonDocument.two}]" - "Documents not ordered correctly" + let writer = writeStream stream + try + do! Json.writeByFieldsOrdered + SqliteDb.TableName writer All [ Field.LessOrEqual "NumValue" 10 ] [ Field.Named "Value" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.three},{JsonDocument.one},{JsonDocument.two}]" + "Documents not ordered correctly" + finally + writer.Complete() } testTask "succeeds when sorting case-insensitively" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeByFieldsOrdered - SqliteDb.TableName writer All [ Field.LessOrEqual "NumValue" 10 ] [ Field.Named "i:Value" ] - Expect.equal - (streamText stream) - $"[{JsonDocument.three},{JsonDocument.two},{JsonDocument.one}]" - "Documents not ordered correctly" + let writer = writeStream stream + try + do! Json.writeByFieldsOrdered + SqliteDb.TableName writer All [ Field.LessOrEqual "NumValue" 10 ] [ Field.Named "i:Value" ] + Expect.equal + (streamText stream) + $"[{JsonDocument.three},{JsonDocument.two},{JsonDocument.one}]" + "Documents not ordered correctly" + finally + writer.Complete() } ] testList "writeFirstByFields" [ @@ -1162,29 +1216,38 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Value" "another" ] - Expect.equal (streamText stream) JsonDocument.two "The incorrect document was returned" + let writer = writeStream stream + try + do! Json.writeFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Value" "another" ] + Expect.equal (streamText stream) JsonDocument.two "The incorrect document was returned" + finally + writer.Complete() } testTask "succeeds when multiple documents are found" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Sub.Foo" "green" ] - let json = streamText stream - Expect.notEqual json "{}" "There should have been a document returned" - verifyAny json [ JsonDocument.two; JsonDocument.four ] + let writer = writeStream stream + try + do! Json.writeFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Sub.Foo" "green" ] + let json = streamText stream + Expect.notEqual json "{}" "There should have been a document returned" + verifyAny json [ JsonDocument.two; JsonDocument.four ] + finally + writer.Complete() } testTask "succeeds when a document is not found" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Value" "absent" ] - verifyNoDoc (streamText stream) + let writer = writeStream stream + try + do! Json.writeFirstByFields SqliteDb.TableName writer Any [ Field.Equal "Value" "absent" ] + verifyNoDoc (streamText stream) + finally + writer.Complete() } ] testList "writeFirstByFieldsOrdered" [ @@ -1193,20 +1256,26 @@ let jsonTests = testList "Json" [ do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByFieldsOrdered - SqliteDb.TableName writer Any [ Field.Equal "Sub.Foo" "green" ] [ Field.Named "Sub.Bar" ] - Expect.equal (streamText stream) JsonDocument.two "An incorrect document was returned" + let writer = writeStream stream + try + do! Json.writeFirstByFieldsOrdered + SqliteDb.TableName writer Any [ Field.Equal "Sub.Foo" "green" ] [ Field.Named "Sub.Bar" ] + Expect.equal (streamText stream) JsonDocument.two "An incorrect document was returned" + finally + writer.Complete() } testTask "succeeds when sorting descending" { use! db = SqliteDb.BuildDb() do! loadDocs () use stream = new MemoryStream() - use writer = writeStream stream - do! Json.writeFirstByFieldsOrdered - SqliteDb.TableName writer Any [ Field.Equal "Sub.Foo" "green" ] [ Field.Named "Sub.Bar DESC" ] - Expect.equal (streamText stream) JsonDocument.four "An incorrect document was returned" + let writer = writeStream stream + try + do! Json.writeFirstByFieldsOrdered + SqliteDb.TableName writer Any [ Field.Equal "Sub.Foo" "green" ] [ Field.Named "Sub.Bar DESC" ] + Expect.equal (streamText stream) JsonDocument.four "An incorrect document was returned" + finally + writer.Complete() } ] ]