Add missing index function for SQLite

- Add toCount and toExists for SQLite results
This commit is contained in:
Daniel J. Summers 2023-12-31 07:29:26 -05:00
parent e4add06648
commit 52c00d2485
6 changed files with 104 additions and 53 deletions

View File

@ -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
[<Extension>]
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
[<Extension>]

View File

@ -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<SqliteDataReader, 'TDoc>) = backgroundTask {
let! results = toCustomList<'TDoc> cmd mapFunc.Invoke
return ResizeArray<'TDoc> results
}
/// Create a list of items for the results of the given command
[<CompiledName "FSharpToDocumentList">]
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
[<CompiledName "ToCount">]
let toCount (row: SqliteDataReader) =
row.GetInt64 0
/// Extract a true/false value from a count in the first column
[<CompiledName "ToExists">]
let toExists row =
toCount(row) > 0L
[<AutoOpen>]
@ -203,8 +198,8 @@ module WithConn =
}
/// Create an index on a document table
[<CompiledName "EnsureIndex">]
let ensureIndex tableName indexName fields conn =
[<CompiledName "EnsureFieldIndex">]
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
[<CompiledName "All">]
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
[<CompiledName "ByField">]
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
[<RequireQualifiedAccess>]
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
[<CompiledName "ById">]
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
[<CompiledName "ByField">]
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
[<RequireQualifiedAccess>]
@ -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
[<CompiledName "EnsureFieldIndex">]
let ensureFieldIndex tableName indexName fields =
use conn = Configuration.dbConn ()
WithConn.Definition.ensureFieldIndex tableName indexName fields conn
/// Document insert/save functions
[<AutoOpen>]

View File

@ -108,12 +108,9 @@ public static class SqliteCSharpExtensionTests
await using var conn = Sqlite.Configuration.DbConn();
Func<string, ValueTask<bool>> 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 () =>

View File

@ -200,11 +200,25 @@ public static class SqliteCSharpTests
async ValueTask<bool> 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[]

View File

@ -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()

View File

@ -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" {