Final tweaks for v4 (#9)
- Add .NET 9, PostgreSQL 17 support - Drop .NET 6, PostgreSQL 12 support - Finalize READMEs Reviewed-on: #9
This commit was merged in pull request #9.
This commit is contained in:
@@ -14,8 +14,9 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Npgsql.FSharp" Version="5.7.0" />
|
||||
<PackageReference Update="FSharp.Core" Version="8.0.300" />
|
||||
<PackageReference Include="Npgsql" Version="9.0.2" />
|
||||
<PackageReference Include="Npgsql.FSharp" Version="8.0.0" />
|
||||
<PackageReference Update="FSharp.Core" Version="9.0.100" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -71,7 +71,7 @@ module WithProps =
|
||||
|
||||
/// Retrieve the first document matching a JSON field comparison (->> =); returns null if not found
|
||||
[<System.Obsolete "Use FirstByFields instead ~ will be removed in v4.1">]
|
||||
let FirstByField<'TDoc when 'TDoc: null>(tableName, field, sqlProps) =
|
||||
let FirstByField<'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, field, sqlProps) =
|
||||
WithProps.Find.FirstByFields<'TDoc>(tableName, Any, Seq.singleton field, sqlProps)
|
||||
|
||||
[<RequireQualifiedAccess>]
|
||||
@@ -144,7 +144,7 @@ module Find =
|
||||
|
||||
/// Retrieve the first document matching a JSON field comparison (->> =); returns null if not found
|
||||
[<System.Obsolete "Use FirstByFields instead ~ will be removed in v4.1">]
|
||||
let FirstByField<'TDoc when 'TDoc: null>(tableName, field) =
|
||||
let FirstByField<'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, field) =
|
||||
Find.FirstByFields<'TDoc>(tableName, Any, Seq.singleton field)
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ type NpgsqlConnectionCSharpCompatExtensions =
|
||||
/// Retrieve the first document matching a JSON field comparison query (->> =); returns null if not found
|
||||
[<Extension>]
|
||||
[<System.Obsolete "Use FindFirstByFields instead ~ will be removed in v4.1">]
|
||||
static member inline FindFirstByField<'TDoc when 'TDoc: null>(conn, tableName, field) =
|
||||
static member inline FindFirstByField<'TDoc when 'TDoc: null and 'TDoc: not struct>(conn, tableName, field) =
|
||||
WithProps.Find.FirstByFields<'TDoc>(tableName, Any, [ field ], Sql.existingConnection conn)
|
||||
|
||||
/// Patch documents using a JSON field comparison query in the WHERE clause (->> =)
|
||||
|
||||
@@ -211,7 +211,7 @@ type NpgsqlConnectionCSharpExtensions =
|
||||
|
||||
/// Execute a query that returns one or no results; returns None if not found
|
||||
[<Extension>]
|
||||
static member inline CustomSingle<'TDoc when 'TDoc: null>(
|
||||
static member inline CustomSingle<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
conn, query, parameters, mapFunc: System.Func<RowReader, 'TDoc>) =
|
||||
WithProps.Custom.Single<'TDoc>(query, parameters, mapFunc, Sql.existingConnection conn)
|
||||
|
||||
@@ -303,7 +303,7 @@ type NpgsqlConnectionCSharpExtensions =
|
||||
|
||||
/// Retrieve a document by its ID; returns None if not found
|
||||
[<Extension>]
|
||||
static member inline FindById<'TKey, 'TDoc when 'TDoc: null>(conn, tableName, docId: 'TKey) =
|
||||
static member inline FindById<'TKey, 'TDoc when 'TDoc: null and 'TDoc: not struct>(conn, tableName, docId: 'TKey) =
|
||||
WithProps.Find.ById<'TKey, 'TDoc>(tableName, docId, Sql.existingConnection conn)
|
||||
|
||||
/// Retrieve documents matching a JSON field comparison query (->> =)
|
||||
@@ -339,38 +339,41 @@ type NpgsqlConnectionCSharpExtensions =
|
||||
|
||||
/// Retrieve the first document matching a JSON field comparison query (->> =); returns null if not found
|
||||
[<Extension>]
|
||||
static member inline FindFirstByFields<'TDoc when 'TDoc: null>(conn, tableName, howMatched, fields) =
|
||||
static member inline FindFirstByFields<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
conn, tableName, howMatched, fields) =
|
||||
WithProps.Find.FirstByFields<'TDoc>(tableName, howMatched, fields, Sql.existingConnection conn)
|
||||
|
||||
/// Retrieve the first document matching a JSON field comparison query (->> =) ordered by the given fields in the
|
||||
/// document; returns null if not found
|
||||
[<Extension>]
|
||||
static member inline FindFirstByFieldsOrdered<'TDoc when 'TDoc: null>(
|
||||
static member inline FindFirstByFieldsOrdered<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
conn, tableName, howMatched, queryFields, orderFields) =
|
||||
WithProps.Find.FirstByFieldsOrdered<'TDoc>(
|
||||
tableName, howMatched, queryFields, orderFields, Sql.existingConnection conn)
|
||||
|
||||
/// Retrieve the first document matching a JSON containment query (@>); returns None if not found
|
||||
[<Extension>]
|
||||
static member inline FindFirstByContains<'TDoc when 'TDoc: null>(conn, tableName, criteria: obj) =
|
||||
static member inline FindFirstByContains<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
conn, tableName, criteria: obj) =
|
||||
WithProps.Find.FirstByContains<'TDoc>(tableName, criteria, Sql.existingConnection conn)
|
||||
|
||||
/// Retrieve the first document matching a JSON containment query (@>) ordered by the given fields in the document;
|
||||
/// returns None if not found
|
||||
[<Extension>]
|
||||
static member inline FindFirstByContainsOrdered<'TDoc when 'TDoc: null>(
|
||||
static member inline FindFirstByContainsOrdered<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
conn, tableName, criteria: obj, orderFields) =
|
||||
WithProps.Find.FirstByContainsOrdered<'TDoc>(tableName, criteria, orderFields, Sql.existingConnection conn)
|
||||
|
||||
/// Retrieve the first document matching a JSON Path match query (@?); returns None if not found
|
||||
[<Extension>]
|
||||
static member inline FindFirstByJsonPath<'TDoc when 'TDoc: null>(conn, tableName, jsonPath) =
|
||||
static member inline FindFirstByJsonPath<'TDoc when 'TDoc: null and 'TDoc: not struct>(conn, tableName, jsonPath) =
|
||||
WithProps.Find.FirstByJsonPath<'TDoc>(tableName, jsonPath, Sql.existingConnection conn)
|
||||
|
||||
/// Retrieve the first document matching a JSON Path match query (@?) ordered by the given fields in the document;
|
||||
/// returns None if not found
|
||||
[<Extension>]
|
||||
static member inline FindFirstByJsonPathOrdered<'TDoc when 'TDoc: null>(conn, tableName, jsonPath, orderFields) =
|
||||
static member inline FindFirstByJsonPathOrdered<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
conn, tableName, jsonPath, orderFields) =
|
||||
WithProps.Find.FirstByJsonPathOrdered<'TDoc>(tableName, jsonPath, orderFields, Sql.existingConnection conn)
|
||||
|
||||
/// Update an entire document by its ID
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
/// The type of index to generate for the document
|
||||
[<Struct>]
|
||||
type DocumentIndex =
|
||||
|
||||
/// A GIN index with standard operations (all operators supported)
|
||||
| Full
|
||||
|
||||
/// A GIN index with JSONPath operations (optimized for @>, @?, @@ operators)
|
||||
| Optimized
|
||||
|
||||
@@ -36,6 +38,7 @@ open Npgsql.FSharp
|
||||
/// Helper functions
|
||||
[<AutoOpen>]
|
||||
module private Helpers =
|
||||
|
||||
/// Shorthand to retrieve the data source as SqlProps
|
||||
let internal fromDataSource () =
|
||||
Configuration.dataSource () |> Sql.fromDataSource
|
||||
@@ -272,7 +275,7 @@ module WithProps =
|
||||
}
|
||||
|
||||
/// Execute a query that returns one or no results; returns null if not found
|
||||
let Single<'TDoc when 'TDoc: null>(
|
||||
let Single<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
query, parameters, mapFunc: System.Func<RowReader, 'TDoc>, sqlProps) = backgroundTask {
|
||||
let! result = single<'TDoc> query parameters mapFunc.Invoke sqlProps
|
||||
return Option.toObj result
|
||||
@@ -439,7 +442,7 @@ module WithProps =
|
||||
Custom.single (Query.byId (Query.find tableName) docId) [ idParam docId ] fromData<'TDoc> sqlProps
|
||||
|
||||
/// Retrieve a document by its ID (returns null if not found)
|
||||
let ById<'TKey, 'TDoc when 'TDoc: null>(tableName, docId: 'TKey, sqlProps) =
|
||||
let ById<'TKey, 'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, docId: 'TKey, sqlProps) =
|
||||
Custom.Single<'TDoc>(
|
||||
Query.byId (Query.find tableName) docId, [ idParam docId ], fromData<'TDoc>, sqlProps)
|
||||
|
||||
@@ -549,7 +552,7 @@ module WithProps =
|
||||
sqlProps
|
||||
|
||||
/// Retrieve the first document matching JSON field comparisons (->> =); returns null if not found
|
||||
let FirstByFields<'TDoc when 'TDoc: null>(tableName, howMatched, fields, sqlProps) =
|
||||
let FirstByFields<'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, howMatched, fields, sqlProps) =
|
||||
Custom.Single<'TDoc>(
|
||||
$"{Query.byFields (Query.find tableName) howMatched fields} LIMIT 1",
|
||||
addFieldParams fields [],
|
||||
@@ -568,7 +571,8 @@ module WithProps =
|
||||
|
||||
/// Retrieve the first document matching JSON field comparisons (->> =) ordered by the given fields in the
|
||||
/// document; returns null if not found
|
||||
let FirstByFieldsOrdered<'TDoc when 'TDoc: null>(tableName, howMatched, queryFields, orderFields, sqlProps) =
|
||||
let FirstByFieldsOrdered<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
tableName, howMatched, queryFields, orderFields, sqlProps) =
|
||||
Custom.Single<'TDoc>(
|
||||
$"{Query.byFields (Query.find tableName) howMatched queryFields}{Query.orderBy orderFields PostgreSQL} LIMIT 1",
|
||||
addFieldParams queryFields [],
|
||||
@@ -585,7 +589,7 @@ module WithProps =
|
||||
sqlProps
|
||||
|
||||
/// Retrieve the first document matching a JSON containment query (@>); returns null if not found
|
||||
let FirstByContains<'TDoc when 'TDoc: null>(tableName, criteria: obj, sqlProps) =
|
||||
let FirstByContains<'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, criteria: obj, sqlProps) =
|
||||
Custom.Single<'TDoc>(
|
||||
$"{Query.byContains (Query.find tableName)} LIMIT 1",
|
||||
[ jsonParam "@criteria" criteria ],
|
||||
@@ -604,7 +608,8 @@ module WithProps =
|
||||
|
||||
/// Retrieve the first document matching a JSON containment query (@>) ordered by the given fields in the
|
||||
/// document; returns null if not found
|
||||
let FirstByContainsOrdered<'TDoc when 'TDoc: null>(tableName, criteria: obj, orderFields, sqlProps) =
|
||||
let FirstByContainsOrdered<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
tableName, criteria: obj, orderFields, sqlProps) =
|
||||
Custom.Single<'TDoc>(
|
||||
$"{Query.byContains (Query.find tableName)}{Query.orderBy orderFields PostgreSQL} LIMIT 1",
|
||||
[ jsonParam "@criteria" criteria ],
|
||||
@@ -621,7 +626,7 @@ module WithProps =
|
||||
sqlProps
|
||||
|
||||
/// Retrieve the first document matching a JSON Path match query (@?); returns null if not found
|
||||
let FirstByJsonPath<'TDoc when 'TDoc: null>(tableName, jsonPath, sqlProps) =
|
||||
let FirstByJsonPath<'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, jsonPath, sqlProps) =
|
||||
Custom.Single<'TDoc>(
|
||||
$"{Query.byPathMatch (Query.find tableName)} LIMIT 1",
|
||||
[ "@path", Sql.string jsonPath ],
|
||||
@@ -640,7 +645,8 @@ module WithProps =
|
||||
|
||||
/// Retrieve the first document matching a JSON Path match query (@?) ordered by the given fields in the
|
||||
/// document; returns null if not found
|
||||
let FirstByJsonPathOrdered<'TDoc when 'TDoc: null>(tableName, jsonPath, orderFields, sqlProps) =
|
||||
let FirstByJsonPathOrdered<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
tableName, jsonPath, orderFields, sqlProps) =
|
||||
Custom.Single<'TDoc>(
|
||||
$"{Query.byPathMatch (Query.find tableName)}{Query.orderBy orderFields PostgreSQL} LIMIT 1",
|
||||
[ "@path", Sql.string jsonPath ],
|
||||
@@ -779,7 +785,8 @@ module Custom =
|
||||
WithProps.Custom.single<'TDoc> query parameters mapFunc (fromDataSource ())
|
||||
|
||||
/// Execute a query that returns one or no results; returns null if not found
|
||||
let Single<'TDoc when 'TDoc: null>(query, parameters, mapFunc: System.Func<RowReader, 'TDoc>) =
|
||||
let Single<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
query, parameters, mapFunc: System.Func<RowReader, 'TDoc>) =
|
||||
WithProps.Custom.Single<'TDoc>(query, parameters, mapFunc, fromDataSource ())
|
||||
|
||||
/// Execute a query that returns no results
|
||||
@@ -910,7 +917,7 @@ module Find =
|
||||
WithProps.Find.byId<'TKey, 'TDoc> tableName docId (fromDataSource ())
|
||||
|
||||
/// Retrieve a document by its ID; returns null if not found
|
||||
let ById<'TKey, 'TDoc when 'TDoc: null>(tableName, docId: 'TKey) =
|
||||
let ById<'TKey, 'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, docId: 'TKey) =
|
||||
WithProps.Find.ById<'TKey, 'TDoc>(tableName, docId, fromDataSource ())
|
||||
|
||||
/// Retrieve documents matching a JSON field comparison query (->> =)
|
||||
@@ -973,7 +980,7 @@ module Find =
|
||||
WithProps.Find.firstByFields<'TDoc> tableName howMatched fields (fromDataSource ())
|
||||
|
||||
/// Retrieve the first document matching a JSON field comparison query (->> =); returns null if not found
|
||||
let FirstByFields<'TDoc when 'TDoc: null>(tableName, howMatched, fields) =
|
||||
let FirstByFields<'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, howMatched, fields) =
|
||||
WithProps.Find.FirstByFields<'TDoc>(tableName, howMatched, fields, fromDataSource ())
|
||||
|
||||
/// Retrieve the first document matching a JSON field comparison query (->> =) ordered by the given fields in the
|
||||
@@ -984,7 +991,8 @@ module Find =
|
||||
|
||||
/// Retrieve the first document matching a JSON field comparison query (->> =) ordered by the given fields in the
|
||||
/// document; returns null if not found
|
||||
let FirstByFieldsOrdered<'TDoc when 'TDoc: null>(tableName, howMatched, queryFields, orderFields) =
|
||||
let FirstByFieldsOrdered<'TDoc when 'TDoc: null and 'TDoc: not struct>(
|
||||
tableName, howMatched, queryFields, orderFields) =
|
||||
WithProps.Find.FirstByFieldsOrdered<'TDoc>(tableName, howMatched, queryFields, orderFields, fromDataSource ())
|
||||
|
||||
/// Retrieve the first document matching a JSON containment query (@>); returns None if not found
|
||||
@@ -993,7 +1001,7 @@ module Find =
|
||||
WithProps.Find.firstByContains<'TDoc> tableName criteria (fromDataSource ())
|
||||
|
||||
/// Retrieve the first document matching a JSON containment query (@>); returns null if not found
|
||||
let FirstByContains<'TDoc when 'TDoc: null>(tableName, criteria: obj) =
|
||||
let FirstByContains<'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, criteria: obj) =
|
||||
WithProps.Find.FirstByContains<'TDoc>(tableName, criteria, fromDataSource ())
|
||||
|
||||
/// Retrieve the first document matching a JSON containment query (@>) ordered by the given fields in the document;
|
||||
@@ -1004,7 +1012,7 @@ module Find =
|
||||
|
||||
/// Retrieve the first document matching a JSON containment query (@>) ordered by the given fields in the document;
|
||||
/// returns null if not found
|
||||
let FirstByContainsOrdered<'TDoc when 'TDoc: null>(tableName, criteria: obj, orderFields) =
|
||||
let FirstByContainsOrdered<'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, criteria: obj, orderFields) =
|
||||
WithProps.Find.FirstByContainsOrdered<'TDoc>(tableName, criteria, orderFields, fromDataSource ())
|
||||
|
||||
/// Retrieve the first document matching a JSON Path match query (@?); returns None if not found
|
||||
@@ -1013,7 +1021,7 @@ module Find =
|
||||
WithProps.Find.firstByJsonPath<'TDoc> tableName jsonPath (fromDataSource ())
|
||||
|
||||
/// Retrieve the first document matching a JSON Path match query (@?); returns null if not found
|
||||
let FirstByJsonPath<'TDoc when 'TDoc: null>(tableName, jsonPath) =
|
||||
let FirstByJsonPath<'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, jsonPath) =
|
||||
WithProps.Find.FirstByJsonPath<'TDoc>(tableName, jsonPath, fromDataSource ())
|
||||
|
||||
/// Retrieve the first document matching a JSON Path match query (@?) ordered by the given fields in the document;
|
||||
@@ -1024,7 +1032,7 @@ module Find =
|
||||
|
||||
/// Retrieve the first document matching a JSON Path match query (@?) ordered by the given fields in the document;
|
||||
/// returns null if not found
|
||||
let FirstByJsonPathOrdered<'TDoc when 'TDoc: null>(tableName, jsonPath, orderFields) =
|
||||
let FirstByJsonPathOrdered<'TDoc when 'TDoc: null and 'TDoc: not struct>(tableName, jsonPath, orderFields) =
|
||||
WithProps.Find.FirstByJsonPathOrdered<'TDoc>(tableName, jsonPath, orderFields, fromDataSource ())
|
||||
|
||||
|
||||
|
||||
@@ -5,11 +5,16 @@ This package provides a lightweight document library backed by [PostgreSQL](http
|
||||
## Features
|
||||
|
||||
- Select, insert, update, save (upsert), delete, count, and check existence of documents, and create tables and indexes for these documents
|
||||
- Automatically generate IDs for documents (numeric IDs, GUIDs, or random strings)
|
||||
- Address documents via ID, via comparison on any field, via equality on any property (using JSON containment, on a likely indexed field), or via condition on any property (using JSON Path queries)
|
||||
- Access documents as your domain models (<abbr title="Plain Old CLR Objects">POCO</abbr>s)
|
||||
- Use `Task`-based async for all data access functions
|
||||
- Use building blocks for more complex queries
|
||||
|
||||
## Upgrading from v3
|
||||
|
||||
There is a breaking API change for `ByField` (C#) / `byField` (F#), along with a compatibility namespace that can mitigate the impact of these changes. See [the migration guide](https://bitbadger.solutions/open-source/relational-documents/upgrade-from-v3-to-v4.html) for full details.
|
||||
|
||||
## Getting Started
|
||||
|
||||
Once the package is installed, the library needs a data source. Construct an `NpgsqlDataSource` instance, and provide it to the library:
|
||||
|
||||
Reference in New Issue
Block a user