From ad62629a1d92248ce87b125b7b960dca215ce44b Mon Sep 17 00:00:00 2001 From: Kyle Ratti Date: Thu, 5 Sep 2024 23:03:43 -0400 Subject: [PATCH] feat: add F# tryQueryFirst --- ...tyFoundation.DataAccess.Abstractions.FSharp.fsproj | 2 ++ .../ReadOnlyDb.fs | 6 ++++++ .../ReadWriteDb.fs | 6 ++++++ .../FruityFoundation.DataAccess.Abstractions.csproj | 4 ++++ .../IDatabaseConnection.cs | 2 ++ .../INonTransactionalDbConnection.cs | 1 + FruityFoundation.DataAccess.Core/DbTransaction.cs | 11 +++++++++++ .../FruityFoundation.DataAccess.Core.csproj | 1 + .../NonTransactionalDbConnection.cs | 10 ++++++++++ 9 files changed, 43 insertions(+) diff --git a/FruityFoundation.DataAccess.Abstractions.FSharp/FruityFoundation.DataAccess.Abstractions.FSharp.fsproj b/FruityFoundation.DataAccess.Abstractions.FSharp/FruityFoundation.DataAccess.Abstractions.FSharp.fsproj index a657707..2bde81f 100644 --- a/FruityFoundation.DataAccess.Abstractions.FSharp/FruityFoundation.DataAccess.Abstractions.FSharp.fsproj +++ b/FruityFoundation.DataAccess.Abstractions.FSharp/FruityFoundation.DataAccess.Abstractions.FSharp.fsproj @@ -21,7 +21,9 @@ + + diff --git a/FruityFoundation.DataAccess.Abstractions.FSharp/ReadOnlyDb.fs b/FruityFoundation.DataAccess.Abstractions.FSharp/ReadOnlyDb.fs index 34f3560..f7a91c9 100644 --- a/FruityFoundation.DataAccess.Abstractions.FSharp/ReadOnlyDb.fs +++ b/FruityFoundation.DataAccess.Abstractions.FSharp/ReadOnlyDb.fs @@ -5,6 +5,7 @@ open System.Collections.Generic open System.Threading open FSharp.Control open FruityFoundation.DataAccess.Abstractions +open FruityFoundation.FsBase let private toKeyValuePair (parms : (string * obj) seq) = parms @@ -22,6 +23,11 @@ let querySingle<'a> (connection : IDatabaseConnection) (cancellationTo return! connection.QuerySingle<'a>(sql, parms |> toKeyValuePair, cancellationToken) } +let tryQueryFirst<'a> (connection : ReadOnly IDatabaseConnection) (cancellationToken : CancellationToken) (sql : string) (parms : (string * obj) seq) = task { + let! result = connection.TryQueryFirst(sql, parms |> toKeyValuePair, cancellationToken) + return result |> Option.fromMaybe +} + let execute (connection : IDatabaseConnection) (cancellationToken : CancellationToken) (sql : string) (parms : (string * obj) seq) = task { return! connection.Execute(sql, parms |> toKeyValuePair, cancellationToken) } diff --git a/FruityFoundation.DataAccess.Abstractions.FSharp/ReadWriteDb.fs b/FruityFoundation.DataAccess.Abstractions.FSharp/ReadWriteDb.fs index b6309e4..7aa168f 100644 --- a/FruityFoundation.DataAccess.Abstractions.FSharp/ReadWriteDb.fs +++ b/FruityFoundation.DataAccess.Abstractions.FSharp/ReadWriteDb.fs @@ -5,6 +5,7 @@ open System.Collections.Generic open System.Threading open FSharp.Control open FruityFoundation.DataAccess.Abstractions +open FruityFoundation.FsBase let private toKeyValuePair (parms : (string * obj) seq) = parms @@ -22,6 +23,11 @@ let querySingle<'a> (connection : IDatabaseConnection) (cancellationT return! connection.QuerySingle<'a>(sql, parms |> toKeyValuePair, cancellationToken) } +let tryQueryFirst<'a> (connection : ReadOnly IDatabaseConnection) (cancellationToken : CancellationToken) (sql : string) (parms : (string * obj) seq) = task { + let! result = connection.TryQueryFirst(sql, parms |> toKeyValuePair, cancellationToken) + return result |> Option.fromMaybe +} + let execute (connection : IDatabaseConnection) (cancellationToken : CancellationToken) (sql : string) (parms : (string * obj) seq) = task { return! connection.Execute(sql, parms |> toKeyValuePair, cancellationToken) } diff --git a/FruityFoundation.DataAccess.Abstractions/FruityFoundation.DataAccess.Abstractions.csproj b/FruityFoundation.DataAccess.Abstractions/FruityFoundation.DataAccess.Abstractions.csproj index 8071f90..9cbb1ec 100644 --- a/FruityFoundation.DataAccess.Abstractions/FruityFoundation.DataAccess.Abstractions.csproj +++ b/FruityFoundation.DataAccess.Abstractions/FruityFoundation.DataAccess.Abstractions.csproj @@ -16,4 +16,8 @@ + + + + diff --git a/FruityFoundation.DataAccess.Abstractions/IDatabaseConnection.cs b/FruityFoundation.DataAccess.Abstractions/IDatabaseConnection.cs index e60597a..f727174 100644 --- a/FruityFoundation.DataAccess.Abstractions/IDatabaseConnection.cs +++ b/FruityFoundation.DataAccess.Abstractions/IDatabaseConnection.cs @@ -1,4 +1,5 @@ using System.Data.Common; +using FruityFoundation.Base.Structures; namespace FruityFoundation.DataAccess.Abstractions; @@ -8,6 +9,7 @@ public interface IDatabaseConnection where TConnectionType public Task> Query(string sql, object? param = null, CancellationToken cancellationToken = default); public IAsyncEnumerable QueryUnbuffered(string sql, object? param = null, CancellationToken cancellationToken = default); public Task QuerySingle(string sql, object? param = null, CancellationToken cancellationToken = default); + public Task> TryQueryFirst(string sql, object? param = null, CancellationToken cancellationToken = default); public Task Execute(string sql, object? param = null, CancellationToken cancellationToken = default); public Task ExecuteScalar(string sql, object? param = null, CancellationToken cancellationToken = default); public Task ExecuteReader(string sql, object? param = null, CancellationToken cancellationToken = default); diff --git a/FruityFoundation.DataAccess.Abstractions/INonTransactionalDbConnection.cs b/FruityFoundation.DataAccess.Abstractions/INonTransactionalDbConnection.cs index 2a8789c..f1fe980 100644 --- a/FruityFoundation.DataAccess.Abstractions/INonTransactionalDbConnection.cs +++ b/FruityFoundation.DataAccess.Abstractions/INonTransactionalDbConnection.cs @@ -1,4 +1,5 @@ using System.Data; +using FruityFoundation.Base.Structures; namespace FruityFoundation.DataAccess.Abstractions; diff --git a/FruityFoundation.DataAccess.Core/DbTransaction.cs b/FruityFoundation.DataAccess.Core/DbTransaction.cs index 1420da7..1908109 100644 --- a/FruityFoundation.DataAccess.Core/DbTransaction.cs +++ b/FruityFoundation.DataAccess.Core/DbTransaction.cs @@ -1,6 +1,7 @@ using System.Data.Common; using System.Runtime.CompilerServices; using Dapper; +using FruityFoundation.Base.Structures; using FruityFoundation.DataAccess.Abstractions; namespace FruityFoundation.DataAccess.Core; @@ -59,6 +60,16 @@ public class DbTransaction : IDatabaseTransactionConnection(command); } + /// + public async Task> TryQueryFirst(string sql, object? param = null, CancellationToken cancellationToken = default) + { + if (_transaction.Connection is not { } conn) + throw new InvalidOperationException("Transaction connection cannot be null"); + + return await conn.QueryUnbufferedAsync(sql, param, transaction: _transaction) + .FirstOrEmptyAsync(cancellationToken); + } + /// public async Task Execute(string sql, object? param = null, CancellationToken cancellationToken = default) { diff --git a/FruityFoundation.DataAccess.Core/FruityFoundation.DataAccess.Core.csproj b/FruityFoundation.DataAccess.Core/FruityFoundation.DataAccess.Core.csproj index e67b563..0d0ac7b 100644 --- a/FruityFoundation.DataAccess.Core/FruityFoundation.DataAccess.Core.csproj +++ b/FruityFoundation.DataAccess.Core/FruityFoundation.DataAccess.Core.csproj @@ -17,6 +17,7 @@ + diff --git a/FruityFoundation.DataAccess.Core/NonTransactionalDbConnection.cs b/FruityFoundation.DataAccess.Core/NonTransactionalDbConnection.cs index 2c898e9..1e54d96 100644 --- a/FruityFoundation.DataAccess.Core/NonTransactionalDbConnection.cs +++ b/FruityFoundation.DataAccess.Core/NonTransactionalDbConnection.cs @@ -2,6 +2,7 @@ using System.Data.Common; using System.Runtime.CompilerServices; using Dapper; +using FruityFoundation.Base.Structures; using FruityFoundation.DataAccess.Abstractions; namespace FruityFoundation.DataAccess.Core; @@ -48,6 +49,15 @@ public class NonTransactionalDbConnection : INonTransactionalDb CancellationToken cancellationToken = default ) => await _connection.QuerySingleAsync(new CommandDefinition(sql, param, cancellationToken: cancellationToken)); + /// + public async Task> TryQueryFirst( + string sql, + object? param = null, + CancellationToken cancellationToken = default + ) => + await _connection.QueryUnbufferedAsync(sql, param, transaction: null) + .FirstOrEmptyAsync(cancellationToken); + /// public async Task Execute( string sql,