< Summary

Information
Class: SQLite.SQLiteAsyncConnection
Assembly: SQLite.Tests
File(s): /home/runner/work/sqlite-net/sqlite-net/src/SQLiteAsync.cs
Tag: 172_8459418968
Line coverage
71%
Covered lines: 193
Uncovered lines: 76
Coverable lines: 269
Total lines: 1628
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.Linq;
 27using System.Linq.Expressions;
 28using System.Threading;
 29using System.Threading.Tasks;
 30
 31#pragma warning disable 1591 // XML Doc Comments
 32
 33namespace SQLite
 34{
 35  public interface ISQLiteAsyncConnection
 36  {
 37    string DatabasePath { get; }
 38    int LibVersionNumber { get; }
 39    string DateTimeStringFormat { get; }
 40    bool StoreDateTimeAsTicks { get; }
 41    bool StoreTimeSpanAsTicks { get; }
 42    bool Trace { get; set; }
 43    Action<string> Tracer { get; set; }
 44    bool TimeExecution { get; set; }
 45    IEnumerable<TableMapping> TableMappings { get; }
 46
 47    Task BackupAsync (string destinationDatabasePath, string databaseName = "main");
 48    Task CloseAsync ();
 49    Task<int> CreateIndexAsync (string tableName, string columnName, bool unique = false);
 50    Task<int> CreateIndexAsync (string indexName, string tableName, string columnName, bool unique = false);
 51    Task<int> CreateIndexAsync (string tableName, string[] columnNames, bool unique = false);
 52    Task<int> CreateIndexAsync (string indexName, string tableName, string[] columnNames, bool unique = false);
 53    Task<int> CreateIndexAsync<T> (Expression<Func<T, object>> property, bool unique = false);
 54    Task<CreateTableResult> CreateTableAsync<T> (CreateFlags createFlags = CreateFlags.None) where T : new();
 55    Task<CreateTableResult> CreateTableAsync (Type ty, CreateFlags createFlags = CreateFlags.None);
 56    Task<CreateTablesResult> CreateTablesAsync<T, T2> (CreateFlags createFlags = CreateFlags.None)
 57      where T : new()
 58      where T2 : new();
 59    Task<CreateTablesResult> CreateTablesAsync<T, T2, T3> (CreateFlags createFlags = CreateFlags.None)
 60      where T : new()
 61      where T2 : new()
 62      where T3 : new();
 63    Task<CreateTablesResult> CreateTablesAsync<T, T2, T3, T4> (CreateFlags createFlags = CreateFlags.None)
 64      where T : new()
 65      where T2 : new()
 66      where T3 : new()
 67      where T4 : new();
 68    Task<CreateTablesResult> CreateTablesAsync<T, T2, T3, T4, T5> (CreateFlags createFlags = CreateFlags.None)
 69      where T : new()
 70      where T2 : new()
 71      where T3 : new()
 72      where T4 : new()
 73      where T5 : new();
 74    Task<CreateTablesResult> CreateTablesAsync (CreateFlags createFlags = CreateFlags.None, params Type[] types);
 75    Task<IEnumerable<T>> DeferredQueryAsync<T> (string query, params object[] args) where T : new();
 76    Task<IEnumerable<object>> DeferredQueryAsync (TableMapping map, string query, params object[] args);
 77    Task<int> DeleteAllAsync<T> ();
 78    Task<int> DeleteAllAsync (TableMapping map);
 79    Task<int> DeleteAsync (object objectToDelete);
 80    Task<int> DeleteAsync<T> (object primaryKey);
 81    Task<int> DeleteAsync (object primaryKey, TableMapping map);
 82    Task<int> DropTableAsync<T> () where T : new();
 83    Task<int> DropTableAsync (TableMapping map);
 84    Task EnableLoadExtensionAsync (bool enabled);
 85    Task EnableWriteAheadLoggingAsync ();
 86    Task<int> ExecuteAsync (string query, params object[] args);
 87    Task<T> ExecuteScalarAsync<T> (string query, params object[] args);
 88    Task<T> FindAsync<T> (object pk) where T : new();
 89    Task<object> FindAsync (object pk, TableMapping map);
 90    Task<T> FindAsync<T> (Expression<Func<T, bool>> predicate) where T : new();
 91    Task<T> FindWithQueryAsync<T> (string query, params object[] args) where T : new();
 92    Task<object> FindWithQueryAsync (TableMapping map, string query, params object[] args);
 93    Task<T> GetAsync<T> (object pk) where T : new();
 94    Task<object> GetAsync (object pk, TableMapping map);
 95    Task<T> GetAsync<T> (Expression<Func<T, bool>> predicate) where T : new();
 96    TimeSpan GetBusyTimeout ();
 97    SQLiteConnectionWithLock GetConnection ();
 98    Task<TableMapping> GetMappingAsync (Type type, CreateFlags createFlags = CreateFlags.None);
 99    Task<TableMapping> GetMappingAsync<T> (CreateFlags createFlags = CreateFlags.None) where T : new();
 100    Task<List<SQLiteConnection.ColumnInfo>> GetTableInfoAsync (string tableName);
 101    Task<int> InsertAllAsync (IEnumerable objects, bool runInTransaction = true);
 102    Task<int> InsertAllAsync (IEnumerable objects, string extra, bool runInTransaction = true);
 103    Task<int> InsertAllAsync (IEnumerable objects, Type objType, bool runInTransaction = true);
 104    Task<int> InsertAsync (object obj);
 105    Task<int> InsertAsync (object obj, Type objType);
 106    Task<int> InsertAsync (object obj, string extra);
 107    Task<int> InsertAsync (object obj, string extra, Type objType);
 108    Task<int> InsertOrReplaceAsync (object obj);
 109    Task<int> InsertOrReplaceAsync (object obj, Type objType);
 110    Task<List<T>> QueryAsync<T> (string query, params object[] args) where T : new();
 111    Task<List<object>> QueryAsync (TableMapping map, string query, params object[] args);
 112    Task<List<T>> QueryScalarsAsync<T> (string query, params object[] args);
 113    Task ReKeyAsync (string key);
 114    Task ReKeyAsync (byte[] key);
 115    Task RunInTransactionAsync (Action<SQLiteConnection> action);
 116    Task SetBusyTimeoutAsync (TimeSpan value);
 117    AsyncTableQuery<T> Table<T> () where T : new();
 118    Task<int> UpdateAllAsync (IEnumerable objects, bool runInTransaction = true);
 119    Task<int> UpdateAsync (object obj);
 120    Task<int> UpdateAsync (object obj, Type objType);
 121  }
 122
 123  /// <summary>
 124  /// A pooled asynchronous connection to a SQLite database.
 125  /// </summary>
 126  public partial class SQLiteAsyncConnection : ISQLiteAsyncConnection
 127  {
 128    readonly SQLiteConnectionString _connectionString;
 129
 130    /// <summary>
 131    /// Constructs a new SQLiteAsyncConnection and opens a pooled SQLite database specified by databasePath.
 132    /// </summary>
 133    /// <param name="databasePath">
 134    /// Specifies the path to the database file.
 135    /// </param>
 136    /// <param name="storeDateTimeAsTicks">
 137    /// Specifies whether to store DateTime properties as ticks (true) or strings (false). You
 138    /// absolutely do want to store them as Ticks in all new projects. The value of false is
 139    /// only here for backwards compatibility. There is a *significant* speed advantage, with no
 140    /// down sides, when setting storeDateTimeAsTicks = true.
 141    /// If you use DateTimeOffset properties, it will be always stored as ticks regardingless
 142    /// the storeDateTimeAsTicks parameter.
 143    /// </param>
 144    public SQLiteAsyncConnection (string databasePath, bool storeDateTimeAsTicks = true)
 70145      : this (new SQLiteConnectionString (databasePath, SQLiteOpenFlags.Create | SQLiteOpenFlags.ReadWrite | SQLiteOpenF
 70146    {
 70147    }
 148
 149    /// <summary>
 150    /// Constructs a new SQLiteAsyncConnection and opens a pooled SQLite database specified by databasePath.
 151    /// </summary>
 152    /// <param name="databasePath">
 153    /// Specifies the path to the database file.
 154    /// </param>
 155    /// <param name="openFlags">
 156    /// Flags controlling how the connection should be opened.
 157    /// Async connections should have the FullMutex flag set to provide best performance.
 158    /// </param>
 159    /// <param name="storeDateTimeAsTicks">
 160    /// Specifies whether to store DateTime properties as ticks (true) or strings (false). You
 161    /// absolutely do want to store them as Ticks in all new projects. The value of false is
 162    /// only here for backwards compatibility. There is a *significant* speed advantage, with no
 163    /// down sides, when setting storeDateTimeAsTicks = true.
 164    /// If you use DateTimeOffset properties, it will be always stored as ticks regardingless
 165    /// the storeDateTimeAsTicks parameter.
 166    /// </param>
 167    public SQLiteAsyncConnection (string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = true)
 0168      : this (new SQLiteConnectionString (databasePath, openFlags, storeDateTimeAsTicks))
 0169    {
 0170    }
 171
 172    /// <summary>
 173    /// Constructs a new SQLiteAsyncConnection and opens a pooled SQLite database
 174    /// using the given connection string.
 175    /// </summary>
 176    /// <param name="connectionString">
 177    /// Details on how to find and open the database.
 178    /// </param>
 77179    public SQLiteAsyncConnection (SQLiteConnectionString connectionString)
 77180    {
 77181      _connectionString = connectionString;
 77182    }
 183
 184    /// <summary>
 185    /// Gets the database path used by this connection.
 186    /// </summary>
 0187    public string DatabasePath => GetConnection ().DatabasePath;
 188
 189    /// <summary>
 190    /// Gets the SQLite library version number. 3007014 would be v3.7.14
 191    /// </summary>
 0192    public int LibVersionNumber => GetConnection ().LibVersionNumber;
 193
 194    /// <summary>
 195    /// The format to use when storing DateTime properties as strings. Ignored if StoreDateTimeAsTicks is true.
 196    /// </summary>
 197    /// <value>The date time string format.</value>
 0198    public string DateTimeStringFormat => GetConnection ().DateTimeStringFormat;
 199
 200    /// <summary>
 201    /// The amount of time to wait for a table to become unlocked.
 202    /// </summary>
 203    public TimeSpan GetBusyTimeout ()
 2204    {
 2205      return GetConnection ().BusyTimeout;
 2206    }
 207
 208    /// <summary>
 209    /// Sets the amount of time to wait for a table to become unlocked.
 210    /// </summary>
 211    public Task SetBusyTimeoutAsync (TimeSpan value)
 2212    {
 4213      return ReadAsync<object> (conn => {
 4214        conn.BusyTimeout = value;
 4215        return null;
 4216      });
 2217    }
 218
 219    /// <summary>
 220    /// Enables the write ahead logging. WAL is significantly faster in most scenarios
 221    /// by providing better concurrency and better disk IO performance than the normal
 222    /// journal mode. You only need to call this function once in the lifetime of the database.
 223    /// </summary>
 224    public Task EnableWriteAheadLoggingAsync ()
 1225    {
 2226      return WriteAsync<object> (conn => {
 2227        conn.EnableWriteAheadLogging ();
 2228        return null;
 2229      });
 1230    }
 231
 232    /// <summary>
 233    /// Whether to store DateTime properties as ticks (true) or strings (false).
 234    /// </summary>
 0235    public bool StoreDateTimeAsTicks => GetConnection ().StoreDateTimeAsTicks;
 236
 237    /// <summary>
 238    /// Whether to store TimeSpan properties as ticks (true) or strings (false).
 239    /// </summary>
 0240    public bool StoreTimeSpanAsTicks => GetConnection ().StoreTimeSpanAsTicks;
 241
 242    /// <summary>
 243    /// Whether to writer queries to <see cref="Tracer"/> during execution.
 244    /// </summary>
 245    /// <value>The tracer.</value>
 246    public bool Trace {
 0247      get { return GetConnection ().Trace; }
 45248      set { GetConnection ().Trace = value; }
 249    }
 250
 251    /// <summary>
 252    /// The delegate responsible for writing trace lines.
 253    /// </summary>
 254    /// <value>The tracer.</value>
 255    public Action<string> Tracer {
 0256      get { return GetConnection ().Tracer; }
 45257      set { GetConnection ().Tracer = value; }
 258    }
 259
 260    /// <summary>
 261    /// Whether Trace lines should be written that show the execution time of queries.
 262    /// </summary>
 263    public bool TimeExecution {
 0264      get { return GetConnection ().TimeExecution; }
 0265      set { GetConnection ().TimeExecution = value; }
 266    }
 267
 268    /// <summary>
 269    /// Returns the mappings from types to tables that the connection
 270    /// currently understands.
 271    /// </summary>
 0272    public IEnumerable<TableMapping> TableMappings => GetConnection ().TableMappings;
 273
 274    /// <summary>
 275    /// Closes all connections to all async databases.
 276    /// You should *never* need to do this.
 277    /// This is a blocking operation that will return when all connections
 278    /// have been closed.
 279    /// </summary>
 280    public static void ResetPool ()
 0281    {
 0282      SQLiteConnectionPool.Shared.Reset ();
 0283    }
 284
 285    /// <summary>
 286    /// Gets the pooled lockable connection used by this async connection.
 287    /// You should never need to use this. This is provided only to add additional
 288    /// functionality to SQLite-net. If you use this connection, you must use
 289    /// the Lock method on it while using it.
 290    /// </summary>
 291    public SQLiteConnectionWithLock GetConnection ()
 1330292    {
 1330293      return SQLiteConnectionPool.Shared.GetConnection (_connectionString);
 1330294    }
 295
 296    SQLiteConnectionWithLock GetConnectionAndTransactionLock (out object transactionLock)
 6297    {
 6298      return SQLiteConnectionPool.Shared.GetConnectionAndTransactionLock (_connectionString, out transactionLock);
 6299    }
 300
 301    /// <summary>
 302    /// Closes any pooled connections used by the database.
 303    /// </summary>
 304    public Task CloseAsync ()
 62305    {
 124306      return Task.Factory.StartNew (() => {
 124307        SQLiteConnectionPool.Shared.CloseConnection (_connectionString);
 124308      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 62309    }
 310
 311    Task<T> ReadAsync<T> (Func<SQLiteConnectionWithLock, T> read)
 30312    {
 60313      return Task.Factory.StartNew (() => {
 60314        var conn = GetConnection ();
 90315        using (conn.Lock ()) {
 60316          return read (conn);
 30317        }
 60318      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 30319    }
 320
 321    Task<T> WriteAsync<T> (Func<SQLiteConnectionWithLock, T> write)
 739322    {
 1478323      return Task.Factory.StartNew (() => {
 1478324        var conn = GetConnection ();
 2217325        using (conn.Lock ()) {
 1478326          return write (conn);
 739327        }
 1478328      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 739329    }
 330
 331    Task<T> TransactAsync<T> (Func<SQLiteConnectionWithLock, T> transact)
 6332    {
 12333      return Task.Factory.StartNew (() => {
 12334        var conn = GetConnectionAndTransactionLock (out var transactionLock);
 18335        lock (transactionLock) {
 18336          using (conn.Lock ()) {
 12337            return transact (conn);
 6338          }
 6339        }
 10340      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 6341    }
 342
 343    /// <summary>
 344    /// Enable or disable extension loading.
 345    /// </summary>
 346    public Task EnableLoadExtensionAsync (bool enabled)
 0347    {
 0348      return WriteAsync<object> (conn => {
 0349        conn.EnableLoadExtension (enabled);
 0350        return null;
 0351      });
 0352    }
 353
 354    /// <summary>
 355    /// Executes a "create table if not exists" on the database. It also
 356    /// creates any specified indexes on the columns of the table. It uses
 357    /// a schema automatically generated from the specified type. You can
 358    /// later access this schema by calling GetMapping.
 359    /// </summary>
 360    /// <returns>
 361    /// Whether the table was created or migrated.
 362    /// </returns>
 363    public Task<CreateTableResult> CreateTableAsync<T> (CreateFlags createFlags = CreateFlags.None)
 364      where T : new()
 68365    {
 136366      return WriteAsync (conn => conn.CreateTable<T> (createFlags));
 68367    }
 368
 369    /// <summary>
 370    /// Executes a "create table if not exists" on the database. It also
 371    /// creates any specified indexes on the columns of the table. It uses
 372    /// a schema automatically generated from the specified type. You can
 373    /// later access this schema by calling GetMapping.
 374    /// </summary>
 375    /// <param name="ty">Type to reflect to a database table.</param>
 376    /// <param name="createFlags">Optional flags allowing implicit PK and indexes based on naming conventions.</param>
 377    /// <returns>
 378    /// Whether the table was created or migrated.
 379    /// </returns>
 380    public Task<CreateTableResult> CreateTableAsync (Type ty, CreateFlags createFlags = CreateFlags.None)
 3381    {
 6382      return WriteAsync (conn => conn.CreateTable (ty, createFlags));
 3383    }
 384
 385    /// <summary>
 386    /// Executes a "create table if not exists" on the database for each type. It also
 387    /// creates any specified indexes on the columns of the table. It uses
 388    /// a schema automatically generated from the specified type. You can
 389    /// later access this schema by calling GetMapping.
 390    /// </summary>
 391    /// <returns>
 392    /// Whether the table was created or migrated for each type.
 393    /// </returns>
 394    public Task<CreateTablesResult> CreateTablesAsync<T, T2> (CreateFlags createFlags = CreateFlags.None)
 395      where T : new()
 396      where T2 : new()
 1397    {
 1398      return CreateTablesAsync (createFlags, typeof (T), typeof (T2));
 1399    }
 400
 401    /// <summary>
 402    /// Executes a "create table if not exists" on the database for each type. It also
 403    /// creates any specified indexes on the columns of the table. It uses
 404    /// a schema automatically generated from the specified type. You can
 405    /// later access this schema by calling GetMapping.
 406    /// </summary>
 407    /// <returns>
 408    /// Whether the table was created or migrated for each type.
 409    /// </returns>
 410    public Task<CreateTablesResult> CreateTablesAsync<T, T2, T3> (CreateFlags createFlags = CreateFlags.None)
 411      where T : new()
 412      where T2 : new()
 413      where T3 : new()
 1414    {
 1415      return CreateTablesAsync (createFlags, typeof (T), typeof (T2), typeof (T3));
 1416    }
 417
 418    /// <summary>
 419    /// Executes a "create table if not exists" on the database for each type. It also
 420    /// creates any specified indexes on the columns of the table. It uses
 421    /// a schema automatically generated from the specified type. You can
 422    /// later access this schema by calling GetMapping.
 423    /// </summary>
 424    /// <returns>
 425    /// Whether the table was created or migrated for each type.
 426    /// </returns>
 427    public Task<CreateTablesResult> CreateTablesAsync<T, T2, T3, T4> (CreateFlags createFlags = CreateFlags.None)
 428      where T : new()
 429      where T2 : new()
 430      where T3 : new()
 431      where T4 : new()
 1432    {
 1433      return CreateTablesAsync (createFlags, typeof (T), typeof (T2), typeof (T3), typeof (T4));
 1434    }
 435
 436    /// <summary>
 437    /// Executes a "create table if not exists" on the database for each type. It also
 438    /// creates any specified indexes on the columns of the table. It uses
 439    /// a schema automatically generated from the specified type. You can
 440    /// later access this schema by calling GetMapping.
 441    /// </summary>
 442    /// <returns>
 443    /// Whether the table was created or migrated for each type.
 444    /// </returns>
 445    public Task<CreateTablesResult> CreateTablesAsync<T, T2, T3, T4, T5> (CreateFlags createFlags = CreateFlags.None)
 446      where T : new()
 447      where T2 : new()
 448      where T3 : new()
 449      where T4 : new()
 450      where T5 : new()
 1451    {
 1452      return CreateTablesAsync (createFlags, typeof (T), typeof (T2), typeof (T3), typeof (T4), typeof (T5));
 1453    }
 454
 455    /// <summary>
 456    /// Executes a "create table if not exists" on the database for each type. It also
 457    /// creates any specified indexes on the columns of the table. It uses
 458    /// a schema automatically generated from the specified type. You can
 459    /// later access this schema by calling GetMapping.
 460    /// </summary>
 461    /// <returns>
 462    /// Whether the table was created or migrated for each type.
 463    /// </returns>
 464    public Task<CreateTablesResult> CreateTablesAsync (CreateFlags createFlags = CreateFlags.None, params Type[] types)
 5465    {
 10466      return WriteAsync (conn => conn.CreateTables (createFlags, types));
 5467    }
 468
 469    /// <summary>
 470    /// Executes a "drop table" on the database.  This is non-recoverable.
 471    /// </summary>
 472    public Task<int> DropTableAsync<T> ()
 473      where T : new()
 2474    {
 4475      return WriteAsync (conn => conn.DropTable<T> ());
 2476    }
 477
 478    /// <summary>
 479    /// Executes a "drop table" on the database.  This is non-recoverable.
 480    /// </summary>
 481    /// <param name="map">
 482    /// The TableMapping used to identify the table.
 483    /// </param>
 484    public Task<int> DropTableAsync (TableMapping map)
 1485    {
 2486      return WriteAsync (conn => conn.DropTable (map));
 1487    }
 488
 489    /// <summary>
 490    /// Creates an index for the specified table and column.
 491    /// </summary>
 492    /// <param name="tableName">Name of the database table</param>
 493    /// <param name="columnName">Name of the column to index</param>
 494    /// <param name="unique">Whether the index should be unique</param>
 495    /// <returns>Zero on success.</returns>
 496    public Task<int> CreateIndexAsync (string tableName, string columnName, bool unique = false)
 1497    {
 2498      return WriteAsync (conn => conn.CreateIndex (tableName, columnName, unique));
 1499    }
 500
 501    /// <summary>
 502    /// Creates an index for the specified table and column.
 503    /// </summary>
 504    /// <param name="indexName">Name of the index to create</param>
 505    /// <param name="tableName">Name of the database table</param>
 506    /// <param name="columnName">Name of the column to index</param>
 507    /// <param name="unique">Whether the index should be unique</param>
 508    /// <returns>Zero on success.</returns>
 509    public Task<int> CreateIndexAsync (string indexName, string tableName, string columnName, bool unique = false)
 1510    {
 2511      return WriteAsync (conn => conn.CreateIndex (indexName, tableName, columnName, unique));
 1512    }
 513
 514    /// <summary>
 515    /// Creates an index for the specified table and columns.
 516    /// </summary>
 517    /// <param name="tableName">Name of the database table</param>
 518    /// <param name="columnNames">An array of column names to index</param>
 519    /// <param name="unique">Whether the index should be unique</param>
 520    /// <returns>Zero on success.</returns>
 521    public Task<int> CreateIndexAsync (string tableName, string[] columnNames, bool unique = false)
 1522    {
 2523      return WriteAsync (conn => conn.CreateIndex (tableName, columnNames, unique));
 1524    }
 525
 526    /// <summary>
 527    /// Creates an index for the specified table and columns.
 528    /// </summary>
 529    /// <param name="indexName">Name of the index to create</param>
 530    /// <param name="tableName">Name of the database table</param>
 531    /// <param name="columnNames">An array of column names to index</param>
 532    /// <param name="unique">Whether the index should be unique</param>
 533    /// <returns>Zero on success.</returns>
 534    public Task<int> CreateIndexAsync (string indexName, string tableName, string[] columnNames, bool unique = false)
 1535    {
 2536      return WriteAsync (conn => conn.CreateIndex (indexName, tableName, columnNames, unique));
 1537    }
 538
 539    /// <summary>
 540    /// Creates an index for the specified object property.
 541    /// e.g. CreateIndex&lt;Client&gt;(c => c.Name);
 542    /// </summary>
 543    /// <typeparam name="T">Type to reflect to a database table.</typeparam>
 544    /// <param name="property">Property to index</param>
 545    /// <param name="unique">Whether the index should be unique</param>
 546    /// <returns>Zero on success.</returns>
 547    public Task<int> CreateIndexAsync<T> (Expression<Func<T, object>> property, bool unique = false)
 1548    {
 2549      return WriteAsync (conn => conn.CreateIndex (property, unique));
 1550    }
 551
 552    /// <summary>
 553    /// Inserts the given object and (and updates its
 554    /// auto incremented primary key if it has one).
 555    /// </summary>
 556    /// <param name="obj">
 557    /// The object to insert.
 558    /// </param>
 559    /// <returns>
 560    /// The number of rows added to the table.
 561    /// </returns>
 562    public Task<int> InsertAsync (object obj)
 620563    {
 1240564      return WriteAsync (conn => conn.Insert (obj));
 620565    }
 566
 567    /// <summary>
 568    /// Inserts the given object (and updates its
 569    /// auto incremented primary key if it has one).
 570    /// The return value is the number of rows added to the table.
 571    /// </summary>
 572    /// <param name="obj">
 573    /// The object to insert.
 574    /// </param>
 575    /// <param name="objType">
 576    /// The type of object to insert.
 577    /// </param>
 578    /// <returns>
 579    /// The number of rows added to the table.
 580    /// </returns>
 581    public Task<int> InsertAsync (object obj, Type objType)
 1582    {
 2583      return WriteAsync (conn => conn.Insert (obj, objType));
 1584    }
 585
 586    /// <summary>
 587    /// Inserts the given object (and updates its
 588    /// auto incremented primary key if it has one).
 589    /// The return value is the number of rows added to the table.
 590    /// </summary>
 591    /// <param name="obj">
 592    /// The object to insert.
 593    /// </param>
 594    /// <param name="extra">
 595    /// Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
 596    /// </param>
 597    /// <returns>
 598    /// The number of rows added to the table.
 599    /// </returns>
 600    public Task<int> InsertAsync (object obj, string extra)
 1601    {
 2602      return WriteAsync (conn => conn.Insert (obj, extra));
 1603    }
 604
 605    /// <summary>
 606    /// Inserts the given object (and updates its
 607    /// auto incremented primary key if it has one).
 608    /// The return value is the number of rows added to the table.
 609    /// </summary>
 610    /// <param name="obj">
 611    /// The object to insert.
 612    /// </param>
 613    /// <param name="extra">
 614    /// Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
 615    /// </param>
 616    /// <param name="objType">
 617    /// The type of object to insert.
 618    /// </param>
 619    /// <returns>
 620    /// The number of rows added to the table.
 621    /// </returns>
 622    public Task<int> InsertAsync (object obj, string extra, Type objType)
 1623    {
 2624      return WriteAsync (conn => conn.Insert (obj, extra, objType));
 1625    }
 626
 627    /// <summary>
 628    /// Inserts the given object (and updates its
 629    /// auto incremented primary key if it has one).
 630    /// The return value is the number of rows added to the table.
 631    /// If a UNIQUE constraint violation occurs with
 632    /// some pre-existing object, this function deletes
 633    /// the old object.
 634    /// </summary>
 635    /// <param name="obj">
 636    /// The object to insert.
 637    /// </param>
 638    /// <returns>
 639    /// The number of rows modified.
 640    /// </returns>
 641    public Task<int> InsertOrReplaceAsync (object obj)
 1642    {
 2643      return WriteAsync (conn => conn.InsertOrReplace (obj));
 1644    }
 645
 646    /// <summary>
 647    /// Inserts the given object (and updates its
 648    /// auto incremented primary key if it has one).
 649    /// The return value is the number of rows added to the table.
 650    /// If a UNIQUE constraint violation occurs with
 651    /// some pre-existing object, this function deletes
 652    /// the old object.
 653    /// </summary>
 654    /// <param name="obj">
 655    /// The object to insert.
 656    /// </param>
 657    /// <param name="objType">
 658    /// The type of object to insert.
 659    /// </param>
 660    /// <returns>
 661    /// The number of rows modified.
 662    /// </returns>
 663    public Task<int> InsertOrReplaceAsync (object obj, Type objType)
 1664    {
 2665      return WriteAsync (conn => conn.InsertOrReplace (obj, objType));
 1666    }
 667
 668    /// <summary>
 669    /// Updates all of the columns of a table using the specified object
 670    /// except for its primary key.
 671    /// The object is required to have a primary key.
 672    /// </summary>
 673    /// <param name="obj">
 674    /// The object to update. It must have a primary key designated using the PrimaryKeyAttribute.
 675    /// </param>
 676    /// <returns>
 677    /// The number of rows updated.
 678    /// </returns>
 679    public Task<int> UpdateAsync (object obj)
 1680    {
 2681      return WriteAsync (conn => conn.Update (obj));
 1682    }
 683
 684    /// <summary>
 685    /// Updates all of the columns of a table using the specified object
 686    /// except for its primary key.
 687    /// The object is required to have a primary key.
 688    /// </summary>
 689    /// <param name="obj">
 690    /// The object to update. It must have a primary key designated using the PrimaryKeyAttribute.
 691    /// </param>
 692    /// <param name="objType">
 693    /// The type of object to insert.
 694    /// </param>
 695    /// <returns>
 696    /// The number of rows updated.
 697    /// </returns>
 698    public Task<int> UpdateAsync (object obj, Type objType)
 1699    {
 2700      return WriteAsync (conn => conn.Update (obj, objType));
 1701    }
 702
 703    /// <summary>
 704    /// Updates all specified objects.
 705    /// </summary>
 706    /// <param name="objects">
 707    /// An <see cref="IEnumerable"/> of the objects to insert.
 708    /// </param>
 709    /// <param name="runInTransaction">
 710    /// A boolean indicating if the inserts should be wrapped in a transaction
 711    /// </param>
 712    /// <returns>
 713    /// The number of rows modified.
 714    /// </returns>
 715    public Task<int> UpdateAllAsync (IEnumerable objects, bool runInTransaction = true)
 1716    {
 2717      return WriteAsync (conn => conn.UpdateAll (objects, runInTransaction));
 1718    }
 719
 720    /// <summary>
 721    /// Deletes the given object from the database using its primary key.
 722    /// </summary>
 723    /// <param name="objectToDelete">
 724    /// The object to delete. It must have a primary key designated using the PrimaryKeyAttribute.
 725    /// </param>
 726    /// <returns>
 727    /// The number of rows deleted.
 728    /// </returns>
 729    public Task<int> DeleteAsync (object objectToDelete)
 2730    {
 4731      return WriteAsync (conn => conn.Delete (objectToDelete));
 2732    }
 733
 734    /// <summary>
 735    /// Deletes the object with the specified primary key.
 736    /// </summary>
 737    /// <param name="primaryKey">
 738    /// The primary key of the object to delete.
 739    /// </param>
 740    /// <returns>
 741    /// The number of objects deleted.
 742    /// </returns>
 743    /// <typeparam name='T'>
 744    /// The type of object.
 745    /// </typeparam>
 746    public Task<int> DeleteAsync<T> (object primaryKey)
 0747    {
 0748      return WriteAsync (conn => conn.Delete<T> (primaryKey));
 0749    }
 750
 751    /// <summary>
 752    /// Deletes the object with the specified primary key.
 753    /// </summary>
 754    /// <param name="primaryKey">
 755    /// The primary key of the object to delete.
 756    /// </param>
 757    /// <param name="map">
 758    /// The TableMapping used to identify the table.
 759    /// </param>
 760    /// <returns>
 761    /// The number of objects deleted.
 762    /// </returns>
 763    public Task<int> DeleteAsync (object primaryKey, TableMapping map)
 0764    {
 0765      return WriteAsync (conn => conn.Delete (primaryKey, map));
 0766    }
 767
 768    /// <summary>
 769    /// Deletes all the objects from the specified table.
 770    /// WARNING WARNING: Let me repeat. It deletes ALL the objects from the
 771    /// specified table. Do you really want to do that?
 772    /// </summary>
 773    /// <returns>
 774    /// The number of objects deleted.
 775    /// </returns>
 776    /// <typeparam name='T'>
 777    /// The type of objects to delete.
 778    /// </typeparam>
 779    public Task<int> DeleteAllAsync<T> ()
 1780    {
 2781      return WriteAsync (conn => conn.DeleteAll<T> ());
 1782    }
 783
 784    /// <summary>
 785    /// Deletes all the objects from the specified table.
 786    /// WARNING WARNING: Let me repeat. It deletes ALL the objects from the
 787    /// specified table. Do you really want to do that?
 788    /// </summary>
 789    /// <param name="map">
 790    /// The TableMapping used to identify the table.
 791    /// </param>
 792    /// <returns>
 793    /// The number of objects deleted.
 794    /// </returns>
 795    public Task<int> DeleteAllAsync (TableMapping map)
 0796    {
 0797      return WriteAsync (conn => conn.DeleteAll (map));
 0798    }
 799
 800    /// <summary>
 801    /// Backup the entire database to the specified path.
 802    /// </summary>
 803    /// <param name="destinationDatabasePath">Path to backup file.</param>
 804    /// <param name="databaseName">The name of the database to backup (usually "main").</param>
 805    public Task BackupAsync (string destinationDatabasePath, string databaseName = "main")
 1806    {
 2807      return WriteAsync (conn => {
 2808        conn.Backup (destinationDatabasePath, databaseName);
 2809        return 0;
 2810      });
 1811    }
 812
 813    /// <summary>
 814    /// Attempts to retrieve an object with the given primary key from the table
 815    /// associated with the specified type. Use of this method requires that
 816    /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
 817    /// </summary>
 818    /// <param name="pk">
 819    /// The primary key.
 820    /// </param>
 821    /// <returns>
 822    /// The object with the given primary key. Throws a not found exception
 823    /// if the object is not found.
 824    /// </returns>
 825    public Task<T> GetAsync<T> (object pk)
 826      where T : new()
 10827    {
 20828      return ReadAsync (conn => conn.Get<T> (pk));
 10829    }
 830
 831    /// <summary>
 832    /// Attempts to retrieve an object with the given primary key from the table
 833    /// associated with the specified type. Use of this method requires that
 834    /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
 835    /// </summary>
 836    /// <param name="pk">
 837    /// The primary key.
 838    /// </param>
 839    /// <param name="map">
 840    /// The TableMapping used to identify the table.
 841    /// </param>
 842    /// <returns>
 843    /// The object with the given primary key. Throws a not found exception
 844    /// if the object is not found.
 845    /// </returns>
 846    public Task<object> GetAsync (object pk, TableMapping map)
 0847    {
 0848      return ReadAsync (conn => conn.Get (pk, map));
 0849    }
 850
 851    /// <summary>
 852    /// Attempts to retrieve the first object that matches the predicate from the table
 853    /// associated with the specified type.
 854    /// </summary>
 855    /// <param name="predicate">
 856    /// A predicate for which object to find.
 857    /// </param>
 858    /// <returns>
 859    /// The object that matches the given predicate. Throws a not found exception
 860    /// if the object is not found.
 861    /// </returns>
 862    public Task<T> GetAsync<T> (Expression<Func<T, bool>> predicate)
 863      where T : new()
 1864    {
 2865      return ReadAsync (conn => conn.Get<T> (predicate));
 1866    }
 867
 868    /// <summary>
 869    /// Attempts to retrieve an object with the given primary key from the table
 870    /// associated with the specified type. Use of this method requires that
 871    /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
 872    /// </summary>
 873    /// <param name="pk">
 874    /// The primary key.
 875    /// </param>
 876    /// <returns>
 877    /// The object with the given primary key or null
 878    /// if the object is not found.
 879    /// </returns>
 880    public Task<T> FindAsync<T> (object pk)
 881      where T : new()
 2882    {
 4883      return ReadAsync (conn => conn.Find<T> (pk));
 2884    }
 885
 886    /// <summary>
 887    /// Attempts to retrieve an object with the given primary key from the table
 888    /// associated with the specified type. Use of this method requires that
 889    /// the given type have a designated PrimaryKey (using the PrimaryKeyAttribute).
 890    /// </summary>
 891    /// <param name="pk">
 892    /// The primary key.
 893    /// </param>
 894    /// <param name="map">
 895    /// The TableMapping used to identify the table.
 896    /// </param>
 897    /// <returns>
 898    /// The object with the given primary key or null
 899    /// if the object is not found.
 900    /// </returns>
 901    public Task<object> FindAsync (object pk, TableMapping map)
 0902    {
 0903      return ReadAsync (conn => conn.Find (pk, map));
 0904    }
 905
 906    /// <summary>
 907    /// Attempts to retrieve the first object that matches the predicate from the table
 908    /// associated with the specified type.
 909    /// </summary>
 910    /// <param name="predicate">
 911    /// A predicate for which object to find.
 912    /// </param>
 913    /// <returns>
 914    /// The object that matches the given predicate or null
 915    /// if the object is not found.
 916    /// </returns>
 917    public Task<T> FindAsync<T> (Expression<Func<T, bool>> predicate)
 918      where T : new()
 2919    {
 4920      return ReadAsync (conn => conn.Find<T> (predicate));
 2921    }
 922
 923    /// <summary>
 924    /// Attempts to retrieve the first object that matches the query from the table
 925    /// associated with the specified type.
 926    /// </summary>
 927    /// <param name="query">
 928    /// The fully escaped SQL.
 929    /// </param>
 930    /// <param name="args">
 931    /// Arguments to substitute for the occurences of '?' in the query.
 932    /// </param>
 933    /// <returns>
 934    /// The object that matches the given predicate or null
 935    /// if the object is not found.
 936    /// </returns>
 937    public Task<T> FindWithQueryAsync<T> (string query, params object[] args)
 938      where T : new()
 0939    {
 0940      return ReadAsync (conn => conn.FindWithQuery<T> (query, args));
 0941    }
 942
 943    /// <summary>
 944    /// Attempts to retrieve the first object that matches the query from the table
 945    /// associated with the specified type.
 946    /// </summary>
 947    /// <param name="map">
 948    /// The TableMapping used to identify the table.
 949    /// </param>
 950    /// <param name="query">
 951    /// The fully escaped SQL.
 952    /// </param>
 953    /// <param name="args">
 954    /// Arguments to substitute for the occurences of '?' in the query.
 955    /// </param>
 956    /// <returns>
 957    /// The object that matches the given predicate or null
 958    /// if the object is not found.
 959    /// </returns>
 960    public Task<object> FindWithQueryAsync (TableMapping map, string query, params object[] args)
 0961    {
 0962      return ReadAsync (conn => conn.FindWithQuery (map, query, args));
 0963    }
 964
 965    /// <summary>
 966    /// Retrieves the mapping that is automatically generated for the given type.
 967    /// </summary>
 968    /// <param name="type">
 969    /// The type whose mapping to the database is returned.
 970    /// </param>
 971    /// <param name="createFlags">
 972    /// Optional flags allowing implicit PK and indexes based on naming conventions
 973    /// </param>
 974    /// <returns>
 975    /// The mapping represents the schema of the columns of the database and contains
 976    /// methods to set and get properties of objects.
 977    /// </returns>
 978    public Task<TableMapping> GetMappingAsync (Type type, CreateFlags createFlags = CreateFlags.None)
 1979    {
 2980      return ReadAsync (conn => conn.GetMapping (type, createFlags));
 1981    }
 982
 983    /// <summary>
 984    /// Retrieves the mapping that is automatically generated for the given type.
 985    /// </summary>
 986    /// <param name="createFlags">
 987    /// Optional flags allowing implicit PK and indexes based on naming conventions
 988    /// </param>
 989    /// <returns>
 990    /// The mapping represents the schema of the columns of the database and contains
 991    /// methods to set and get properties of objects.
 992    /// </returns>
 993    public Task<TableMapping> GetMappingAsync<T> (CreateFlags createFlags = CreateFlags.None)
 994      where T : new()
 0995    {
 0996      return ReadAsync (conn => conn.GetMapping<T> (createFlags));
 0997    }
 998
 999    /// <summary>
 1000    /// Query the built-in sqlite table_info table for a specific tables columns.
 1001    /// </summary>
 1002    /// <returns>The columns contains in the table.</returns>
 1003    /// <param name="tableName">Table name.</param>
 1004    public Task<List<SQLiteConnection.ColumnInfo>> GetTableInfoAsync (string tableName)
 01005    {
 01006      return ReadAsync (conn => conn.GetTableInfo (tableName));
 01007    }
 1008
 1009    /// <summary>
 1010    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1011    /// in the command text for each of the arguments and then executes that command.
 1012    /// Use this method instead of Query when you don't expect rows back. Such cases include
 1013    /// INSERTs, UPDATEs, and DELETEs.
 1014    /// You can set the Trace or TimeExecution properties of the connection
 1015    /// to profile execution.
 1016    /// </summary>
 1017    /// <param name="query">
 1018    /// The fully escaped SQL.
 1019    /// </param>
 1020    /// <param name="args">
 1021    /// Arguments to substitute for the occurences of '?' in the query.
 1022    /// </param>
 1023    /// <returns>
 1024    /// The number of rows modified in the database as a result of this execution.
 1025    /// </returns>
 1026    public Task<int> ExecuteAsync (string query, params object[] args)
 101027    {
 201028      return WriteAsync (conn => conn.Execute (query, args));
 101029    }
 1030
 1031    /// <summary>
 1032    /// Inserts all specified objects.
 1033    /// </summary>
 1034    /// <param name="objects">
 1035    /// An <see cref="IEnumerable"/> of the objects to insert.
 1036    /// <param name="runInTransaction"/>
 1037    /// A boolean indicating if the inserts should be wrapped in a transaction.
 1038    /// </param>
 1039    /// <returns>
 1040    /// The number of rows added to the table.
 1041    /// </returns>
 1042    public Task<int> InsertAllAsync (IEnumerable objects, bool runInTransaction = true)
 31043    {
 61044      return WriteAsync (conn => conn.InsertAll (objects, runInTransaction));
 31045    }
 1046
 1047    /// <summary>
 1048    /// Inserts all specified objects.
 1049    /// </summary>
 1050    /// <param name="objects">
 1051    /// An <see cref="IEnumerable"/> of the objects to insert.
 1052    /// </param>
 1053    /// <param name="extra">
 1054    /// Literal SQL code that gets placed into the command. INSERT {extra} INTO ...
 1055    /// </param>
 1056    /// <param name="runInTransaction">
 1057    /// A boolean indicating if the inserts should be wrapped in a transaction.
 1058    /// </param>
 1059    /// <returns>
 1060    /// The number of rows added to the table.
 1061    /// </returns>
 1062    public Task<int> InsertAllAsync (IEnumerable objects, string extra, bool runInTransaction = true)
 01063    {
 01064      return WriteAsync (conn => conn.InsertAll (objects, extra, runInTransaction));
 01065    }
 1066
 1067    /// <summary>
 1068    /// Inserts all specified objects.
 1069    /// </summary>
 1070    /// <param name="objects">
 1071    /// An <see cref="IEnumerable"/> of the objects to insert.
 1072    /// </param>
 1073    /// <param name="objType">
 1074    /// The type of object to insert.
 1075    /// </param>
 1076    /// <param name="runInTransaction">
 1077    /// A boolean indicating if the inserts should be wrapped in a transaction.
 1078    /// </param>
 1079    /// <returns>
 1080    /// The number of rows added to the table.
 1081    /// </returns>
 1082    public Task<int> InsertAllAsync (IEnumerable objects, Type objType, bool runInTransaction = true)
 01083    {
 01084      return WriteAsync (conn => conn.InsertAll (objects, objType, runInTransaction));
 01085    }
 1086
 1087    /// <summary>
 1088    /// Executes <paramref name="action"/> within a (possibly nested) transaction by wrapping it in a SAVEPOINT. If an
 1089    /// exception occurs the whole transaction is rolled back, not just the current savepoint. The exception
 1090    /// is rethrown.
 1091    /// </summary>
 1092    /// <param name="action">
 1093    /// The <see cref="Action"/> to perform within a transaction. <paramref name="action"/> can contain any number
 1094    /// of operations on the connection but should never call <see cref="SQLiteConnection.Commit"/> or
 1095    /// <see cref="SQLiteConnection.Commit"/>.
 1096    /// </param>
 1097    public Task RunInTransactionAsync (Action<SQLiteConnection> action)
 61098    {
 121099      return TransactAsync<object> (conn => {
 121100        conn.BeginTransaction ();
 121101        try {
 121102          action (conn);
 111103          conn.Commit ();
 101104          return null;
 61105        }
 101106        catch (Exception) {
 81107          conn.Rollback ();
 81108          throw;
 61109        }
 101110      });
 61111    }
 1112
 1113    /// <summary>
 1114    /// Returns a queryable interface to the table represented by the given type.
 1115    /// </summary>
 1116    /// <returns>
 1117    /// A queryable object that is able to translate Where, OrderBy, and Take
 1118    /// queries into native SQL.
 1119    /// </returns>
 1120    public AsyncTableQuery<T> Table<T> ()
 1121      where T : new()
 5291122    {
 1123      //
 1124      // This isn't async as the underlying connection doesn't go out to the database
 1125      // until the query is performed. The Async methods are on the query iteself.
 1126      //
 5291127      var conn = GetConnection ();
 5291128      return new AsyncTableQuery<T> (conn.Table<T> ());
 5291129    }
 1130
 1131    /// <summary>
 1132    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1133    /// in the command text for each of the arguments and then executes that command.
 1134    /// Use this method when return primitive values.
 1135    /// You can set the Trace or TimeExecution properties of the connection
 1136    /// to profile execution.
 1137    /// </summary>
 1138    /// <param name="query">
 1139    /// The fully escaped SQL.
 1140    /// </param>
 1141    /// <param name="args">
 1142    /// Arguments to substitute for the occurences of '?' in the query.
 1143    /// </param>
 1144    /// <returns>
 1145    /// The number of rows modified in the database as a result of this execution.
 1146    /// </returns>
 1147    public Task<T> ExecuteScalarAsync<T> (string query, params object[] args)
 91148    {
 181149      return WriteAsync (conn => {
 181150        var command = conn.CreateCommand (query, args);
 181151        return command.ExecuteScalar<T> ();
 181152      });
 91153    }
 1154
 1155    /// <summary>
 1156    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1157    /// in the command text for each of the arguments and then executes that command.
 1158    /// It returns each row of the result using the mapping automatically generated for
 1159    /// the given type.
 1160    /// </summary>
 1161    /// <param name="query">
 1162    /// The fully escaped SQL.
 1163    /// </param>
 1164    /// <param name="args">
 1165    /// Arguments to substitute for the occurences of '?' in the query.
 1166    /// </param>
 1167    /// <returns>
 1168    /// A list with one result for each row returned by the query.
 1169    /// </returns>
 1170    public Task<List<T>> QueryAsync<T> (string query, params object[] args)
 1171      where T : new()
 81172    {
 161173      return ReadAsync (conn => conn.Query<T> (query, args));
 81174    }
 1175
 1176    /// <summary>
 1177    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1178    /// in the command text for each of the arguments and then executes that command.
 1179    /// It returns the first column of each row of the result.
 1180    /// </summary>
 1181    /// <param name="query">
 1182    /// The fully escaped SQL.
 1183    /// </param>
 1184    /// <param name="args">
 1185    /// Arguments to substitute for the occurences of '?' in the query.
 1186    /// </param>
 1187    /// <returns>
 1188    /// A list with one result for the first column of each row returned by the query.
 1189    /// </returns>
 1190    public Task<List<T>> QueryScalarsAsync<T> (string query, params object[] args)
 41191    {
 81192      return ReadAsync (conn => conn.QueryScalars<T> (query, args));
 41193    }
 1194
 1195    /// <summary>
 1196    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1197    /// in the command text for each of the arguments and then executes that command.
 1198    /// It returns each row of the result using the specified mapping. This function is
 1199    /// only used by libraries in order to query the database via introspection. It is
 1200    /// normally not used.
 1201    /// </summary>
 1202    /// <param name="map">
 1203    /// A <see cref="TableMapping"/> to use to convert the resulting rows
 1204    /// into objects.
 1205    /// </param>
 1206    /// <param name="query">
 1207    /// The fully escaped SQL.
 1208    /// </param>
 1209    /// <param name="args">
 1210    /// Arguments to substitute for the occurences of '?' in the query.
 1211    /// </param>
 1212    /// <returns>
 1213    /// An enumerable with one result for each row returned by the query.
 1214    /// </returns>
 1215    public Task<List<object>> QueryAsync (TableMapping map, string query, params object[] args)
 01216    {
 01217      return ReadAsync (conn => conn.Query (map, query, args));
 01218    }
 1219
 1220    /// <summary>
 1221    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1222    /// in the command text for each of the arguments and then executes that command.
 1223    /// It returns each row of the result using the mapping automatically generated for
 1224    /// the given type.
 1225    /// </summary>
 1226    /// <param name="query">
 1227    /// The fully escaped SQL.
 1228    /// </param>
 1229    /// <param name="args">
 1230    /// Arguments to substitute for the occurences of '?' in the query.
 1231    /// </param>
 1232    /// <returns>
 1233    /// An enumerable with one result for each row returned by the query.
 1234    /// The enumerator will call sqlite3_step on each call to MoveNext, so the database
 1235    /// connection must remain open for the lifetime of the enumerator.
 1236    /// </returns>
 1237    public Task<IEnumerable<T>> DeferredQueryAsync<T> (string query, params object[] args)
 1238      where T : new()
 01239    {
 01240      return ReadAsync (conn => (IEnumerable<T>)conn.DeferredQuery<T> (query, args).ToList ());
 01241    }
 1242
 1243    /// <summary>
 1244    /// Creates a SQLiteCommand given the command text (SQL) with arguments. Place a '?'
 1245    /// in the command text for each of the arguments and then executes that command.
 1246    /// It returns each row of the result using the specified mapping. This function is
 1247    /// only used by libraries in order to query the database via introspection. It is
 1248    /// normally not used.
 1249    /// </summary>
 1250    /// <param name="map">
 1251    /// A <see cref="TableMapping"/> to use to convert the resulting rows
 1252    /// into objects.
 1253    /// </param>
 1254    /// <param name="query">
 1255    /// The fully escaped SQL.
 1256    /// </param>
 1257    /// <param name="args">
 1258    /// Arguments to substitute for the occurences of '?' in the query.
 1259    /// </param>
 1260    /// <returns>
 1261    /// An enumerable with one result for each row returned by the query.
 1262    /// The enumerator will call sqlite3_step on each call to MoveNext, so the database
 1263    /// connection must remain open for the lifetime of the enumerator.
 1264    /// </returns>
 1265    public Task<IEnumerable<object>> DeferredQueryAsync (TableMapping map, string query, params object[] args)
 01266    {
 01267      return ReadAsync (conn => (IEnumerable<object>)conn.DeferredQuery (map, query, args).ToList ());
 01268    }
 1269
 1270    /// <summary>
 1271    /// Change the encryption key for a SQLCipher database with "pragma rekey = ...".
 1272    /// </summary>
 1273    /// <param name="key">Encryption key plain text that is converted to the real encryption key using PBKDF2 key deriva
 1274    public Task ReKeyAsync (string key)
 01275    {
 01276      return WriteAsync<object> (conn => {
 01277        conn.ReKey (key);
 01278        return null;
 01279      });
 01280    }
 1281
 1282    /// <summary>
 1283    /// Change the encryption key for a SQLCipher database.
 1284    /// </summary>
 1285    /// <param name="key">256-bit (32 byte) or 384-bit (48 bytes) encryption key data</param>
 1286    public Task ReKeyAsync (byte[] key)
 01287    {
 01288      return WriteAsync<object> (conn => {
 01289        conn.ReKey (key);
 01290        return null;
 01291      });
 01292    }
 1293  }
 1294
 1295  /// <summary>
 1296  /// Query to an asynchronous database connection.
 1297  /// </summary>
 1298  public class AsyncTableQuery<T>
 1299    where T : new()
 1300  {
 1301    TableQuery<T> _innerQuery;
 1302
 1303    /// <summary>
 1304    /// Creates a new async query that uses given the synchronous query.
 1305    /// </summary>
 1306    public AsyncTableQuery (TableQuery<T> innerQuery)
 1307    {
 1308      _innerQuery = innerQuery;
 1309    }
 1310
 1311    Task<U> ReadAsync<U> (Func<SQLiteConnectionWithLock, U> read)
 1312    {
 1313      return Task.Factory.StartNew (() => {
 1314        var conn = (SQLiteConnectionWithLock)_innerQuery.Connection;
 1315        using (conn.Lock ()) {
 1316          return read (conn);
 1317        }
 1318      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 1319    }
 1320
 1321    Task<U> WriteAsync<U> (Func<SQLiteConnectionWithLock, U> write)
 1322    {
 1323      return Task.Factory.StartNew (() => {
 1324        var conn = (SQLiteConnectionWithLock)_innerQuery.Connection;
 1325        using (conn.Lock ()) {
 1326          return write (conn);
 1327        }
 1328      }, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default);
 1329    }
 1330
 1331    /// <summary>
 1332    /// Filters the query based on a predicate.
 1333    /// </summary>
 1334    public AsyncTableQuery<T> Where (Expression<Func<T, bool>> predExpr)
 1335    {
 1336      return new AsyncTableQuery<T> (_innerQuery.Where (predExpr));
 1337    }
 1338
 1339    /// <summary>
 1340    /// Skips a given number of elements from the query and then yields the remainder.
 1341    /// </summary>
 1342    public AsyncTableQuery<T> Skip (int n)
 1343    {
 1344      return new AsyncTableQuery<T> (_innerQuery.Skip (n));
 1345    }
 1346
 1347    /// <summary>
 1348    /// Yields a given number of elements from the query and then skips the remainder.
 1349    /// </summary>
 1350    public AsyncTableQuery<T> Take (int n)
 1351    {
 1352      return new AsyncTableQuery<T> (_innerQuery.Take (n));
 1353    }
 1354
 1355    /// <summary>
 1356    /// Order the query results according to a key.
 1357    /// </summary>
 1358    public AsyncTableQuery<T> OrderBy<U> (Expression<Func<T, U>> orderExpr)
 1359    {
 1360      return new AsyncTableQuery<T> (_innerQuery.OrderBy<U> (orderExpr));
 1361    }
 1362
 1363    /// <summary>
 1364    /// Order the query results according to a key.
 1365    /// </summary>
 1366    public AsyncTableQuery<T> OrderByDescending<U> (Expression<Func<T, U>> orderExpr)
 1367    {
 1368      return new AsyncTableQuery<T> (_innerQuery.OrderByDescending<U> (orderExpr));
 1369    }
 1370
 1371    /// <summary>
 1372    /// Order the query results according to a key.
 1373    /// </summary>
 1374    public AsyncTableQuery<T> ThenBy<U> (Expression<Func<T, U>> orderExpr)
 1375    {
 1376      return new AsyncTableQuery<T> (_innerQuery.ThenBy<U> (orderExpr));
 1377    }
 1378
 1379    /// <summary>
 1380    /// Order the query results according to a key.
 1381    /// </summary>
 1382    public AsyncTableQuery<T> ThenByDescending<U> (Expression<Func<T, U>> orderExpr)
 1383    {
 1384      return new AsyncTableQuery<T> (_innerQuery.ThenByDescending<U> (orderExpr));
 1385    }
 1386
 1387    /// <summary>
 1388    /// Queries the database and returns the results as a List.
 1389    /// </summary>
 1390    public Task<List<T>> ToListAsync ()
 1391    {
 1392      return ReadAsync (conn => _innerQuery.ToList ());
 1393    }
 1394
 1395    /// <summary>
 1396    /// Queries the database and returns the results as an array.
 1397    /// </summary>
 1398    public Task<T[]> ToArrayAsync ()
 1399    {
 1400      return ReadAsync (conn => _innerQuery.ToArray ());
 1401    }
 1402
 1403    /// <summary>
 1404    /// Execute SELECT COUNT(*) on the query
 1405    /// </summary>
 1406    public Task<int> CountAsync ()
 1407    {
 1408      return ReadAsync (conn => _innerQuery.Count ());
 1409    }
 1410
 1411    /// <summary>
 1412    /// Execute SELECT COUNT(*) on the query with an additional WHERE clause.
 1413    /// </summary>
 1414    public Task<int> CountAsync (Expression<Func<T, bool>> predExpr)
 1415    {
 1416      return ReadAsync (conn => _innerQuery.Count (predExpr));
 1417    }
 1418
 1419    /// <summary>
 1420    /// Returns the element at a given index
 1421    /// </summary>
 1422    public Task<T> ElementAtAsync (int index)
 1423    {
 1424      return ReadAsync (conn => _innerQuery.ElementAt (index));
 1425    }
 1426
 1427    /// <summary>
 1428    /// Returns the first element of this query.
 1429    /// </summary>
 1430    public Task<T> FirstAsync ()
 1431    {
 1432      return ReadAsync (conn => _innerQuery.First ());
 1433    }
 1434
 1435    /// <summary>
 1436    /// Returns the first element of this query, or null if no element is found.
 1437    /// </summary>
 1438    public Task<T> FirstOrDefaultAsync ()
 1439    {
 1440      return ReadAsync (conn => _innerQuery.FirstOrDefault ());
 1441    }
 1442
 1443    /// <summary>
 1444    /// Returns the first element of this query that matches the predicate.
 1445    /// </summary>
 1446    public Task<T> FirstAsync (Expression<Func<T, bool>> predExpr)
 1447    {
 1448      return ReadAsync (conn => _innerQuery.First (predExpr));
 1449    }
 1450
 1451    /// <summary>
 1452    /// Returns the first element of this query that matches the predicate.
 1453    /// </summary>
 1454    public Task<T> FirstOrDefaultAsync (Expression<Func<T, bool>> predExpr)
 1455    {
 1456      return ReadAsync (conn => _innerQuery.FirstOrDefault (predExpr));
 1457    }
 1458
 1459    /// <summary>
 1460    /// Delete all the rows that match this query and the given predicate.
 1461    /// </summary>
 1462    public Task<int> DeleteAsync (Expression<Func<T, bool>> predExpr)
 1463    {
 1464      return WriteAsync (conn => _innerQuery.Delete (predExpr));
 1465    }
 1466
 1467    /// <summary>
 1468    /// Delete all the rows that match this query.
 1469    /// </summary>
 1470    public Task<int> DeleteAsync ()
 1471    {
 1472      return WriteAsync (conn => _innerQuery.Delete ());
 1473    }
 1474  }
 1475
 1476  class SQLiteConnectionPool
 1477  {
 1478    class Entry
 1479    {
 1480      public SQLiteConnectionWithLock Connection { get; private set; }
 1481
 1482      public SQLiteConnectionString ConnectionString { get; }
 1483
 1484      public object TransactionLock { get; } = new object ();
 1485
 1486      public Entry (SQLiteConnectionString connectionString)
 1487      {
 1488        ConnectionString = connectionString;
 1489        Connection = new SQLiteConnectionWithLock (ConnectionString);
 1490
 1491        // If the database is FullMutex, then we don't need to bother locking
 1492        if (ConnectionString.OpenFlags.HasFlag (SQLiteOpenFlags.FullMutex)) {
 1493          Connection.SkipLock = true;
 1494        }
 1495      }
 1496
 1497      public void Close ()
 1498      {
 1499        var wc = Connection;
 1500        Connection = null;
 1501        if (wc != null) {
 1502          wc.Close ();
 1503        }
 1504      }
 1505    }
 1506
 1507    readonly Dictionary<string, Entry> _entries = new Dictionary<string, Entry> ();
 1508    readonly object _entriesLock = new object ();
 1509
 1510    static readonly SQLiteConnectionPool _shared = new SQLiteConnectionPool ();
 1511
 1512    /// <summary>
 1513    /// Gets the singleton instance of the connection tool.
 1514    /// </summary>
 1515    public static SQLiteConnectionPool Shared {
 1516      get {
 1517        return _shared;
 1518      }
 1519    }
 1520
 1521    public SQLiteConnectionWithLock GetConnection (SQLiteConnectionString connectionString)
 1522    {
 1523      return GetConnectionAndTransactionLock (connectionString, out var _);
 1524    }
 1525
 1526    public SQLiteConnectionWithLock GetConnectionAndTransactionLock (SQLiteConnectionString connectionString, out object
 1527    {
 1528      var key = connectionString.UniqueKey;
 1529      Entry entry;
 1530      lock (_entriesLock) {
 1531        if (!_entries.TryGetValue (key, out entry)) {
 1532          // The opens the database while we're locked
 1533          // This is to ensure another thread doesn't get an unopened database
 1534          entry = new Entry (connectionString);
 1535          _entries[key] = entry;
 1536        }
 1537        transactionLock = entry.TransactionLock;
 1538        return entry.Connection;
 1539      }
 1540    }
 1541
 1542    public void CloseConnection (SQLiteConnectionString connectionString)
 1543    {
 1544      var key = connectionString.UniqueKey;
 1545      Entry entry;
 1546      lock (_entriesLock) {
 1547        if (_entries.TryGetValue (key, out entry)) {
 1548          _entries.Remove (key);
 1549        }
 1550      }
 1551      entry?.Close ();
 1552    }
 1553
 1554    /// <summary>
 1555    /// Closes all connections managed by this pool.
 1556    /// </summary>
 1557    public void Reset ()
 1558    {
 1559      List<Entry> entries;
 1560      lock (_entriesLock) {
 1561        entries = new List<Entry> (_entries.Values);
 1562        _entries.Clear ();
 1563      }
 1564
 1565      foreach (var e in entries) {
 1566        e.Close ();
 1567      }
 1568    }
 1569  }
 1570
 1571  /// <summary>
 1572  /// This is a normal connection except it contains a Lock method that
 1573  /// can be used to serialize access to the database
 1574  /// in lieu of using the sqlite's FullMutex support.
 1575  /// </summary>
 1576  public class SQLiteConnectionWithLock : SQLiteConnection
 1577  {
 1578    readonly object _lockPoint = new object ();
 1579
 1580    /// <summary>
 1581    /// Initializes a new instance of the <see cref="T:SQLite.SQLiteConnectionWithLock"/> class.
 1582    /// </summary>
 1583    /// <param name="connectionString">Connection string containing the DatabasePath.</param>
 1584    public SQLiteConnectionWithLock (SQLiteConnectionString connectionString)
 1585      : base (connectionString)
 1586    {
 1587    }
 1588
 1589    /// <summary>
 1590    /// Gets or sets a value indicating whether this <see cref="T:SQLite.SQLiteConnectionWithLock"/> skip lock.
 1591    /// </summary>
 1592    /// <value><c>true</c> if skip lock; otherwise, <c>false</c>.</value>
 1593    public bool SkipLock { get; set; }
 1594
 1595    /// <summary>
 1596    /// Lock the database to serialize access to it. To unlock it, call Dispose
 1597    /// on the returned object.
 1598    /// </summary>
 1599    /// <returns>The lock.</returns>
 1600    public IDisposable Lock ()
 1601    {
 1602      return SkipLock ? (IDisposable)new FakeLockWrapper() : new LockWrapper (_lockPoint);
 1603    }
 1604
 1605    class LockWrapper : IDisposable
 1606    {
 1607      object _lockPoint;
 1608
 1609      public LockWrapper (object lockPoint)
 1610      {
 1611        _lockPoint = lockPoint;
 1612        Monitor.Enter (_lockPoint);
 1613      }
 1614
 1615      public void Dispose ()
 1616      {
 1617        Monitor.Exit (_lockPoint);
 1618      }
 1619    }
 1620    class FakeLockWrapper : IDisposable
 1621    {
 1622      public void Dispose ()
 1623      {
 1624      }
 1625    }
 1626  }
 1627}
 1628

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[])