Add case-insensitive ordering

This commit is contained in:
Daniel J. Summers 2024-08-21 21:03:38 -04:00
parent 2c24e2e912
commit 27b8a83a7a
5 changed files with 81 additions and 6 deletions

View File

@ -401,10 +401,13 @@ module Query =
{ it with Name = parts[0] }, Some $" {parts[1]}" { it with Name = parts[0] }, Some $" {parts[1]}"
else it, None) else it, None)
|> Seq.map (fun (field, direction) -> |> Seq.map (fun (field, direction) ->
match dialect, field.Name.StartsWith "n:" with if field.Name.StartsWith "n:" then
| PostgreSQL, true -> $"({ { field with Name = field.Name[2..] }.Path PostgreSQL})::numeric" let f = { field with Name = field.Name[2..] }
| SQLite, true -> { field with Name = field.Name[2..] }.Path SQLite match dialect with PostgreSQL -> $"({f.Path PostgreSQL})::numeric" | SQLite -> f.Path SQLite
| _, _ -> field.Path dialect elif field.Name.StartsWith "i:" then
let p = { field with Name = field.Name[2..] }.Path dialect
match dialect with PostgreSQL -> $"LOWER({p})" | SQLite -> $"{p} COLLATE NOCASE"
else field.Path dialect
|> function path -> path + defaultArg direction "") |> function path -> path + defaultArg direction "")
|> String.concat ", " |> String.concat ", "
|> function it -> $" ORDER BY {it}" |> function it -> $" ORDER BY {it}"

View File

@ -613,6 +613,18 @@ public static class CommonCSharpTests
{ {
Expect.equal(Query.OrderBy([Field.Named("n:Test")], Dialect.SQLite), " ORDER BY data->>'Test'", Expect.equal(Query.OrderBy([Field.Named("n:Test")], Dialect.SQLite), " ORDER BY data->>'Test'",
"Order By not constructed correctly for numeric field"); "Order By not constructed correctly for numeric field");
}),
TestCase("succeeds for PostgreSQL case-insensitive ordering", () =>
{
Expect.equal(Query.OrderBy([Field.Named("i:Test.Field DESC")], Dialect.PostgreSQL),
" ORDER BY LOWER(data#>>'{Test,Field}') DESC",
"Order By not constructed correctly for case-insensitive field");
}),
TestCase("succeeds for SQLite case-insensitive ordering", () =>
{
Expect.equal(Query.OrderBy([Field.Named("i:Test.Field ASC")], Dialect.SQLite),
" ORDER BY data->>'Test'->>'Field' COLLATE NOCASE ASC",
"Order By not constructed correctly for case-insensitive field");
}) })
]) ])
]); ]);

View File

@ -627,8 +627,9 @@ public static class SqliteCSharpTests
var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.GT("NumValue", 15)], [Field.Named("Id")]); [Field.GT("NumValue", 15)], [Field.Named("Id")]);
Expect.hasLength(docs, 2, "There should have been two documents returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "five|four",
"There should have been two documents returned"); "The documents were not sorted correctly");
}), }),
TestCase("succeeds when documents are not found", async () => TestCase("succeeds when documents are not found", async () =>
{ {
@ -637,8 +638,31 @@ public static class SqliteCSharpTests
var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any, var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.GT("NumValue", 15)], [Field.Named("Id DESC")]); [Field.GT("NumValue", 15)], [Field.Named("Id DESC")]);
Expect.hasLength(docs, 2, "There should have been two documents returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five", Expect.equal(string.Join('|', docs.Select(x => x.Id)), "four|five",
"There should have been two documents returned"); "The documents were not sorted correctly");
}),
TestCase("succeeds when sorting case-sensitively", async () =>
{
await using var db = await SqliteDb.BuildDb();
await LoadDocs();
var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.LE("NumValue", 10)], [Field.Named("Value")]);
Expect.hasLength(docs, 3, "There should have been three documents returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "three|one|two",
"The documents were not sorted correctly");
}),
TestCase("succeeds when sorting case-insensitively", async () =>
{
await using var db = await SqliteDb.BuildDb();
await LoadDocs();
var docs = await Find.ByFieldsOrdered<JsonDocument>(SqliteDb.TableName, FieldMatch.Any,
[Field.LE("NumValue", 10)], [Field.Named("i:Value")]);
Expect.hasLength(docs, 3, "There should have been three documents returned");
Expect.equal(string.Join('|', docs.Select(x => x.Id)), "three|two|one",
"The documents were not sorted correctly");
}) })
]), ]),
TestList("FirstByFields", TestList("FirstByFields",

View File

@ -450,6 +450,18 @@ let queryTests = testList "Query" [
" ORDER BY data->>'Test'" " ORDER BY data->>'Test'"
"Order By not constructed correctly for numeric field" "Order By not constructed correctly for numeric field"
} }
test "succeeds for PostgreSQL case-insensitive ordering" {
Expect.equal
(Query.orderBy [ Field.Named "i:Test.Field DESC" ] PostgreSQL)
" ORDER BY LOWER(data#>>'{Test,Field}') DESC"
"Order By not constructed correctly for case-insensitive field"
}
test "succeeds for SQLite case-insensitive ordering" {
Expect.equal
(Query.orderBy [ Field.Named "i:Test.Field ASC" ] SQLite)
" ORDER BY data->>'Test'->>'Field' COLLATE NOCASE ASC"
"Order By not constructed correctly for case-insensitive field"
}
] ]
] ]

View File

@ -527,6 +527,7 @@ let findTests = testList "Find" [
let! docs = let! docs =
Find.byFieldsOrdered<JsonDocument> Find.byFieldsOrdered<JsonDocument>
SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id" ] SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id" ]
Expect.hasLength docs 2 "There should have been two documents returned"
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "five|four" "The documents were not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "five|four" "The documents were not ordered correctly"
} }
@ -537,9 +538,32 @@ let findTests = testList "Find" [
let! docs = let! docs =
Find.byFieldsOrdered<JsonDocument> Find.byFieldsOrdered<JsonDocument>
SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id DESC" ] SqliteDb.TableName Any [ Field.GT "NumValue" 15 ] [ Field.Named "Id DESC" ]
Expect.hasLength docs 2 "There should have been two documents returned"
Expect.equal Expect.equal
(docs |> List.map _.Id |> String.concat "|") "four|five" "The documents were not ordered correctly" (docs |> List.map _.Id |> String.concat "|") "four|five" "The documents were not ordered correctly"
} }
testTask "succeeds when sorting case-sensitively" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let! docs =
Find.byFieldsOrdered<JsonDocument>
SqliteDb.TableName All [ Field.LE "NumValue" 10 ] [ Field.Named "Value" ]
Expect.hasLength docs 3 "There should have been three documents returned"
Expect.equal
(docs |> List.map _.Id |> String.concat "|") "three|one|two" "Documents not ordered correctly"
}
testTask "succeeds when sorting case-insensitively" {
use! db = SqliteDb.BuildDb()
do! loadDocs ()
let! docs =
Find.byFieldsOrdered<JsonDocument>
SqliteDb.TableName All [ Field.LE "NumValue" 10 ] [ Field.Named "i:Value" ]
Expect.hasLength docs 3 "There should have been three documents returned"
Expect.equal
(docs |> List.map _.Id |> String.concat "|") "three|two|one" "Documents not ordered correctly"
}
] ]
testList "firstByFields" [ testList "firstByFields" [
testTask "succeeds when a document is found" { testTask "succeeds when a document is found" {