diff --git a/src/Sqlite/Extensions.fs b/src/Sqlite/Extensions.fs index 509669c..91304b5 100644 --- a/src/Sqlite/Extensions.fs +++ b/src/Sqlite/Extensions.fs @@ -29,8 +29,8 @@ module Extensions = WithConn.Definition.ensureTable name conn /// Create an index on a document table - member conn.ensureIndex tableName indexName fields = - WithConn.Definition.ensureIndex tableName indexName fields conn + member conn.ensureFieldIndex tableName indexName fields = + WithConn.Definition.ensureFieldIndex tableName indexName fields conn /// Insert a new document member conn.insert<'TDoc> tableName (document: 'TDoc) = @@ -131,8 +131,8 @@ type SqliteConnectionCSharpExtensions = /// Create an index on one or more fields in a document table [] - static member inline EnsureIndex(conn, tableName, indexName, fields) = - WithConn.Definition.ensureIndex tableName indexName fields conn + static member inline EnsureFieldIndex(conn, tableName, indexName, fields) = + WithConn.Definition.ensureFieldIndex tableName indexName fields conn /// Insert a new document [] diff --git a/src/Sqlite/Library.fs b/src/Sqlite/Library.fs index c80ad11..6a9c4a2 100644 --- a/src/Sqlite/Library.fs +++ b/src/Sqlite/Library.fs @@ -103,21 +103,16 @@ module Results = it <- Seq.append it (Seq.singleton (mapFunc rdr)) return List.ofSeq it } - - /// Create a list of items for the results of the given command, using the specified mapping function - let ToCustomList<'TDoc>(cmd, mapFunc: System.Func) = backgroundTask { - let! results = toCustomList<'TDoc> cmd mapFunc.Invoke - return ResizeArray<'TDoc> results - } - - /// Create a list of items for the results of the given command - [] - let toDocumentList<'TDoc> (cmd: SqliteCommand) = - toCustomList<'TDoc> cmd fromData - - /// Create a list of items for the results of the given command - let ToDocumentList<'TDoc> cmd = - ToCustomList<'TDoc>(cmd, fromData<'TDoc>) + + /// Extract a count from the first column + [] + let toCount (row: SqliteDataReader) = + row.GetInt64 0 + + /// Extract a true/false value from a count in the first column + [] + let toExists row = + toCount(row) > 0L [] @@ -203,8 +198,8 @@ module WithConn = } /// Create an index on a document table - [] - let ensureIndex tableName indexName fields conn = + [] + let ensureFieldIndex tableName indexName fields conn = Custom.nonQuery (Query.Definition.ensureIndexOn tableName indexName fields) [] conn /// Insert a new document @@ -224,30 +219,26 @@ module WithConn = /// Count all documents in a table [] let all tableName conn = - Custom.scalar (Query.Count.all tableName) [] (_.GetInt64(0)) conn + Custom.scalar (Query.Count.all tableName) [] toCount conn /// Count matching documents using a comparison on a JSON field [] let byField tableName fieldName op (value: obj) conn = - Custom.scalar (Query.Count.byField tableName fieldName op) [ fieldParam value ] (_.GetInt64(0)) conn + Custom.scalar (Query.Count.byField tableName fieldName op) [ fieldParam value ] toCount conn /// Commands to determine if documents exist [] module Exists = - /// SQLite returns a 0 for not-exists and 1 for exists - let private exists (rdr: SqliteDataReader) = - rdr.GetInt64(0) > 0 - /// Determine if a document exists for the given ID [] let byId tableName (docId: 'TKey) conn = - Custom.scalar (Query.Exists.byId tableName) [ idParam docId ] exists conn + Custom.scalar (Query.Exists.byId tableName) [ idParam docId ] toExists conn /// Determine if a document exists using a comparison on a JSON field [] let byField tableName fieldName op (value: obj) conn = - Custom.scalar (Query.Exists.byField tableName fieldName op) [ fieldParam value ] exists conn + Custom.scalar (Query.Exists.byField tableName fieldName op) [ fieldParam value ] toExists conn /// Commands to retrieve documents [] @@ -391,6 +382,12 @@ module Definition = let ensureTable name = use conn = Configuration.dbConn () WithConn.Definition.ensureTable name conn + + /// Create an index on a document table + [] + let ensureFieldIndex tableName indexName fields = + use conn = Configuration.dbConn () + WithConn.Definition.ensureFieldIndex tableName indexName fields conn /// Document insert/save functions [] diff --git a/src/Tests.CSharp/SqliteCSharpExtensionTests.cs b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs index e48def8..cc5fb5f 100644 --- a/src/Tests.CSharp/SqliteCSharpExtensionTests.cs +++ b/src/Tests.CSharp/SqliteCSharpExtensionTests.cs @@ -108,12 +108,9 @@ public static class SqliteCSharpExtensionTests await using var conn = Sqlite.Configuration.DbConn(); Func> itExists = async name => - { - var result = await conn.CustomScalar( + await conn.CustomScalar( $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it", - new SqliteParameter[] { new("@name", name) }, rdr => rdr.GetInt64(0)); - return result > 0L; - }; + new SqliteParameter[] { new("@name", name) }, Results.ToExists); var exists = await itExists("ensured"); var alsoExists = await itExists("idx_ensured_key"); @@ -127,6 +124,22 @@ public static class SqliteCSharpExtensionTests Expect.isTrue(exists, "The table should now exist"); Expect.isTrue(alsoExists, "The key index should now exist"); }), + TestCase("EnsureFieldIndex succeeds", async () => + { + await using var db = await SqliteDb.BuildDb(); + await using var conn = Sqlite.Configuration.DbConn(); + var indexExists = () => conn.CustomScalar( + $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it", + Parameters.None, Results.ToExists); + + var exists = await indexExists(); + Expect.isFalse(exists, "The index should not exist already"); + + await conn.EnsureTable("ensured"); + await conn.EnsureFieldIndex("ensured", "test", new[] { "Id", "Category" }); + exists = await indexExists(); + Expect.isTrue(exists, "The index should now exist"); + }), TestList("Insert", new[] { TestCase("succeeds", async () => diff --git a/src/Tests.CSharp/SqliteCSharpTests.cs b/src/Tests.CSharp/SqliteCSharpTests.cs index 9e68118..f2e0621 100644 --- a/src/Tests.CSharp/SqliteCSharpTests.cs +++ b/src/Tests.CSharp/SqliteCSharpTests.cs @@ -200,11 +200,25 @@ public static class SqliteCSharpTests async ValueTask ItExists(string name) { - var result = await Custom.Scalar( + return await Custom.Scalar( $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it", - new SqliteParameter[] { new("@name", name) }, rdr => rdr.GetInt64(0)); - return result > 0L; + new SqliteParameter[] { new("@name", name) }, Results.ToExists); } + }), + TestCase("EnsureFieldIndex succeeds", async () => + { + await using var db = await SqliteDb.BuildDb(); + var indexExists = () => Custom.Scalar( + $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it", + Parameters.None, Results.ToExists); + + var exists = await indexExists(); + Expect.isFalse(exists, "The index should not exist already"); + + await Definition.EnsureTable("ensured"); + await Definition.EnsureFieldIndex("ensured", "test", new[] { "Id", "Category" }); + exists = await indexExists(); + Expect.isTrue(exists, "The index should now exist"); }) }), TestList("Document.Insert", new[] diff --git a/src/Tests/SqliteExtensionTests.fs b/src/Tests/SqliteExtensionTests.fs index d53c72c..4c6e2b5 100644 --- a/src/Tests/SqliteExtensionTests.fs +++ b/src/Tests/SqliteExtensionTests.fs @@ -16,14 +16,11 @@ let integrationTests = testTask "ensureTable succeeds" { use! db = SqliteDb.BuildDb() use conn = Configuration.dbConn () - let itExists (name: string) = task { - let! result = - conn.customScalar - $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it" - [ SqliteParameter("@name", name) ] - _.GetInt64(0) - return result > 0 - } + let itExists (name: string) = + conn.customScalar + $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it" + [ SqliteParameter("@name", name) ] + toExists let! exists = itExists "ensured" let! alsoExists = itExists "idx_ensured_key" @@ -36,6 +33,23 @@ let integrationTests = Expect.isTrue exists' "The table should now exist" Expect.isTrue alsoExists' "The key index should now exist" } + testTask "ensureFieldIndex succeeds" { + use! db = SqliteDb.BuildDb() + use conn = Configuration.dbConn () + let indexExists () = + conn.customScalar + $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it" + [] + toExists + + let! exists = indexExists () + Expect.isFalse exists "The index should not exist already" + + do! conn.ensureTable "ensured" + do! conn.ensureFieldIndex "ensured" "test" [ "Name"; "Age" ] + let! exists' = indexExists () + Expect.isTrue exists' "The index should now exist" + } testList "insert" [ testTask "succeeds" { use! db = SqliteDb.BuildDb() diff --git a/src/Tests/SqliteTests.fs b/src/Tests/SqliteTests.fs index 14dfee3..caaa437 100644 --- a/src/Tests/SqliteTests.fs +++ b/src/Tests/SqliteTests.fs @@ -184,14 +184,11 @@ let integrationTests = testList "Definition" [ testTask "ensureTable succeeds" { use! db = SqliteDb.BuildDb() - let itExists (name: string) = task { - let! result = - Custom.scalar - $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it" - [ SqliteParameter("@name", name) ] - _.GetInt64(0) - return result > 0 - } + let itExists (name: string) = + Custom.scalar + $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = @name) AS it" + [ SqliteParameter("@name", name) ] + toExists let! exists = itExists "ensured" let! alsoExists = itExists "idx_ensured_key" @@ -204,6 +201,22 @@ let integrationTests = Expect.isTrue exists' "The table should now exist" Expect.isTrue alsoExists' "The key index should now exist" } + testTask "ensureFieldIndex succeeds" { + use! db = SqliteDb.BuildDb() + let indexExists () = + Custom.scalar + $"SELECT EXISTS (SELECT 1 FROM {SqliteDb.Catalog} WHERE name = 'idx_ensured_test') AS it" + [] + toExists + + let! exists = indexExists () + Expect.isFalse exists "The index should not exist already" + + do! Definition.ensureTable "ensured" + do! Definition.ensureFieldIndex "ensured" "test" [ "Name"; "Age" ] + let! exists' = indexExists () + Expect.isTrue exists' "The index should now exist" + } ] testList "insert" [ testTask "succeeds" {