< Summary

Information
Class: SQLite.SQLiteAsyncConnection
Assembly: SQLite.Tests
File(s): /home/runner/work/sqlite-net/sqlite-net/src/SQLiteAsync.cs
Tag: 197_13668160376
Line coverage
71%
Covered lines: 193
Uncovered lines: 76
Coverable lines: 269
Total lines: 1992
Line coverage: 71.7%
Branch coverage
50%
Covered branches: 3
Total branches: 6
Branch coverage: 50%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)0%110100%
.ctor(...)0%2100%
.ctor(...)0%110100%
GetBusyTimeout()0%110100%
SetBusyTimeoutAsync(...)0%110100%
EnableWriteAheadLoggingAsync()66.67%222100%
ResetPool()0%2100%
GetConnection()0%110100%
GetConnectionAndTransactionLock(...)0%110100%
CloseAsync()0%110100%
ReadAsync(...)0%110100%
WriteAsync(...)0%110100%
TransactAsync(...)0%110100%
EnableLoadExtensionAsync(...)0%2100%
CreateTableAsync(...)0%110100%
CreateTableAsync(...)0%110100%
CreateTablesAsync(...)0%110100%
CreateTablesAsync(...)0%110100%
DropTableAsync()66.67%222100%
DropTableAsync(...)0%110100%
CreateIndexAsync(...)0%110100%
CreateIndexAsync(...)0%110100%
CreateIndexAsync(...)0%110100%
CreateIndexAsync(...)0%110100%
CreateIndexAsync(...)0%110100%
InsertAsync(...)0%110100%
InsertAsync(...)0%110100%
InsertAsync(...)0%110100%
InsertAsync(...)0%110100%
InsertOrReplaceAsync(...)0%110100%
InsertOrReplaceAsync(...)0%110100%
UpdateAsync(...)0%110100%
UpdateAsync(...)0%110100%
UpdateAllAsync(...)0%110100%
DeleteAsync(...)0%210100%
DeleteAsync(...)0%2100%
DeleteAllAsync()66.67%222100%
DeleteAllAsync(...)0%2100%
BackupAsync(...)0%110100%
GetAsync(...)0%110100%
GetAsync(...)0%2100%
GetAsync(...)0%110100%
FindAsync(...)0%110100%
FindAsync(...)0%2100%
FindAsync(...)0%110100%
FindWithQueryAsync(...)0%2100%
FindWithQueryAsync(...)0%2100%
GetMappingAsync(...)0%110100%
GetMappingAsync(...)0%2100%
GetTableInfoAsync(...)0%2100%
ExecuteAsync(...)0%110100%
InsertAllAsync(...)0%110100%
InsertAllAsync(...)0%2100%
InsertAllAsync(...)0%2100%
RunInTransactionAsync(...)0%110100%
Table()0%110100%
ExecuteScalarAsync(...)0%110100%
QueryAsync(...)0%110100%
QueryScalarsAsync(...)0%110100%
QueryAsync(...)0%2100%
DeferredQueryAsync(...)0%2100%
DeferredQueryAsync(...)0%2100%
ReKeyAsync(...)0%2100%
ReKeyAsync(...)0%2100%

File(s)

/home/runner/work/sqlite-net/sqlite-net/src/SQLiteAsync.cs

#LineLine coverage
 1//
 2// Copyright (c) 2012-2024 Krueger Systems, Inc.
 3//
 4// Permission is hereby granted, free of charge, to any person obtaining a copy
 5// of this software and associated documentation files (the "Software"), to deal
 6// in the Software without restriction, including without limitation the rights
 7// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 8// copies of the Software, and to permit persons to whom the Software is
 9// furnished to do so, subject to the following conditions:
 10//
 11// The above copyright notice and this permission notice shall be included in
 12// all copies or substantial portions of the Software.
 13//
 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20// THE SOFTWARE.
 21//
 22
 23using System;
 24using System.Collections;
 25using System.Collections.Generic;
 26using System.Diagnostics.CodeAnalysis;
 27using System.Linq;
 28using System.Linq.Expressions;
 29using System.Threading;
 30using System.Threading.Tasks;
 31
 32#pragma warning disable 1591 // XML Doc Comments
 33
 34namespace SQLite
 35{
 36  public interface ISQLiteAsyncConnection
 37  {
 38    string DatabasePath { get; }
 39    int LibVersionNumber { get; }
 40    string DateTimeStringFormat { get; }
 41    bool StoreDateTimeAsTicks { get; }
 42    bool StoreTimeSpanAsTicks { get; }
 43    bool Trace { get; set; }
 44    Action<string> Tracer { get; set; }
 45    bool TimeExecution { get; set; }
 46    IEnumerable<TableMapping> TableMappings { get; }
 47
 48    Task BackupAsync (string destinationDatabasePath, string databaseName = "main");
 49    Task CloseAsync ();
 50    Task<int> CreateIndexAsync (string tableName, string columnName, bool unique = false);
 51    Task<int> CreateIndexAsync (string indexName, string tableName, string columnName, bool unique = false);
 52    Task<int> CreateIndexAsync (string tableName, string[] columnNames, bool unique = false);
 53    Task<int> CreateIndexAsync (string indexName, string tableName, string[] columnNames, bool unique = false);
 54    Task<int> CreateIndexAsync<
 55#if NET8_0_OR_GREATER
 56      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 57#endif
 58      T> (Expression<Func<T, object>> property, bool unique = false);
 59    Task<CreateTableResult> CreateTableAsync<
 60#if NET8_0_OR_GREATER
 61      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 62#endif
 63      T> (CreateFlags createFlags = CreateFlags.None) where T : new();
 64    Task<CreateTableResult> CreateTableAsync (
 65#if NET8_0_OR_GREATER
 66      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 67#endif
 68      Type ty,
 69      CreateFlags createFlags = CreateFlags.None);
 70    Task<CreateTablesResult> CreateTablesAsync<
 71#if NET8_0_OR_GREATER
 72      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 73#endif
 74      T,
 75#if NET8_0_OR_GREATER
 76      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 77#endif
 78      T2> (CreateFlags createFlags = CreateFlags.None)
 79      where T : new()
 80      where T2 : new();
 81    Task<CreateTablesResult> CreateTablesAsync<
 82#if NET8_0_OR_GREATER
 83      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 84#endif
 85      T,
 86#if NET8_0_OR_GREATER
 87      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 88#endif
 89      T2,
 90#if NET8_0_OR_GREATER
 91      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 92#endif
 93      T3> (CreateFlags createFlags = CreateFlags.None)
 94      where T : new()
 95      where T2 : new()
 96      where T3 : new();
 97    Task<CreateTablesResult> CreateTablesAsync<
 98#if NET8_0_OR_GREATER
 99      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 100#endif
 101      T,
 102#if NET8_0_OR_GREATER
 103      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 104#endif
 105      T2,
 106#if NET8_0_OR_GREATER
 107      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 108#endif
 109      T3,
 110#if NET8_0_OR_GREATER
 111      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 112#endif
 113      T4> (CreateFlags createFlags = CreateFlags.None)
 114      where T : new()
 115      where T2 : new()
 116      where T3 : new()
 117      where T4 : new();
 118    Task<CreateTablesResult> CreateTablesAsync<
 119#if NET8_0_OR_GREATER
 120      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 121#endif
 122      T,
 123#if NET8_0_OR_GREATER
 124      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 125#endif
 126      T2,
 127#if NET8_0_OR_GREATER
 128      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 129#endif
 130      T3,
 131#if NET8_0_OR_GREATER
 132      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 133#endif
 134      T4,
 135#if NET8_0_OR_GREATER
 136      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 137#endif
 138      T5> (CreateFlags createFlags = CreateFlags.None)
 139      where T : new()
 140      where T2 : new()
 141      where T3 : new()
 142      where T4 : new()
 143      where T5 : new();
 144#if NET8_0_OR_GREATER
 145    [RequiresUnreferencedCode ("This method requires 'DynamicallyAccessedMemberTypes.All' on each input 'Type' instance.
 146#endif
 147    Task<CreateTablesResult> CreateTablesAsync (CreateFlags createFlags = CreateFlags.None, params Type[] types);
 148    Task<IEnumerable<T>> DeferredQueryAsync<
 149#if NET8_0_OR_GREATER
 150      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 151#endif
 152      T> (string query, params object[] args) where T : new();
 153    Task<IEnumerable<object>> DeferredQueryAsync (TableMapping map, string query, params object[] args);
 154    Task<int> DeleteAllAsync<
 155#if NET8_0_OR_GREATER
 156      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 157#endif
 158      T> ();
 159    Task<int> DeleteAllAsync (TableMapping map);
 160#if NET8_0_OR_GREATER
 161    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of 'objec
 162#endif
 163    Task<int> DeleteAsync (object objectToDelete);
 164    Task<int> DeleteAsync<
 165#if NET8_0_OR_GREATER
 166      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 167#endif
 168      T> (object primaryKey);
 169    Task<int> DeleteAsync (object primaryKey, TableMapping map);
 170    Task<int> DropTableAsync<
 171#if NET8_0_OR_GREATER
 172      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 173#endif
 174      T> () where T : new();
 175    Task<int> DropTableAsync (TableMapping map);
 176    Task EnableLoadExtensionAsync (bool enabled);
 177    Task EnableWriteAheadLoggingAsync ();
 178    Task<int> ExecuteAsync (string query, params object[] args);
 179    Task<T> ExecuteScalarAsync<T> (string query, params object[] args);
 180    Task<T> FindAsync<
 181#if NET8_0_OR_GREATER
 182      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 183#endif
 184      T> (object pk) where T : new();
 185    Task<object> FindAsync (object pk, TableMapping map);
 186    Task<T> FindAsync<
 187#if NET8_0_OR_GREATER
 188      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 189#endif
 190      T> (Expression<Func<T, bool>> predicate) where T : new();
 191    Task<T> FindWithQueryAsync<
 192#if NET8_0_OR_GREATER
 193      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 194#endif
 195      T> (string query, params object[] args) where T : new();
 196    Task<object> FindWithQueryAsync (TableMapping map, string query, params object[] args);
 197    Task<T> GetAsync<
 198#if NET8_0_OR_GREATER
 199      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 200#endif
 201      T> (object pk) where T : new();
 202    Task<object> GetAsync (object pk, TableMapping map);
 203    Task<T> GetAsync<
 204#if NET8_0_OR_GREATER
 205      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 206#endif
 207      T> (Expression<Func<T, bool>> predicate) where T : new();
 208    TimeSpan GetBusyTimeout ();
 209    SQLiteConnectionWithLock GetConnection ();
 210    Task<TableMapping> GetMappingAsync (
 211#if NET8_0_OR_GREATER
 212      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 213#endif
 214      Type type,
 215      CreateFlags createFlags = CreateFlags.None);
 216    Task<TableMapping> GetMappingAsync<
 217#if NET8_0_OR_GREATER
 218      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 219#endif
 220      T> (CreateFlags createFlags = CreateFlags.None) where T : new();
 221    Task<List<SQLiteConnection.ColumnInfo>> GetTableInfoAsync (string tableName);
 222#if NET8_0_OR_GREATER
 223    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of all ob
 224#endif
 225    Task<int> InsertAllAsync (IEnumerable objects, bool runInTransaction = true);
 226#if NET8_0_OR_GREATER
 227    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of all ob
 228#endif
 229    Task<int> InsertAllAsync (IEnumerable objects, string extra, bool runInTransaction = true);
 230#if NET8_0_OR_GREATER
 231    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of all ob
 232#endif
 233    Task<int> InsertAllAsync (IEnumerable objects, Type objType, bool runInTransaction = true);
 234#if NET8_0_OR_GREATER
 235    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of 'obj'.
 236#endif
 237    Task<int> InsertAsync (object obj);
 238    Task<int> InsertAsync (
 239      object obj,
 240#if NET8_0_OR_GREATER
 241      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 242#endif
 243      Type objType);
 244#if NET8_0_OR_GREATER
 245    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of 'obj'.
 246#endif
 247    Task<int> InsertAsync (object obj, string extra);
 248    Task<int> InsertAsync (
 249      object obj,
 250      string extra,
 251#if NET8_0_OR_GREATER
 252      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 253#endif
 254      Type objType);
 255#if NET8_0_OR_GREATER
 256    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of 'obj'.
 257#endif
 258    Task<int> InsertOrReplaceAsync (object obj);
 259    Task<int> InsertOrReplaceAsync (
 260      object obj,
 261#if NET8_0_OR_GREATER
 262      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 263#endif
 264      Type objType);
 265    Task<List<T>> QueryAsync<
 266#if NET8_0_OR_GREATER
 267      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 268#endif
 269      T> (string query, params object[] args) where T : new();
 270    Task<List<object>> QueryAsync (TableMapping map, string query, params object[] args);
 271    Task<List<T>> QueryScalarsAsync<T> (string query, params object[] args);
 272    Task ReKeyAsync (string key);
 273    Task ReKeyAsync (byte[] key);
 274    Task RunInTransactionAsync (Action<SQLiteConnection> action);
 275    Task SetBusyTimeoutAsync (TimeSpan value);
 276    AsyncTableQuery<T> Table<
 277#if NET8_0_OR_GREATER
 278      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 279#endif
 280      T> () where T : new();
 281#if NET8_0_OR_GREATER
 282    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of all ob
 283#endif
 284    Task<int> UpdateAllAsync (IEnumerable objects, bool runInTransaction = true);
 285#if NET8_0_OR_GREATER
 286    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of 'obj'.
 287#endif
 288    Task<int> UpdateAsync (object obj);
 289    Task<int> UpdateAsync (
 290      object obj,
 291#if NET8_0_OR_GREATER
 292      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 293#endif
 294      Type objType);
 295  }
 296
 297  /// <summary>
 298  /// A pooled asynchronous connection to a SQLite database.
 299  /// </summary>
 300  public partial class SQLiteAsyncConnection : ISQLiteAsyncConnection
 301  {
 302    readonly SQLiteConnectionString _connectionString;
 303
 304    /// <summary>
 305    /// Constructs a new SQLiteAsyncConnection and opens a pooled SQLite database specified by databasePath.
 306    /// </summary>
 307    /// <param name="databasePath">
 308    /// Specifies the path to the database file.
 309    /// </param>
 310    /// <param name="storeDateTimeAsTicks">
 311    /// Specifies whether to store DateTime properties as ticks (true) or strings (false). You
 312    /// absolutely do want to store them as Ticks in all new projects. The value of false is
 313    /// only here for backwards compatibility. There is a *significant* speed advantage, with no
 314    /// down sides, when setting storeDateTimeAsTicks = true.
 315    /// If you use DateTimeOffset properties, it will be always stored as ticks regardingless
 316    /// the storeDateTimeAsTicks parameter.
 317    /// </param>
 318    public SQLiteAsyncConnection (string databasePath, bool storeDateTimeAsTicks = true)
 70319      : this (new SQLiteConnectionString (databasePath, SQLiteOpenFlags.Create | SQLiteOpenFlags.ReadWrite | SQLiteOpenF
 70320    {
 70321    }
 322
 323    /// <summary>
 324    /// Constructs a new SQLiteAsyncConnection and opens a pooled SQLite database specified by databasePath.
 325    /// </summary>
 326    /// <param name="databasePath">
 327    /// Specifies the path to the database file.
 328    /// </param>
 329    /// <param name="openFlags">
 330    /// Flags controlling how the connection should be opened.
 331    /// Async connections should have the FullMutex flag set to provide best performance.
 332    /// </param>
 333    /// <param name="storeDateTimeAsTicks">
 334    /// Specifies whether to store DateTime properties as ticks (true) or strings (false). You
 335    /// absolutely do want to store them as Ticks in all new projects. The value of false is
 336    /// only here for backwards compatibility. There is a *significant* speed advantage, with no
 337    /// down sides, when setting storeDateTimeAsTicks = true.
 338    /// If you use DateTimeOffset properties, it will be always stored as ticks regardingless
 339    /// the storeDateTimeAsTicks parameter.
 340    /// </param>
 341    public SQLiteAsyncConnection (string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = true)
 0342      : this (new SQLiteConnectionString (databasePath, openFlags, storeDateTimeAsTicks))
 0343    {
 0344    }
 345
 346    /// <summary>
 347    /// Constructs a new SQLiteAsyncConnection and opens a pooled SQLite database
 348    /// using the given connection string.
 349    /// </summary>
 350    /// <param name="connectionString">
 351    /// Details on how to find and open the database.
 352    /// </param>
 77353    public SQLiteAsyncConnection (SQLiteConnectionString connectionString)
 77354    {
 77355      _connectionString = connectionString;
 77356    }
 357
 358    /// <summary>
 359    /// Gets the database path used by this connection.
 360    /// </summary>
 0361    public string DatabasePath => GetConnection ().DatabasePath;
 362
 363    /// <summary>
 364    /// Gets the SQLite library version number. 3007014 would be v3.7.14
 365    /// </summary>
 0366    public int LibVersionNumber => GetConnection ().LibVersionNumber;
 367
 368    /// <summary>
 369    /// The format to use when storing DateTime properties as strings. Ignored if StoreDateTimeAsTicks is true.
 370    /// </summary>
 371    /// <value>The date time string format.</value>
 0372    public string DateTimeStringFormat => GetConnection ().DateTimeStringFormat;
 373
 374    /// <summary>
 375    /// The amount of time to wait for a table to become unlocked.
 376    /// </summary>
 377    public TimeSpan GetBusyTimeout ()
 2378    {
 2379      return GetConnection ().BusyTimeout;
 2380    }
 381
 382    /// <summary>
 383    /// Sets the amount of time to wait for a table to become unlocked.
 384    /// </summary>
 385    public Task SetBusyTimeoutAsync (TimeSpan value)
 2386    {
 4387      return ReadAsync<object> (conn => {
 4388        conn.BusyTimeout = value;
 4389        return null;
 4390      });
 2391    }
 392
 393    /// <summary>
 394    /// Enables the write ahead logging. WAL is significantly faster in most scenarios
 395    /// by providing better concurrency and better disk IO performance than the normal
 396    /// journal mode. You only need to call this function once in the lifetime of the database.
 397    /// </summary>
 398    public Task EnableWriteAheadLoggingAsync ()
 1399    {
 2400      return WriteAsync<object> (conn => {
 2401        conn.EnableWriteAheadLogging ();
 2402        return null;
 2403      });
 1404    }
 405
 406    /// <summary>
 407    /// Whether to store DateTime properties as ticks (true) or strings (false).
 408    /// </summary>
 0409    public bool StoreDateTimeAsTicks => GetConnection ().StoreDateTimeAsTicks;
 410
 411    /// <summary>
 412    /// Whether to store TimeSpan properties as ticks (true) or strings (false).
 413    /// </summary>
 0414    public bool StoreTimeSpanAsTicks => GetConnection ().StoreTimeSpanAsTicks;
 415
 416    /// <summary>
 417    /// Whether to writer queries to <see cref="Tracer"/> during execution.
 418    /// </summary>
 419    /// <value>The tracer.</value>
 420    public bool Trace {
 0421      get { return GetConnection ().Trace; }
 45422      set { GetConnection ().Trace = value; }
 423    }
 424
 425    /// <summary>
 426    /// The delegate responsible for writing trace lines.
 427    /// </summary>
 428    /// <value>The tracer.</value>
 429    public Action<string> Tracer {
 0430      get { return GetConnection ().Tracer; }
 45431      set { GetConnection ().Tracer = value; }
 432    }
 433
 434    /// <summary>
 435    /// Whether Trace lines should be written that show the execution time of queries.
 436    /// </summary>
 437    public bool TimeExecution {
 0438      get { return GetConnection ().TimeExecution; }
 0439      set { GetConnection ().TimeExecution = value; }
 440    }
 441
 442    /// <summary>
 443    /// Returns the mappings from types to tables that the connection
 444    /// currently understands.
 445    /// </summary>
 0446    public IEnumerable<TableMapping> TableMappings => GetConnection ().TableMappings;
 447
 448    /// <summary>
 449    /// Closes all connections to all async databases.
 450    /// You should *never* need to do this.
 451    /// This is a blocking operation that will return when all connections
 452    /// have been closed.
 453    /// </summary>
 454    public static void ResetPool ()
 0455    {
 0456      SQLiteConnectionPool.Shared.Reset ();
 0457    }
 458
 459    /// <summary>
 460    /// Gets the pooled lockable connection used by this async connection.
 461    /// You should never need to use this. This is provided only to add additional
 462    /// functionality to SQLite-net. If you use this connection, you must use
 463    /// the Lock method on it while using it.
 464    /// </summary>
 465    public SQLiteConnectionWithLock GetConnection ()
 1330466    {
 1330467      return SQLiteConnectionPool.Shared.GetConnection (_connectionString);
 1330468    }
 469
 470    SQLiteConnectionWithLock GetConnectionAndTransactionLock (out object transactionLock)
 6471    {
 6472      return SQLiteConnectionPool.Shared.GetConnectionAndTransactionLock (_connectionString, out transactionLock);
 6473    }
 474
 475    /// <summary>
 476    /// Closes any pooled connections used by the database.
 477    /// </summary>
 478    public Task CloseAsync ()
 62479    {
 124480      return Task.Factory.StartNew (() => {
 124481        SQLiteConnectionPool.Shared.CloseConnection (_connectionString);
 124482      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 62483    }
 484
 485    Task<T> ReadAsync<T> (Func<SQLiteConnectionWithLock, T> read)
 30486    {
 60487      return Task.Factory.StartNew (() => {
 60488        var conn = GetConnection ();
 90489        using (conn.Lock ()) {
 60490          return read (conn);
 30491        }
 60492      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 30493    }
 494
 495    Task<T> WriteAsync<T> (Func<SQLiteConnectionWithLock, T> write)
 739496    {
 1478497      return Task.Factory.StartNew (() => {
 1478498        var conn = GetConnection ();
 2217499        using (conn.Lock ()) {
 1478500          return write (conn);
 739501        }
 1478502      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 739503    }
 504
 505    Task<T> TransactAsync<T> (Func<SQLiteConnectionWithLock, T> transact)
 6506    {
 12507      return Task.Factory.StartNew (() => {
 12508        var conn = GetConnectionAndTransactionLock (out var transactionLock);
 18509        lock (transactionLock) {
 18510          using (conn.Lock ()) {
 12511            return transact (conn);
 6512          }
 6513        }
 10514      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 6515    }
 516
 517    /// <summary>
 518    /// Enable or disable extension loading.
 519    /// </summary>
 520    public Task EnableLoadExtensionAsync (bool enabled)
 0521    {
 0522      return WriteAsync<object> (conn => {
 0523        conn.EnableLoadExtension (enabled);
 0524        return null;
 0525      });
 0526    }
 527
 528    /// <summary>
 529    /// Executes a "create table if not exists" on the database. It also
 530    /// creates any specified indexes on the columns of the table. It uses
 531    /// a schema automatically generated from the specified type. You can
 532    /// later access this schema by calling GetMapping.
 533    /// </summary>
 534    /// <returns>
 535    /// Whether the table was created or migrated.
 536    /// </returns>
 537    public Task<CreateTableResult> CreateTableAsync<
 538#if NET8_0_OR_GREATER
 539      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 540#endif
 541      T> (CreateFlags createFlags = CreateFlags.None)
 542      where T : new()
 68543    {
 136544      return WriteAsync (conn => conn.CreateTable<T> (createFlags));
 68545    }
 546
 547    /// <summary>
 548    /// Executes a "create table if not exists" on the database. It also
 549    /// creates any specified indexes on the columns of the table. It uses
 550    /// a schema automatically generated from the specified type. You can
 551    /// later access this schema by calling GetMapping.
 552    /// </summary>
 553    /// <param name="ty">Type to reflect to a database table.</param>
 554    /// <param name="createFlags">Optional flags allowing implicit PK and indexes based on naming conventions.</param>
 555    /// <returns>
 556    /// Whether the table was created or migrated.
 557    /// </returns>
 558    public Task<CreateTableResult> CreateTableAsync (
 559#if NET8_0_OR_GREATER
 560      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 561#endif
 562      Type ty,
 563      CreateFlags createFlags = CreateFlags.None)
 3564    {
 6565      return WriteAsync (conn => conn.CreateTable (ty, createFlags));
 3566    }
 567
 568    /// <summary>
 569    /// Executes a "create table if not exists" on the database for each type. It also
 570    /// creates any specified indexes on the columns of the table. It uses
 571    /// a schema automatically generated from the specified type. You can
 572    /// later access this schema by calling GetMapping.
 573    /// </summary>
 574    /// <returns>
 575    /// Whether the table was created or migrated for each type.
 576    /// </returns>
 577#if NET8_0_OR_GREATER
 578    [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "This method preserves metadata for all type ar
 579#endif
 580    public Task<CreateTablesResult> CreateTablesAsync<
 581#if NET8_0_OR_GREATER
 582      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 583#endif
 584      T,
 585#if NET8_0_OR_GREATER
 586      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 587#endif
 588      T2> (CreateFlags createFlags = CreateFlags.None)
 589      where T : new()
 590      where T2 : new()
 1591    {
 1592      return CreateTablesAsync (createFlags, typeof (T), typeof (T2));
 1593    }
 594
 595    /// <summary>
 596    /// Executes a "create table if not exists" on the database for each type. It also
 597    /// creates any specified indexes on the columns of the table. It uses
 598    /// a schema automatically generated from the specified type. You can
 599    /// later access this schema by calling GetMapping.
 600    /// </summary>
 601    /// <returns>
 602    /// Whether the table was created or migrated for each type.
 603    /// </returns>
 604#if NET8_0_OR_GREATER
 605    [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "This method preserves metadata for all type ar
 606#endif
 607    public Task<CreateTablesResult> CreateTablesAsync<
 608#if NET8_0_OR_GREATER
 609      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 610#endif
 611      T,
 612#if NET8_0_OR_GREATER
 613      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 614#endif
 615      T2,
 616#if NET8_0_OR_GREATER
 617      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 618#endif
 619      T3> (CreateFlags createFlags = CreateFlags.None)
 620      where T : new()
 621      where T2 : new()
 622      where T3 : new()
 1623    {
 1624      return CreateTablesAsync (createFlags, typeof (T), typeof (T2), typeof (T3));
 1625    }
 626
 627    /// <summary>
 628    /// Executes a "create table if not exists" on the database for each type. It also
 629    /// creates any specified indexes on the columns of the table. It uses
 630    /// a schema automatically generated from the specified type. You can
 631    /// later access this schema by calling GetMapping.
 632    /// </summary>
 633    /// <returns>
 634    /// Whether the table was created or migrated for each type.
 635    /// </returns>
 636#if NET8_0_OR_GREATER
 637    [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "This method preserves metadata for all type ar
 638#endif
 639    public Task<CreateTablesResult> CreateTablesAsync<
 640#if NET8_0_OR_GREATER
 641      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 642#endif
 643      T,
 644#if NET8_0_OR_GREATER
 645      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 646#endif
 647      T2,
 648#if NET8_0_OR_GREATER
 649      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 650#endif
 651      T3,
 652#if NET8_0_OR_GREATER
 653      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 654#endif
 655      T4> (CreateFlags createFlags = CreateFlags.None)
 656      where T : new()
 657      where T2 : new()
 658      where T3 : new()
 659      where T4 : new()
 1660    {
 1661      return CreateTablesAsync (createFlags, typeof (T), typeof (T2), typeof (T3), typeof (T4));
 1662    }
 663
 664    /// <summary>
 665    /// Executes a "create table if not exists" on the database for each type. It also
 666    /// creates any specified indexes on the columns of the table. It uses
 667    /// a schema automatically generated from the specified type. You can
 668    /// later access this schema by calling GetMapping.
 669    /// </summary>
 670    /// <returns>
 671    /// Whether the table was created or migrated for each type.
 672    /// </returns>
 673#if NET8_0_OR_GREATER
 674    [UnconditionalSuppressMessage ("Trimming", "IL2026", Justification = "This method preserves metadata for all type ar
 675#endif
 676    public Task<CreateTablesResult> CreateTablesAsync<
 677#if NET8_0_OR_GREATER
 678      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 679#endif
 680      T,
 681#if NET8_0_OR_GREATER
 682      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 683#endif
 684      T2,
 685#if NET8_0_OR_GREATER
 686      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 687#endif
 688      T3,
 689#if NET8_0_OR_GREATER
 690      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 691#endif
 692      T4,
 693#if NET8_0_OR_GREATER
 694      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 695#endif
 696      T5> (CreateFlags createFlags = CreateFlags.None)
 697      where T : new()
 698      where T2 : new()
 699      where T3 : new()
 700      where T4 : new()
 701      where T5 : new()
 1702    {
 1703      return CreateTablesAsync (createFlags, typeof (T), typeof (T2), typeof (T3), typeof (T4), typeof (T5));
 1704    }
 705
 706    /// <summary>
 707    /// Executes a "create table if not exists" on the database for each type. It also
 708    /// creates any specified indexes on the columns of the table. It uses
 709    /// a schema automatically generated from the specified type. You can
 710    /// later access this schema by calling GetMapping.
 711    /// </summary>
 712    /// <returns>
 713    /// Whether the table was created or migrated for each type.
 714    /// </returns>
 715#if NET8_0_OR_GREATER
 716    [RequiresUnreferencedCode ("This method requires 'DynamicallyAccessedMemberTypes.All' on each input 'Type' instance.
 717#endif
 718    public Task<CreateTablesResult> CreateTablesAsync (CreateFlags createFlags = CreateFlags.None, params Type[] types)
 5719    {
 10720      return WriteAsync (conn => conn.CreateTables (createFlags, types));
 5721    }
 722
 723    /// <summary>
 724    /// Executes a "drop table" on the database.  This is non-recoverable.
 725    /// </summary>
 726    public Task<int> DropTableAsync<
 727#if NET8_0_OR_GREATER
 728      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 729#endif
 730      T> ()
 731      where T : new()
 2732    {
 4733      return WriteAsync (conn => conn.DropTable<T> ());
 2734    }
 735
 736    /// <summary>
 737    /// Executes a "drop table" on the database.  This is non-recoverable.
 738    /// </summary>
 739    /// <param name="map">
 740    /// The TableMapping used to identify the table.
 741    /// </param>
 742    public Task<int> DropTableAsync (TableMapping map)
 1743    {
 2744      return WriteAsync (conn => conn.DropTable (map));
 1745    }
 746
 747    /// <summary>
 748    /// Creates an index for the specified table and column.
 749    /// </summary>
 750    /// <param name="tableName">Name of the database table</param>
 751    /// <param name="columnName">Name of the column to index</param>
 752    /// <param name="unique">Whether the index should be unique</param>
 753    /// <returns>Zero on success.</returns>
 754    public Task<int> CreateIndexAsync (string tableName, string columnName, bool unique = false)
 1755    {
 2756      return WriteAsync (conn => conn.CreateIndex (tableName, columnName, unique));
 1757    }
 758
 759    /// <summary>
 760    /// Creates an index for the specified table and column.
 761    /// </summary>
 762    /// <param name="indexName">Name of the index to create</param>
 763    /// <param name="tableName">Name of the database table</param>
 764    /// <param name="columnName">Name of the column to index</param>
 765    /// <param name="unique">Whether the index should be unique</param>
 766    /// <returns>Zero on success.</returns>
 767    public Task<int> CreateIndexAsync (string indexName, string tableName, string columnName, bool unique = false)
 1768    {
 2769      return WriteAsync (conn => conn.CreateIndex (indexName, tableName, columnName, unique));
 1770    }
 771
 772    /// <summary>
 773    /// Creates an index for the specified table and columns.
 774    /// </summary>
 775    /// <param name="tableName">Name of the database table</param>
 776    /// <param name="columnNames">An array of column names to index</param>
 777    /// <param name="unique">Whether the index should be unique</param>
 778    /// <returns>Zero on success.</returns>
 779    public Task<int> CreateIndexAsync (string tableName, string[] columnNames, bool unique = false)
 1780    {
 2781      return WriteAsync (conn => conn.CreateIndex (tableName, columnNames, unique));
 1782    }
 783
 784    /// <summary>
 785    /// Creates an index for the specified table and columns.
 786    /// </summary>
 787    /// <param name="indexName">Name of the index to create</param>
 788    /// <param name="tableName">Name of the database table</param>
 789    /// <param name="columnNames">An array of column names to index</param>
 790    /// <param name="unique">Whether the index should be unique</param>
 791    /// <returns>Zero on success.</returns>
 792    public Task<int> CreateIndexAsync (string indexName, string tableName, string[] columnNames, bool unique = false)
 1793    {
 2794      return WriteAsync (conn => conn.CreateIndex (indexName, tableName, columnNames, unique));
 1795    }
 796
 797    /// <summary>
 798    /// Creates an index for the specified object property.
 799    /// e.g. CreateIndex&lt;Client&gt;(c => c.Name);
 800    /// </summary>
 801    /// <typeparam name="T">Type to reflect to a database table.</typeparam>
 802    /// <param name="property">Property to index</param>
 803    /// <param name="unique">Whether the index should be unique</param>
 804    /// <returns>Zero on success.</returns>
 805    public Task<int> CreateIndexAsync<
 806#if NET8_0_OR_GREATER
 807      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 808#endif
 809      T> (Expression<Func<T, object>> property, bool unique = false)
 1810    {
 2811      return WriteAsync (conn => conn.CreateIndex (property, unique));
 1812    }
 813
 814    /// <summary>
 815    /// Inserts the given object and (and updates its
 816    /// auto incremented primary key if it has one).
 817    /// </summary>
 818    /// <param name="obj">
 819    /// The object to insert.
 820    /// </param>
 821    /// <returns>
 822    /// The number of rows added to the table.
 823    /// </returns>
 824#if NET8_0_OR_GREATER
 825    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of 'obj'.
 826#endif
 827    public Task<int> InsertAsync (object obj)
 620828    {
 1240829      return WriteAsync (conn => conn.Insert (obj));
 620830    }
 831
 832    /// <summary>
 833    /// Inserts the given object (and updates its
 834    /// auto incremented primary key if it has one).
 835    /// The return value is the number of rows added to the table.
 836    /// </summary>
 837    /// <param name="obj">
 838    /// The object to insert.
 839    /// </param>
 840    /// <param name="objType">
 841    /// The type of object to insert.
 842    /// </param>
 843    /// <returns>
 844    /// The number of rows added to the table.
 845    /// </returns>
 846    public Task<int> InsertAsync (
 847      object obj,
 848#if NET8_0_OR_GREATER
 849      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 850#endif
 851      Type objType)
 1852    {
 2853      return WriteAsync (conn => conn.Insert (obj, objType));
 1854    }
 855
 856    /// <summary>
 857    /// Inserts the given object (and updates its
 858    /// auto incremented primary key if it has one).
 859    /// The return value is the number of rows added to the table.
 860    /// </summary>
 861    /// <param name="obj">
 862    /// The object to insert.
 863    /// </param>
 864    /// <param name="extra">
 865    /// Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
 866    /// </param>
 867    /// <returns>
 868    /// The number of rows added to the table.
 869    /// </returns>
 870#if NET8_0_OR_GREATER
 871    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of 'obj'.
 872#endif
 873    public Task<int> InsertAsync (object obj, string extra)
 1874    {
 2875      return WriteAsync (conn => conn.Insert (obj, extra));
 1876    }
 877
 878    /// <summary>
 879    /// Inserts the given object (and updates its
 880    /// auto incremented primary key if it has one).
 881    /// The return value is the number of rows added to the table.
 882    /// </summary>
 883    /// <param name="obj">
 884    /// The object to insert.
 885    /// </param>
 886    /// <param name="extra">
 887    /// Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
 888    /// </param>
 889    /// <param name="objType">
 890    /// The type of object to insert.
 891    /// </param>
 892    /// <returns>
 893    /// The number of rows added to the table.
 894    /// </returns>
 895    public Task<int> InsertAsync (
 896      object obj,
 897      string extra,
 898#if NET8_0_OR_GREATER
 899      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 900#endif
 901      Type objType)
 1902    {
 2903      return WriteAsync (conn => conn.Insert (obj, extra, objType));
 1904    }
 905
 906    /// <summary>
 907    /// Inserts the given object (and updates its
 908    /// auto incremented primary key if it has one).
 909    /// The return value is the number of rows added to the table.
 910    /// If a UNIQUE constraint violation occurs with
 911    /// some pre-existing object, this function deletes
 912    /// the old object.
 913    /// </summary>
 914    /// <param name="obj">
 915    /// The object to insert.
 916    /// </param>
 917    /// <returns>
 918    /// The number of rows modified.
 919    /// </returns>
 920#if NET8_0_OR_GREATER
 921    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of 'obj'.
 922#endif
 923    public Task<int> InsertOrReplaceAsync (object obj)
 1924    {
 2925      return WriteAsync (conn => conn.InsertOrReplace (obj));
 1926    }
 927
 928    /// <summary>
 929    /// Inserts the given object (and updates its
 930    /// auto incremented primary key if it has one).
 931    /// The return value is the number of rows added to the table.
 932    /// If a UNIQUE constraint violation occurs with
 933    /// some pre-existing object, this function deletes
 934    /// the old object.
 935    /// </summary>
 936    /// <param name="obj">
 937    /// The object to insert.
 938    /// </param>
 939    /// <param name="objType">
 940    /// The type of object to insert.
 941    /// </param>
 942    /// <returns>
 943    /// The number of rows modified.
 944    /// </returns>
 945    public Task<int> InsertOrReplaceAsync (
 946      object obj,
 947#if NET8_0_OR_GREATER
 948      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 949#endif
 950      Type objType)
 1951    {
 2952      return WriteAsync (conn => conn.InsertOrReplace (obj, objType));
 1953    }
 954
 955    /// <summary>
 956    /// Updates all of the columns of a table using the specified object
 957    /// except for its primary key.
 958    /// The object is required to have a primary key.
 959    /// </summary>
 960    /// <param name="obj">
 961    /// The object to update. It must have a primary key designated using the PrimaryKeyAttribute.
 962    /// </param>
 963    /// <returns>
 964    /// The number of rows updated.
 965    /// </returns>
 966#if NET8_0_OR_GREATER
 967    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of 'obj'.
 968#endif
 969    public Task<int> UpdateAsync (object obj)
 1970    {
 2971      return WriteAsync (conn => conn.Update (obj));
 1972    }
 973
 974    /// <summary>
 975    /// Updates all of the columns of a table using the specified object
 976    /// except for its primary key.
 977    /// The object is required to have a primary key.
 978    /// </summary>
 979    /// <param name="obj">
 980    /// The object to update. It must have a primary key designated using the PrimaryKeyAttribute.
 981    /// </param>
 982    /// <param name="objType">
 983    /// The type of object to insert.
 984    /// </param>
 985    /// <returns>
 986    /// The number of rows updated.
 987    /// </returns>
 988    public Task<int> UpdateAsync (
 989      object obj,
 990#if NET8_0_OR_GREATER
 991      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 992#endif
 993      Type objType)
 1994    {
 2995      return WriteAsync (conn => conn.Update (obj, objType));
 1996    }
 997
 998    /// <summary>
 999    /// Updates all specified objects.
 1000    /// </summary>
 1001    /// <param name="objects">
 1002    /// An <see cref="IEnumerable"/> of the objects to insert.
 1003    /// </param>
 1004    /// <param name="runInTransaction">
 1005    /// A boolean indicating if the inserts should be wrapped in a transaction
 1006    /// </param>
 1007    /// <returns>
 1008    /// The number of rows modified.
 1009    /// </returns>
 1010#if NET8_0_OR_GREATER
 1011    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of all ob
 1012#endif
 1013    public Task<int> UpdateAllAsync (IEnumerable objects, bool runInTransaction = true)
 11014    {
 21015      return WriteAsync (conn => conn.UpdateAll (objects, runInTransaction));
 11016    }
 1017
 1018    /// <summary>
 1019    /// Deletes the given object from the database using its primary key.
 1020    /// </summary>
 1021    /// <param name="objectToDelete">
 1022    /// The object to delete. It must have a primary key designated using the PrimaryKeyAttribute.
 1023    /// </param>
 1024    /// <returns>
 1025    /// The number of rows deleted.
 1026    /// </returns>
 1027#if NET8_0_OR_GREATER
 1028    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of 'objec
 1029#endif
 1030    public Task<int> DeleteAsync (object objectToDelete)
 21031    {
 41032      return WriteAsync (conn => conn.Delete (objectToDelete));
 21033    }
 1034
 1035    /// <summary>
 1036    /// Deletes the object with the specified primary key.
 1037    /// </summary>
 1038    /// <param name="primaryKey">
 1039    /// The primary key of the object to delete.
 1040    /// </param>
 1041    /// <returns>
 1042    /// The number of objects deleted.
 1043    /// </returns>
 1044    /// <typeparam name='T'>
 1045    /// The type of object.
 1046    /// </typeparam>
 1047    public Task<int> DeleteAsync<
 1048#if NET8_0_OR_GREATER
 1049      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1050#endif
 1051      T> (object primaryKey)
 01052    {
 01053      return WriteAsync (conn => conn.Delete<T> (primaryKey));
 01054    }
 1055
 1056    /// <summary>
 1057    /// Deletes the object with the specified primary key.
 1058    /// </summary>
 1059    /// <param name="primaryKey">
 1060    /// The primary key of the object to delete.
 1061    /// </param>
 1062    /// <param name="map">
 1063    /// The TableMapping used to identify the table.
 1064    /// </param>
 1065    /// <returns>
 1066    /// The number of objects deleted.
 1067    /// </returns>
 1068    public Task<int> DeleteAsync (object primaryKey, TableMapping map)
 01069    {
 01070      return WriteAsync (conn => conn.Delete (primaryKey, map));
 01071    }
 1072
 1073    /// <summary>
 1074    /// Deletes all the objects from the specified table.
 1075    /// WARNING WARNING: Let me repeat. It deletes ALL the objects from the
 1076    /// specified table. Do you really want to do that?
 1077    /// </summary>
 1078    /// <returns>
 1079    /// The number of objects deleted.
 1080    /// </returns>
 1081    /// <typeparam name='T'>
 1082    /// The type of objects to delete.
 1083    /// </typeparam>
 1084    public Task<int> DeleteAllAsync<
 1085#if NET8_0_OR_GREATER
 1086      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1087#endif
 1088      T> ()
 11089    {
 21090      return WriteAsync (conn => conn.DeleteAll<T> ());
 11091    }
 1092
 1093    /// <summary>
 1094    /// Deletes all the objects from the specified table.
 1095    /// WARNING WARNING: Let me repeat. It deletes ALL the objects from the
 1096    /// specified table. Do you really want to do that?
 1097    /// </summary>
 1098    /// <param name="map">
 1099    /// The TableMapping used to identify the table.
 1100    /// </param>
 1101    /// <returns>
 1102    /// The number of objects deleted.
 1103    /// </returns>
 1104    public Task<int> DeleteAllAsync (TableMapping map)
 01105    {
 01106      return WriteAsync (conn => conn.DeleteAll (map));
 01107    }
 1108
 1109    /// <summary>
 1110    /// Backup the entire database to the specified path.
 1111    /// </summary>
 1112    /// <param name="destinationDatabasePath">Path to backup file.</param>
 1113    /// <param name="databaseName">The name of the database to backup (usually "main").</param>
 1114    public Task BackupAsync (string destinationDatabasePath, string databaseName = "main")
 11115    {
 21116      return WriteAsync (conn => {
 21117        conn.Backup (destinationDatabasePath, databaseName);
 21118        return 0;
 21119      });
 11120    }
 1121
 1122    /// <summary>
 1123    /// Attempts to retrieve an object with the given primary key from the table
 1124    /// associated with the specified type. Use of this method requires that
 1125    /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
 1126    /// </summary>
 1127    /// <param name="pk">
 1128    /// The primary key.
 1129    /// </param>
 1130    /// <returns>
 1131    /// The object with the given primary key. Throws a not found exception
 1132    /// if the object is not found.
 1133    /// </returns>
 1134    public Task<T> GetAsync<
 1135#if NET8_0_OR_GREATER
 1136      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1137#endif
 1138      T> (object pk)
 1139      where T : new()
 101140    {
 201141      return ReadAsync (conn => conn.Get<T> (pk));
 101142    }
 1143
 1144    /// <summary>
 1145    /// Attempts to retrieve an object with the given primary key from the table
 1146    /// associated with the specified type. Use of this method requires that
 1147    /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
 1148    /// </summary>
 1149    /// <param name="pk">
 1150    /// The primary key.
 1151    /// </param>
 1152    /// <param name="map">
 1153    /// The TableMapping used to identify the table.
 1154    /// </param>
 1155    /// <returns>
 1156    /// The object with the given primary key. Throws a not found exception
 1157    /// if the object is not found.
 1158    /// </returns>
 1159    public Task<object> GetAsync (object pk, TableMapping map)
 01160    {
 01161      return ReadAsync (conn => conn.Get (pk, map));
 01162    }
 1163
 1164    /// <summary>
 1165    /// Attempts to retrieve the first object that matches the predicate from the table
 1166    /// associated with the specified type.
 1167    /// </summary>
 1168    /// <param name="predicate">
 1169    /// A predicate for which object to find.
 1170    /// </param>
 1171    /// <returns>
 1172    /// The object that matches the given predicate. Throws a not found exception
 1173    /// if the object is not found.
 1174    /// </returns>
 1175    public Task<T> GetAsync<
 1176#if NET8_0_OR_GREATER
 1177      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1178# endif
 1179      T> (Expression<Func<T, bool>> predicate)
 1180      where T : new()
 11181    {
 21182      return ReadAsync (conn => conn.Get<T> (predicate));
 11183    }
 1184
 1185    /// <summary>
 1186    /// Attempts to retrieve an object with the given primary key from the table
 1187    /// associated with the specified type. Use of this method requires that
 1188    /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
 1189    /// </summary>
 1190    /// <param name="pk">
 1191    /// The primary key.
 1192    /// </param>
 1193    /// <returns>
 1194    /// The object with the given primary key or null
 1195    /// if the object is not found.
 1196    /// </returns>
 1197    public Task<T> FindAsync<
 1198#if NET8_0_OR_GREATER
 1199      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1200#endif
 1201      T> (object pk)
 1202      where T : new()
 21203    {
 41204      return ReadAsync (conn => conn.Find<T> (pk));
 21205    }
 1206
 1207    /// <summary>
 1208    /// Attempts to retrieve an object with the given primary key from the table
 1209    /// associated with the specified type. Use of this method requires that
 1210    /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
 1211    /// </summary>
 1212    /// <param name="pk">
 1213    /// The primary key.
 1214    /// </param>
 1215    /// <param name="map">
 1216    /// The TableMapping used to identify the table.
 1217    /// </param>
 1218    /// <returns>
 1219    /// The object with the given primary key or null
 1220    /// if the object is not found.
 1221    /// </returns>
 1222    public Task<object> FindAsync (object pk, TableMapping map)
 01223    {
 01224      return ReadAsync (conn => conn.Find (pk, map));
 01225    }
 1226
 1227    /// <summary>
 1228    /// Attempts to retrieve the first object that matches the predicate from the table
 1229    /// associated with the specified type.
 1230    /// </summary>
 1231    /// <param name="predicate">
 1232    /// A predicate for which object to find.
 1233    /// </param>
 1234    /// <returns>
 1235    /// The object that matches the given predicate or null
 1236    /// if the object is not found.
 1237    /// </returns>
 1238    public Task<T> FindAsync<
 1239#if NET8_0_OR_GREATER
 1240      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1241#endif
 1242      T> (Expression<Func<T, bool>> predicate)
 1243      where T : new()
 21244    {
 41245      return ReadAsync (conn => conn.Find<T> (predicate));
 21246    }
 1247
 1248    /// <summary>
 1249    /// Attempts to retrieve the first object that matches the query from the table
 1250    /// associated with the specified type.
 1251    /// </summary>
 1252    /// <param name="query">
 1253    /// The fully escaped SQL.
 1254    /// </param>
 1255    /// <param name="args">
 1256    /// Arguments to substitute for the occurences of '?' in the query.
 1257    /// </param>
 1258    /// <returns>
 1259    /// The object that matches the given predicate or null
 1260    /// if the object is not found.
 1261    /// </returns>
 1262    public Task<T> FindWithQueryAsync<
 1263#if NET8_0_OR_GREATER
 1264      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1265#endif
 1266      T> (string query, params object[] args)
 1267      where T : new()
 01268    {
 01269      return ReadAsync (conn => conn.FindWithQuery<T> (query, args));
 01270    }
 1271
 1272    /// <summary>
 1273    /// Attempts to retrieve the first object that matches the query from the table
 1274    /// associated with the specified type.
 1275    /// </summary>
 1276    /// <param name="map">
 1277    /// The TableMapping used to identify the table.
 1278    /// </param>
 1279    /// <param name="query">
 1280    /// The fully escaped SQL.
 1281    /// </param>
 1282    /// <param name="args">
 1283    /// Arguments to substitute for the occurences of '?' in the query.
 1284    /// </param>
 1285    /// <returns>
 1286    /// The object that matches the given predicate or null
 1287    /// if the object is not found.
 1288    /// </returns>
 1289    public Task<object> FindWithQueryAsync (TableMapping map, string query, params object[] args)
 01290    {
 01291      return ReadAsync (conn => conn.FindWithQuery (map, query, args));
 01292    }
 1293
 1294    /// <summary>
 1295    /// Retrieves the mapping that is automatically generated for the given type.
 1296    /// </summary>
 1297    /// <param name="type">
 1298    /// The type whose mapping to the database is returned.
 1299    /// </param>
 1300    /// <param name="createFlags">
 1301    /// Optional flags allowing implicit PK and indexes based on naming conventions
 1302    /// </param>
 1303    /// <returns>
 1304    /// The mapping represents the schema of the columns of the database and contains
 1305    /// methods to set and get properties of objects.
 1306    /// </returns>
 1307    public Task<TableMapping> GetMappingAsync (
 1308#if NET8_0_OR_GREATER
 1309      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1310#endif
 1311      Type type,
 1312      CreateFlags createFlags = CreateFlags.None)
 11313    {
 21314      return ReadAsync (conn => conn.GetMapping (type, createFlags));
 11315    }
 1316
 1317    /// <summary>
 1318    /// Retrieves the mapping that is automatically generated for the given type.
 1319    /// </summary>
 1320    /// <param name="createFlags">
 1321    /// Optional flags allowing implicit PK and indexes based on naming conventions
 1322    /// </param>
 1323    /// <returns>
 1324    /// The mapping represents the schema of the columns of the database and contains
 1325    /// methods to set and get properties of objects.
 1326    /// </returns>
 1327    public Task<TableMapping> GetMappingAsync<
 1328#if NET8_0_OR_GREATER
 1329      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1330#endif
 1331      T> (CreateFlags createFlags = CreateFlags.None)
 1332      where T : new()
 01333    {
 01334      return ReadAsync (conn => conn.GetMapping<T> (createFlags));
 01335    }
 1336
 1337    /// <summary>
 1338    /// Query the built-in sqlite table_info table for a specific tables columns.
 1339    /// </summary>
 1340    /// <returns>The columns contains in the table.</returns>
 1341    /// <param name="tableName">Table name.</param>
 1342    public Task<List<SQLiteConnection.ColumnInfo>> GetTableInfoAsync (string tableName)
 01343    {
 01344      return ReadAsync (conn => conn.GetTableInfo (tableName));
 01345    }
 1346
 1347    /// <summary>
 1348    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1349    /// in the command text for each of the arguments and then executes that command.
 1350    /// Use this method instead of Query when you don't expect rows back. Such cases include
 1351    /// INSERTs, UPDATEs, and DELETEs.
 1352    /// You can set the Trace or TimeExecution properties of the connection
 1353    /// to profile execution.
 1354    /// </summary>
 1355    /// <param name="query">
 1356    /// The fully escaped SQL.
 1357    /// </param>
 1358    /// <param name="args">
 1359    /// Arguments to substitute for the occurences of '?' in the query.
 1360    /// </param>
 1361    /// <returns>
 1362    /// The number of rows modified in the database as a result of this execution.
 1363    /// </returns>
 1364    public Task<int> ExecuteAsync (string query, params object[] args)
 101365    {
 201366      return WriteAsync (conn => conn.Execute (query, args));
 101367    }
 1368
 1369    /// <summary>
 1370    /// Inserts all specified objects.
 1371    /// </summary>
 1372    /// <param name="objects">
 1373    /// An <see cref="IEnumerable"/> of the objects to insert.
 1374    /// </param>
 1375    /// <param name="runInTransaction">
 1376    /// A boolean indicating if the inserts should be wrapped in a transaction.
 1377    /// </param>
 1378    /// <returns>
 1379    /// The number of rows added to the table.
 1380    /// </returns>
 1381#if NET8_0_OR_GREATER
 1382    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of all ob
 1383#endif
 1384    public Task<int> InsertAllAsync (IEnumerable objects, bool runInTransaction = true)
 31385    {
 61386      return WriteAsync (conn => conn.InsertAll (objects, runInTransaction));
 31387    }
 1388
 1389    /// <summary>
 1390    /// Inserts all specified objects.
 1391    /// </summary>
 1392    /// <param name="objects">
 1393    /// An <see cref="IEnumerable"/> of the objects to insert.
 1394    /// </param>
 1395    /// <param name="extra">
 1396    /// Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
 1397    /// </param>
 1398    /// <param name="runInTransaction">
 1399    /// A boolean indicating if the inserts should be wrapped in a transaction.
 1400    /// </param>
 1401    /// <returns>
 1402    /// The number of rows added to the table.
 1403    /// </returns>
 1404#if NET8_0_OR_GREATER
 1405    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of all ob
 1406#endif
 1407    public Task<int> InsertAllAsync (IEnumerable objects, string extra, bool runInTransaction = true)
 01408    {
 01409      return WriteAsync (conn => conn.InsertAll (objects, extra, runInTransaction));
 01410    }
 1411
 1412    /// <summary>
 1413    /// Inserts all specified objects.
 1414    /// </summary>
 1415    /// <param name="objects">
 1416    /// An <see cref="IEnumerable"/> of the objects to insert.
 1417    /// </param>
 1418    /// <param name="objType">
 1419    /// The type of object to insert.
 1420    /// </param>
 1421    /// <param name="runInTransaction">
 1422    /// A boolean indicating if the inserts should be wrapped in a transaction.
 1423    /// </param>
 1424    /// <returns>
 1425    /// The number of rows added to the table.
 1426    /// </returns>
 1427#if NET8_0_OR_GREATER
 1428    [RequiresUnreferencedCode ("This method requires ''DynamicallyAccessedMemberTypes.All' on the runtime type of all ob
 1429#endif
 1430    public Task<int> InsertAllAsync (IEnumerable objects, Type objType, bool runInTransaction = true)
 01431    {
 01432      return WriteAsync (conn => conn.InsertAll (objects, objType, runInTransaction));
 01433    }
 1434
 1435    /// <summary>
 1436    /// Executes <paramref name="action"/> within a (possibly nested) transaction by wrapping it in a SAVEPOINT. If an
 1437    /// exception occurs the whole transaction is rolled back, not just the current savepoint. The exception
 1438    /// is rethrown.
 1439    /// </summary>
 1440    /// <param name="action">
 1441    /// The <see cref="Action"/> to perform within a transaction. <paramref name="action"/> can contain any number
 1442    /// of operations on the connection but should never call <see cref="SQLiteConnection.Commit"/> or
 1443    /// <see cref="SQLiteConnection.Commit"/>.
 1444    /// </param>
 1445    public Task RunInTransactionAsync (Action<SQLiteConnection> action)
 61446    {
 121447      return TransactAsync<object> (conn => {
 121448        conn.BeginTransaction ();
 121449        try {
 121450          action (conn);
 111451          conn.Commit ();
 101452          return null;
 61453        }
 101454        catch (Exception) {
 81455          conn.Rollback ();
 81456          throw;
 61457        }
 101458      });
 61459    }
 1460
 1461    /// <summary>
 1462    /// Returns a queryable interface to the table represented by the given type.
 1463    /// </summary>
 1464    /// <returns>
 1465    /// A queryable object that is able to translate Where, OrderBy, and Take
 1466    /// queries into native SQL.
 1467    /// </returns>
 1468    public AsyncTableQuery<T> Table<
 1469#if NET8_0_OR_GREATER
 1470      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1471#endif
 1472      T> ()
 1473      where T : new()
 5291474    {
 1475      //
 1476      // This isn't async as the underlying connection doesn't go out to the database
 1477      // until the query is performed. The Async methods are on the query iteself.
 1478      //
 5291479      var conn = GetConnection ();
 5291480      return new AsyncTableQuery<T> (conn.Table<T> ());
 5291481    }
 1482
 1483    /// <summary>
 1484    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1485    /// in the command text for each of the arguments and then executes that command.
 1486    /// Use this method when return primitive values.
 1487    /// You can set the Trace or TimeExecution properties of the connection
 1488    /// to profile execution.
 1489    /// </summary>
 1490    /// <param name="query">
 1491    /// The fully escaped SQL.
 1492    /// </param>
 1493    /// <param name="args">
 1494    /// Arguments to substitute for the occurences of '?' in the query.
 1495    /// </param>
 1496    /// <returns>
 1497    /// The number of rows modified in the database as a result of this execution.
 1498    /// </returns>
 1499    public Task<T> ExecuteScalarAsync<T> (string query, params object[] args)
 91500    {
 181501      return WriteAsync (conn => {
 181502        var command = conn.CreateCommand (query, args);
 181503        return command.ExecuteScalar<T> ();
 181504      });
 91505    }
 1506
 1507    /// <summary>
 1508    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1509    /// in the command text for each of the arguments and then executes that command.
 1510    /// It returns each row of the result using the mapping automatically generated for
 1511    /// the given type.
 1512    /// </summary>
 1513    /// <param name="query">
 1514    /// The fully escaped SQL.
 1515    /// </param>
 1516    /// <param name="args">
 1517    /// Arguments to substitute for the occurences of '?' in the query.
 1518    /// </param>
 1519    /// <returns>
 1520    /// A list with one result for each row returned by the query.
 1521    /// </returns>
 1522    public Task<List<T>> QueryAsync<
 1523#if NET8_0_OR_GREATER
 1524      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1525#endif
 1526      T> (string query, params object[] args)
 1527      where T : new()
 81528    {
 161529      return ReadAsync (conn => conn.Query<T> (query, args));
 81530    }
 1531
 1532    /// <summary>
 1533    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1534    /// in the command text for each of the arguments and then executes that command.
 1535    /// It returns the first column of each row of the result.
 1536    /// </summary>
 1537    /// <param name="query">
 1538    /// The fully escaped SQL.
 1539    /// </param>
 1540    /// <param name="args">
 1541    /// Arguments to substitute for the occurences of '?' in the query.
 1542    /// </param>
 1543    /// <returns>
 1544    /// A list with one result for the first column of each row returned by the query.
 1545    /// </returns>
 1546    public Task<List<T>> QueryScalarsAsync<T> (string query, params object[] args)
 41547    {
 81548      return ReadAsync (conn => conn.QueryScalars<T> (query, args));
 41549    }
 1550
 1551    /// <summary>
 1552    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1553    /// in the command text for each of the arguments and then executes that command.
 1554    /// It returns each row of the result using the specified mapping. This function is
 1555    /// only used by libraries in order to query the database via introspection. It is
 1556    /// normally not used.
 1557    /// </summary>
 1558    /// <param name="map">
 1559    /// A <see cref="TableMapping"/> to use to convert the resulting rows
 1560    /// into objects.
 1561    /// </param>
 1562    /// <param name="query">
 1563    /// The fully escaped SQL.
 1564    /// </param>
 1565    /// <param name="args">
 1566    /// Arguments to substitute for the occurences of '?' in the query.
 1567    /// </param>
 1568    /// <returns>
 1569    /// An enumerable with one result for each row returned by the query.
 1570    /// </returns>
 1571    public Task<List<object>> QueryAsync (TableMapping map, string query, params object[] args)
 01572    {
 01573      return ReadAsync (conn => conn.Query (map, query, args));
 01574    }
 1575
 1576    /// <summary>
 1577    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1578    /// in the command text for each of the arguments and then executes that command.
 1579    /// It returns each row of the result using the mapping automatically generated for
 1580    /// the given type.
 1581    /// </summary>
 1582    /// <param name="query">
 1583    /// The fully escaped SQL.
 1584    /// </param>
 1585    /// <param name="args">
 1586    /// Arguments to substitute for the occurences of '?' in the query.
 1587    /// </param>
 1588    /// <returns>
 1589    /// An enumerable with one result for each row returned by the query.
 1590    /// The enumerator will call sqlite3_step on each call to MoveNext, so the database
 1591    /// connection must remain open for the lifetime of the enumerator.
 1592    /// </returns>
 1593    public Task<IEnumerable<T>> DeferredQueryAsync<
 1594#if NET8_0_OR_GREATER
 1595      [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1596#endif
 1597      T> (string query, params object[] args)
 1598      where T : new()
 01599    {
 01600      return ReadAsync (conn => (IEnumerable<T>)conn.DeferredQuery<T> (query, args).ToList ());
 01601    }
 1602
 1603    /// <summary>
 1604    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1605    /// in the command text for each of the arguments and then executes that command.
 1606    /// It returns each row of the result using the specified mapping. This function is
 1607    /// only used by libraries in order to query the database via introspection. It is
 1608    /// normally not used.
 1609    /// </summary>
 1610    /// <param name="map">
 1611    /// A <see cref="TableMapping"/> to use to convert the resulting rows
 1612    /// into objects.
 1613    /// </param>
 1614    /// <param name="query">
 1615    /// The fully escaped SQL.
 1616    /// </param>
 1617    /// <param name="args">
 1618    /// Arguments to substitute for the occurences of '?' in the query.
 1619    /// </param>
 1620    /// <returns>
 1621    /// An enumerable with one result for each row returned by the query.
 1622    /// The enumerator will call sqlite3_step on each call to MoveNext, so the database
 1623    /// connection must remain open for the lifetime of the enumerator.
 1624    /// </returns>
 1625    public Task<IEnumerable<object>> DeferredQueryAsync (TableMapping map, string query, params object[] args)
 01626    {
 01627      return ReadAsync (conn => (IEnumerable<object>)conn.DeferredQuery (map, query, args).ToList ());
 01628    }
 1629
 1630    /// <summary>
 1631    /// Change the encryption key for a SQLCipher database with "pragma rekey = ...".
 1632    /// </summary>
 1633    /// <param name="key">Encryption key plain text that is converted to the real encryption key using PBKDF2 key deriva
 1634    public Task ReKeyAsync (string key)
 01635    {
 01636      return WriteAsync<object> (conn => {
 01637        conn.ReKey (key);
 01638        return null;
 01639      });
 01640    }
 1641
 1642    /// <summary>
 1643    /// Change the encryption key for a SQLCipher database.
 1644    /// </summary>
 1645    /// <param name="key">256-bit (32 byte) or 384-bit (48 bytes) encryption key data</param>
 1646    public Task ReKeyAsync (byte[] key)
 01647    {
 01648      return WriteAsync<object> (conn => {
 01649        conn.ReKey (key);
 01650        return null;
 01651      });
 01652    }
 1653  }
 1654
 1655  /// <summary>
 1656  /// Query to an asynchronous database connection.
 1657  /// </summary>
 1658  public class AsyncTableQuery<
 1659#if NET8_0_OR_GREATER
 1660    [DynamicallyAccessedMembers (DynamicallyAccessedMemberTypes.All)]
 1661#endif
 1662  T>
 1663    where T : new()
 1664  {
 1665    TableQuery<T> _innerQuery;
 1666
 1667    /// <summary>
 1668    /// Creates a new async query that uses given the synchronous query.
 1669    /// </summary>
 1670    public AsyncTableQuery (TableQuery<T> innerQuery)
 1671    {
 1672      _innerQuery = innerQuery;
 1673    }
 1674
 1675    Task<U> ReadAsync<U> (Func<SQLiteConnectionWithLock, U> read)
 1676    {
 1677      return Task.Factory.StartNew (() => {
 1678        var conn = (SQLiteConnectionWithLock)_innerQuery.Connection;
 1679        using (conn.Lock ()) {
 1680          return read (conn);
 1681        }
 1682      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 1683    }
 1684
 1685    Task<U> WriteAsync<U> (Func<SQLiteConnectionWithLock, U> write)
 1686    {
 1687      return Task.Factory.StartNew (() => {
 1688        var conn = (SQLiteConnectionWithLock)_innerQuery.Connection;
 1689        using (conn.Lock ()) {
 1690          return write (conn);
 1691        }
 1692      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 1693    }
 1694
 1695    /// <summary>
 1696    /// Filters the query based on a predicate.
 1697    /// </summary>
 1698    public AsyncTableQuery<T> Where (Expression<Func<T, bool>> predExpr)
 1699    {
 1700      return new AsyncTableQuery<T> (_innerQuery.Where (predExpr));
 1701    }
 1702
 1703    /// <summary>
 1704    /// Skips a given number of elements from the query and then yields the remainder.
 1705    /// </summary>
 1706    public AsyncTableQuery<T> Skip (int n)
 1707    {
 1708      return new AsyncTableQuery<T> (_innerQuery.Skip (n));
 1709    }
 1710
 1711    /// <summary>
 1712    /// Yields a given number of elements from the query and then skips the remainder.
 1713    /// </summary>
 1714    public AsyncTableQuery<T> Take (int n)
 1715    {
 1716      return new AsyncTableQuery<T> (_innerQuery.Take (n));
 1717    }
 1718
 1719    /// <summary>
 1720    /// Order the query results according to a key.
 1721    /// </summary>
 1722    public AsyncTableQuery<T> OrderBy<U> (Expression<Func<T, U>> orderExpr)
 1723    {
 1724      return new AsyncTableQuery<T> (_innerQuery.OrderBy<U> (orderExpr));
 1725    }
 1726
 1727    /// <summary>
 1728    /// Order the query results according to a key.
 1729    /// </summary>
 1730    public AsyncTableQuery<T> OrderByDescending<U> (Expression<Func<T, U>> orderExpr)
 1731    {
 1732      return new AsyncTableQuery<T> (_innerQuery.OrderByDescending<U> (orderExpr));
 1733    }
 1734
 1735    /// <summary>
 1736    /// Order the query results according to a key.
 1737    /// </summary>
 1738    public AsyncTableQuery<T> ThenBy<U> (Expression<Func<T, U>> orderExpr)
 1739    {
 1740      return new AsyncTableQuery<T> (_innerQuery.ThenBy<U> (orderExpr));
 1741    }
 1742
 1743    /// <summary>
 1744    /// Order the query results according to a key.
 1745    /// </summary>
 1746    public AsyncTableQuery<T> ThenByDescending<U> (Expression<Func<T, U>> orderExpr)
 1747    {
 1748      return new AsyncTableQuery<T> (_innerQuery.ThenByDescending<U> (orderExpr));
 1749    }
 1750
 1751    /// <summary>
 1752    /// Queries the database and returns the results as a List.
 1753    /// </summary>
 1754    public Task<List<T>> ToListAsync ()
 1755    {
 1756      return ReadAsync (conn => _innerQuery.ToList ());
 1757    }
 1758
 1759    /// <summary>
 1760    /// Queries the database and returns the results as an array.
 1761    /// </summary>
 1762    public Task<T[]> ToArrayAsync ()
 1763    {
 1764      return ReadAsync (conn => _innerQuery.ToArray ());
 1765    }
 1766
 1767    /// <summary>
 1768    /// Execute SELECT COUNT(*) on the query
 1769    /// </summary>
 1770    public Task<int> CountAsync ()
 1771    {
 1772      return ReadAsync (conn => _innerQuery.Count ());
 1773    }
 1774
 1775    /// <summary>
 1776    /// Execute SELECT COUNT(*) on the query with an additional WHERE clause.
 1777    /// </summary>
 1778    public Task<int> CountAsync (Expression<Func<T, bool>> predExpr)
 1779    {
 1780      return ReadAsync (conn => _innerQuery.Count (predExpr));
 1781    }
 1782
 1783    /// <summary>
 1784    /// Returns the element at a given index
 1785    /// </summary>
 1786    public Task<T> ElementAtAsync (int index)
 1787    {
 1788      return ReadAsync (conn => _innerQuery.ElementAt (index));
 1789    }
 1790
 1791    /// <summary>
 1792    /// Returns the first element of this query.
 1793    /// </summary>
 1794    public Task<T> FirstAsync ()
 1795    {
 1796      return ReadAsync (conn => _innerQuery.First ());
 1797    }
 1798
 1799    /// <summary>
 1800    /// Returns the first element of this query, or null if no element is found.
 1801    /// </summary>
 1802    public Task<T> FirstOrDefaultAsync ()
 1803    {
 1804      return ReadAsync (conn => _innerQuery.FirstOrDefault ());
 1805    }
 1806
 1807    /// <summary>
 1808    /// Returns the first element of this query that matches the predicate.
 1809    /// </summary>
 1810    public Task<T> FirstAsync (Expression<Func<T, bool>> predExpr)
 1811    {
 1812      return ReadAsync (conn => _innerQuery.First (predExpr));
 1813    }
 1814
 1815    /// <summary>
 1816    /// Returns the first element of this query that matches the predicate.
 1817    /// </summary>
 1818    public Task<T> FirstOrDefaultAsync (Expression<Func<T, bool>> predExpr)
 1819    {
 1820      return ReadAsync (conn => _innerQuery.FirstOrDefault (predExpr));
 1821    }
 1822
 1823    /// <summary>
 1824    /// Delete all the rows that match this query and the given predicate.
 1825    /// </summary>
 1826    public Task<int> DeleteAsync (Expression<Func<T, bool>> predExpr)
 1827    {
 1828      return WriteAsync (conn => _innerQuery.Delete (predExpr));
 1829    }
 1830
 1831    /// <summary>
 1832    /// Delete all the rows that match this query.
 1833    /// </summary>
 1834    public Task<int> DeleteAsync ()
 1835    {
 1836      return WriteAsync (conn => _innerQuery.Delete ());
 1837    }
 1838  }
 1839
 1840  class SQLiteConnectionPool
 1841  {
 1842    class Entry
 1843    {
 1844      public SQLiteConnectionWithLock Connection { get; private set; }
 1845
 1846      public SQLiteConnectionString ConnectionString { get; }
 1847
 1848      public object TransactionLock { get; } = new object ();
 1849
 1850      public Entry (SQLiteConnectionString connectionString)
 1851      {
 1852        ConnectionString = connectionString;
 1853        Connection = new SQLiteConnectionWithLock (ConnectionString);
 1854
 1855        // If the database is FullMutex, then we don't need to bother locking
 1856        if (ConnectionString.OpenFlags.HasFlag (SQLiteOpenFlags.FullMutex)) {
 1857          Connection.SkipLock = true;
 1858        }
 1859      }
 1860
 1861      public void Close ()
 1862      {
 1863        var wc = Connection;
 1864        Connection = null;
 1865        if (wc != null) {
 1866          wc.Close ();
 1867        }
 1868      }
 1869    }
 1870
 1871    readonly Dictionary<string, Entry> _entries = new Dictionary<string, Entry> ();
 1872    readonly object _entriesLock = new object ();
 1873
 1874    static readonly SQLiteConnectionPool _shared = new SQLiteConnectionPool ();
 1875
 1876    /// <summary>
 1877    /// Gets the singleton instance of the connection tool.
 1878    /// </summary>
 1879    public static SQLiteConnectionPool Shared {
 1880      get {
 1881        return _shared;
 1882      }
 1883    }
 1884
 1885    public SQLiteConnectionWithLock GetConnection (SQLiteConnectionString connectionString)
 1886    {
 1887      return GetConnectionAndTransactionLock (connectionString, out var _);
 1888    }
 1889
 1890    public SQLiteConnectionWithLock GetConnectionAndTransactionLock (SQLiteConnectionString connectionString, out object
 1891    {
 1892      var key = connectionString.UniqueKey;
 1893      Entry entry;
 1894      lock (_entriesLock) {
 1895        if (!_entries.TryGetValue (key, out entry)) {
 1896          // The opens the database while we're locked
 1897          // This is to ensure another thread doesn't get an unopened database
 1898          entry = new Entry (connectionString);
 1899          _entries[key] = entry;
 1900        }
 1901        transactionLock = entry.TransactionLock;
 1902        return entry.Connection;
 1903      }
 1904    }
 1905
 1906    public void CloseConnection (SQLiteConnectionString connectionString)
 1907    {
 1908      var key = connectionString.UniqueKey;
 1909      Entry entry;
 1910      lock (_entriesLock) {
 1911        if (_entries.TryGetValue (key, out entry)) {
 1912          _entries.Remove (key);
 1913        }
 1914      }
 1915      entry?.Close ();
 1916    }
 1917
 1918    /// <summary>
 1919    /// Closes all connections managed by this pool.
 1920    /// </summary>
 1921    public void Reset ()
 1922    {
 1923      List<Entry> entries;
 1924      lock (_entriesLock) {
 1925        entries = new List<Entry> (_entries.Values);
 1926        _entries.Clear ();
 1927      }
 1928
 1929      foreach (var e in entries) {
 1930        e.Close ();
 1931      }
 1932    }
 1933  }
 1934
 1935  /// <summary>
 1936  /// This is a normal connection except it contains a Lock method that
 1937  /// can be used to serialize access to the database
 1938  /// in lieu of using the sqlite's FullMutex support.
 1939  /// </summary>
 1940  public class SQLiteConnectionWithLock : SQLiteConnection
 1941  {
 1942    readonly object _lockPoint = new object ();
 1943
 1944    /// <summary>
 1945    /// Initializes a new instance of the <see cref="T:SQLite.SQLiteConnectionWithLock"/> class.
 1946    /// </summary>
 1947    /// <param name="connectionString">Connection string containing the DatabasePath.</param>
 1948    public SQLiteConnectionWithLock (SQLiteConnectionString connectionString)
 1949      : base (connectionString)
 1950    {
 1951    }
 1952
 1953    /// <summary>
 1954    /// Gets or sets a value indicating whether this <see cref="T:SQLite.SQLiteConnectionWithLock"/> skip lock.
 1955    /// </summary>
 1956    /// <value><c>true</c> if skip lock; otherwise, <c>false</c>.</value>
 1957    public bool SkipLock { get; set; }
 1958
 1959    /// <summary>
 1960    /// Lock the database to serialize access to it. To unlock it, call Dispose
 1961    /// on the returned object.
 1962    /// </summary>
 1963    /// <returns>The lock.</returns>
 1964    public IDisposable Lock ()
 1965    {
 1966      return SkipLock ? (IDisposable)new FakeLockWrapper() : new LockWrapper (_lockPoint);
 1967    }
 1968
 1969    class LockWrapper : IDisposable
 1970    {
 1971      object _lockPoint;
 1972
 1973      public LockWrapper (object lockPoint)
 1974      {
 1975        _lockPoint = lockPoint;
 1976        Monitor.Enter (_lockPoint);
 1977      }
 1978
 1979      public void Dispose ()
 1980      {
 1981        Monitor.Exit (_lockPoint);
 1982      }
 1983    }
 1984    class FakeLockWrapper : IDisposable
 1985    {
 1986      public void Dispose ()
 1987      {
 1988      }
 1989    }
 1990  }
 1991}
 1992

Methods/Properties

.ctor(System.String,System.Boolean)
.ctor(System.String,SQLite.SQLiteOpenFlags,System.Boolean)
.ctor(SQLite.SQLiteConnectionString)
DatabasePath()
LibVersionNumber()
DateTimeStringFormat()
GetBusyTimeout()
SetBusyTimeoutAsync(System.TimeSpan)
EnableWriteAheadLoggingAsync()
StoreDateTimeAsTicks()
StoreTimeSpanAsTicks()
Trace()
Trace(System.Boolean)
Tracer()
Tracer(System.Action`1<System.String>)
TimeExecution()
TimeExecution(System.Boolean)
TableMappings()
ResetPool()
GetConnection()
GetConnectionAndTransactionLock(System.Object&)
CloseAsync()
ReadAsync(System.Func`2<SQLite.SQLiteConnectionWithLock,T>)
WriteAsync(System.Func`2<SQLite.SQLiteConnectionWithLock,T>)
TransactAsync(System.Func`2<SQLite.SQLiteConnectionWithLock,T>)
EnableLoadExtensionAsync(System.Boolean)
CreateTableAsync(SQLite.CreateFlags)
CreateTableAsync(System.Type,SQLite.CreateFlags)
CreateTablesAsync(SQLite.CreateFlags)
CreateTablesAsync(SQLite.CreateFlags)
CreateTablesAsync(SQLite.CreateFlags)
CreateTablesAsync(SQLite.CreateFlags)
CreateTablesAsync(SQLite.CreateFlags,System.Type[])
DropTableAsync()
DropTableAsync(SQLite.TableMapping)
CreateIndexAsync(System.String,System.String,System.Boolean)
CreateIndexAsync(System.String,System.String,System.String,System.Boolean)
CreateIndexAsync(System.String,System.String[],System.Boolean)
CreateIndexAsync(System.String,System.String,System.String[],System.Boolean)
CreateIndexAsync(System.Linq.Expressions.Expression`1<System.Func`2<T,System.Object>>,System.Boolean)
InsertAsync(System.Object)
InsertAsync(System.Object,System.Type)
InsertAsync(System.Object,System.String)
InsertAsync(System.Object,System.String,System.Type)
InsertOrReplaceAsync(System.Object)
InsertOrReplaceAsync(System.Object,System.Type)
UpdateAsync(System.Object)
UpdateAsync(System.Object,System.Type)
UpdateAllAsync(System.Collections.IEnumerable,System.Boolean)
DeleteAsync(System.Object)
DeleteAsync(System.Object)
DeleteAsync(System.Object,SQLite.TableMapping)
DeleteAllAsync()
DeleteAllAsync(SQLite.TableMapping)
BackupAsync(System.String,System.String)
GetAsync(System.Object)
GetAsync(System.Object,SQLite.TableMapping)
GetAsync(System.Linq.Expressions.Expression`1<System.Func`2<T,System.Boolean>>)
FindAsync(System.Object)
FindAsync(System.Object,SQLite.TableMapping)
FindAsync(System.Linq.Expressions.Expression`1<System.Func`2<T,System.Boolean>>)
FindWithQueryAsync(System.String,System.Object[])
FindWithQueryAsync(SQLite.TableMapping,System.String,System.Object[])
GetMappingAsync(System.Type,SQLite.CreateFlags)
GetMappingAsync(SQLite.CreateFlags)
GetTableInfoAsync(System.String)
ExecuteAsync(System.String,System.Object[])
InsertAllAsync(System.Collections.IEnumerable,System.Boolean)
InsertAllAsync(System.Collections.IEnumerable,System.String,System.Boolean)
InsertAllAsync(System.Collections.IEnumerable,System.Type,System.Boolean)
RunInTransactionAsync(System.Action`1<SQLite.SQLiteConnection>)
Table()
ExecuteScalarAsync(System.String,System.Object[])
QueryAsync(System.String,System.Object[])
QueryScalarsAsync(System.String,System.Object[])
QueryAsync(SQLite.TableMapping,System.String,System.Object[])
DeferredQueryAsync(System.String,System.Object[])
DeferredQueryAsync(SQLite.TableMapping,System.String,System.Object[])
ReKeyAsync(System.String)
ReKeyAsync(System.Byte[])