Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of AsyncLoggers Experimental v21.2.3
BepInEx/patchers/AsyncLoggers.dll
Decompiled 5 months ago
The result has been truncated due to the large size, download it to view full contents!
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 }; }