using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml;
using AsyncLoggers.API;
using AsyncLoggers.BepInExListeners;
using AsyncLoggers.Buffer;
using AsyncLoggers.Cecil;
using AsyncLoggers.Cecil.Decompiler;
using AsyncLoggers.Cecil.Decompiler.Implementation;
using AsyncLoggers.Cecil.Decompiler.Implementation.Composite;
using AsyncLoggers.Config;
using AsyncLoggers.Patches;
using AsyncLoggers.Proxy;
using AsyncLoggers.Proxy.WinAPI;
using AsyncLoggers.Sqlite;
using AsyncLoggers.Wrappers;
using AsyncLoggers.Wrappers.EventArgs;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using JetBrains.Annotations;
using Microsoft.CodeAnalysis;
using Mono.Cecil;
using Mono.Cecil.Cil;
using Mono.Collections.Generic;
using MonoMod.RuntimeDetour;
using SQLite;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: IgnoresAccessChecksTo("BepInEx")]
[assembly: IgnoresAccessChecksTo("UnityEngine.AccessibilityModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.AIModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.AndroidJNIModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.AnimationModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.AssetBundleModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.AudioModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ClothModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ClusterInputModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ClusterRendererModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ContentLoadModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.CoreModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.CrashReportingModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.DirectorModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine")]
[assembly: IgnoresAccessChecksTo("UnityEngine.DSPGraphModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.GameCenterModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.GIModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.GridModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.HotReloadModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ImageConversionModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.IMGUIModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.InputLegacyModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.InputModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.JSONSerializeModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.LocalizationModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ParticleSystemModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.PerformanceReportingModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.Physics2DModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.PhysicsModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ProfilerModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.PropertiesModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.ScreenCaptureModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.SharedInternalsModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.SpriteMaskModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.SpriteShapeModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.StreamingModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.SubstanceModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.SubsystemsModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.TerrainModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.TerrainPhysicsModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.TextCoreFontEngineModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.TextCoreTextEngineModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.TextRenderingModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.TilemapModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.TLSModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UIElementsModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UIModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UmbraModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UnityAnalyticsCommonModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UnityAnalyticsModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UnityConnectModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UnityCurlModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UnityTestProtocolModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UnityWebRequestAssetBundleModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UnityWebRequestAudioModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UnityWebRequestModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UnityWebRequestTextureModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.UnityWebRequestWWWModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.VehiclesModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.VFXModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.VideoModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.VirtualTexturingModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.VRModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.WindModule")]
[assembly: IgnoresAccessChecksTo("UnityEngine.XRModule")]
[assembly: AssemblyCompany("mattymatty")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("2.2.3")]
[assembly: AssemblyInformationalVersion("2.2.3+c2d530c9b40a146ec9ee31cb50146a58da20f107")]
[assembly: AssemblyProduct("AsyncLoggers")]
[assembly: AssemblyTitle("AsyncLoggers - Plugin")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("2.2.3.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace SQLite
{
public class SQLiteException : Exception
{
public SQLite3.Result Result { get; private set; }
protected SQLiteException(SQLite3.Result r, string message)
: base(message)
{
Result = r;
}
public static SQLiteException New(SQLite3.Result r, string message)
{
return new SQLiteException(r, message);
}
}
public class NotNullConstraintViolationException : SQLiteException
{
public IEnumerable<TableMapping.Column> Columns { get; protected set; }
protected NotNullConstraintViolationException(SQLite3.Result r, string message)
: this(r, message, null, null)
{
}
protected NotNullConstraintViolationException(SQLite3.Result r, string message, TableMapping mapping, object obj)
: base(r, message)
{
if (mapping != null && obj != null)
{
Columns = mapping.Columns.Where((TableMapping.Column c) => !c.IsNullable && c.GetValue(obj) == null);
}
}
public new static NotNullConstraintViolationException New(SQLite3.Result r, string message)
{
return new NotNullConstraintViolationException(r, message);
}
public static NotNullConstraintViolationException New(SQLite3.Result r, string message, TableMapping mapping, object obj)
{
return new NotNullConstraintViolationException(r, message, mapping, obj);
}
public static NotNullConstraintViolationException New(SQLiteException exception, TableMapping mapping, object obj)
{
return new NotNullConstraintViolationException(exception.Result, exception.Message, mapping, obj);
}
}
[Flags]
public enum SQLiteOpenFlags
{
ReadOnly = 1,
ReadWrite = 2,
Create = 4,
NoMutex = 0x8000,
FullMutex = 0x10000,
SharedCache = 0x20000,
PrivateCache = 0x40000,
ProtectionComplete = 0x100000,
ProtectionCompleteUnlessOpen = 0x200000,
ProtectionCompleteUntilFirstUserAuthentication = 0x300000,
ProtectionNone = 0x400000
}
[Flags]
public enum CreateFlags
{
None = 0,
ImplicitPK = 1,
ImplicitIndex = 2,
AllImplicit = 3,
AutoIncPK = 4,
FullTextSearch3 = 0x100,
FullTextSearch4 = 0x200
}
public interface ISQLiteConnection
{
IntPtr Handle { get; }
string DatabasePath { get; }
int LibVersionNumber { get; }
bool TimeExecution { get; set; }
bool Trace { get; set; }
Action<string> Tracer { get; set; }
bool StoreDateTimeAsTicks { get; }
bool StoreTimeSpanAsTicks { get; }
string DateTimeStringFormat { get; }
TimeSpan BusyTimeout { get; set; }
IEnumerable<TableMapping> TableMappings { get; }
bool IsInTransaction { get; }
event EventHandler<NotifyTableChangedEventArgs> TableChanged;
void Backup(string destinationDatabasePath, string databaseName = "main");
void BeginTransaction();
void Close();
void Commit();
SQLiteCommand CreateCommand(string cmdText, params object[] ps);
SQLiteCommand CreateCommand(string cmdText, Dictionary<string, object> args);
int CreateIndex(string indexName, string tableName, string[] columnNames, bool unique = false);
int CreateIndex(string indexName, string tableName, string columnName, bool unique = false);
int CreateIndex(string tableName, string columnName, bool unique = false);
int CreateIndex(string tableName, string[] columnNames, bool unique = false);
int CreateIndex<T>(Expression<Func<T, object>> property, bool unique = false);
CreateTableResult CreateTable<T>(CreateFlags createFlags = CreateFlags.None);
CreateTableResult CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None);
CreateTablesResult CreateTables<T, T2>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new();
CreateTablesResult CreateTables<T, T2, T3>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new();
CreateTablesResult CreateTables<T, T2, T3, T4>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new() where T4 : new();
CreateTablesResult CreateTables<T, T2, T3, T4, T5>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new() where T4 : new() where T5 : new();
CreateTablesResult CreateTables(CreateFlags createFlags = CreateFlags.None, params Type[] types);
IEnumerable<T> DeferredQuery<T>(string query, params object[] args) where T : new();
IEnumerable<object> DeferredQuery(TableMapping map, string query, params object[] args);
int Delete(object objectToDelete);
int Delete<T>(object primaryKey);
int Delete(object primaryKey, TableMapping map);
int DeleteAll<T>();
int DeleteAll(TableMapping map);
void Dispose();
int DropTable<T>();
int DropTable(TableMapping map);
void EnableLoadExtension(bool enabled);
void EnableWriteAheadLogging();
int Execute(string query, params object[] args);
T ExecuteScalar<T>(string query, params object[] args);
T Find<T>(object pk) where T : new();
object Find(object pk, TableMapping map);
T Find<T>(Expression<Func<T, bool>> predicate) where T : new();
T FindWithQuery<T>(string query, params object[] args) where T : new();
object FindWithQuery(TableMapping map, string query, params object[] args);
T Get<T>(object pk) where T : new();
object Get(object pk, TableMapping map);
T Get<T>(Expression<Func<T, bool>> predicate) where T : new();
TableMapping GetMapping(Type type, CreateFlags createFlags = CreateFlags.None);
TableMapping GetMapping<T>(CreateFlags createFlags = CreateFlags.None);
List<SQLiteConnection.ColumnInfo> GetTableInfo(string tableName);
int Insert(object obj);
int Insert(object obj, Type objType);
int Insert(object obj, string extra);
int Insert(object obj, string extra, Type objType);
int InsertAll(IEnumerable objects, bool runInTransaction = true);
int InsertAll(IEnumerable objects, string extra, bool runInTransaction = true);
int InsertAll(IEnumerable objects, Type objType, bool runInTransaction = true);
int InsertOrReplace(object obj);
int InsertOrReplace(object obj, Type objType);
List<T> Query<T>(string query, params object[] args) where T : new();
List<object> Query(TableMapping map, string query, params object[] args);
List<T> QueryScalars<T>(string query, params object[] args);
void Release(string savepoint);
void Rollback();
void RollbackTo(string savepoint);
void RunInTransaction(Action action);
string SaveTransactionPoint();
TableQuery<T> Table<T>() where T : new();
int Update(object obj);
int Update(object obj, Type objType);
int UpdateAll(IEnumerable objects, bool runInTransaction = true);
}
[Preserve(AllMembers = true)]
public class SQLiteConnection : IDisposable, ISQLiteConnection
{
private struct IndexedColumn
{
public int Order;
public string ColumnName;
}
private struct IndexInfo
{
public string IndexName;
public string TableName;
public bool Unique;
public List<IndexedColumn> Columns;
}
[Preserve(AllMembers = true)]
public class ColumnInfo
{
[Column("name")]
public string Name { get; set; }
public int notnull { get; set; }
public override string ToString()
{
return Name;
}
}
private bool _open;
private TimeSpan _busyTimeout;
private static readonly Dictionary<string, TableMapping> _mappings = new Dictionary<string, TableMapping>();
private Stopwatch _sw;
private long _elapsedMilliseconds;
private int _transactionDepth;
private Random _rand = new Random();
private static readonly IntPtr NullHandle = default(IntPtr);
private static readonly IntPtr NullBackupHandle = default(IntPtr);
private readonly Dictionary<Tuple<string, string>, PreparedSqlLiteInsertCommand> _insertCommandMap = new Dictionary<Tuple<string, string>, PreparedSqlLiteInsertCommand>();
public IntPtr Handle { get; private set; }
public string DatabasePath { get; private set; }
public int LibVersionNumber { get; private set; }
public bool TimeExecution { get; set; }
public bool Trace { get; set; }
public Action<string> Tracer { get; set; }
public bool StoreDateTimeAsTicks { get; private set; }
public bool StoreTimeSpanAsTicks { get; private set; }
public string DateTimeStringFormat { get; private set; }
internal DateTimeStyles DateTimeStyle { get; private set; }
public TimeSpan BusyTimeout
{
get
{
return _busyTimeout;
}
set
{
_busyTimeout = value;
if (Handle != NullHandle)
{
SQLite3.BusyTimeout(Handle, (int)_busyTimeout.TotalMilliseconds);
}
}
}
public IEnumerable<TableMapping> TableMappings
{
get
{
lock (_mappings)
{
return new List<TableMapping>(_mappings.Values);
}
}
}
public bool IsInTransaction => _transactionDepth > 0;
public event EventHandler<NotifyTableChangedEventArgs> TableChanged;
public SQLiteConnection(string databasePath, bool storeDateTimeAsTicks = true)
: this(new SQLiteConnectionString(databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks))
{
}
public SQLiteConnection(string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks = true)
: this(new SQLiteConnectionString(databasePath, openFlags, storeDateTimeAsTicks))
{
}
public SQLiteConnection(SQLiteConnectionString connectionString)
{
if (connectionString == null)
{
throw new ArgumentNullException("connectionString");
}
if (connectionString.DatabasePath == null)
{
throw new InvalidOperationException("DatabasePath must be specified");
}
DatabasePath = connectionString.DatabasePath;
LibVersionNumber = SQLite3.LibVersionNumber();
byte[] nullTerminatedUtf = GetNullTerminatedUtf8(connectionString.DatabasePath);
IntPtr db;
SQLite3.Result result = SQLite3.Open(nullTerminatedUtf, out db, (int)connectionString.OpenFlags, connectionString.VfsName);
Handle = db;
if (result != 0)
{
throw SQLiteException.New(result, $"Could not open database file: {DatabasePath} ({result})");
}
_open = true;
StoreDateTimeAsTicks = connectionString.StoreDateTimeAsTicks;
StoreTimeSpanAsTicks = connectionString.StoreTimeSpanAsTicks;
DateTimeStringFormat = connectionString.DateTimeStringFormat;
DateTimeStyle = connectionString.DateTimeStyle;
BusyTimeout = TimeSpan.FromSeconds(1.0);
Tracer = delegate
{
};
connectionString.PreKeyAction?.Invoke(this);
if (connectionString.Key is string key)
{
SetKey(key);
}
else if (connectionString.Key is byte[] key2)
{
SetKey(key2);
}
else if (connectionString.Key != null)
{
throw new InvalidOperationException("Encryption keys must be strings or byte arrays");
}
connectionString.PostKeyAction?.Invoke(this);
}
public void EnableWriteAheadLogging()
{
ExecuteScalar<string>("PRAGMA journal_mode=WAL", Array.Empty<object>());
}
private static string Quote(string unsafeString)
{
if (unsafeString == null)
{
return "NULL";
}
string text = unsafeString.Replace("'", "''");
return "'" + text + "'";
}
private void SetKey(string key)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
string text = Quote(key);
ExecuteScalar<string>("pragma key = " + text, Array.Empty<object>());
}
private void SetKey(byte[] key)
{
if (key == null)
{
throw new ArgumentNullException("key");
}
if (key.Length != 32 && key.Length != 48)
{
throw new ArgumentException("Key must be 32 bytes (256-bit) or 48 bytes (384-bit)", "key");
}
string text = string.Join("", key.Select((byte x) => x.ToString("X2")));
ExecuteScalar<string>("pragma key = \"x'" + text + "'\"", Array.Empty<object>());
}
public void EnableLoadExtension(bool enabled)
{
SQLite3.Result result = SQLite3.EnableLoadExtension(Handle, enabled ? 1 : 0);
if (result != 0)
{
string errmsg = SQLite3.GetErrmsg(Handle);
throw SQLiteException.New(result, errmsg);
}
}
private static byte[] GetNullTerminatedUtf8(string s)
{
int byteCount = Encoding.UTF8.GetByteCount(s);
byte[] array = new byte[byteCount + 1];
byteCount = Encoding.UTF8.GetBytes(s, 0, s.Length, array, 0);
return array;
}
public TableMapping GetMapping(Type type, CreateFlags createFlags = CreateFlags.None)
{
string fullName = type.FullName;
TableMapping value;
lock (_mappings)
{
if (_mappings.TryGetValue(fullName, out value))
{
if (createFlags != 0 && createFlags != value.CreateFlags)
{
value = new TableMapping(type, createFlags);
_mappings[fullName] = value;
}
}
else
{
value = new TableMapping(type, createFlags);
_mappings.Add(fullName, value);
}
}
return value;
}
public TableMapping GetMapping<T>(CreateFlags createFlags = CreateFlags.None)
{
return GetMapping(typeof(T), createFlags);
}
public int DropTable<T>()
{
return DropTable(GetMapping(typeof(T)));
}
public int DropTable(TableMapping map)
{
string query = $"drop table if exists \"{map.TableName}\"";
return Execute(query);
}
public CreateTableResult CreateTable<T>(CreateFlags createFlags = CreateFlags.None)
{
return CreateTable(typeof(T), createFlags);
}
public CreateTableResult CreateTable(Type ty, CreateFlags createFlags = CreateFlags.None)
{
TableMapping mapping = GetMapping(ty, createFlags);
if (mapping.Columns.Length == 0)
{
throw new Exception($"Cannot create a table without columns (does '{ty.FullName}' have public properties?)");
}
CreateTableResult result = CreateTableResult.Created;
List<ColumnInfo> tableInfo = GetTableInfo(mapping.TableName);
if (tableInfo.Count == 0)
{
bool flag = (createFlags & CreateFlags.FullTextSearch3) != 0;
bool flag2 = (createFlags & CreateFlags.FullTextSearch4) != 0;
string text = ((flag || flag2) ? "virtual " : string.Empty);
string text2 = (flag ? "using fts3 " : (flag2 ? "using fts4 " : string.Empty));
string text3 = "create " + text + "table if not exists \"" + mapping.TableName + "\" " + text2 + "(\n";
IEnumerable<string> source = mapping.Columns.Select((TableMapping.Column p) => Orm.SqlDecl(p, StoreDateTimeAsTicks, StoreTimeSpanAsTicks));
string text4 = string.Join(",\n", source.ToArray());
text3 += text4;
text3 += ")";
if (mapping.WithoutRowId)
{
text3 += " without rowid";
}
Execute(text3);
}
else
{
result = CreateTableResult.Migrated;
MigrateTable(mapping, tableInfo);
}
Dictionary<string, IndexInfo> dictionary = new Dictionary<string, IndexInfo>();
TableMapping.Column[] columns = mapping.Columns;
foreach (TableMapping.Column column in columns)
{
foreach (IndexedAttribute index in column.Indices)
{
string text5 = index.Name ?? (mapping.TableName + "_" + column.Name);
if (!dictionary.TryGetValue(text5, out var value))
{
IndexInfo indexInfo = default(IndexInfo);
indexInfo.IndexName = text5;
indexInfo.TableName = mapping.TableName;
indexInfo.Unique = index.Unique;
indexInfo.Columns = new List<IndexedColumn>();
value = indexInfo;
dictionary.Add(text5, value);
}
if (index.Unique != value.Unique)
{
throw new Exception("All the columns in an index must have the same value for their Unique property");
}
value.Columns.Add(new IndexedColumn
{
Order = index.Order,
ColumnName = column.Name
});
}
}
foreach (string key in dictionary.Keys)
{
IndexInfo indexInfo2 = dictionary[key];
string[] columnNames = (from i in indexInfo2.Columns
orderby i.Order
select i.ColumnName).ToArray();
CreateIndex(key, indexInfo2.TableName, columnNames, indexInfo2.Unique);
}
return result;
}
public CreateTablesResult CreateTables<T, T2>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new()
{
return CreateTables(createFlags, typeof(T), typeof(T2));
}
public CreateTablesResult CreateTables<T, T2, T3>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new()
{
return CreateTables(createFlags, typeof(T), typeof(T2), typeof(T3));
}
public CreateTablesResult CreateTables<T, T2, T3, T4>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new() where T4 : new()
{
return CreateTables(createFlags, typeof(T), typeof(T2), typeof(T3), typeof(T4));
}
public CreateTablesResult CreateTables<T, T2, T3, T4, T5>(CreateFlags createFlags = CreateFlags.None) where T : new() where T2 : new() where T3 : new() where T4 : new() where T5 : new()
{
return CreateTables(createFlags, typeof(T), typeof(T2), typeof(T3), typeof(T4), typeof(T5));
}
public CreateTablesResult CreateTables(CreateFlags createFlags = CreateFlags.None, params Type[] types)
{
CreateTablesResult createTablesResult = new CreateTablesResult();
foreach (Type type in types)
{
CreateTableResult value = CreateTable(type, createFlags);
createTablesResult.Results[type] = value;
}
return createTablesResult;
}
public int CreateIndex(string indexName, string tableName, string[] columnNames, bool unique = false)
{
string query = string.Format("create {2} index if not exists \"{3}\" on \"{0}\"(\"{1}\")", tableName, string.Join("\", \"", columnNames), unique ? "unique" : "", indexName);
return Execute(query);
}
public int CreateIndex(string indexName, string tableName, string columnName, bool unique = false)
{
return CreateIndex(indexName, tableName, new string[1] { columnName }, unique);
}
public int CreateIndex(string tableName, string columnName, bool unique = false)
{
return CreateIndex(tableName + "_" + columnName, tableName, columnName, unique);
}
public int CreateIndex(string tableName, string[] columnNames, bool unique = false)
{
return CreateIndex(tableName + "_" + string.Join("_", columnNames), tableName, columnNames, unique);
}
public int CreateIndex<T>(Expression<Func<T, object>> property, bool unique = false)
{
MemberExpression memberExpression = ((property.Body.NodeType != ExpressionType.Convert) ? (property.Body as MemberExpression) : (((UnaryExpression)property.Body).Operand as MemberExpression));
PropertyInfo propertyInfo = memberExpression.Member as PropertyInfo;
if (propertyInfo == null)
{
throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
}
string name = propertyInfo.Name;
TableMapping mapping = GetMapping<T>();
string name2 = mapping.FindColumnWithPropertyName(name).Name;
return CreateIndex(mapping.TableName, name2, unique);
}
public List<ColumnInfo> GetTableInfo(string tableName)
{
string query = "pragma table_info(\"" + tableName + "\")";
return Query<ColumnInfo>(query, Array.Empty<object>());
}
private void MigrateTable(TableMapping map, List<ColumnInfo> existingCols)
{
List<TableMapping.Column> list = new List<TableMapping.Column>();
TableMapping.Column[] columns = map.Columns;
foreach (TableMapping.Column column in columns)
{
bool flag = false;
foreach (ColumnInfo existingCol in existingCols)
{
flag = string.Compare(column.Name, existingCol.Name, StringComparison.OrdinalIgnoreCase) == 0;
if (flag)
{
break;
}
}
if (!flag)
{
list.Add(column);
}
}
foreach (TableMapping.Column item in list)
{
string query = "alter table \"" + map.TableName + "\" add column " + Orm.SqlDecl(item, StoreDateTimeAsTicks, StoreTimeSpanAsTicks);
Execute(query);
}
}
protected virtual SQLiteCommand NewCommand()
{
return new SQLiteCommand(this);
}
public SQLiteCommand CreateCommand(string cmdText, params object[] ps)
{
if (!_open)
{
throw SQLiteException.New(SQLite3.Result.Error, "Cannot create commands from unopened database");
}
SQLiteCommand sQLiteCommand = NewCommand();
sQLiteCommand.CommandText = cmdText;
foreach (object val in ps)
{
sQLiteCommand.Bind(val);
}
return sQLiteCommand;
}
public SQLiteCommand CreateCommand(string cmdText, Dictionary<string, object> args)
{
if (!_open)
{
throw SQLiteException.New(SQLite3.Result.Error, "Cannot create commands from unopened database");
}
SQLiteCommand sQLiteCommand = NewCommand();
sQLiteCommand.CommandText = cmdText;
foreach (KeyValuePair<string, object> arg in args)
{
sQLiteCommand.Bind(arg.Key, arg.Value);
}
return sQLiteCommand;
}
public int Execute(string query, params object[] args)
{
SQLiteCommand sQLiteCommand = CreateCommand(query, args);
if (TimeExecution)
{
if (_sw == null)
{
_sw = new Stopwatch();
}
_sw.Reset();
_sw.Start();
}
int result = sQLiteCommand.ExecuteNonQuery();
if (TimeExecution)
{
_sw.Stop();
_elapsedMilliseconds += _sw.ElapsedMilliseconds;
Tracer?.Invoke($"Finished in {_sw.ElapsedMilliseconds} ms ({(double)_elapsedMilliseconds / 1000.0:0.0} s total)");
}
return result;
}
public T ExecuteScalar<T>(string query, params object[] args)
{
SQLiteCommand sQLiteCommand = CreateCommand(query, args);
if (TimeExecution)
{
if (_sw == null)
{
_sw = new Stopwatch();
}
_sw.Reset();
_sw.Start();
}
T result = sQLiteCommand.ExecuteScalar<T>();
if (TimeExecution)
{
_sw.Stop();
_elapsedMilliseconds += _sw.ElapsedMilliseconds;
Tracer?.Invoke($"Finished in {_sw.ElapsedMilliseconds} ms ({(double)_elapsedMilliseconds / 1000.0:0.0} s total)");
}
return result;
}
public List<T> Query<T>(string query, params object[] args) where T : new()
{
SQLiteCommand sQLiteCommand = CreateCommand(query, args);
return sQLiteCommand.ExecuteQuery<T>();
}
public List<T> QueryScalars<T>(string query, params object[] args)
{
SQLiteCommand sQLiteCommand = CreateCommand(query, args);
return sQLiteCommand.ExecuteQueryScalars<T>().ToList();
}
public IEnumerable<T> DeferredQuery<T>(string query, params object[] args) where T : new()
{
SQLiteCommand sQLiteCommand = CreateCommand(query, args);
return sQLiteCommand.ExecuteDeferredQuery<T>();
}
public List<object> Query(TableMapping map, string query, params object[] args)
{
SQLiteCommand sQLiteCommand = CreateCommand(query, args);
return sQLiteCommand.ExecuteQuery<object>(map);
}
public IEnumerable<object> DeferredQuery(TableMapping map, string query, params object[] args)
{
SQLiteCommand sQLiteCommand = CreateCommand(query, args);
return sQLiteCommand.ExecuteDeferredQuery<object>(map);
}
public TableQuery<T> Table<T>() where T : new()
{
return new TableQuery<T>(this);
}
public T Get<T>(object pk) where T : new()
{
TableMapping mapping = GetMapping(typeof(T));
return Query<T>(mapping.GetByPrimaryKeySql, new object[1] { pk }).First();
}
public object Get(object pk, TableMapping map)
{
return Query(map, map.GetByPrimaryKeySql, pk).First();
}
public T Get<T>(Expression<Func<T, bool>> predicate) where T : new()
{
return Table<T>().Where(predicate).First();
}
public T Find<T>(object pk) where T : new()
{
TableMapping mapping = GetMapping(typeof(T));
return Query<T>(mapping.GetByPrimaryKeySql, new object[1] { pk }).FirstOrDefault();
}
public object Find(object pk, TableMapping map)
{
return Query(map, map.GetByPrimaryKeySql, pk).FirstOrDefault();
}
public T Find<T>(Expression<Func<T, bool>> predicate) where T : new()
{
return Table<T>().Where(predicate).FirstOrDefault();
}
public T FindWithQuery<T>(string query, params object[] args) where T : new()
{
return Query<T>(query, args).FirstOrDefault();
}
public object FindWithQuery(TableMapping map, string query, params object[] args)
{
return Query(map, query, args).FirstOrDefault();
}
public void BeginTransaction()
{
if (Interlocked.CompareExchange(ref _transactionDepth, 1, 0) == 0)
{
try
{
Execute("begin transaction");
return;
}
catch (Exception ex)
{
if (ex is SQLiteException ex2)
{
switch (ex2.Result)
{
case SQLite3.Result.Busy:
case SQLite3.Result.NoMem:
case SQLite3.Result.Interrupt:
case SQLite3.Result.IOError:
case SQLite3.Result.Full:
RollbackTo(null, noThrow: true);
break;
}
}
else
{
Interlocked.Decrement(ref _transactionDepth);
}
throw;
}
}
throw new InvalidOperationException("Cannot begin a transaction while already in a transaction.");
}
public string SaveTransactionPoint()
{
int num = Interlocked.Increment(ref _transactionDepth) - 1;
string text = "S" + _rand.Next(32767) + "D" + num;
try
{
Execute("savepoint " + text);
return text;
}
catch (Exception ex)
{
if (ex is SQLiteException ex2)
{
switch (ex2.Result)
{
case SQLite3.Result.Busy:
case SQLite3.Result.NoMem:
case SQLite3.Result.Interrupt:
case SQLite3.Result.IOError:
case SQLite3.Result.Full:
RollbackTo(null, noThrow: true);
break;
}
}
else
{
Interlocked.Decrement(ref _transactionDepth);
}
throw;
}
}
public void Rollback()
{
RollbackTo(null, noThrow: false);
}
public void RollbackTo(string savepoint)
{
RollbackTo(savepoint, noThrow: false);
}
private void RollbackTo(string savepoint, bool noThrow)
{
try
{
if (string.IsNullOrEmpty(savepoint))
{
if (Interlocked.Exchange(ref _transactionDepth, 0) > 0)
{
Execute("rollback");
}
}
else
{
DoSavePointExecute(savepoint, "rollback to ");
}
}
catch (SQLiteException)
{
if (!noThrow)
{
throw;
}
}
}
public void Release(string savepoint)
{
try
{
DoSavePointExecute(savepoint, "release ");
}
catch (SQLiteException ex)
{
if (ex.Result == SQLite3.Result.Busy)
{
try
{
Execute("rollback");
}
catch
{
}
}
throw;
}
}
private void DoSavePointExecute(string savepoint, string cmd)
{
int num = savepoint.IndexOf('D');
if (num >= 2 && savepoint.Length > num + 1 && int.TryParse(savepoint.Substring(num + 1), out var result) && 0 <= result && result < _transactionDepth)
{
Thread.VolatileWrite(ref _transactionDepth, result);
Execute(cmd + savepoint);
return;
}
throw new ArgumentException("savePoint is not valid, and should be the result of a call to SaveTransactionPoint.", "savePoint");
}
public void Commit()
{
if (Interlocked.Exchange(ref _transactionDepth, 0) == 0)
{
return;
}
try
{
Execute("commit");
}
catch
{
try
{
Execute("rollback");
}
catch
{
}
throw;
}
}
public void RunInTransaction(Action action)
{
try
{
string savepoint = SaveTransactionPoint();
action();
Release(savepoint);
}
catch (Exception)
{
Rollback();
throw;
}
}
public int InsertAll(IEnumerable objects, bool runInTransaction = true)
{
int c = 0;
if (runInTransaction)
{
RunInTransaction(delegate
{
foreach (object @object in objects)
{
c += Insert(@object);
}
});
}
else
{
foreach (object object2 in objects)
{
c += Insert(object2);
}
}
return c;
}
public int InsertAll(IEnumerable objects, string extra, bool runInTransaction = true)
{
int c = 0;
if (runInTransaction)
{
RunInTransaction(delegate
{
foreach (object @object in objects)
{
c += Insert(@object, extra);
}
});
}
else
{
foreach (object object2 in objects)
{
c += Insert(object2, extra);
}
}
return c;
}
public int InsertAll(IEnumerable objects, Type objType, bool runInTransaction = true)
{
int c = 0;
if (runInTransaction)
{
RunInTransaction(delegate
{
foreach (object @object in objects)
{
c += Insert(@object, objType);
}
});
}
else
{
foreach (object object2 in objects)
{
c += Insert(object2, objType);
}
}
return c;
}
public int Insert(object obj)
{
if (obj == null)
{
return 0;
}
return Insert(obj, "", Orm.GetType(obj));
}
public int InsertOrReplace(object obj)
{
if (obj == null)
{
return 0;
}
return Insert(obj, "OR REPLACE", Orm.GetType(obj));
}
public int Insert(object obj, Type objType)
{
return Insert(obj, "", objType);
}
public int InsertOrReplace(object obj, Type objType)
{
return Insert(obj, "OR REPLACE", objType);
}
public int Insert(object obj, string extra)
{
if (obj == null)
{
return 0;
}
return Insert(obj, extra, Orm.GetType(obj));
}
public int Insert(object obj, string extra, Type objType)
{
if (obj == null || objType == null)
{
return 0;
}
TableMapping mapping = GetMapping(objType);
if (mapping.PK != null && mapping.PK.IsAutoGuid && mapping.PK.GetValue(obj).Equals(Guid.Empty))
{
mapping.PK.SetValue(obj, Guid.NewGuid());
}
TableMapping.Column[] array = ((string.Compare(extra, "OR REPLACE", StringComparison.OrdinalIgnoreCase) == 0) ? mapping.InsertOrReplaceColumns : mapping.InsertColumns);
object[] array2 = new object[array.Length];
for (int i = 0; i < array2.Length; i++)
{
array2[i] = array[i].GetValue(obj);
}
PreparedSqlLiteInsertCommand insertCommand = GetInsertCommand(mapping, extra);
int num;
lock (insertCommand)
{
try
{
num = insertCommand.ExecuteNonQuery(array2);
}
catch (SQLiteException ex)
{
if (SQLite3.ExtendedErrCode(Handle) == SQLite3.ExtendedResult.ConstraintNotNull)
{
throw NotNullConstraintViolationException.New(ex.Result, ex.Message, mapping, obj);
}
throw;
}
if (mapping.HasAutoIncPK)
{
long id = SQLite3.LastInsertRowid(Handle);
mapping.SetAutoIncPK(obj, id);
}
}
if (num > 0)
{
OnTableChanged(mapping, NotifyTableChangedAction.Insert);
}
return num;
}
private PreparedSqlLiteInsertCommand GetInsertCommand(TableMapping map, string extra)
{
Tuple<string, string> key = Tuple.Create(map.MappedType.FullName, extra);
PreparedSqlLiteInsertCommand value;
lock (_insertCommandMap)
{
if (_insertCommandMap.TryGetValue(key, out value))
{
return value;
}
}
value = CreateInsertCommand(map, extra);
lock (_insertCommandMap)
{
if (_insertCommandMap.TryGetValue(key, out var value2))
{
value.Dispose();
return value2;
}
_insertCommandMap.Add(key, value);
return value;
}
}
private PreparedSqlLiteInsertCommand CreateInsertCommand(TableMapping map, string extra)
{
TableMapping.Column[] array = map.InsertColumns;
string commandText;
if (array.Length == 0 && map.Columns.Length == 1 && map.Columns[0].IsAutoInc)
{
commandText = string.Format("insert {1} into \"{0}\" default values", map.TableName, extra);
}
else
{
if (string.Compare(extra, "OR REPLACE", StringComparison.OrdinalIgnoreCase) == 0)
{
array = map.InsertOrReplaceColumns;
}
commandText = string.Format("insert {3} into \"{0}\"({1}) values ({2})", map.TableName, string.Join(",", array.Select((TableMapping.Column c) => "\"" + c.Name + "\"").ToArray()), string.Join(",", array.Select((TableMapping.Column c) => "?").ToArray()), extra);
}
return new PreparedSqlLiteInsertCommand(this, commandText);
}
public int Update(object obj)
{
if (obj == null)
{
return 0;
}
return Update(obj, Orm.GetType(obj));
}
public int Update(object obj, Type objType)
{
int num = 0;
if (obj == null || objType == null)
{
return 0;
}
TableMapping mapping = GetMapping(objType);
TableMapping.Column pk = mapping.PK;
if (pk == null)
{
throw new NotSupportedException("Cannot update " + mapping.TableName + ": it has no PK");
}
IEnumerable<TableMapping.Column> source = mapping.Columns.Where((TableMapping.Column p) => p != pk);
IEnumerable<object> collection = source.Select((TableMapping.Column c) => c.GetValue(obj));
List<object> list = new List<object>(collection);
if (list.Count == 0)
{
source = mapping.Columns;
collection = source.Select((TableMapping.Column c) => c.GetValue(obj));
list = new List<object>(collection);
}
list.Add(pk.GetValue(obj));
string query = string.Format("update \"{0}\" set {1} where \"{2}\" = ? ", mapping.TableName, string.Join(",", source.Select((TableMapping.Column c) => "\"" + c.Name + "\" = ? ").ToArray()), pk.Name);
try
{
num = Execute(query, list.ToArray());
}
catch (SQLiteException ex)
{
if (ex.Result == SQLite3.Result.Constraint && SQLite3.ExtendedErrCode(Handle) == SQLite3.ExtendedResult.ConstraintNotNull)
{
throw NotNullConstraintViolationException.New(ex, mapping, obj);
}
throw ex;
}
if (num > 0)
{
OnTableChanged(mapping, NotifyTableChangedAction.Update);
}
return num;
}
public int UpdateAll(IEnumerable objects, bool runInTransaction = true)
{
int c = 0;
if (runInTransaction)
{
RunInTransaction(delegate
{
foreach (object @object in objects)
{
c += Update(@object);
}
});
}
else
{
foreach (object object2 in objects)
{
c += Update(object2);
}
}
return c;
}
public int Delete(object objectToDelete)
{
TableMapping mapping = GetMapping(Orm.GetType(objectToDelete));
TableMapping.Column pK = mapping.PK;
if (pK == null)
{
throw new NotSupportedException("Cannot delete " + mapping.TableName + ": it has no PK");
}
string query = $"delete from \"{mapping.TableName}\" where \"{pK.Name}\" = ?";
int num = Execute(query, pK.GetValue(objectToDelete));
if (num > 0)
{
OnTableChanged(mapping, NotifyTableChangedAction.Delete);
}
return num;
}
public int Delete<T>(object primaryKey)
{
return Delete(primaryKey, GetMapping(typeof(T)));
}
public int Delete(object primaryKey, TableMapping map)
{
TableMapping.Column pK = map.PK;
if (pK == null)
{
throw new NotSupportedException("Cannot delete " + map.TableName + ": it has no PK");
}
string query = $"delete from \"{map.TableName}\" where \"{pK.Name}\" = ?";
int num = Execute(query, primaryKey);
if (num > 0)
{
OnTableChanged(map, NotifyTableChangedAction.Delete);
}
return num;
}
public int DeleteAll<T>()
{
TableMapping mapping = GetMapping(typeof(T));
return DeleteAll(mapping);
}
public int DeleteAll(TableMapping map)
{
string query = $"delete from \"{map.TableName}\"";
int num = Execute(query);
if (num > 0)
{
OnTableChanged(map, NotifyTableChangedAction.Delete);
}
return num;
}
public void Backup(string destinationDatabasePath, string databaseName = "main")
{
SQLite3.Result result = SQLite3.Open(destinationDatabasePath, out var db);
if (result != 0)
{
throw SQLiteException.New(result, "Failed to open destination database");
}
IntPtr intPtr = SQLite3.BackupInit(db, databaseName, Handle, databaseName);
if (intPtr == NullBackupHandle)
{
SQLite3.Close(db);
throw new Exception("Failed to create backup");
}
SQLite3.BackupStep(intPtr, -1);
SQLite3.BackupFinish(intPtr);
result = SQLite3.GetResult(db);
string message = "";
if (result != 0)
{
message = SQLite3.GetErrmsg(db);
}
SQLite3.Close(db);
if (result != 0)
{
throw SQLiteException.New(result, message);
}
}
~SQLiteConnection()
{
Dispose(disposing: false);
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
public void Close()
{
Dispose(disposing: true);
}
protected virtual void Dispose(bool disposing)
{
bool flag = LibVersionNumber >= 3007014;
if (!_open || !(Handle != NullHandle))
{
return;
}
try
{
if (disposing)
{
lock (_insertCommandMap)
{
foreach (PreparedSqlLiteInsertCommand value in _insertCommandMap.Values)
{
value.Dispose();
}
_insertCommandMap.Clear();
}
SQLite3.Result result = (flag ? SQLite3.Close2(Handle) : SQLite3.Close(Handle));
if (result != 0)
{
string errmsg = SQLite3.GetErrmsg(Handle);
throw SQLiteException.New(result, errmsg);
}
}
else
{
SQLite3.Result result2 = (flag ? SQLite3.Close2(Handle) : SQLite3.Close(Handle));
}
}
finally
{
Handle = NullHandle;
_open = false;
}
}
private void OnTableChanged(TableMapping table, NotifyTableChangedAction action)
{
this.TableChanged?.Invoke(this, new NotifyTableChangedEventArgs(table, action));
}
}
public class NotifyTableChangedEventArgs : EventArgs
{
public TableMapping Table { get; private set; }
public NotifyTableChangedAction Action { get; private set; }
public NotifyTableChangedEventArgs(TableMapping table, NotifyTableChangedAction action)
{
Table = table;
Action = action;
}
}
public enum NotifyTableChangedAction
{
Insert,
Update,
Delete
}
public class SQLiteConnectionString
{
private const string DateTimeSqliteDefaultFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff";
public string UniqueKey { get; }
public string DatabasePath { get; }
public bool StoreDateTimeAsTicks { get; }
public bool StoreTimeSpanAsTicks { get; }
public string DateTimeStringFormat { get; }
public DateTimeStyles DateTimeStyle { get; }
public object Key { get; }
public SQLiteOpenFlags OpenFlags { get; }
public Action<SQLiteConnection> PreKeyAction { get; }
public Action<SQLiteConnection> PostKeyAction { get; }
public string VfsName { get; }
public SQLiteConnectionString(string databasePath, bool storeDateTimeAsTicks = true)
: this(databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks)
{
}
public SQLiteConnectionString(string databasePath, bool storeDateTimeAsTicks, object key = null, Action<SQLiteConnection> preKeyAction = null, Action<SQLiteConnection> postKeyAction = null, string vfsName = null)
: this(databasePath, SQLiteOpenFlags.ReadWrite | SQLiteOpenFlags.Create, storeDateTimeAsTicks, key, preKeyAction, postKeyAction, vfsName)
{
}
public SQLiteConnectionString(string databasePath, SQLiteOpenFlags openFlags, bool storeDateTimeAsTicks, object key = null, Action<SQLiteConnection> preKeyAction = null, Action<SQLiteConnection> postKeyAction = null, string vfsName = null, string dateTimeStringFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'fff", bool storeTimeSpanAsTicks = true)
{
if (key != null && !(key is byte[]) && !(key is string))
{
throw new ArgumentException("Encryption keys must be strings or byte arrays", "key");
}
UniqueKey = $"{databasePath}_{(uint)openFlags:X8}";
StoreDateTimeAsTicks = storeDateTimeAsTicks;
StoreTimeSpanAsTicks = storeTimeSpanAsTicks;
DateTimeStringFormat = dateTimeStringFormat;
DateTimeStyle = (("o".Equals(DateTimeStringFormat, StringComparison.OrdinalIgnoreCase) || "r".Equals(DateTimeStringFormat, StringComparison.OrdinalIgnoreCase)) ? DateTimeStyles.RoundtripKind : DateTimeStyles.None);
Key = key;
PreKeyAction = preKeyAction;
PostKeyAction = postKeyAction;
OpenFlags = openFlags;
VfsName = vfsName;
DatabasePath = databasePath;
}
}
[AttributeUsage(AttributeTargets.Class)]
public class TableAttribute : Attribute
{
public string Name { get; set; }
public bool WithoutRowId { get; set; }
public TableAttribute(string name)
{
Name = name;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class ColumnAttribute : Attribute
{
public string Name { get; set; }
public ColumnAttribute(string name)
{
Name = name;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class PrimaryKeyAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class AutoIncrementAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class IndexedAttribute : Attribute
{
public string Name { get; set; }
public int Order { get; set; }
public virtual bool Unique { get; set; }
public IndexedAttribute()
{
}
public IndexedAttribute(string name, int order)
{
Name = name;
Order = order;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class IgnoreAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Property)]
public class UniqueAttribute : IndexedAttribute
{
public override bool Unique
{
get
{
return true;
}
set
{
}
}
}
[AttributeUsage(AttributeTargets.Property)]
public class MaxLengthAttribute : Attribute
{
public int Value { get; private set; }
public MaxLengthAttribute(int length)
{
Value = length;
}
}
public sealed class PreserveAttribute : Attribute
{
public bool AllMembers;
public bool Conditional;
}
[AttributeUsage(AttributeTargets.Property)]
public class CollationAttribute : Attribute
{
public string Value { get; private set; }
public CollationAttribute(string collation)
{
Value = collation;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class NotNullAttribute : Attribute
{
}
[AttributeUsage(AttributeTargets.Enum)]
public class StoreAsTextAttribute : Attribute
{
}
public class TableMapping
{
public class Column
{
private MemberInfo _member;
public string Name { get; private set; }
public PropertyInfo PropertyInfo => _member as PropertyInfo;
public string PropertyName => _member.Name;
public Type ColumnType { get; private set; }
public string Collation { get; private set; }
public bool IsAutoInc { get; private set; }
public bool IsAutoGuid { get; private set; }
public bool IsPK { get; private set; }
public IEnumerable<IndexedAttribute> Indices { get; set; }
public bool IsNullable { get; private set; }
public int? MaxStringLength { get; private set; }
public bool StoreAsText { get; private set; }
public Column(MemberInfo member, CreateFlags createFlags = CreateFlags.None)
{
_member = member;
Type memberType = GetMemberType(member);
CustomAttributeData customAttributeData = member.CustomAttributes.FirstOrDefault((CustomAttributeData x) => x.AttributeType == typeof(ColumnAttribute));
Name = ((customAttributeData == null || customAttributeData.ConstructorArguments.Count <= 0) ? member.Name : customAttributeData.ConstructorArguments[0].Value?.ToString());
ColumnType = Nullable.GetUnderlyingType(memberType) ?? memberType;
Collation = Orm.Collation(member);
IsPK = Orm.IsPK(member) || ((createFlags & CreateFlags.ImplicitPK) == CreateFlags.ImplicitPK && string.Compare(member.Name, "Id", StringComparison.OrdinalIgnoreCase) == 0);
bool flag = Orm.IsAutoInc(member) || (IsPK && (createFlags & CreateFlags.AutoIncPK) == CreateFlags.AutoIncPK);
IsAutoGuid = flag && ColumnType == typeof(Guid);
IsAutoInc = flag && !IsAutoGuid;
Indices = Orm.GetIndices(member);
if (!Indices.Any() && !IsPK && (createFlags & CreateFlags.ImplicitIndex) == CreateFlags.ImplicitIndex && Name.EndsWith("Id", StringComparison.OrdinalIgnoreCase))
{
Indices = new IndexedAttribute[1]
{
new IndexedAttribute()
};
}
IsNullable = !IsPK && !Orm.IsMarkedNotNull(member);
MaxStringLength = Orm.MaxStringLength(member);
StoreAsText = memberType.GetTypeInfo().CustomAttributes.Any((CustomAttributeData x) => x.AttributeType == typeof(StoreAsTextAttribute));
}
public Column(PropertyInfo member, CreateFlags createFlags = CreateFlags.None)
: this((MemberInfo)member, createFlags)
{
}
public void SetValue(object obj, object val)
{
if (_member is PropertyInfo propertyInfo)
{
if (val != null && ColumnType.GetTypeInfo().IsEnum)
{
propertyInfo.SetValue(obj, Enum.ToObject(ColumnType, val));
}
else
{
propertyInfo.SetValue(obj, val);
}
return;
}
if (_member is FieldInfo fieldInfo)
{
if (val != null && ColumnType.GetTypeInfo().IsEnum)
{
fieldInfo.SetValue(obj, Enum.ToObject(ColumnType, val));
}
else
{
fieldInfo.SetValue(obj, val);
}
return;
}
throw new InvalidProgramException("unreachable condition");
}
public object GetValue(object obj)
{
if (_member is PropertyInfo propertyInfo)
{
return propertyInfo.GetValue(obj);
}
if (_member is FieldInfo fieldInfo)
{
return fieldInfo.GetValue(obj);
}
throw new InvalidProgramException("unreachable condition");
}
private static Type GetMemberType(MemberInfo m)
{
return m.MemberType switch
{
MemberTypes.Property => ((PropertyInfo)m).PropertyType,
MemberTypes.Field => ((FieldInfo)m).FieldType,
_ => throw new InvalidProgramException("TableMapping supports properties or fields only."),
};
}
}
internal enum MapMethod
{
ByName,
ByPosition
}
private readonly Column _autoPk;
private readonly Column[] _insertColumns;
private readonly Column[] _insertOrReplaceColumns;
public Type MappedType { get; private set; }
public string TableName { get; private set; }
public bool WithoutRowId { get; private set; }
public Column[] Columns { get; private set; }
public Column PK { get; private set; }
public string GetByPrimaryKeySql { get; private set; }
public CreateFlags CreateFlags { get; private set; }
internal MapMethod Method { get; private set; }
public bool HasAutoIncPK { get; private set; }
public Column[] InsertColumns => _insertColumns;
public Column[] InsertOrReplaceColumns => _insertOrReplaceColumns;
public TableMapping(Type type, CreateFlags createFlags = CreateFlags.None)
{
MappedType = type;
CreateFlags = createFlags;
TypeInfo typeInfo = type.GetTypeInfo();
TableAttribute tableAttribute = (from x in typeInfo.CustomAttributes
where x.AttributeType == typeof(TableAttribute)
select (TableAttribute)Orm.InflateAttribute(x)).FirstOrDefault();
TableName = ((tableAttribute != null && !string.IsNullOrEmpty(tableAttribute.Name)) ? tableAttribute.Name : MappedType.Name);
WithoutRowId = tableAttribute?.WithoutRowId ?? false;
IReadOnlyCollection<MemberInfo> publicMembers = GetPublicMembers(type);
List<Column> list = new List<Column>(publicMembers.Count);
foreach (MemberInfo item in publicMembers)
{
if (!item.IsDefined(typeof(IgnoreAttribute), inherit: true))
{
list.Add(new Column(item, createFlags));
}
}
Columns = list.ToArray();
Column[] columns = Columns;
foreach (Column column in columns)
{
if (column.IsAutoInc && column.IsPK)
{
_autoPk = column;
}
if (column.IsPK)
{
PK = column;
}
}
HasAutoIncPK = _autoPk != null;
if (PK != null)
{
GetByPrimaryKeySql = $"select * from \"{TableName}\" where \"{PK.Name}\" = ?";
}
else
{
GetByPrimaryKeySql = $"select * from \"{TableName}\" limit 1";
}
_insertColumns = Columns.Where((Column c) => !c.IsAutoInc).ToArray();
_insertOrReplaceColumns = Columns.ToArray();
}
private IReadOnlyCollection<MemberInfo> GetPublicMembers(Type type)
{
if (type.Name.StartsWith("ValueTuple`"))
{
return GetFieldsFromValueTuple(type);
}
List<MemberInfo> list = new List<MemberInfo>();
HashSet<string> memberNames = new HashSet<string>();
List<MemberInfo> list2 = new List<MemberInfo>();
do
{
TypeInfo typeInfo = type.GetTypeInfo();
list2.Clear();
list2.AddRange(typeInfo.DeclaredProperties.Where((PropertyInfo p) => !memberNames.Contains(p.Name) && p.CanRead && p.CanWrite && p.GetMethod != null && p.SetMethod != null && p.GetMethod.IsPublic && p.SetMethod.IsPublic && !p.GetMethod.IsStatic && !p.SetMethod.IsStatic));
list.AddRange(list2);
foreach (MemberInfo item in list2)
{
memberNames.Add(item.Name);
}
type = typeInfo.BaseType;
}
while (type != typeof(object));
return list;
}
private IReadOnlyCollection<MemberInfo> GetFieldsFromValueTuple(Type type)
{
Method = MapMethod.ByPosition;
FieldInfo[] fields = type.GetFields();
if (fields.Length >= 8)
{
throw new NotSupportedException("ValueTuple with more than 7 members not supported due to nesting; see https://docs.microsoft.com/en-us/dotnet/api/system.valuetuple-8.rest");
}
return (IReadOnlyCollection<MemberInfo>)(object)fields;
}
public void SetAutoIncPK(object obj, long id)
{
if (_autoPk != null)
{
_autoPk.SetValue(obj, Convert.ChangeType(id, _autoPk.ColumnType, null));
}
}
public Column FindColumnWithPropertyName(string propertyName)
{
return Columns.FirstOrDefault((Column c) => c.PropertyName == propertyName);
}
public Column FindColumn(string columnName)
{
if (Method != 0)
{
throw new InvalidOperationException(string.Format("This {0} is not mapped by name, but {1}.", "TableMapping", Method));
}
return Columns.FirstOrDefault((Column c) => c.Name.ToLower() == columnName.ToLower());
}
}
internal class EnumCacheInfo
{
public bool IsEnum { get; private set; }
public bool StoreAsText { get; private set; }
public Dictionary<int, string> EnumValues { get; private set; }
public EnumCacheInfo(Type type)
{
TypeInfo typeInfo = type.GetTypeInfo();
IsEnum = typeInfo.IsEnum;
if (!IsEnum)
{
return;
}
StoreAsText = typeInfo.CustomAttributes.Any((CustomAttributeData x) => x.AttributeType == typeof(StoreAsTextAttribute));
if (!StoreAsText)
{
return;
}
EnumValues = new Dictionary<int, string>();
foreach (object value in Enum.GetValues(type))
{
EnumValues[Convert.ToInt32(value)] = value.ToString();
}
}
}
internal static class EnumCache
{
private static readonly Dictionary<Type, EnumCacheInfo> Cache = new Dictionary<Type, EnumCacheInfo>();
public static EnumCacheInfo GetInfo<T>()
{
return GetInfo(typeof(T));
}
public static EnumCacheInfo GetInfo(Type type)
{
lock (Cache)
{
EnumCacheInfo value = null;
if (!Cache.TryGetValue(type, out value))
{
value = new EnumCacheInfo(type);
Cache[type] = value;
}
return value;
}
}
}
public static class Orm
{
public const int DefaultMaxStringLength = 140;
public const string ImplicitPkName = "Id";
public const string ImplicitIndexSuffix = "Id";
public static Type GetType(object obj)
{
if (obj == null)
{
return typeof(object);
}
if (obj is IReflectableType reflectableType)
{
return reflectableType.GetTypeInfo().AsType();
}
return obj.GetType();
}
public static string SqlDecl(TableMapping.Column p, bool storeDateTimeAsTicks, bool storeTimeSpanAsTicks)
{
string text = "\"" + p.Name + "\" " + SqlType(p, storeDateTimeAsTicks, storeTimeSpanAsTicks) + " ";
if (p.IsPK)
{
text += "primary key ";
}
if (p.IsAutoInc)
{
text += "autoincrement ";
}
if (!p.IsNullable)
{
text += "not null ";
}
if (!string.IsNullOrEmpty(p.Collation))
{
text = text + "collate " + p.Collation + " ";
}
return text;
}
public static string SqlType(TableMapping.Column p, bool storeDateTimeAsTicks, bool storeTimeSpanAsTicks)
{
Type columnType = p.ColumnType;
if (columnType == typeof(bool) || columnType == typeof(byte) || columnType == typeof(ushort) || columnType == typeof(sbyte) || columnType == typeof(short) || columnType == typeof(int) || columnType == typeof(uint) || columnType == typeof(long))
{
return "integer";
}
if (columnType == typeof(float) || columnType == typeof(double) || columnType == typeof(decimal))
{
return "float";
}
if (columnType == typeof(string) || columnType == typeof(StringBuilder) || columnType == typeof(Uri) || columnType == typeof(UriBuilder))
{
int? maxStringLength = p.MaxStringLength;
if (maxStringLength.HasValue)
{
return "varchar(" + maxStringLength.Value + ")";
}
return "varchar";
}
if (columnType == typeof(TimeSpan))
{
if (!storeTimeSpanAsTicks)
{
return "time";
}
return "bigint";
}
if (columnType == typeof(DateTime))
{
if (!storeDateTimeAsTicks)
{
return "datetime";
}
return "bigint";
}
if (columnType == typeof(DateTimeOffset))
{
return "bigint";
}
if (columnType.GetTypeInfo().IsEnum)
{
if (p.StoreAsText)
{
return "varchar";
}
return "integer";
}
if (columnType == typeof(byte[]))
{
return "blob";
}
if (columnType == typeof(Guid))
{
return "varchar(36)";
}
throw new NotSupportedException("Don't know about " + columnType);
}
public static bool IsPK(MemberInfo p)
{
return p.CustomAttributes.Any((CustomAttributeData x) => x.AttributeType == typeof(PrimaryKeyAttribute));
}
public static string Collation(MemberInfo p)
{
return p.CustomAttributes.Where((CustomAttributeData x) => typeof(CollationAttribute) == x.AttributeType).Select(delegate(CustomAttributeData x)
{
IList<CustomAttributeTypedArgument> constructorArguments = x.ConstructorArguments;
return (constructorArguments.Count <= 0) ? "" : ((constructorArguments[0].Value as string) ?? "");
}).FirstOrDefault() ?? "";
}
public static bool IsAutoInc(MemberInfo p)
{
return p.CustomAttributes.Any((CustomAttributeData x) => x.AttributeType == typeof(AutoIncrementAttribute));
}
public static FieldInfo GetField(TypeInfo t, string name)
{
FieldInfo declaredField = t.GetDeclaredField(name);
if (declaredField != null)
{
return declaredField;
}
return GetField(t.BaseType.GetTypeInfo(), name);
}
public static PropertyInfo GetProperty(TypeInfo t, string name)
{
PropertyInfo declaredProperty = t.GetDeclaredProperty(name);
if (declaredProperty != null)
{
return declaredProperty;
}
return GetProperty(t.BaseType.GetTypeInfo(), name);
}
public static object InflateAttribute(CustomAttributeData x)
{
Type attributeType = x.AttributeType;
TypeInfo typeInfo = attributeType.GetTypeInfo();
object[] args = x.ConstructorArguments.Select((CustomAttributeTypedArgument a) => a.Value).ToArray();
object obj = Activator.CreateInstance(x.AttributeType, args);
foreach (CustomAttributeNamedArgument namedArgument in x.NamedArguments)
{
if (namedArgument.IsField)
{
GetField(typeInfo, namedArgument.MemberName).SetValue(obj, namedArgument.TypedValue.Value);
}
else
{
GetProperty(typeInfo, namedArgument.MemberName).SetValue(obj, namedArgument.TypedValue.Value);
}
}
return obj;
}
public static IEnumerable<IndexedAttribute> GetIndices(MemberInfo p)
{
TypeInfo indexedInfo = typeof(IndexedAttribute).GetTypeInfo();
return from x in p.CustomAttributes
where indexedInfo.IsAssignableFrom(x.AttributeType.GetTypeInfo())
select (IndexedAttribute)InflateAttribute(x);
}
public static int? MaxStringLength(MemberInfo p)
{
CustomAttributeData customAttributeData = p.CustomAttributes.FirstOrDefault((CustomAttributeData x) => x.AttributeType == typeof(MaxLengthAttribute));
if (customAttributeData != null)
{
MaxLengthAttribute maxLengthAttribute = (MaxLengthAttribute)InflateAttribute(customAttributeData);
return maxLengthAttribute.Value;
}
return null;
}
public static int? MaxStringLength(PropertyInfo p)
{
return MaxStringLength((MemberInfo)p);
}
public static bool IsMarkedNotNull(MemberInfo p)
{
return p.CustomAttributes.Any((CustomAttributeData x) => x.AttributeType == typeof(NotNullAttribute));
}
}
public class SQLiteCommand
{
private class Binding
{
public string Name { get; set; }
public object Value { get; set; }
public int Index { get; set; }
}
[CompilerGenerated]
private sealed class <ExecuteDeferredQuery>d__12<T> : IEnumerable<T>, IEnumerable, IEnumerator<T>, IEnumerator, IDisposable
{
private int <>1__state;
private T <>2__current;
private int <>l__initialThreadId;
public SQLiteCommand <>4__this;
private TableMapping map;
public TableMapping <>3__map;
private IntPtr <stmt>5__2;
private TableMapping.Column[] <cols>5__3;
private Action<object, IntPtr, int>[] <fastColumnSetters>5__4;
T IEnumerator<T>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ExecuteDeferredQuery>d__12(int <>1__state)
{
this.<>1__state = <>1__state;
<>l__initialThreadId = Environment.CurrentManagedThreadId;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
int num = <>1__state;
if (num == -3 || num == 1)
{
try
{
}
finally
{
<>m__Finally1();
}
}
<cols>5__3 = null;
<fastColumnSetters>5__4 = null;
<>1__state = -2;
}
private bool MoveNext()
{
try
{
int num = <>1__state;
SQLiteCommand sQLiteCommand = <>4__this;
switch (num)
{
default:
return false;
case 0:
<>1__state = -1;
if (sQLiteCommand._conn.Trace)
{
sQLiteCommand._conn.Tracer?.Invoke("Executing Query: " + sQLiteCommand);
}
<stmt>5__2 = sQLiteCommand.Prepare();
<>1__state = -3;
<cols>5__3 = new TableMapping.Column[SQLite3.ColumnCount(<stmt>5__2)];
<fastColumnSetters>5__4 = new Action<object, IntPtr, int>[SQLite3.ColumnCount(<stmt>5__2)];
if (map.Method == TableMapping.MapMethod.ByPosition)
{
Array.Copy(map.Columns, <cols>5__3, Math.Min(<cols>5__3.Length, map.Columns.Length));
}
else
{
if (map.Method != 0)
{
break;
}
MethodInfo methodInfo = null;
if (typeof(T) != map.MappedType)
{
methodInfo = typeof(FastColumnSetter).GetMethod("GetFastSetter", BindingFlags.Static | BindingFlags.NonPublic).MakeGenericMethod(map.MappedType);
}
for (int i = 0; i < <cols>5__3.Length; i++)
{
string columnName = SQLite3.ColumnName16(<stmt>5__2, i);
<cols>5__3[i] = map.FindColumn(columnName);
if (<cols>5__3[i] != null)
{
if (methodInfo != null)
{
<fastColumnSetters>5__4[i] = (Action<object, IntPtr, int>)methodInfo.Invoke(null, new object[2]
{
sQLiteCommand._conn,
<cols>5__3[i]
});
}
else
{
<fastColumnSetters>5__4[i] = FastColumnSetter.GetFastSetter<T>(sQLiteCommand._conn, <cols>5__3[i]);
}
}
}
}
break;
case 1:
<>1__state = -3;
break;
}
if (SQLite3.Step(<stmt>5__2) == SQLite3.Result.Row)
{
object obj = Activator.CreateInstance(map.MappedType);
for (int j = 0; j < <cols>5__3.Length; j++)
{
if (<cols>5__3[j] != null)
{
if (<fastColumnSetters>5__4[j] != null)
{
<fastColumnSetters>5__4[j](obj, <stmt>5__2, j);
continue;
}
SQLite3.ColType type = SQLite3.ColumnType(<stmt>5__2, j);
object val = sQLiteCommand.ReadCol(<stmt>5__2, j, type, <cols>5__3[j].ColumnType);
<cols>5__3[j].SetValue(obj, val);
}
}
sQLiteCommand.OnInstanceCreated(obj);
<>2__current = (T)obj;
<>1__state = 1;
return true;
}
<cols>5__3 = null;
<fastColumnSetters>5__4 = null;
<>m__Finally1();
return false;
}
catch
{
//try-fault
((IDisposable)this).Dispose();
throw;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
private void <>m__Finally1()
{
<>1__state = -1;
SQLite3.Finalize(<stmt>5__2);
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
[DebuggerHidden]
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
<ExecuteDeferredQuery>d__12<T> <ExecuteDeferredQuery>d__;
if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
{
<>1__state = 0;
<ExecuteDeferredQuery>d__ = this;
}
else
{
<ExecuteDeferredQuery>d__ = new <ExecuteDeferredQuery>d__12<T>(0)
{
<>4__this = <>4__this
};
}
<ExecuteDeferredQuery>d__.map = <>3__map;
return <ExecuteDeferredQuery>d__;
}
[DebuggerHidden]
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)this).GetEnumerator();
}
}
[CompilerGenerated]
private sealed class <ExecuteQueryScalars>d__14<T> : IEnumerable<T>, IEnumerable, IEnumerator<T>, IEnumerator, IDisposable
{
private int <>1__state;
private T <>2__current;
private int <>l__initialThreadId;
public SQLiteCommand <>4__this;
private IntPtr <stmt>5__2;
T IEnumerator<T>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <ExecuteQueryScalars>d__14(int <>1__state)
{
this.<>1__state = <>1__state;
<>l__initialThreadId = Environment.CurrentManagedThreadId;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
int num = <>1__state;
if (num == -3 || (uint)(num - 1) <= 1u)
{
try
{
}
finally
{
<>m__Finally1();
}
}
<>1__state = -2;
}
private bool MoveNext()
{
try
{
int num = <>1__state;
SQLiteCommand sQLiteCommand = <>4__this;
switch (num)
{
default:
return false;
case 0:
<>1__state = -1;
if (sQLiteCommand._conn.Trace)
{
sQLiteCommand._conn.Tracer?.Invoke("Executing Query: " + sQLiteCommand);
}
<stmt>5__2 = sQLiteCommand.Prepare();
<>1__state = -3;
if (SQLite3.ColumnCount(<stmt>5__2) < 1)
{
throw new InvalidOperationException("QueryScalars should return at least one column");
}
break;
case 1:
<>1__state = -3;
break;
case 2:
<>1__state = -3;
break;
}
if (SQLite3.Step(<stmt>5__2) == SQLite3.Result.Row)
{
SQLite3.ColType type = SQLite3.ColumnType(<stmt>5__2, 0);
object obj = sQLiteCommand.ReadCol(<stmt>5__2, 0, type, typeof(T));
if (obj == null)
{
<>2__current = default(T);
<>1__state = 1;
return true;
}
<>2__current = (T)obj;
<>1__state = 2;
return true;
}
<>m__Finally1();
return false;
}
catch
{
//try-fault
((IDisposable)this).Dispose();
throw;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
private void <>m__Finally1()
{
<>1__state = -1;
SQLiteCommand sQLiteCommand = <>4__this;
sQLiteCommand.Finalize(<stmt>5__2);
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
[DebuggerHidden]
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
<ExecuteQueryScalars>d__14<T> result;
if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId)
{
<>1__state = 0;
result = this;
}
else
{
result = new <ExecuteQueryScalars>d__14<T>(0)
{
<>4__this = <>4__this
};
}
return result;
}
[DebuggerHidden]
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<T>)this).GetEnumerator();
}
}
private SQLiteConnection _conn;
private List<Binding> _bindings;
private static IntPtr NegativePointer = new IntPtr(-1);
public string CommandText { get; set; }
public SQLiteCommand(SQLiteConnection conn)
{
_conn = conn;
_bindings = new List<Binding>();
CommandText = "";
}
public int ExecuteNonQuery()
{
if (_conn.Trace)
{
_conn.Tracer?.Invoke("Executing: " + this);
}
SQLite3.Result result = SQLite3.Result.OK;
IntPtr stmt = Prepare();
result = SQLite3.Step(stmt);
Finalize(stmt);
switch (result)
{
case SQLite3.Result.Done:
return SQLite3.Changes(_conn.Handle);
case SQLite3.Result.Error:
{
string errmsg = SQLite3.GetErrmsg(_conn.Handle);
throw SQLiteException.New(result, errmsg);
}
case SQLite3.Result.Constraint:
if (SQLite3.ExtendedErrCode(_conn.Handle) == SQLite3.ExtendedResult.ConstraintNotNull)
{
throw NotNullConstraintViolationException.New(result, SQLite3.GetErrmsg(_conn.Handle));
}
break;
}
throw SQLiteException.New(result, SQLite3.GetErrmsg(_conn.Handle));
}
public IEnumerable<T> ExecuteDeferredQuery<T>()
{
return ExecuteDeferredQuery<T>(_conn.GetMapping(typeof(T)));
}
public List<T> ExecuteQuery<T>()
{
return ExecuteDeferredQuery<T>(_conn.GetMapping(typeof(T))).ToList();
}
public List<T> ExecuteQuery<T>(TableMapping map)
{
return ExecuteDeferredQuery<T>(map).ToList();
}
protected virtual void OnInstanceCreated(object obj)
{
}
[IteratorStateMachine(typeof(<ExecuteDeferredQuery>d__12<>))]
public IEnumerable<T> ExecuteDeferredQuery<T>(TableMapping map)
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ExecuteDeferredQuery>d__12<T>(-2)
{
<>4__this = this,
<>3__map = map
};
}
public T ExecuteScalar<T>()
{
if (_conn.Trace)
{
_conn.Tracer?.Invoke("Executing Query: " + this);
}
T result = default(T);
IntPtr stmt = Prepare();
try
{
SQLite3.Result result2 = SQLite3.Step(stmt);
switch (result2)
{
case SQLite3.Result.Row:
{
SQLite3.ColType type = SQLite3.ColumnType(stmt, 0);
object obj = ReadCol(stmt, 0, type, typeof(T));
if (obj != null)
{
result = (T)obj;
return result;
}
break;
}
case SQLite3.Result.Done:
break;
default:
throw SQLiteException.New(result2, SQLite3.GetErrmsg(_conn.Handle));
}
}
finally
{
Finalize(stmt);
}
return result;
}
[IteratorStateMachine(typeof(<ExecuteQueryScalars>d__14<>))]
public IEnumerable<T> ExecuteQueryScalars<T>()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <ExecuteQueryScalars>d__14<T>(-2)
{
<>4__this = this
};
}
public void Bind(string name, object val)
{
_bindings.Add(new Binding
{
Name = name,
Value = val
});
}
public void Bind(object val)
{
Bind(null, val);
}
public override string ToString()
{
string[] array = new string[1 + _bindings.Count];
array[0] = CommandText;
int num = 1;
foreach (Binding binding in _bindings)
{
array[num] = $" {num - 1}: {binding.Value}";
num++;
}
return string.Join(Environment.NewLine, array);
}
private IntPtr Prepare()
{
IntPtr intPtr = SQLite3.Prepare2(_conn.Handle, CommandText);
BindAll(intPtr);
return intPtr;
}
private void Finalize(IntPtr stmt)
{
SQLite3.Finalize(stmt);
}
private void BindAll(IntPtr stmt)
{
int num = 1;
foreach (Binding binding in _bindings)
{
if (binding.Name != null)
{
binding.Index = SQLite3.BindParameterIndex(stmt, binding.Name);
}
else
{
binding.Index = num++;
}
BindParameter(stmt, binding.Index, binding.Value, _conn.StoreDateTimeAsTicks, _conn.DateTimeStringFormat, _conn.StoreTimeSpanAsTicks);
}
}
internal static void BindParameter(IntPtr stmt, int index, object value, bool storeDateTimeAsTicks, string dateTimeStringFormat, bool storeTimeSpanAsTicks)
{
if (value == null)
{
SQLite3.BindNull(stmt, index);
return;
}
if (value is int)
{
SQLite3.BindInt(stmt, index, (int)value);
return;
}
if (value is string)
{
SQLite3.BindText(stmt, index, (string)value, -1, NegativePointer);
return;
}
if (value is byte || value is ushort || value is sbyte || value is short)
{
SQLite3.BindInt(stmt, index, Convert.ToInt32(value));
return;
}
if (value is bool)
{
SQLite3.BindInt(stmt, index, ((bool)value) ? 1 : 0);
return;
}
if (value is uint || value is long)
{
SQLite3.BindInt64(stmt, index, Convert.ToInt64(value));
return;
}
if (value is float || value is double || value is decimal)
{
SQLite3.BindDouble(stmt, index, Convert.ToDouble(value));
return;
}
if (value is TimeSpan)
{
if (storeTimeSpanAsTicks)
{
SQLite3.BindInt64(stmt, index, ((TimeSpan)value).Ticks);
}
else
{
SQLite3.BindText(stmt, index, ((TimeSpan)value).ToString(), -1, NegativePointer);
}
return;
}
if (value is DateTime)
{
if (storeDateTimeAsTicks)
{
SQLite3.BindInt64(stmt, index, ((DateTime)value).Ticks);
}
else
{
SQLite3.BindText(stmt, index, ((DateTime)value).ToString(dateTimeStringFormat, CultureInfo.InvariantCulture), -1, NegativePointer);
}
return;
}
if (value is DateTimeOffset)
{
SQLite3.BindInt64(stmt, index, ((DateTimeOffset)value).UtcTicks);
return;
}
if (value is byte[])
{
SQLite3.BindBlob(stmt, index, (byte[])value, ((byte[])value).Length, NegativePointer);
return;
}
if (value is Guid)
{
SQLite3.BindText(stmt, index, ((Guid)value).ToString(), 72, NegativePointer);
return;
}
if (value is Uri)
{
SQLite3.BindText(stmt, index, ((Uri)value).ToString(), -1, NegativePointer);
return;
}
if (value is StringBuilder)
{
SQLite3.BindText(stmt, index, ((StringBuilder)value).ToString(), -1, NegativePointer);
return;
}
if (value is UriBuilder)
{
SQLite3.BindText(stmt, index, ((UriBuilder)value).ToString(), -1, NegativePointer);
return;
}
Type type = value.GetType();
EnumCacheInfo info = EnumCache.GetInfo(type);
if (info.IsEnum)
{
int num = Convert.ToInt32(value);
if (info.StoreAsText)
{
SQLite3.BindText(stmt, index, info.EnumValues[num], -1, NegativePointer);
}
else
{
SQLite3.BindInt(stmt, index, num);
}
return;
}
throw new NotSupportedException("Cannot store type: " + Orm.GetType(value));
}
private object ReadCol(IntPtr stmt, int index, SQLite3.ColType type, Type clrType)
{
if (type == SQLite3.ColType.Null)
{
return null;
}
TypeInfo typeInfo = clrType.GetTypeInfo();
if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
{
clrType = typeInfo.GenericTypeArguments[0];
typeInfo = clrType.GetTypeInfo();
}
if (clrType == typeof(string))
{
return SQLite3.ColumnString(stmt, index);
}
if (clrType == typeof(int))
{
return SQLite3.ColumnInt(stmt, index);
}
if (clrType == typeof(bool))
{
return SQLite3.ColumnInt(stmt, index) == 1;
}
if (clrType == typeof(double))
{
return SQLite3.ColumnDouble(stmt, index);
}
if (clrType == typeof(float))
{
return (float)SQLite3.ColumnDouble(stmt, index);
}
if (clrType == typeof(TimeSpan))
{
if (_conn.StoreTimeSpanAsTicks)
{
return new TimeSpan(SQLite3.ColumnInt64(stmt, index));
}
string text = SQLite3.ColumnString(stmt, index);
if (!TimeSpan.TryParseExact(text, "c", CultureInfo.InvariantCulture, TimeSpanStyles.None, out var result))
{
result = TimeSpan.Parse(text);
}
return result;
}
if (clrType == typeof(DateTime))
{
if (_conn.StoreDateTimeAsTicks)
{
return new DateTime(SQLite3.ColumnInt64(stmt, index));
}
string s = SQLite3.ColumnString(stmt, index);
if (!DateTime.TryParseExact(s, _conn.DateTimeStringFormat, CultureInfo.InvariantCulture, _conn.DateTimeStyle, out var result2))
{
result2 = DateTime.Parse(s);
}
return result2;
}
if (clrType == typeof(DateTimeOffset))
{
return new DateTimeOffset(SQLite3.ColumnInt64(stmt, index), TimeSpan.Zero);
}
if (typeInfo.IsEnum)
{
if (type == SQLite3.ColType.Text)
{
string text2 = SQLite3.ColumnString(stmt, index);
return Enum.Parse(clrType, text2.ToString(), ignoreCase: true);
}
return SQLite3.ColumnInt(stmt, index);
}
if (clrType == typeof(long))
{
return SQLite3.ColumnInt64(stmt, index);
}
if (clrType == typeof(uint))
{
return (uint)SQLite3.ColumnInt64(stmt, index);
}
if (clrType == typeof(decimal))
{
return (decimal)SQLite3.ColumnDouble(stmt, index);
}
if (clrType == typeof(byte))
{
return (byte)SQLite3.ColumnInt(stmt, index);
}
if (clrType == typeof(ushort))
{
return (ushort)SQLite3.ColumnInt(stmt, index);
}
if (clrType == typeof(short))
{
return (short)SQLite3.ColumnInt(stmt, index);
}
if (clrType == typeof(sbyte))
{
return (sbyte)SQLite3.ColumnInt(stmt, index);
}
if (clrType == typeof(byte[]))
{
return SQLite3.ColumnByteArray(stmt, index);
}
if (clrType == typeof(Guid))
{
string g = SQLite3.ColumnString(stmt, index);
return new Guid(g);
}
if (clrType == typeof(Uri))
{
string uriString = SQLite3.ColumnString(stmt, index);
return new Uri(uriString);
}
if (clrType == typeof(StringBuilder))
{
string value = SQLite3.ColumnString(stmt, index);
return new StringBuilder(value);
}
if (clrType == typeof(UriBuilder))
{
string uri = SQLite3.ColumnString(stmt, index);
return new UriBuilder(uri);
}
throw new NotSupportedException("Don't know how to read " + clrType);
}
}
internal class FastColumnSetter
{
internal static Action<object, IntPtr, int> GetFastSetter<T>(SQLiteConnection conn, TableMapping.Column column)
{
Action<object, IntPtr, int> result = null;
Type type = column.PropertyInfo.PropertyType;
TypeInfo typeInfo = type.GetTypeInfo();
if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
{
type = typeInfo.GenericTypeArguments[0];
typeInfo = type.GetTypeInfo();
}
if (type == typeof(string))
{
result = CreateTypedSetterDelegate<T, string>(column, (IntPtr stmt, int index) => SQLite3.ColumnString(stmt, index));
}
else if (type == typeof(int))
{
result = CreateNullableTypedSetterDelegate<T, int>(column, (IntPtr stmt, int index) => SQLite3.ColumnInt(stmt, index));
}
else if (type == typeof(bool))
{
result = CreateNullableTypedSetterDelegate<T, bool>(column, (IntPtr stmt, int index) => SQLite3.ColumnInt(stmt, index) == 1);
}
else if (type == typeof(double))
{
result = CreateNullableTypedSetterDelegate<T, double>(column, (IntPtr stmt, int index) => SQLite3.ColumnDouble(stmt, index));
}
else if (type == typeof(float))
{
result = CreateNullableTypedSetterDelegate<T, float>(column, (IntPtr stmt, int index) => (float)SQLite3.ColumnDouble(stmt, index));
}
else if (type == typeof(TimeSpan))
{
result = ((!conn.StoreTimeSpanAsTicks) ? CreateNullableTypedSetterDelegate<T, TimeSpan>(column, delegate(IntPtr stmt, int index)
{
string text = SQLite3.ColumnString(stmt, index);
TimeSpan result3;
return (!TimeSpan.TryParseExact(text, "c", CultureInfo.InvariantCulture, TimeSpanStyles.None, out result3)) ? TimeSpan.Parse(text) : result3;
}) : CreateNullableTypedSetterDelegate<T, TimeSpan>(column, (IntPtr stmt, int index) => new TimeSpan(SQLite3.ColumnInt64(stmt, index))));
}
else if (type == typeof(DateTime))
{
result = ((!conn.StoreDateTimeAsTicks) ? CreateNullableTypedSetterDelegate<T, DateTime>(column, delegate(IntPtr stmt, int index)
{
string s = SQLite3.ColumnString(stmt, index);
DateTime result2;
return (!DateTime.TryParseExact(s, conn.DateTimeStringFormat, CultureInfo.InvariantCulture, conn.DateTimeStyle, out result2)) ? DateTime.Parse(s) : result2;
}) : CreateNullableTypedSetterDelegate<T, DateTime>(column, (IntPtr stmt, int index) => new DateTime(SQLite3.ColumnInt64(stmt, index))));
}
else if (type == typeof(DateTimeOffset))
{
result = CreateNullableTypedSetterDelegate<T, DateTimeOffset>(column, (IntPtr stmt, int index) => new DateTimeOffset(SQLite3.ColumnInt64(stmt, index), TimeSpan.Zero));
}
else if (!typeInfo.IsEnum)
{
if (type == typeof(long))
{
result = CreateNullableTypedSetterDelegate<T, long>(column, (IntPtr stmt, int index) => SQLite3.ColumnInt64(stmt, index));
}
else if (type == typeof(uint))
{
result = CreateNullableTypedSetterDelegate<T, uint>(column, (IntPtr stmt, int index) => (uint)SQLite3.ColumnInt64(stmt, index));
}
else if (type == typeof(decimal))
{
result = CreateNullableTypedSetterDelegate<T, decimal>(column, (IntPtr stmt, int index) => (decimal)SQLite3.ColumnDouble(stmt, index));
}
else if (type == typeof(byte))
{
result = CreateNullableTypedSetterDelegate<T, byte>(column, (IntPtr stmt, int index) => (byte)SQLite3.ColumnInt(stmt, index));
}
else if (type == typeof(ushort))
{
result = CreateNullableTypedSetterDelegate<T, ushort>(column, (IntPtr stmt, int index) => (ushort)SQLite3.ColumnInt(stmt, index));
}
else if (type == typeof(short))
{
result = CreateNullableTypedSetterDelegate<T, short>(column, (IntPtr stmt, int index) => (short)SQLite3.ColumnInt(stmt, index));
}
else if (type == typeof(sbyte))
{
result = CreateNullableTypedSetterDelegate<T, sbyte>(column, (IntPtr stmt, int index) => (sbyte)SQLite3.ColumnInt(stmt, index));
}
else if (type == typeof(byte[]))
{
result = CreateTypedSetterDelegate<T, byte[]>(column, (IntPtr stmt, int index) => SQLite3.ColumnByteArray(stmt, index));
}
else if (type == typeof(Guid))
{
result = CreateNullableTypedSetterDelegate<T, Guid>(column, delegate(IntPtr stmt, int index)
{
string g = SQLite3.ColumnString(stmt, index);
return new Guid(g);
});
}
else if (type == typeof(Uri))
{
result = CreateTypedSetterDelegate<T, Uri>(column, delegate(IntPtr stmt, int index)
{
string uriString = SQLite3.ColumnString(stmt, index);
return new Uri(uriString);
});
}
else if (type == typeof(StringBuilder))
{
result = CreateTypedSetterDelegate<T, StringBuilder>(column, delegate(IntPtr stmt, int index)
{
string value = SQLite3.ColumnString(stmt, index);
return new StringBuilder(value);
});
}
else if (type == typeof(UriBuilder))
{
result = CreateTypedSetterDelegate<T, UriBuilder>(column, delegate(IntPtr stmt, int index)
{
string uri = SQLite3.ColumnString(stmt, index);
return new UriBuilder(uri);
});
}
}
return result;
}
private static Action<object, IntPtr, int> CreateNullableTypedSetterDelegate<ObjectType, ColumnMemberType>(TableMapping.Column column, Func<IntPtr, int, ColumnMemberType> getColumnValue) where ColumnMemberType : struct
{
TypeInfo typeInfo = column.PropertyInfo.PropertyType.GetTypeInfo();
bool flag = false;
if (typeInfo.IsGenericType && typeInfo.GetGenericTypeDefinition() == typeof(Nullable<>))
{
flag = true;
}
if (flag)
{
Action<ObjectType, ColumnMemberType?> setProperty = (Action<ObjectType, ColumnMemberType?>)Delegate.CreateDelegate(typeof(Action<ObjectType, ColumnMemberType?>), null, column.PropertyInfo.GetSetMethod());
return delegate(object o, IntPtr stmt, int i)
{
SQLite3.ColType colType = SQLite3.ColumnType(stmt, i);
if (colType != SQLite3.ColType.Null)
{
setProperty((ObjectType)o, getColumnValue(stmt, i));
}
};
}
return CreateTypedSetterDelegate<ObjectType, ColumnMemberType>(column, getColumnValue);
}
private static Action<object, IntPtr, int> CreateTypedSetterDelegate<ObjectType, ColumnMemberType>(TableMapping.Column column, Func<IntPtr, int, ColumnMemberType> getColumnValue)
{
Action<ObjectType, ColumnMemberType> setProperty = (Action<ObjectType, ColumnMemberType>)Delegate.CreateDelegate(typeof(Action<ObjectType, ColumnMemberType>), null, column.PropertyInfo.GetSetMethod());
return delegate(object o, IntPtr stmt, int i)
{
SQLite3.ColType colType = SQLite3.ColumnType(stmt, i);
if (colType != SQLite3.ColType.Null)
{
setProperty((ObjectType)o, getColumnValue(stmt, i));
}
};
}
}
internal class PreparedSqlLiteInsertCommand : IDisposable
{
private bool Initialized;
private SQLiteConnection Connection;
private string CommandText;
private IntPtr Statement;
private static readonly IntPtr NullStatement;
public PreparedSqlLiteInsertCommand(SQLiteConnection conn, string commandText)
{
Connection = conn;
CommandText = commandText;
}
public int ExecuteNonQuery(object[] source)
{
if (Initialized && Statement == NullStatement)
{
throw new ObjectDisposedException("PreparedSqlLiteInsertCommand");
}
if (Connection.Trace)
{
Connection.Tracer?.Invoke("Executing: " + CommandText);
}
SQLite3.Result result = SQLite3.Result.OK;
if (!Initialized)
{
Statement = SQLite3.Prepare2(Connection.Handle, CommandText);
Initialized = true;
}
if (source != null)
{
for (int i = 0; i < source.Length; i++)
{
SQLiteCommand.BindParameter(Statement, i + 1, source[i], Connection.StoreDateTimeAsTicks, Connection.DateTimeStringFormat, Connection.StoreTimeSpanAsTicks);
}
}
result = SQLite3.Step(Statement);
switch (result)
{
case SQLite3.Result.Done:
{
int result2 = SQLite3.Changes(Connection.Handle);
SQLite3.Reset(Statement);
return result2;
}
case SQLite3.Result.Error:
{
string errmsg = SQLite3.GetErrmsg(Connection.Handle);
SQLite3.Reset(Statement);
throw SQLiteException.New(result, errmsg);
}
case SQLite3.Result.Constraint:
if (SQLite3.ExtendedErrCode(Connection.Handle) == SQLite3.ExtendedResult.ConstraintNotNull)
{
SQLite3.Reset(Statement);
throw NotNullConstraintViolationException.New(result, SQLite3.GetErrmsg(Connection.Handle));
}
break;
}
SQLite3.Reset(Statement);
throw SQLiteException.New(result, SQLite3.GetErrmsg(Connection.Handle));
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
IntPtr statement = Statement;
Statement = NullStatement;
Connection = null;
if (statement != NullStatement)
{
SQLite3.Finalize(statement);
}
}
~PreparedSqlLiteInsertCommand()
{
Dispose(disposing: false);
}
}
public enum CreateTableResult
{
Created,
Migrated
}
public class CreateTablesResult
{
public Dictionary<Type, CreateTableResult> Results { get; private set; }
public CreateTablesResult()
{
Results = new Dictionary<Type, CreateTableResult>();
}
}
public abstract class BaseTableQuery
{
protected class Ordering
{
public string ColumnName { get; set; }
public bool Ascending { get; set; }
}
}
public class TableQuery<T> : BaseTableQuery, IEnumerable<T>, IEnumerable
{
private class CompileResult
{
public string CommandText { get; set; }
public object Value { get; set; }
}
private Expression _where;
private List<Ordering> _orderBys;
private int? _limit;
private int? _offset;
private BaseTableQuery _joinInner;
private Expression _joinInnerKeySelector;
private BaseTableQuery _joinOuter;
private Expression _joinOuterKeySelector;
private Expression _joinSelector;
private Expression _selector;
private bool _deferred;
public SQLiteConnection Connection { get; private set; }
public TableMapping Table { get; private set; }
private TableQuery(SQLiteConnection conn, TableMapping table)
{
Connection = conn;
Table = table;
}
public TableQuery(SQLiteConnection conn)
{
Connection = conn;
Table = Connection.GetMapping(typeof(T));
}
public TableQuery<U> Clone<U>()
{
TableQuery<U> tableQuery = new TableQuery<U>(Connection, Table);
tableQuery._where = _where;
tableQuery._deferred = _deferred;
if (_orderBys != null)
{
tableQuery._orderBys = new List<Ordering>(_orderBys);
}
tableQuery._limit = _limit;
tableQuery._offset = _offset;
tableQuery._joinInner = _joinInner;
tableQuery._joinInnerKeySelector = _joinInnerKeySelector;
tableQuery._joinOuter = _joinOuter;
tableQuery._joinOuterKeySelector = _joinOuterKeySelector;
tableQuery._joinSelector = _joinSelector;
tableQuery._selector = _selector;
return tableQuery;
}
public TableQuery<T> Where(Expression<Func<T, bool>> predExpr)
{
if (predExpr.NodeType == ExpressionType.Lambda)
{
Expression body = predExpr.Body;
TableQuery<T> tableQuery = Clone<T>();
tableQuery.AddWhere(body);
return tableQuery;
}
throw new NotSupportedException("Must be a predicate");
}
public int Delete()
{
return Delete(null);
}
public int Delete(Expression<Func<T, bool>> predExpr)
{
if (_limit.HasValue || _offset.HasValue)
{
throw new InvalidOperationException("Cannot delete with limits or offsets");
}
if (_where == null && predExpr == null)
{
throw new InvalidOperationException("No condition specified");
}
Expression expression = _where;
if (predExpr != null && predExpr.NodeType == ExpressionType.Lambda)
{
expression = ((expression != null) ? Expression.AndAlso(expression, predExpr.Body) : predExpr.Body);
}
List<object> list = new List<object>();
string text = "delete from \"" + Table.TableName + "\"";
CompileResult compileResult = CompileExpr(expression, list);
text = text + " where " + compileResult.CommandText;
SQLiteCommand sQLiteCommand = Connection.CreateCommand(text, list.ToArray());
return sQLiteCommand.ExecuteNonQuery();
}
public TableQuery<T> Take(int n)
{
TableQuery<T> tableQuery = Clone<T>();
tableQuery._limit = n;
return tableQuery;
}
public TableQuery<T> Skip(int n)
{
TableQuery<T> tableQuery = Clone<T>();
tableQuery._offset = n;
return tableQuery;
}
public T ElementAt(int index)
{
return Skip(index).Take(1).First();
}
public TableQuery<T> Deferred()
{
TableQuery<T> tableQuery = Clone<T>();
tableQuery._deferred = true;
return tableQuery;
}
public TableQuery<T> OrderBy<U>(Expression<Func<T, U>> orderExpr)
{
return AddOrderBy(orderExpr, asc: true);
}
public TableQuery<T> OrderByDescending<U>(Expression<Func<T, U>> orderExpr)
{
return AddOrderBy(orderExpr, asc: false);
}
public TableQuery<T> ThenBy<U>(Expression<Func<T, U>> orderExpr)
{
return AddOrderBy(orderExpr, asc: true);
}
public TableQuery<T> ThenByDescending<U>(Expression<Func<T, U>> orderExpr)
{
return AddOrderBy(orderExpr, asc: false);
}
private TableQuery<T> AddOrderBy<U>(Expression<Func<T, U>> orderExpr, bool asc)
{
if (orderExpr.NodeType == ExpressionType.Lambda)
{
MemberExpression memberExpression = null;
memberExpression = ((!(orderExpr.Body is UnaryExpression unaryExpression) || unaryExpression.NodeType != ExpressionType.Convert) ? (orderExpr.Body as MemberExpression) : (unaryExpression.Operand as MemberExpression));
if (memberExpression != null && memberExpression.Expression.NodeType == ExpressionType.Parameter)
{
TableQuery<T> tableQuery = Clone<T>();
if (tableQuery._orderBys == null)
{
tableQuery._orderBys = new List<Ordering>();
}
tableQuery._orderBys.Add(new Ordering
{
ColumnName = Table.FindColumnWithPropertyName(memberExpression.Member.Name).Name,
Ascending = asc
});
return tableQuery;
}
throw new NotSupportedException("Order By does not support: " + orderExpr);
}
throw new NotSupportedException("Must be a predicate");
}
private void AddWhere(Expression pred)
{
if (_where == null)
{
_where = pred;
}
else
{
_where = Expression.AndAlso(_where, pred);
}
}
private SQLiteCommand GenerateCommand(string selectionList)
{
if (_joinInner != null && _joinOuter != null)
{
throw new NotSupportedException("Joins are not supported.");
}
string text = "select " + selectionList + " from \"" + Table.TableName + "\"";
List<object> list = new List<object>();
if (_where != null)
{
CompileResult compileResult = CompileExpr(_where, list);
text = text + " where " + compileResult.CommandText;
}
if (_orderBys != null && _orderBys.Count > 0)
{
string text2 = string.Join(", ", _orderBys.Select((Ordering o) => "\"" + o.ColumnName + "\"" + (o.Ascending ? "" : " desc")).ToArray());
text = text + " order by " + text2;
}
if (_limit.HasValue)
{
text = text + " limit " + _limit.Value;
}
if (_offset.HasValue)
{
if (!_limit.HasValue)
{
text += " limit -1 ";
}
text = text + " offset " + _offset.Value;
}
return Connection.CreateCommand(text, list.ToArray());
}
private CompileResult CompileExpr(Expression expr, List<object> queryArgs)
{
if (expr == null)
{
throw new NotSupportedException("Expression is NULL");
}
if (expr is BinaryExpression)
{
BinaryExpression binaryExpression = (BinaryExpression)expr;
if (binaryExpression.Left.NodeType == ExpressionType.Call)
{
MethodCallExpression methodCallExpression = (MethodCallExpression)binaryExpression.Left;
if (methodCallExpression.Method.DeclaringType.FullName == "Microsoft.VisualBasic.CompilerServices.Operators" && methodCallExpression.Method.Name == "CompareString")
{
binaryExpression = Expression.MakeBinary(binaryExpression.NodeType, methodCallExpression.Arguments[0], methodCallExpression.Arguments[1]);
}
}
CompileResult compileResult = CompileExpr(binaryExpression.Left, queryArgs);
CompileResult compileResult2 = CompileExpr(binaryExpression.Right, queryArgs);
string commandText = ((compileResult.CommandText == "?" && compileResult.Value == null) ? CompileNullBinaryExpression(binaryExpression, compileResult2) : ((!(compileResult2.CommandText == "?") || compileResult2.Value != null) ? ("(" + compileResult.CommandText + " " + GetSqlName(binaryExpression) + " " + compileResult2.CommandText + ")") : CompileNullBinaryExpression(binaryExpression, compileResult)));
return new CompileResult
{
CommandText = commandText
};
}
if (expr.NodeType == ExpressionType.Not)
{
Expression operand = ((UnaryExpression)expr).Operand;
CompileResult compileResult3 = CompileExpr(operand, queryArgs);
object obj = compileResult3.Value;
if (obj is bool)
{
obj = !(bool)obj;
}
return new CompileResult
{
CommandText = "NOT(" + compileResult3.CommandText + ")",
Value = obj
};
}
if (expr.NodeType == ExpressionType.Call)
{
MethodCallExpression methodCallExpression2 = (MethodCallExpression)expr;
CompileResult[] array = new CompileResult[methodCallExpression2.Arguments.Count];
CompileResult compileResult4 = ((methodCallExpression2.Object != null) ? CompileExpr(methodCallExpression2.Object, queryArgs) : null);
for (int i = 0; i < array.Length; i++)
{
array[i] = CompileExpr(methodCallExpression2.Arguments[i], queryArgs);
}
string commandText2 = "";
if (methodCallExpression2.Method.Name == "Like" && array.Length == 2)
{
commandText2 = "(" + array[0].CommandText + " like " + array[1].CommandText + ")";
}
else if (methodCallExpression2.Method.Name == "Contains" && array.Length == 2)
{
commandText2 = "(" + array[1].CommandText + " in " + array[0].CommandText + ")";
}
else if (methodCallExpression2.Method.Name == "Contains" && array.Length == 1)
{
commandText2 = ((methodCallExpression2.Object == null || !(methodCallExpression2.Object.Type == typeof(string))) ? ("(" + array[0].CommandText + " in " + compileResult4.CommandText + ")") : ("( instr(" + compileResult4.CommandText + "," + array[0].CommandText + ") >0 )"));
}
else if (methodCallExpression2.Method.Name == "StartsWith" && array.Length >= 1)
{
StringComparison stringComparison = StringComparison.CurrentCulture;
if (array.Length == 2)
{
stringComparison = (StringComparison)array[1].Value;
}
switch (stringComparison)
{
case StringComparison.CurrentCulture:
case StringComparison.Ordinal:
commandText2 = "( substr(" + compileResult4.CommandText + ", 1, " + array[0].Value.ToString().Length + ") = " + array[0].CommandText + ")";
break;
case StringComparison.CurrentCultureIgnoreCase:
case StringComparison.OrdinalIgnoreCase:
commandText2 = "(" + compileResult4.CommandText + " like (" + array[0].CommandText + " || '%'))";
break;
}
}
else if (!(methodCallExpression2.Method.Name == "EndsWith") || array.Length < 1)
{
commandText2 = ((methodCallExpression2.Method.Name == "Equals" && array.Length == 1) ? ("(" + compileResult4.CommandText + " = (" + array[0].CommandText + "))") : ((methodCallExpression2.Method.Name == "ToLower") ? ("(lower(" + compileResult4.CommandText + "))") : ((methodCallExpression2.Method.Name == "ToUpper") ? ("(upper(" + compileResult4.CommandText + "))") : ((methodCallExpression2.Method.Name == "Replace" && array.Length == 2) ? ("(replace(" + compileResult4.CommandText + "," + array[0].CommandText + "," + array[1].CommandText + "))") : ((!(methodCallExpression2.Method.Name == "IsNullOrEmpty") || array.Length != 1) ? (methodCallExpression2.Method.Name.ToLower() + "(" + string.Join(",", array.Select((CompileResult a) => a.CommandText).ToArray()) + ")") : ("(" + array[0].CommandText + " is null or" + array[0].CommandText + " ='' )"))))));
}
else
{
StringComparison stringComparison2 = StringComparison.CurrentCulture;
if (array.Length == 2)
{
stringComparison2 = (StringComparison)array[1].Value;
}
switch (stringComparison2)
{
case StringComparison.CurrentCulture:
case StringComparison.Ordinal:
commandText2 = "( substr(" + compileResult4.CommandText + ", length(" + compileResult4.CommandText + ") - " + array[0].Value.ToString().Length + "+1, " + array[0].Value.ToString().Length + ") = " + array[0].CommandText + ")";
break;
case StringComparison.CurrentCultureIgnoreCase:
case StringComparison.OrdinalIgnoreCase:
commandText2 = "(" + compileResult4.CommandText + " like ('%' || " + array[0].CommandText + "))";
break;
}
}
return new CompileResult
{
CommandText = commandText2
};
}