Decompiled source of VampireDB v0.1.1

VampireDB.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using LiteDB;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("VampireDB")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyDescription("Stupid simple wrapper for LiteDB")]
[assembly: AssemblyFileVersion("0.1.10.0")]
[assembly: AssemblyInformationalVersion("0.1.10+36fa1f86df7af3a70628a68d5ac63188d5334d99")]
[assembly: AssemblyProduct("VampireDB")]
[assembly: AssemblyTitle("VampireDB")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.10.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 VampireDB
{
	[BepInPlugin("phlebotomist.morphine.VampireDB", "VampireDB", "0.1.10")]
	public class Plugin : BasePlugin
	{
		public static ManualLogSource Logger;

		public override void Load()
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Expected O, but got Unknown
			Logger = ((BasePlugin)this).Log;
			ManualLogSource logger = Logger;
			bool flag = default(bool);
			BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(24, 2, ref flag);
			if (flag)
			{
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Plugin ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("phlebotomist.morphine.VampireDB");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" version ");
				((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>("0.1.10");
				((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" loaded!");
			}
			logger.LogInfo(val);
		}

		public override bool Unload()
		{
			Storage.Instance.Dispose();
			return true;
		}
	}
	public static class PluginInfo
	{
		public const string PLUGIN_GUID = "phlebotomist.morphine.VampireDB";

		public const string PLUGIN_NAME = "VampireDB";

		public const string PLUGIN_VERSION = "0.1.10";
	}
	public sealed class Storage : IDisposable
	{
		private class Record
		{
			public string Id { get; set; }

			public ulong PlatformId { get; set; }

			public string Key { get; set; }

			public BsonValue Value { get; set; }
		}

		private static readonly object _sync = new object();

		private readonly LiteDatabase _db;

		private readonly ILiteCollection<Record> _col;

		private const string DATA_FILE_NAME = "VampireDB.db";

		private const string DB_PATH = "BepInEx/config/VampireDB/";

		public static Storage Instance { get; } = new Storage(Path.Combine("BepInEx/config/VampireDB/", "VampireDB.db"));


		private Storage(string filePath)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0061: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Expected O, but got Unknown
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Expected O, but got Unknown
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			string directoryName = Path.GetDirectoryName(filePath);
			if (!Directory.Exists(directoryName))
			{
				ManualLogSource logger = Plugin.Logger;
				bool flag = default(bool);
				BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(38, 1, ref flag);
				if (flag)
				{
					((BepInExLogInterpolatedStringHandler)val).AppendLiteral("No storage found creating storage at: ");
					((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(filePath);
				}
				logger.LogInfo(val);
				Directory.CreateDirectory(Path.GetDirectoryName(filePath));
			}
			_db = new LiteDatabase(new ConnectionString
			{
				Filename = filePath,
				Connection = (ConnectionType)1
			}, (BsonMapper)null);
			_col = _db.GetCollection<Record>("records", (BsonAutoId)10);
			_col.EnsureIndex((Record r) => new { r.PlatformId, r.Key }, true);
		}

		public void RunInTransaction(Action body)
		{
			if (!_db.BeginTrans())
			{
				throw new InvalidOperationException("Another transaction in progress");
			}
			try
			{
				body();
				_db.Commit();
			}
			catch
			{
				_db.Rollback();
				throw;
			}
		}

		public T Update<T>(ulong platformId, string key, Func<T, T> mutator, T defaultValue = default(T))
		{
			lock (_sync)
			{
				T value;
				T arg = (TryGet<T>(platformId, key, out value) ? value : defaultValue);
				T val = mutator(arg);
				Set(platformId, key, val);
				return val;
			}
		}

		public void Set<T>(ulong platformId, string key, T value)
		{
			lock (_sync)
			{
				Record record = new Record();
				record.Id = $"{platformId}:{key}";
				record.PlatformId = platformId;
				record.Key = key;
				record.Value = _db.Mapper.Serialize(typeof(T), (object)value);
				Record record2 = record;
				_col.Upsert(record2);
			}
		}

		public Dictionary<ulong, T> GetAll<T>(string key)
		{
			lock (_sync)
			{
				Dictionary<ulong, T> dictionary = new Dictionary<ulong, T>();
				foreach (Record item in _col.Find((Expression<Func<Record, bool>>)((Record r) => r.Key == key), 0, int.MaxValue))
				{
					T value = (T)_db.Mapper.Deserialize(typeof(T), item.Value);
					dictionary[item.PlatformId] = value;
				}
				return dictionary;
			}
		}

		public bool TryGet<T>(ulong platformId, string key, out T value)
		{
			lock (_sync)
			{
				Record record = _col.FindOne((Expression<Func<Record, bool>>)((Record r) => r.PlatformId == platformId && r.Key == key));
				if (record != null)
				{
					value = (T)_db.Mapper.Deserialize(typeof(T), record.Value);
					return true;
				}
				value = default(T);
				return false;
			}
		}

		public bool Delete(ulong platformId, string key)
		{
			lock (_sync)
			{
				return _col.DeleteMany((Expression<Func<Record, bool>>)((Record r) => r.PlatformId == platformId && r.Key == key)) > 0;
			}
		}

		public void Dispose()
		{
			LiteDatabase db = _db;
			if (db != null)
			{
				db.Dispose();
			}
		}
	}
	public static class MyPluginInfo
	{
		public const string PLUGIN_GUID = "VampireDB";

		public const string PLUGIN_NAME = "VampireDB";

		public const string PLUGIN_VERSION = "0.1.10";
	}
}

LiteDB.dll

Decompiled 2 weeks ago
using System;
using System.Buffers;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using LiteDB.Engine;
using LiteDB.Utils;
using LiteDB.Utils.Extensions;
using Microsoft.CodeAnalysis;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: InternalsVisibleTo("LiteDB.Tests, PublicKey=002400000480000094000000060200000024000052534131000400000100010029e66990e22110ce40a7197e37f8f82df3332c399e696df7f27d09e14ee590ac2dda735d4777fe554c427540bde93b14d3d26c04731c963383dcaa18859c8cbcd4a1a9c394d1204f474c2ab6f23a2eaadf81eb8a7a3d3cc73658868b0302163b92a2614ca050ab703be33c3e1d76f55b11f4f87cb73558f3aa69c1ce726d9ee8")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")]
[assembly: AssemblyCompany("Maurício David")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyCopyright("MIT")]
[assembly: AssemblyDescription("LiteDB - A lightweight embedded .NET NoSQL document store in a single datafile")]
[assembly: AssemblyFileVersion("5.0.21")]
[assembly: AssemblyInformationalVersion("5.0.21+391cc9318c5be6e56cb71b3ce14b1ed9cb324763")]
[assembly: AssemblyProduct("LiteDB")]
[assembly: AssemblyTitle("LiteDB")]
[assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/mbdavid/LiteDB")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("5.0.21.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]
	internal sealed class IsReadOnlyAttribute : Attribute
	{
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 LiteDB
{
	public sealed class LiteCollection<T> : ILiteCollection<T>
	{
		private readonly string _collection;

		private readonly ILiteEngine _engine;

		private readonly List<BsonExpression> _includes;

		private readonly BsonMapper _mapper;

		private readonly EntityMapper _entity;

		private readonly MemberMapper _id;

		private readonly BsonAutoId _autoId;

		public string Name => _collection;

		public BsonAutoId AutoId => _autoId;

		public EntityMapper EntityMapper => _entity;

		public int Count()
		{
			return Query().Count();
		}

		public int Count(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Where(predicate).Count();
		}

		public int Count(string predicate, BsonDocument parameters)
		{
			return Count(BsonExpression.Create(predicate, parameters));
		}

		public int Count(string predicate, params BsonValue[] args)
		{
			return Count(BsonExpression.Create(predicate, args));
		}

		public int Count(Expression<Func<T, bool>> predicate)
		{
			return Count(_mapper.GetExpression(predicate));
		}

		public int Count(Query query)
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).Count();
		}

		public long LongCount()
		{
			return Query().LongCount();
		}

		public long LongCount(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Where(predicate).LongCount();
		}

		public long LongCount(string predicate, BsonDocument parameters)
		{
			return LongCount(BsonExpression.Create(predicate, parameters));
		}

		public long LongCount(string predicate, params BsonValue[] args)
		{
			return LongCount(BsonExpression.Create(predicate, args));
		}

		public long LongCount(Expression<Func<T, bool>> predicate)
		{
			return LongCount(_mapper.GetExpression(predicate));
		}

		public long LongCount(Query query)
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).Count();
		}

		public bool Exists(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Where(predicate).Exists();
		}

		public bool Exists(string predicate, BsonDocument parameters)
		{
			return Exists(BsonExpression.Create(predicate, parameters));
		}

		public bool Exists(string predicate, params BsonValue[] args)
		{
			return Exists(BsonExpression.Create(predicate, args));
		}

		public bool Exists(Expression<Func<T, bool>> predicate)
		{
			return Exists(_mapper.GetExpression(predicate));
		}

		public bool Exists(Query query)
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).Exists();
		}

		public BsonValue Min(BsonExpression keySelector)
		{
			if (string.IsNullOrEmpty(keySelector))
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonDocument bsonDocument = Query().OrderBy(keySelector).Select(keySelector).ToDocuments()
				.First();
			return bsonDocument[bsonDocument.Keys.First()];
		}

		public BsonValue Min()
		{
			return Min("_id");
		}

		public K Min<K>(Expression<Func<T, K>> keySelector)
		{
			if (keySelector == null)
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonExpression expression = _mapper.GetExpression(keySelector);
			BsonValue value = Min(expression);
			return (K)_mapper.Deserialize(typeof(K), value);
		}

		public BsonValue Max(BsonExpression keySelector)
		{
			if (string.IsNullOrEmpty(keySelector))
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonDocument bsonDocument = Query().OrderByDescending(keySelector).Select(keySelector).ToDocuments()
				.First();
			return bsonDocument[bsonDocument.Keys.First()];
		}

		public BsonValue Max()
		{
			return Max("_id");
		}

		public K Max<K>(Expression<Func<T, K>> keySelector)
		{
			if (keySelector == null)
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonExpression expression = _mapper.GetExpression(keySelector);
			BsonValue value = Max(expression);
			return (K)_mapper.Deserialize(typeof(K), value);
		}

		public bool Delete(BsonValue id)
		{
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			return _engine.Delete(_collection, new BsonValue[1] { id }) == 1;
		}

		public int DeleteAll()
		{
			return _engine.DeleteMany(_collection, null);
		}

		public int DeleteMany(BsonExpression predicate)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return _engine.DeleteMany(_collection, predicate);
		}

		public int DeleteMany(string predicate, BsonDocument parameters)
		{
			return DeleteMany(BsonExpression.Create(predicate, parameters));
		}

		public int DeleteMany(string predicate, params BsonValue[] args)
		{
			return DeleteMany(BsonExpression.Create(predicate, args));
		}

		public int DeleteMany(Expression<Func<T, bool>> predicate)
		{
			return DeleteMany(_mapper.GetExpression(predicate));
		}

		public ILiteQueryable<T> Query()
		{
			return new LiteQueryable<T>(_engine, _mapper, _collection, new Query()).Include(_includes);
		}

		public IEnumerable<T> Find(BsonExpression predicate, int skip = 0, int limit = int.MaxValue)
		{
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			return Query().Include(_includes).Where(predicate).Skip(skip)
				.Limit(limit)
				.ToEnumerable();
		}

		public IEnumerable<T> Find(Query query, int skip = 0, int limit = int.MaxValue)
		{
			if (query == null)
			{
				throw new ArgumentNullException("query");
			}
			if (skip != 0)
			{
				query.Offset = skip;
			}
			if (limit != int.MaxValue)
			{
				query.Limit = limit;
			}
			return new LiteQueryable<T>(_engine, _mapper, _collection, query).ToEnumerable();
		}

		public IEnumerable<T> Find(Expression<Func<T, bool>> predicate, int skip = 0, int limit = int.MaxValue)
		{
			return Find(_mapper.GetExpression(predicate), skip, limit);
		}

		public T FindById(BsonValue id)
		{
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			return Find(BsonExpression.Create("_id = @0", id)).FirstOrDefault();
		}

		public T FindOne(BsonExpression predicate)
		{
			return Find(predicate).FirstOrDefault();
		}

		public T FindOne(string predicate, BsonDocument parameters)
		{
			return FindOne(BsonExpression.Create(predicate, parameters));
		}

		public T FindOne(BsonExpression predicate, params BsonValue[] args)
		{
			return FindOne(BsonExpression.Create(predicate, args));
		}

		public T FindOne(Expression<Func<T, bool>> predicate)
		{
			return FindOne(_mapper.GetExpression(predicate));
		}

		public T FindOne(Query query)
		{
			return Find(query).FirstOrDefault();
		}

		public IEnumerable<T> FindAll()
		{
			return Query().Include(_includes).ToEnumerable();
		}

		public ILiteCollection<T> Include<K>(Expression<Func<T, K>> keySelector)
		{
			if (keySelector == null)
			{
				throw new ArgumentNullException("keySelector");
			}
			BsonExpression expression = _mapper.GetExpression(keySelector);
			return Include(expression);
		}

		public ILiteCollection<T> Include(BsonExpression keySelector)
		{
			if (string.IsNullOrEmpty(keySelector))
			{
				throw new ArgumentNullException("keySelector");
			}
			LiteCollection<T> liteCollection = new LiteCollection<T>(_collection, _autoId, _engine, _mapper);
			liteCollection._includes.AddRange(_includes);
			liteCollection._includes.Add(keySelector);
			return liteCollection;
		}

		public bool EnsureIndex(string name, BsonExpression expression, bool unique = false)
		{
			if (string.IsNullOrEmpty(name))
			{
				throw new ArgumentNullException("name");
			}
			if (expression == null)
			{
				throw new ArgumentNullException("expression");
			}
			return _engine.EnsureIndex(_collection, name, expression, unique);
		}

		public bool EnsureIndex(BsonExpression expression, bool unique = false)
		{
			if (expression == null)
			{
				throw new ArgumentNullException("expression");
			}
			string name = Regex.Replace(expression.Source, "[^a-z0-9]", "", RegexOptions.IgnoreCase | RegexOptions.Compiled);
			return EnsureIndex(name, expression, unique);
		}

		public bool EnsureIndex<K>(Expression<Func<T, K>> keySelector, bool unique = false)
		{
			BsonExpression indexExpression = GetIndexExpression(keySelector);
			return EnsureIndex(indexExpression, unique);
		}

		public bool EnsureIndex<K>(string name, Expression<Func<T, K>> keySelector, bool unique = false)
		{
			BsonExpression indexExpression = GetIndexExpression(keySelector);
			return EnsureIndex(name, indexExpression, unique);
		}

		private BsonExpression GetIndexExpression<K>(Expression<Func<T, K>> keySelector)
		{
			BsonExpression bsonExpression = _mapper.GetIndexExpression(keySelector);
			if (typeof(K).IsEnumerable() && bsonExpression.IsScalar)
			{
				if (bsonExpression.Type != BsonExpressionType.Path)
				{
					throw new LiteException(0, "Expression `" + bsonExpression.Source + "` must return a enumerable expression");
				}
				bsonExpression = bsonExpression.Source + "[*]";
			}
			return bsonExpression;
		}

		public bool DropIndex(string name)
		{
			return _engine.DropIndex(_collection, name);
		}

		public BsonValue Insert(T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bool flag = RemoveDocId(bsonDocument);
			_engine.Insert(_collection, new BsonDocument[1] { bsonDocument }, _autoId);
			BsonValue bsonValue = bsonDocument["_id"];
			if (flag)
			{
				_id.Setter(entity, bsonValue.RawValue);
			}
			return bsonValue;
		}

		public void Insert(BsonValue id, T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bsonDocument["_id"] = id;
			_engine.Insert(_collection, new BsonDocument[1] { bsonDocument }, _autoId);
		}

		public int Insert(IEnumerable<T> entities)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Insert(_collection, GetBsonDocs(entities), _autoId);
		}

		[Obsolete("Use normal Insert()")]
		public int InsertBulk(IEnumerable<T> entities, int batchSize = 5000)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Insert(_collection, GetBsonDocs(entities), _autoId);
		}

		private IEnumerable<BsonDocument> GetBsonDocs(IEnumerable<T> documents)
		{
			foreach (T document in documents)
			{
				BsonDocument doc = _mapper.ToDocument(document);
				bool removed = RemoveDocId(doc);
				yield return doc;
				if (removed && _id != null)
				{
					_id.Setter(document, doc["_id"].RawValue);
				}
			}
		}

		private bool RemoveDocId(BsonDocument doc)
		{
			if (_id != null && doc.TryGetValue("_id", out var value) && ((_autoId == BsonAutoId.Int32 && value.IsInt32 && value.AsInt32 == 0) || (_autoId == BsonAutoId.ObjectId && (value.IsNull || (value.IsObjectId && value.AsObjectId == ObjectId.Empty))) || (_autoId == BsonAutoId.Guid && value.IsGuid && value.AsGuid == Guid.Empty) || (_autoId == BsonAutoId.Int64 && value.IsInt64 && value.AsInt64 == 0L)))
			{
				doc.Remove("_id");
				return true;
			}
			return false;
		}

		public bool Update(T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			return _engine.Update(_collection, new BsonDocument[1] { bsonDocument }) > 0;
		}

		public bool Update(BsonValue id, T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bsonDocument["_id"] = id;
			return _engine.Update(_collection, new BsonDocument[1] { bsonDocument }) > 0;
		}

		public int Update(IEnumerable<T> entities)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Update(_collection, entities.Select((T x) => _mapper.ToDocument(x)));
		}

		public int UpdateMany(BsonExpression transform, BsonExpression predicate)
		{
			if (transform == null)
			{
				throw new ArgumentNullException("transform");
			}
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			if (transform.Type != BsonExpressionType.Document)
			{
				throw new ArgumentException("Extend expression must return a document. Eg: `col.UpdateMany('{ Name: UPPER(Name) }', 'Age > 10')`");
			}
			return _engine.UpdateMany(_collection, transform, predicate);
		}

		public int UpdateMany(Expression<Func<T, T>> extend, Expression<Func<T, bool>> predicate)
		{
			if (extend == null)
			{
				throw new ArgumentNullException("extend");
			}
			if (predicate == null)
			{
				throw new ArgumentNullException("predicate");
			}
			BsonExpression expression = _mapper.GetExpression(extend);
			BsonExpression expression2 = _mapper.GetExpression(predicate);
			if (expression.Type != BsonExpressionType.Document)
			{
				throw new ArgumentException("Extend expression must return an anonymous class to be merge with entities. Eg: `col.UpdateMany(x => new { Name = x.Name.ToUpper() }, x => x.Age > 10)`");
			}
			return _engine.UpdateMany(_collection, expression, expression2);
		}

		public bool Upsert(T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			return Upsert(new T[1] { entity }) == 1;
		}

		public int Upsert(IEnumerable<T> entities)
		{
			if (entities == null)
			{
				throw new ArgumentNullException("entities");
			}
			return _engine.Upsert(_collection, GetBsonDocs(entities), _autoId);
		}

		public bool Upsert(BsonValue id, T entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (id == null || id.IsNull)
			{
				throw new ArgumentNullException("id");
			}
			BsonDocument bsonDocument = _mapper.ToDocument(entity);
			bsonDocument["_id"] = id;
			return _engine.Upsert(_collection, new BsonDocument[1] { bsonDocument }, _autoId) > 0;
		}

		internal LiteCollection(string name, BsonAutoId autoId, ILiteEngine engine, BsonMapper mapper)
		{
			_collection = name ?? mapper.ResolveCollectionName(typeof(T));
			_engine = engine;
			_mapper = mapper;
			_includes = new List<BsonExpression>();
			if (typeof(T) == typeof(BsonDocument))
			{
				_entity = null;
				_id = null;
				_autoId = autoId;
				return;
			}
			_entity = mapper.GetEntityMapper(typeof(T));
			_id = _entity.Id;
			if (_id != null && _id.AutoId)
			{
				_autoId = ((_id.DataType == typeof(int) || _id.DataType == typeof(int?)) ? BsonAutoId.Int32 : ((_id.DataType == typeof(long) || _id.DataType == typeof(long?)) ? BsonAutoId.Int64 : ((_id.DataType == typeof(Guid) || _id.DataType == typeof(Guid?)) ? BsonAutoId.Guid : BsonAutoId.ObjectId)));
			}
			else
			{
				_autoId = autoId;
			}
		}
	}
	public interface ILiteCollection<T>
	{
		string Name { get; }

		BsonAutoId AutoId { get; }

		EntityMapper EntityMapper { get; }

		ILiteCollection<T> Include<K>(Expression<Func<T, K>> keySelector);

		ILiteCollection<T> Include(BsonExpression keySelector);

		bool Upsert(T entity);

		int Upsert(IEnumerable<T> entities);

		bool Upsert(BsonValue id, T entity);

		bool Update(T entity);

		bool Update(BsonValue id, T entity);

		int Update(IEnumerable<T> entities);

		int UpdateMany(BsonExpression transform, BsonExpression predicate);

		int UpdateMany(Expression<Func<T, T>> extend, Expression<Func<T, bool>> predicate);

		BsonValue Insert(T entity);

		void Insert(BsonValue id, T entity);

		int Insert(IEnumerable<T> entities);

		int InsertBulk(IEnumerable<T> entities, int batchSize = 5000);

		bool EnsureIndex(string name, BsonExpression expression, bool unique = false);

		bool EnsureIndex(BsonExpression expression, bool unique = false);

		bool EnsureIndex<K>(Expression<Func<T, K>> keySelector, bool unique = false);

		bool EnsureIndex<K>(string name, Expression<Func<T, K>> keySelector, bool unique = false);

		bool DropIndex(string name);

		ILiteQueryable<T> Query();

		IEnumerable<T> Find(BsonExpression predicate, int skip = 0, int limit = int.MaxValue);

		IEnumerable<T> Find(Query query, int skip = 0, int limit = int.MaxValue);

		IEnumerable<T> Find(Expression<Func<T, bool>> predicate, int skip = 0, int limit = int.MaxValue);

		T FindById(BsonValue id);

		T FindOne(BsonExpression predicate);

		T FindOne(string predicate, BsonDocument parameters);

		T FindOne(BsonExpression predicate, params BsonValue[] args);

		T FindOne(Expression<Func<T, bool>> predicate);

		T FindOne(Query query);

		IEnumerable<T> FindAll();

		bool Delete(BsonValue id);

		int DeleteAll();

		int DeleteMany(BsonExpression predicate);

		int DeleteMany(string predicate, BsonDocument parameters);

		int DeleteMany(string predicate, params BsonValue[] args);

		int DeleteMany(Expression<Func<T, bool>> predicate);

		int Count();

		int Count(BsonExpression predicate);

		int Count(string predicate, BsonDocument parameters);

		int Count(string predicate, params BsonValue[] args);

		int Count(Expression<Func<T, bool>> predicate);

		int Count(Query query);

		long LongCount();

		long LongCount(BsonExpression predicate);

		long LongCount(string predicate, BsonDocument parameters);

		long LongCount(string predicate, params BsonValue[] args);

		long LongCount(Expression<Func<T, bool>> predicate);

		long LongCount(Query query);

		bool Exists(BsonExpression predicate);

		bool Exists(string predicate, BsonDocument parameters);

		bool Exists(string predicate, params BsonValue[] args);

		bool Exists(Expression<Func<T, bool>> predicate);

		bool Exists(Query query);

		BsonValue Min(BsonExpression keySelector);

		BsonValue Min();

		K Min<K>(Expression<Func<T, K>> keySelector);

		BsonValue Max(BsonExpression keySelector);

		BsonValue Max();

		K Max<K>(Expression<Func<T, K>> keySelector);
	}
	public interface ILiteDatabase : IDisposable
	{
		BsonMapper Mapper { get; }

		ILiteStorage<string> FileStorage { get; }

		int UserVersion { get; set; }

		TimeSpan Timeout { get; set; }

		bool UtcDate { get; set; }

		long LimitSize { get; set; }

		int CheckpointSize { get; set; }

		Collation Collation { get; }

		ILiteCollection<T> GetCollection<T>(string name, BsonAutoId autoId = BsonAutoId.ObjectId);

		ILiteCollection<T> GetCollection<T>();

		ILiteCollection<T> GetCollection<T>(BsonAutoId autoId);

		ILiteCollection<BsonDocument> GetCollection(string name, BsonAutoId autoId = BsonAutoId.ObjectId);

		bool BeginTrans();

		bool Commit();

		bool Rollback();

		ILiteStorage<TFileId> GetStorage<TFileId>(string filesCollection = "_files", string chunksCollection = "_chunks");

		IEnumerable<string> GetCollectionNames();

		bool CollectionExists(string name);

		bool DropCollection(string name);

		bool RenameCollection(string oldName, string newName);

		IBsonDataReader Execute(TextReader commandReader, BsonDocument parameters = null);

		IBsonDataReader Execute(string command, BsonDocument parameters = null);

		IBsonDataReader Execute(string command, params BsonValue[] args);

		void Checkpoint();

		long Rebuild(RebuildOptions options = null);

		BsonValue Pragma(string name);

		BsonValue Pragma(string name, BsonValue value);
	}
	public interface ILiteQueryable<T> : ILiteQueryableResult<T>
	{
		ILiteQueryable<T> Include(BsonExpression path);

		ILiteQueryable<T> Include(List<BsonExpression> paths);

		ILiteQueryable<T> Include<K>(Expression<Func<T, K>> path);

		ILiteQueryable<T> Where(BsonExpression predicate);

		ILiteQueryable<T> Where(string predicate, BsonDocument parameters);

		ILiteQueryable<T> Where(string predicate, params BsonValue[] args);

		ILiteQueryable<T> Where(Expression<Func<T, bool>> predicate);

		ILiteQueryable<T> OrderBy(BsonExpression keySelector, int order = 1);

		ILiteQueryable<T> OrderBy<K>(Expression<Func<T, K>> keySelector, int order = 1);

		ILiteQueryable<T> OrderByDescending(BsonExpression keySelector);

		ILiteQueryable<T> OrderByDescending<K>(Expression<Func<T, K>> keySelector);

		ILiteQueryable<T> GroupBy(BsonExpression keySelector);

		ILiteQueryable<T> Having(BsonExpression predicate);

		ILiteQueryableResult<BsonDocument> Select(BsonExpression selector);

		ILiteQueryableResult<K> Select<K>(Expression<Func<T, K>> selector);
	}
	public interface ILiteQueryableResult<T>
	{
		ILiteQueryableResult<T> Limit(int limit);

		ILiteQueryableResult<T> Skip(int offset);

		ILiteQueryableResult<T> Offset(int offset);

		ILiteQueryableResult<T> ForUpdate();

		BsonDocument GetPlan();

		IBsonDataReader ExecuteReader();

		IEnumerable<BsonDocument> ToDocuments();

		IEnumerable<T> ToEnumerable();

		List<T> ToList();

		T[] ToArray();

		int Into(string newCollection, BsonAutoId autoId = BsonAutoId.ObjectId);

		T First();

		T FirstOrDefault();

		T Single();

		T SingleOrDefault();

		int Count();

		long LongCount();

		bool Exists();
	}
	public interface ILiteRepository : IDisposable
	{
		ILiteDatabase Database { get; }

		BsonValue Insert<T>(T entity, string collectionName = null);

		int Insert<T>(IEnumerable<T> entities, string collectionName = null);

		bool Update<T>(T entity, string collectionName = null);

		int Update<T>(IEnumerable<T> entities, string collectionName = null);

		bool Upsert<T>(T entity, string collectionName = null);

		int Upsert<T>(IEnumerable<T> entities, string collectionName = null);

		bool Delete<T>(BsonValue id, string collectionName = null);

		int DeleteMany<T>(BsonExpression predicate, string collectionName = null);

		int DeleteMany<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		ILiteQueryable<T> Query<T>(string collectionName = null);

		bool EnsureIndex<T>(string name, BsonExpression expression, bool unique = false, string collectionName = null);

		bool EnsureIndex<T>(BsonExpression expression, bool unique = false, string collectionName = null);

		bool EnsureIndex<T, K>(Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null);

		bool EnsureIndex<T, K>(string name, Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null);

		T SingleById<T>(BsonValue id, string collectionName = null);

		List<T> Fetch<T>(BsonExpression predicate, string collectionName = null);

		List<T> Fetch<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T First<T>(BsonExpression predicate, string collectionName = null);

		T First<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T FirstOrDefault<T>(BsonExpression predicate, string collectionName = null);

		T FirstOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T Single<T>(BsonExpression predicate, string collectionName = null);

		T Single<T>(Expression<Func<T, bool>> predicate, string collectionName = null);

		T SingleOrDefault<T>(BsonExpression predicate, string collectionName = null);

		T SingleOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null);
	}
	public class LiteDatabase : ILiteDatabase, IDisposable
	{
		private readonly ILiteEngine _engine;

		private readonly BsonMapper _mapper;

		private readonly bool _disposeOnClose;

		private ILiteStorage<string> _fs;

		public BsonMapper Mapper => _mapper;

		public ILiteStorage<string> FileStorage => _fs ?? (_fs = GetStorage<string>());

		public int UserVersion
		{
			get
			{
				return _engine.Pragma("USER_VERSION");
			}
			set
			{
				_engine.Pragma("USER_VERSION", value);
			}
		}

		public TimeSpan Timeout
		{
			get
			{
				return TimeSpan.FromSeconds(_engine.Pragma("TIMEOUT").AsInt32);
			}
			set
			{
				_engine.Pragma("TIMEOUT", (int)value.TotalSeconds);
			}
		}

		public bool UtcDate
		{
			get
			{
				return _engine.Pragma("UTC_DATE");
			}
			set
			{
				_engine.Pragma("UTC_DATE", value);
			}
		}

		public long LimitSize
		{
			get
			{
				return _engine.Pragma("LIMIT_SIZE");
			}
			set
			{
				_engine.Pragma("LIMIT_SIZE", value);
			}
		}

		public int CheckpointSize
		{
			get
			{
				return _engine.Pragma("CHECKPOINT");
			}
			set
			{
				_engine.Pragma("CHECKPOINT", value);
			}
		}

		public Collation Collation => new Collation(_engine.Pragma("COLLATION").AsString);

		public LiteDatabase(string connectionString, BsonMapper mapper = null)
			: this(new ConnectionString(connectionString), mapper)
		{
		}

		public LiteDatabase(ConnectionString connectionString, BsonMapper mapper = null)
		{
			if (connectionString == null)
			{
				throw new ArgumentNullException("connectionString");
			}
			_engine = connectionString.CreateEngine();
			_mapper = mapper ?? BsonMapper.Global;
			_disposeOnClose = true;
		}

		public LiteDatabase(Stream stream, BsonMapper mapper = null, Stream logStream = null)
		{
			EngineSettings settings = new EngineSettings
			{
				DataStream = (stream ?? throw new ArgumentNullException("stream")),
				LogStream = logStream
			};
			_engine = new LiteEngine(settings);
			_mapper = mapper ?? BsonMapper.Global;
			_disposeOnClose = true;
		}

		public LiteDatabase(ILiteEngine engine, BsonMapper mapper = null, bool disposeOnClose = true)
		{
			_engine = engine ?? throw new ArgumentNullException("engine");
			_mapper = mapper ?? BsonMapper.Global;
			_disposeOnClose = disposeOnClose;
		}

		public ILiteCollection<T> GetCollection<T>(string name, BsonAutoId autoId = BsonAutoId.ObjectId)
		{
			return new LiteCollection<T>(name, autoId, _engine, _mapper);
		}

		public ILiteCollection<T> GetCollection<T>()
		{
			return GetCollection<T>(null);
		}

		public ILiteCollection<T> GetCollection<T>(BsonAutoId autoId)
		{
			return GetCollection<T>(null, autoId);
		}

		public ILiteCollection<BsonDocument> GetCollection(string name, BsonAutoId autoId = BsonAutoId.ObjectId)
		{
			if (name.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("name");
			}
			return new LiteCollection<BsonDocument>(name, autoId, _engine, _mapper);
		}

		public bool BeginTrans()
		{
			return _engine.BeginTrans();
		}

		public bool Commit()
		{
			return _engine.Commit();
		}

		public bool Rollback()
		{
			return _engine.Rollback();
		}

		public ILiteStorage<TFileId> GetStorage<TFileId>(string filesCollection = "_files", string chunksCollection = "_chunks")
		{
			return new LiteStorage<TFileId>(this, filesCollection, chunksCollection);
		}

		public IEnumerable<string> GetCollectionNames()
		{
			return (from x in GetCollection("$cols").Query().Where("type = 'user'").ToDocuments()
				select x["name"].AsString).ToArray();
		}

		public bool CollectionExists(string name)
		{
			if (name.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("name");
			}
			return GetCollectionNames().Contains<string>(name, StringComparer.OrdinalIgnoreCase);
		}

		public bool DropCollection(string name)
		{
			if (name.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("name");
			}
			return _engine.DropCollection(name);
		}

		public bool RenameCollection(string oldName, string newName)
		{
			if (oldName.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("oldName");
			}
			if (newName.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("newName");
			}
			return _engine.RenameCollection(oldName, newName);
		}

		public IBsonDataReader Execute(TextReader commandReader, BsonDocument parameters = null)
		{
			if (commandReader == null)
			{
				throw new ArgumentNullException("commandReader");
			}
			Tokenizer tokenizer = new Tokenizer(commandReader);
			return new SqlParser(_engine, tokenizer, parameters).Execute();
		}

		public IBsonDataReader Execute(string command, BsonDocument parameters = null)
		{
			if (command == null)
			{
				throw new ArgumentNullException("command");
			}
			Tokenizer tokenizer = new Tokenizer(command);
			return new SqlParser(_engine, tokenizer, parameters).Execute();
		}

		public IBsonDataReader Execute(string command, params BsonValue[] args)
		{
			BsonDocument bsonDocument = new BsonDocument();
			int num = 0;
			foreach (BsonValue value in args)
			{
				bsonDocument[num.ToString()] = value;
				num++;
			}
			return Execute(command, bsonDocument);
		}

		public void Checkpoint()
		{
			_engine.Checkpoint();
		}

		public long Rebuild(RebuildOptions options = null)
		{
			return _engine.Rebuild(options ?? new RebuildOptions());
		}

		public BsonValue Pragma(string name)
		{
			return _engine.Pragma(name);
		}

		public BsonValue Pragma(string name, BsonValue value)
		{
			return _engine.Pragma(name, value);
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		~LiteDatabase()
		{
			Dispose(disposing: false);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing && _disposeOnClose)
			{
				_engine.Dispose();
			}
		}
	}
	public class LiteQueryable<T> : ILiteQueryable<T>, ILiteQueryableResult<T>
	{
		protected readonly ILiteEngine _engine;

		protected readonly BsonMapper _mapper;

		protected readonly string _collection;

		protected readonly Query _query;

		private readonly bool _isSimpleType = Reflection.IsSimpleType(typeof(T));

		internal LiteQueryable(ILiteEngine engine, BsonMapper mapper, string collection, Query query)
		{
			_engine = engine;
			_mapper = mapper;
			_collection = collection;
			_query = query;
		}

		public ILiteQueryable<T> Include<K>(Expression<Func<T, K>> path)
		{
			_query.Includes.Add(_mapper.GetExpression(path));
			return this;
		}

		public ILiteQueryable<T> Include(BsonExpression path)
		{
			_query.Includes.Add(path);
			return this;
		}

		public ILiteQueryable<T> Include(List<BsonExpression> paths)
		{
			_query.Includes.AddRange(paths);
			return this;
		}

		public ILiteQueryable<T> Where(BsonExpression predicate)
		{
			_query.Where.Add(predicate);
			return this;
		}

		public ILiteQueryable<T> Where(string predicate, BsonDocument parameters)
		{
			_query.Where.Add(BsonExpression.Create(predicate, parameters));
			return this;
		}

		public ILiteQueryable<T> Where(string predicate, params BsonValue[] args)
		{
			_query.Where.Add(BsonExpression.Create(predicate, args));
			return this;
		}

		public ILiteQueryable<T> Where(Expression<Func<T, bool>> predicate)
		{
			return Where(_mapper.GetExpression(predicate));
		}

		public ILiteQueryable<T> OrderBy(BsonExpression keySelector, int order = 1)
		{
			if (_query.OrderBy != null)
			{
				throw new ArgumentException("ORDER BY already defined in this query builder");
			}
			_query.OrderBy = keySelector;
			_query.Order = order;
			return this;
		}

		public ILiteQueryable<T> OrderBy<K>(Expression<Func<T, K>> keySelector, int order = 1)
		{
			return OrderBy(_mapper.GetExpression(keySelector), order);
		}

		public ILiteQueryable<T> OrderByDescending(BsonExpression keySelector)
		{
			return OrderBy(keySelector, -1);
		}

		public ILiteQueryable<T> OrderByDescending<K>(Expression<Func<T, K>> keySelector)
		{
			return OrderBy(keySelector, -1);
		}

		public ILiteQueryable<T> GroupBy(BsonExpression keySelector)
		{
			if (_query.GroupBy != null)
			{
				throw new ArgumentException("GROUP BY already defined in this query");
			}
			_query.GroupBy = keySelector;
			return this;
		}

		public ILiteQueryable<T> Having(BsonExpression predicate)
		{
			if (_query.Having != null)
			{
				throw new ArgumentException("HAVING already defined in this query");
			}
			_query.Having = predicate;
			return this;
		}

		public ILiteQueryableResult<BsonDocument> Select(BsonExpression selector)
		{
			_query.Select = selector;
			return new LiteQueryable<BsonDocument>(_engine, _mapper, _collection, _query);
		}

		public ILiteQueryableResult<K> Select<K>(Expression<Func<T, K>> selector)
		{
			if (_query.GroupBy != null)
			{
				throw new ArgumentException("Use Select(BsonExpression selector) when using GroupBy query");
			}
			_query.Select = _mapper.GetExpression(selector);
			return new LiteQueryable<K>(_engine, _mapper, _collection, _query);
		}

		public ILiteQueryableResult<T> ForUpdate()
		{
			_query.ForUpdate = true;
			return this;
		}

		public ILiteQueryableResult<T> Offset(int offset)
		{
			_query.Offset = offset;
			return this;
		}

		public ILiteQueryableResult<T> Skip(int offset)
		{
			return Offset(offset);
		}

		public ILiteQueryableResult<T> Limit(int limit)
		{
			_query.Limit = limit;
			return this;
		}

		public IBsonDataReader ExecuteReader()
		{
			_query.ExplainPlan = false;
			return _engine.Query(_collection, _query);
		}

		public IEnumerable<BsonDocument> ToDocuments()
		{
			using IBsonDataReader reader = ExecuteReader();
			while (reader.Read())
			{
				yield return reader.Current as BsonDocument;
			}
		}

		public IEnumerable<T> ToEnumerable()
		{
			if (_isSimpleType)
			{
				return from x in ToDocuments()
					select x[x.Keys.First()] into x
					select (T)_mapper.Deserialize(typeof(T), x);
			}
			return from x in ToDocuments()
				select (T)_mapper.Deserialize(typeof(T), x);
		}

		public List<T> ToList()
		{
			return ToEnumerable().ToList();
		}

		public T[] ToArray()
		{
			return ToEnumerable().ToArray();
		}

		public BsonDocument GetPlan()
		{
			_query.ExplainPlan = true;
			return _engine.Query(_collection, _query).ToEnumerable().FirstOrDefault()?.AsDocument;
		}

		public T Single()
		{
			return ToEnumerable().Single();
		}

		public T SingleOrDefault()
		{
			return ToEnumerable().SingleOrDefault();
		}

		public T First()
		{
			return ToEnumerable().First();
		}

		public T FirstOrDefault()
		{
			return ToEnumerable().FirstOrDefault();
		}

		public int Count()
		{
			BsonExpression select = _query.Select;
			try
			{
				Select("{ count: COUNT(*._id) }");
				return ToDocuments().Single()["count"].AsInt32;
			}
			finally
			{
				_query.Select = select;
			}
		}

		public long LongCount()
		{
			BsonExpression select = _query.Select;
			try
			{
				Select("{ count: COUNT(*._id) }");
				return ToDocuments().Single()["count"].AsInt64;
			}
			finally
			{
				_query.Select = select;
			}
		}

		public bool Exists()
		{
			BsonExpression select = _query.Select;
			try
			{
				Select("{ exists: ANY(*._id) }");
				return ToDocuments().Single()["exists"].AsBoolean;
			}
			finally
			{
				_query.Select = select;
			}
		}

		public int Into(string newCollection, BsonAutoId autoId = BsonAutoId.ObjectId)
		{
			_query.Into = newCollection;
			_query.IntoAutoId = autoId;
			using IBsonDataReader bsonDataReader = ExecuteReader();
			return bsonDataReader.Current.AsInt32;
		}
	}
	public class LiteRepository : ILiteRepository, IDisposable
	{
		private readonly ILiteDatabase _db;

		public ILiteDatabase Database => _db;

		public LiteRepository(ILiteDatabase database)
		{
			_db = database;
		}

		public LiteRepository(string connectionString, BsonMapper mapper = null)
		{
			_db = new LiteDatabase(connectionString, mapper);
		}

		public LiteRepository(ConnectionString connectionString, BsonMapper mapper = null)
		{
			_db = new LiteDatabase(connectionString, mapper);
		}

		public LiteRepository(Stream stream, BsonMapper mapper = null, Stream logStream = null)
		{
			_db = new LiteDatabase(stream, mapper, logStream);
		}

		public BsonValue Insert<T>(T entity, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Insert(entity);
		}

		public int Insert<T>(IEnumerable<T> entities, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Insert(entities);
		}

		public bool Update<T>(T entity, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Update(entity);
		}

		public int Update<T>(IEnumerable<T> entities, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Update(entities);
		}

		public bool Upsert<T>(T entity, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Upsert(entity);
		}

		public int Upsert<T>(IEnumerable<T> entities, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Upsert(entities);
		}

		public bool Delete<T>(BsonValue id, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Delete(id);
		}

		public int DeleteMany<T>(BsonExpression predicate, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).DeleteMany(predicate);
		}

		public int DeleteMany<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).DeleteMany(predicate);
		}

		public ILiteQueryable<T> Query<T>(string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Query();
		}

		public bool EnsureIndex<T>(string name, BsonExpression expression, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(name, expression, unique);
		}

		public bool EnsureIndex<T>(BsonExpression expression, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(expression, unique);
		}

		public bool EnsureIndex<T, K>(Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(keySelector, unique);
		}

		public bool EnsureIndex<T, K>(string name, Expression<Func<T, K>> keySelector, bool unique = false, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).EnsureIndex(name, keySelector, unique);
		}

		public T SingleById<T>(BsonValue id, string collectionName = null)
		{
			return _db.GetCollection<T>(collectionName).Query().Where("_id = @0", id)
				.Single();
		}

		public List<T> Fetch<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).ToList();
		}

		public List<T> Fetch<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).ToList();
		}

		public T First<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).First();
		}

		public T First<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).First();
		}

		public T FirstOrDefault<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).FirstOrDefault();
		}

		public T FirstOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).FirstOrDefault();
		}

		public T Single<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).Single();
		}

		public T Single<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).Single();
		}

		public T SingleOrDefault<T>(BsonExpression predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).SingleOrDefault();
		}

		public T SingleOrDefault<T>(Expression<Func<T, bool>> predicate, string collectionName = null)
		{
			return Query<T>(collectionName).Where(predicate).SingleOrDefault();
		}

		public void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		~LiteRepository()
		{
			Dispose(disposing: false);
		}

		protected virtual void Dispose(bool disposing)
		{
			if (disposing)
			{
				_db.Dispose();
			}
		}
	}
	public class BsonCtorAttribute : Attribute
	{
	}
	public class BsonFieldAttribute : Attribute
	{
		public string Name { get; set; }

		public BsonFieldAttribute(string name)
		{
			Name = name;
		}

		public BsonFieldAttribute()
		{
		}
	}
	public class BsonIdAttribute : Attribute
	{
		public bool AutoId { get; private set; }

		public BsonIdAttribute()
		{
			AutoId = true;
		}

		public BsonIdAttribute(bool autoId)
		{
			AutoId = autoId;
		}
	}
	public class BsonIgnoreAttribute : Attribute
	{
	}
	public class BsonRefAttribute : Attribute
	{
		public string Collection { get; set; }

		public BsonRefAttribute(string collection)
		{
			Collection = collection;
		}

		public BsonRefAttribute()
		{
			Collection = null;
		}
	}
	public class BsonMapper
	{
		public delegate BsonValue DeserializationCallback(BsonMapper sender, Type target, BsonValue value);

		private readonly Dictionary<Type, EntityMapper> _entities = new Dictionary<Type, EntityMapper>();

		private readonly ConcurrentDictionary<Type, Func<object, BsonValue>> _customSerializer = new ConcurrentDictionary<Type, Func<object, BsonValue>>();

		private readonly ConcurrentDictionary<Type, Func<BsonValue, object>> _customDeserializer = new ConcurrentDictionary<Type, Func<BsonValue, object>>();

		private readonly Func<Type, object> _typeInstantiator;

		private readonly ITypeNameBinder _typeNameBinder;

		public static BsonMapper Global = new BsonMapper();

		public Func<string, string> ResolveFieldName;

		public Action<Type, MemberInfo, MemberMapper> ResolveMember;

		public Func<Type, string> ResolveCollectionName;

		private readonly Regex _lowerCaseDelimiter = new Regex("(?!(^[A-Z]))([A-Z])", RegexOptions.Compiled);

		private readonly HashSet<Type> _bsonTypes = new HashSet<Type>
		{
			typeof(string),
			typeof(int),
			typeof(long),
			typeof(bool),
			typeof(Guid),
			typeof(DateTime),
			typeof(byte[]),
			typeof(ObjectId),
			typeof(double),
			typeof(decimal)
		};

		private readonly HashSet<Type> _basicTypes = new HashSet<Type>
		{
			typeof(short),
			typeof(ushort),
			typeof(uint),
			typeof(float),
			typeof(char),
			typeof(byte),
			typeof(sbyte)
		};

		public bool SerializeNullValues { get; set; }

		public bool TrimWhitespace { get; set; }

		public bool EmptyStringToNull { get; set; }

		public bool EnumAsInteger { get; set; }

		public bool IncludeFields { get; set; }

		public bool IncludeNonPublic { get; set; }

		public int MaxDepth { get; set; }

		public DeserializationCallback? OnDeserialization { get; set; }

		public BsonMapper(Func<Type, object> customTypeInstantiator = null, ITypeNameBinder typeNameBinder = null)
		{
			SerializeNullValues = false;
			TrimWhitespace = true;
			EmptyStringToNull = true;
			EnumAsInteger = false;
			ResolveFieldName = (string s) => s;
			ResolveMember = delegate
			{
			};
			ResolveCollectionName = (Type t) => (!Reflection.IsEnumerable(t)) ? t.Name : Reflection.GetListItemType(t).Name;
			IncludeFields = false;
			MaxDepth = 20;
			_typeInstantiator = customTypeInstantiator ?? ((Func<Type, object>)((Type t) => null));
			_typeNameBinder = typeNameBinder ?? DefaultTypeNameBinder.Instance;
			RegisterType((Uri uri) => uri.IsAbsoluteUri ? uri.AbsoluteUri : uri.ToString(), (BsonValue bson) => new Uri(bson.AsString));
			RegisterType((DateTimeOffset value) => new BsonValue(value.UtcDateTime), (BsonValue bson) => bson.AsDateTime.ToUniversalTime());
			RegisterType((TimeSpan value) => new BsonValue(value.Ticks), (BsonValue bson) => new TimeSpan(bson.AsInt64));
			RegisterType((Regex r) => (r.Options != 0) ? new BsonDocument
			{
				{
					"p",
					r.ToString()
				},
				{
					"o",
					(int)r.Options
				}
			} : new BsonValue(r.ToString()), (BsonValue value) => (!value.IsString) ? new Regex(value.AsDocument["p"].AsString, (RegexOptions)value.AsDocument["o"].AsInt32) : new Regex(value));
		}

		public void RegisterType<T>(Func<T, BsonValue> serialize, Func<BsonValue, T> deserialize)
		{
			_customSerializer[typeof(T)] = (object o) => serialize((T)o);
			_customDeserializer[typeof(T)] = (BsonValue b) => deserialize(b);
		}

		public void RegisterType(Type type, Func<object, BsonValue> serialize, Func<BsonValue, object> deserialize)
		{
			_customSerializer[type] = (object o) => serialize(o);
			_customDeserializer[type] = (BsonValue b) => deserialize(b);
		}

		public EntityBuilder<T> Entity<T>()
		{
			return new EntityBuilder<T>(this, _typeNameBinder);
		}

		public BsonExpression GetExpression<T, K>(Expression<Func<T, K>> predicate)
		{
			return new LinqExpressionVisitor(this, predicate).Resolve(typeof(K) == typeof(bool));
		}

		public BsonExpression GetIndexExpression<T, K>(Expression<Func<T, K>> predicate)
		{
			return new LinqExpressionVisitor(this, predicate).Resolve(predicate: false);
		}

		public BsonMapper UseCamelCase()
		{
			ResolveFieldName = (string s) => char.ToLower(s[0]) + s.Substring(1);
			return this;
		}

		public BsonMapper UseLowerCaseDelimiter(char delimiter = '_')
		{
			ResolveFieldName = (string s) => _lowerCaseDelimiter.Replace(s, delimiter + "$2").ToLower();
			return this;
		}

		internal EntityMapper GetEntityMapper(Type type)
		{
			if (!_entities.TryGetValue(type, out var value))
			{
				lock (_entities)
				{
					if (!_entities.TryGetValue(type, out value))
					{
						return BuildAddEntityMapper(type);
					}
				}
			}
			return value;
		}

		protected virtual EntityMapper BuildAddEntityMapper(Type type)
		{
			EntityMapper entityMapper = new EntityMapper(type);
			_entities[type] = entityMapper;
			Type typeFromHandle = typeof(BsonIdAttribute);
			Type typeFromHandle2 = typeof(BsonIgnoreAttribute);
			Type typeFromHandle3 = typeof(BsonFieldAttribute);
			Type typeFromHandle4 = typeof(BsonRefAttribute);
			IEnumerable<MemberInfo> typeMembers = GetTypeMembers(type);
			MemberInfo idMember = GetIdMember(typeMembers);
			foreach (MemberInfo item in typeMembers)
			{
				if (!CustomAttributeExtensions.IsDefined(item, typeFromHandle2, inherit: true))
				{
					string name = ResolveFieldName(item.Name);
					BsonFieldAttribute bsonFieldAttribute = (BsonFieldAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle3, inherit: true).FirstOrDefault();
					if (bsonFieldAttribute != null && bsonFieldAttribute.Name != null)
					{
						name = bsonFieldAttribute.Name;
					}
					if (item == idMember)
					{
						name = "_id";
					}
					GenericGetter getter = Reflection.CreateGenericGetter(type, item);
					GenericSetter setter = Reflection.CreateGenericSetter(type, item);
					BsonIdAttribute bsonIdAttribute = (BsonIdAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle, inherit: true).FirstOrDefault();
					Type type2 = ((item is PropertyInfo) ? (item as PropertyInfo).PropertyType : (item as FieldInfo).FieldType);
					bool flag = Reflection.IsEnumerable(type2);
					MemberMapper memberMapper = new MemberMapper
					{
						AutoId = (bsonIdAttribute?.AutoId ?? true),
						FieldName = name,
						MemberName = item.Name,
						DataType = type2,
						IsEnumerable = flag,
						UnderlyingType = (flag ? Reflection.GetListItemType(type2) : type2),
						Getter = getter,
						Setter = setter
					};
					BsonRefAttribute bsonRefAttribute = (BsonRefAttribute)CustomAttributeExtensions.GetCustomAttributes(item, typeFromHandle4, inherit: false).FirstOrDefault();
					if (bsonRefAttribute != null && item is PropertyInfo)
					{
						RegisterDbRef(this, memberMapper, _typeNameBinder, bsonRefAttribute.Collection ?? ResolveCollectionName((item as PropertyInfo).PropertyType));
					}
					ResolveMember?.Invoke(type, item, memberMapper);
					if (memberMapper.FieldName != null && !entityMapper.Members.Any((MemberMapper x) => x.FieldName.Equals(name, StringComparison.OrdinalIgnoreCase)) && !memberMapper.IsIgnore)
					{
						entityMapper.Members.Add(memberMapper);
					}
				}
			}
			return entityMapper;
		}

		protected virtual MemberInfo GetIdMember(IEnumerable<MemberInfo> members)
		{
			return Reflection.SelectMember(members, (MemberInfo x) => CustomAttributeExtensions.IsDefined(x, typeof(BsonIdAttribute), inherit: true), (MemberInfo x) => x.Name.Equals("Id", StringComparison.OrdinalIgnoreCase), (MemberInfo x) => x.Name.Equals(x.DeclaringType.Name + "Id", StringComparison.OrdinalIgnoreCase));
		}

		protected virtual IEnumerable<MemberInfo> GetTypeMembers(Type type)
		{
			List<MemberInfo> list = new List<MemberInfo>();
			BindingFlags bindingAttr = (IncludeNonPublic ? (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) : (BindingFlags.Instance | BindingFlags.Public));
			list.AddRange((from x in type.GetProperties(bindingAttr)
				where x.CanRead && x.GetIndexParameters().Length == 0
				select x).Select((Func<PropertyInfo, MemberInfo>)((PropertyInfo x) => x)));
			if (IncludeFields)
			{
				list.AddRange((from x in type.GetFields(bindingAttr)
					where !x.Name.EndsWith("k__BackingField") && !x.IsStatic
					select x).Select((Func<FieldInfo, MemberInfo>)((FieldInfo x) => x)));
			}
			return list;
		}

		protected virtual CreateObject GetTypeCtor(EntityMapper mapper)
		{
			Type type = mapper.ForType;
			List<CreateObject> list = new List<CreateObject>();
			bool flag = false;
			ConstructorInfo[] constructors = type.GetConstructors();
			foreach (ConstructorInfo constructorInfo in constructors)
			{
				ParameterInfo[] parameters = constructorInfo.GetParameters();
				if (parameters.Length == 0)
				{
					flag = true;
					continue;
				}
				KeyValuePair<string, Type>[] paramMap = new KeyValuePair<string, Type>[parameters.Length];
				int j;
				for (j = 0; j < parameters.Length; j++)
				{
					ParameterInfo parameterInfo = parameters[j];
					MemberMapper memberMapper = null;
					foreach (MemberMapper member in mapper.Members)
					{
						if (member.MemberName.ToLower() == parameterInfo.Name.ToLower() && member.DataType == parameterInfo.ParameterType)
						{
							memberMapper = member;
							break;
						}
					}
					if (memberMapper == null)
					{
						break;
					}
					paramMap[j] = new KeyValuePair<string, Type>(memberMapper.FieldName, memberMapper.DataType);
				}
				if (j < parameters.Length)
				{
					continue;
				}
				CreateObject createObject = (BsonDocument value) => Activator.CreateInstance(type, paramMap.Select((KeyValuePair<string, Type> x) => Deserialize(x.Value, value[x.Key])).ToArray());
				if (constructorInfo.GetCustomAttribute<BsonCtorAttribute>() != null)
				{
					return createObject;
				}
				list.Add(createObject);
			}
			if (flag)
			{
				return null;
			}
			return list.FirstOrDefault();
		}

		internal static void RegisterDbRef(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection)
		{
			member.IsDbRef = true;
			if (member.IsEnumerable)
			{
				RegisterDbRefList(mapper, member, typeNameBinder, collection);
			}
			else
			{
				RegisterDbRefItem(mapper, member, typeNameBinder, collection);
			}
		}

		private static void RegisterDbRefItem(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection)
		{
			EntityMapper entity = mapper.GetEntityMapper(member.DataType);
			member.Serialize = delegate(object obj, BsonMapper m)
			{
				if (obj == null)
				{
					return BsonValue.Null;
				}
				object obj2 = (entity.Id ?? throw new LiteException(0, "There is no _id field mapped in your type: " + member.DataType.FullName)).Getter(obj);
				BsonDocument bsonDocument = new BsonDocument
				{
					["$id"] = m.Serialize(obj2.GetType(), obj2, 0),
					["$ref"] = collection
				};
				if (member.DataType != obj.GetType())
				{
					bsonDocument["$type"] = typeNameBinder.GetName(obj.GetType());
				}
				return bsonDocument;
			};
			member.Deserialize = delegate(BsonValue bson, BsonMapper m)
			{
				if (bson == null || !bson.IsDocument)
				{
					return null;
				}
				BsonDocument asDocument = bson.AsDocument;
				BsonValue value = asDocument["$id"];
				bool num = asDocument["$missing"] == true;
				bool flag = !asDocument.ContainsKey("$ref");
				if (num)
				{
					return null;
				}
				if (flag)
				{
					asDocument["_id"] = value;
					if (asDocument.ContainsKey("$type"))
					{
						asDocument["_type"] = bson["$type"];
					}
					return m.Deserialize(entity.ForType, asDocument);
				}
				return m.Deserialize(entity.ForType, asDocument.ContainsKey("$type") ? new BsonDocument
				{
					["_id"] = value,
					["_type"] = bson["$type"]
				} : new BsonDocument { ["_id"] = value });
			};
		}

		private static void RegisterDbRefList(BsonMapper mapper, MemberMapper member, ITypeNameBinder typeNameBinder, string collection)
		{
			EntityMapper entity = mapper.GetEntityMapper(member.UnderlyingType);
			member.Serialize = delegate(object list, BsonMapper m)
			{
				if (list == null)
				{
					return BsonValue.Null;
				}
				BsonArray bsonArray2 = new BsonArray();
				MemberMapper id = entity.Id;
				foreach (object item in (IEnumerable)list)
				{
					if (item != null)
					{
						object obj = id.Getter(item);
						BsonDocument bsonDocument2 = new BsonDocument
						{
							["$id"] = m.Serialize(obj.GetType(), obj, 0),
							["$ref"] = collection
						};
						if (member.UnderlyingType != item.GetType())
						{
							bsonDocument2["$type"] = typeNameBinder.GetName(item.GetType());
						}
						bsonArray2.Add(bsonDocument2);
					}
				}
				return bsonArray2;
			};
			member.Deserialize = delegate(BsonValue bson, BsonMapper m)
			{
				if (!bson.IsArray)
				{
					return null;
				}
				BsonArray asArray = bson.AsArray;
				if (asArray.Count == 0)
				{
					return m.Deserialize(member.DataType, asArray);
				}
				BsonArray bsonArray = new BsonArray();
				foreach (BsonValue item2 in asArray)
				{
					if (item2.IsDocument)
					{
						BsonDocument asDocument = item2.AsDocument;
						BsonValue value = asDocument["$id"];
						bool flag = asDocument["$missing"] == true;
						bool flag2 = !asDocument.ContainsKey("$ref");
						if (!flag)
						{
							if (flag2)
							{
								item2["_id"] = value;
								if (item2.AsDocument.ContainsKey("$type"))
								{
									item2["_type"] = item2["$type"];
								}
								bsonArray.Add(item2);
							}
							else
							{
								BsonDocument bsonDocument = new BsonDocument { ["_id"] = value };
								if (item2.AsDocument.ContainsKey("$type"))
								{
									bsonDocument["_type"] = item2["$type"];
								}
								bsonArray.Add(bsonDocument);
							}
						}
					}
				}
				return m.Deserialize(member.DataType, bsonArray);
			};
		}

		public virtual object ToObject(Type type, BsonDocument doc)
		{
			if (doc == null)
			{
				throw new ArgumentNullException("doc");
			}
			if (type == typeof(BsonDocument))
			{
				return doc;
			}
			return Deserialize(type, doc);
		}

		public virtual T ToObject<T>(BsonDocument doc)
		{
			return (T)ToObject(typeof(T), doc);
		}

		public T Deserialize<T>(BsonValue value)
		{
			if (value == null)
			{
				return default(T);
			}
			return (T)Deserialize(typeof(T), value);
		}

		public object Deserialize(Type type, BsonValue value)
		{
			if (OnDeserialization != null)
			{
				BsonValue bsonValue = OnDeserialization(this, type, value);
				if ((object)bsonValue != null)
				{
					value = bsonValue;
				}
			}
			if (value.IsNull)
			{
				return null;
			}
			if (Reflection.IsNullable(type))
			{
				type = Reflection.UnderlyingTypeOf(type);
			}
			if (_customDeserializer.TryGetValue(type, out var value2))
			{
				return value2(value);
			}
			TypeInfo typeInfo = type.GetTypeInfo();
			if (type == typeof(BsonValue))
			{
				return value;
			}
			if (type == typeof(BsonDocument))
			{
				return value.AsDocument;
			}
			if (type == typeof(BsonArray))
			{
				return value.AsArray;
			}
			if (_bsonTypes.Contains(type))
			{
				return value.RawValue;
			}
			if (_basicTypes.Contains(type))
			{
				return Convert.ChangeType(value.RawValue, type);
			}
			if (type == typeof(ulong))
			{
				return (ulong)value.AsInt64;
			}
			if (typeInfo.IsEnum)
			{
				if (value.IsString)
				{
					return Enum.Parse(type, value.AsString);
				}
				if (value.IsNumber)
				{
					return Enum.ToObject(type, value.AsInt32);
				}
			}
			else
			{
				if (value.IsArray)
				{
					if (type == typeof(object))
					{
						return DeserializeArray(typeof(object), value.AsArray);
					}
					if (type.IsArray)
					{
						return DeserializeArray(type.GetElementType(), value.AsArray);
					}
					return DeserializeList(type, value.AsArray);
				}
				if (value.IsDocument)
				{
					if (type.IsAnonymousType())
					{
						return DeserializeAnonymousType(type, value.AsDocument);
					}
					BsonDocument asDocument = value.AsDocument;
					if (asDocument.TryGetValue("_type", out var value3) && value3.IsString)
					{
						Type type2 = _typeNameBinder.GetType(value3.AsString);
						if (type2 == null)
						{
							throw LiteException.InvalidTypedName(value3.AsString);
						}
						if (!type.IsAssignableFrom(type2))
						{
							throw LiteException.DataTypeNotAssignable(type.FullName, type2.FullName);
						}
						type = type2;
					}
					else if (type == typeof(object))
					{
						type = typeof(Dictionary<string, object>);
					}
					EntityMapper entity = GetEntityMapper(type);
					if (entity.CreateInstance == null)
					{
						entity.CreateInstance = GetTypeCtor(entity) ?? ((CreateObject)((BsonDocument v) => Reflection.CreateInstance(entity.ForType)));
					}
					object obj = _typeInstantiator(type) ?? entity.CreateInstance(asDocument);
					if (obj is IDictionary dict)
					{
						if (obj.GetType().GetTypeInfo().IsGenericType)
						{
							Type k = type.GetGenericArguments()[0];
							Type t = type.GetGenericArguments()[1];
							DeserializeDictionary(k, t, dict, value.AsDocument);
						}
						else
						{
							DeserializeDictionary(typeof(object), typeof(object), dict, value.AsDocument);
						}
					}
					else
					{
						DeserializeObject(entity, obj, asDocument);
					}
					return obj;
				}
			}
			return value.RawValue;
		}

		private object DeserializeArray(Type type, BsonArray array)
		{
			Array array2 = Array.CreateInstance(type, array.Count);
			int num = 0;
			foreach (BsonValue item in array)
			{
				array2.SetValue(Deserialize(type, item), num++);
			}
			return array2;
		}

		private object DeserializeList(Type type, BsonArray value)
		{
			Type listItemType = Reflection.GetListItemType(type);
			IEnumerable enumerable = (IEnumerable)Reflection.CreateInstance(type);
			if (enumerable is IList list)
			{
				foreach (BsonValue item in value)
				{
					list.Add(Deserialize(listItemType, item));
				}
			}
			else
			{
				MethodInfo method = type.GetMethod("Add", new Type[1] { listItemType });
				foreach (BsonValue item2 in value)
				{
					method.Invoke(enumerable, new object[1] { Deserialize(listItemType, item2) });
				}
			}
			return enumerable;
		}

		private void DeserializeDictionary(Type K, Type T, IDictionary dict, BsonDocument value)
		{
			bool isEnum = K.GetTypeInfo().IsEnum;
			foreach (KeyValuePair<string, BsonValue> element in value.GetElements())
			{
				object key = (isEnum ? Enum.Parse(K, element.Key) : ((K == typeof(Uri)) ? new Uri(element.Key) : Convert.ChangeType(element.Key, K)));
				object value2 = Deserialize(T, element.Value);
				dict.Add(key, value2);
			}
		}

		private void DeserializeObject(EntityMapper entity, object obj, BsonDocument value)
		{
			foreach (MemberMapper item in entity.Members.Where((MemberMapper x) => x.Setter != null))
			{
				if (value.TryGetValue(item.FieldName, out var value2))
				{
					if (item.Deserialize != null)
					{
						item.Setter(obj, item.Deserialize(value2, this));
					}
					else
					{
						item.Setter(obj, Deserialize(item.DataType, value2));
					}
				}
			}
		}

		private object DeserializeAnonymousType(Type type, BsonDocument value)
		{
			List<object> list = new List<object>();
			ParameterInfo[] parameters = type.GetConstructors()[0].GetParameters();
			foreach (ParameterInfo parameterInfo in parameters)
			{
				object obj = Deserialize(parameterInfo.ParameterType, value[parameterInfo.Name]);
				if (obj == null && StringComparer.OrdinalIgnoreCase.Equals(parameterInfo.Name, "Id") && value.TryGetValue("_id", out var value2))
				{
					obj = Deserialize(parameterInfo.ParameterType, value2);
				}
				list.Add(obj);
			}
			return Activator.CreateInstance(type, list.ToArray());
		}

		public virtual BsonDocument ToDocument(Type type, object entity)
		{
			if (entity == null)
			{
				throw new ArgumentNullException("entity");
			}
			if (entity is BsonDocument)
			{
				return (BsonDocument)entity;
			}
			return Serialize(type, entity, 0).AsDocument;
		}

		public virtual BsonDocument ToDocument<T>(T entity)
		{
			return ToDocument(typeof(T), entity)?.AsDocument;
		}

		public BsonValue Serialize<T>(T obj)
		{
			return Serialize(typeof(T), obj, 0);
		}

		public BsonValue Serialize(Type type, object obj)
		{
			return Serialize(type, obj, 0);
		}

		internal BsonValue Serialize(Type type, object obj, int depth)
		{
			if (++depth > MaxDepth)
			{
				throw LiteException.DocumentMaxDepth(MaxDepth, type);
			}
			if (obj == null)
			{
				return BsonValue.Null;
			}
			if (obj is BsonValue result)
			{
				return result;
			}
			if (_customSerializer.TryGetValue(type, out var value) || _customSerializer.TryGetValue(obj.GetType(), out value))
			{
				return value(obj);
			}
			if (obj is string)
			{
				string text = (TrimWhitespace ? (obj as string).Trim() : ((string)obj));
				if (EmptyStringToNull && text.Length == 0)
				{
					return BsonValue.Null;
				}
				return new BsonValue(text);
			}
			if (obj is int)
			{
				return new BsonValue((int)obj);
			}
			if (obj is long)
			{
				return new BsonValue((long)obj);
			}
			if (obj is double)
			{
				return new BsonValue((double)obj);
			}
			if (obj is decimal)
			{
				return new BsonValue((decimal)obj);
			}
			if (obj is byte[])
			{
				return new BsonValue((byte[])obj);
			}
			if (obj is ObjectId)
			{
				return new BsonValue((ObjectId)obj);
			}
			if (obj is Guid)
			{
				return new BsonValue((Guid)obj);
			}
			if (obj is bool)
			{
				return new BsonValue((bool)obj);
			}
			if (obj is DateTime)
			{
				return new BsonValue((DateTime)obj);
			}
			if (obj is short || obj is ushort || obj is byte || obj is sbyte)
			{
				return new BsonValue(Convert.ToInt32(obj));
			}
			if (obj is uint)
			{
				return new BsonValue(Convert.ToInt64(obj));
			}
			if (obj is ulong)
			{
				return new BsonValue((long)(ulong)obj);
			}
			if (obj is float)
			{
				return new BsonValue(Convert.ToDouble(obj));
			}
			if (obj is char)
			{
				return new BsonValue(obj.ToString());
			}
			if (obj is Enum)
			{
				if (EnumAsInteger)
				{
					return new BsonValue((int)obj);
				}
				return new BsonValue(obj.ToString());
			}
			if (obj is IDictionary dict)
			{
				if (type == typeof(object))
				{
					type = obj.GetType();
				}
				Type type2 = (type.GetTypeInfo().IsGenericType ? type.GetGenericArguments()[1] : typeof(object));
				return SerializeDictionary(type2, dict, depth);
			}
			if (obj is IEnumerable)
			{
				return SerializeArray(Reflection.GetListItemType(type), obj as IEnumerable, depth);
			}
			return SerializeObject(type, obj, depth);
		}

		private BsonArray SerializeArray(Type type, IEnumerable array, int depth)
		{
			BsonArray bsonArray = new BsonArray();
			foreach (object item in array)
			{
				bsonArray.Add(Serialize(type, item, depth));
			}
			return bsonArray;
		}

		private BsonDocument SerializeDictionary(Type type, IDictionary dict, int depth)
		{
			BsonDocument bsonDocument = new BsonDocument();
			foreach (object key in dict.Keys)
			{
				object obj = dict[key];
				string name = key.ToString();
				if (key is DateTime dateTime)
				{
					name = dateTime.ToString("o");
				}
				bsonDocument[name] = Serialize(type, obj, depth);
			}
			return bsonDocument;
		}

		private BsonDocument SerializeObject(Type type, object obj, int depth)
		{
			Type type2 = obj.GetType();
			BsonDocument bsonDocument = new BsonDocument();
			EntityMapper entityMapper = GetEntityMapper(type2);
			if (type != type2)
			{
				bsonDocument["_type"] = new BsonValue(_typeNameBinder.GetName(type2));
			}
			foreach (MemberMapper item in entityMapper.Members.Where((MemberMapper x) => x.Getter != null))
			{
				object obj2 = item.Getter(obj);
				if (obj2 != null || SerializeNullValues || !(item.FieldName != "_id"))
				{
					if (item.Serialize != null)
					{
						bsonDocument[item.FieldName] = item.Serialize(obj2, this);
					}
					else
					{
						bsonDocument[item.FieldName] = Serialize(item.DataType, obj2, depth);
					}
				}
			}
			return bsonDocument;
		}
	}
	public class EntityBuilder<T>
	{
		private readonly BsonMapper _mapper;

		private readonly EntityMapper _entity;

		private readonly ITypeNameBinder _typeNameBinder;

		internal EntityBuilder(BsonMapper mapper, ITypeNameBinder typeNameBinder)
		{
			_mapper = mapper;
			_typeNameBinder = typeNameBinder;
			_entity = mapper.GetEntityMapper(typeof(T));
		}

		public EntityBuilder<T> Ignore<K>(Expression<Func<T, K>> member)
		{
			return GetMember(member, delegate(MemberMapper p)
			{
				_entity.Members.Remove(p);
			});
		}

		public EntityBuilder<T> Field<K>(Expression<Func<T, K>> member, string field)
		{
			if (field.IsNullOrWhiteSpace())
			{
				throw new ArgumentNullException("field");
			}
			return GetMember(member, delegate(MemberMapper p)
			{
				p.FieldName = field;
			});
		}

		public EntityBuilder<T> Id<K>(Expression<Func<T, K>> member, bool autoId = true)
		{
			return GetMember(member, delegate(MemberMapper p)
			{
				MemberMapper memberMapper = _entity.Members.FirstOrDefault((MemberMapper x) => x.FieldName == "_id");
				if (memberMapper != null)
				{
					memberMapper.FieldName = _mapper.ResolveFieldName(memberMapper.MemberName);
					memberMapper.AutoId = false;
				}
				p.FieldName = "_id";
				p.AutoId = autoId;
			});
		}

		public EntityBuilder<T> Ctor(Func<BsonDocument, T> createInstance)
		{
			_entity.CreateInstance = (BsonDocument v) => createInstance(v);
			return this;
		}

		public EntityBuilder<T> DbRef<K>(Expression<Func<T, K>> member, string collection = null)
		{
			return GetMember(member, delegate(MemberMapper p)
			{
				BsonMapper.RegisterDbRef(_mapper, p, _typeNameBinder, collection ?? _mapper.ResolveCollectionName(typeof(K)));
			});
		}

		private EntityBuilder<T> GetMember<TK, K>(Expression<Func<TK, K>> member, Action<MemberMapper> action)
		{
			if (member == null)
			{
				throw new ArgumentNullException("member");
			}
			MemberMapper member2 = _entity.GetMember(member);
			if (member2 == null)
			{
				throw new ArgumentNullException("Member '" + member.GetPath() + "' not found in type '" + _entity.ForType.Name + "' (use IncludeFields in BsonMapper)");
			}
			action(member2);
			return this;
		}
	}
	public class EntityMapper
	{
		public Type ForType { get; }

		public List<MemberMapper> Members { get; } = new List<MemberMapper>();


		public MemberMapper Id => Members.SingleOrDefault((MemberMapper x) => x.FieldName == "_id");

		public CreateObject CreateInstance { get; set; }

		public EntityMapper(Type forType)
		{
			ForType = forType;
		}

		public MemberMapper GetMember(Expression expr)
		{
			return Members.FirstOrDefault((MemberMapper x) => x.MemberName == expr.GetPath());
		}
	}
	internal class LinqExpressionVisitor : ExpressionVisitor
	{
		private static readonly Dictionary<Type, ITypeResolver> _resolver = new Dictionary<Type, ITypeResolver>
		{
			[typeof(BsonValue)] = new BsonValueResolver(),
			[typeof(BsonArray)] = new BsonValueResolver(),
			[typeof(BsonDocument)] = new BsonValueResolver(),
			[typeof(Convert)] = new ConvertResolver(),
			[typeof(DateTime)] = new DateTimeResolver(),
			[typeof(int)] = new NumberResolver("INT32"),
			[typeof(long)] = new NumberResolver("INT64"),
			[typeof(decimal)] = new NumberResolver("DECIMAL"),
			[typeof(double)] = new NumberResolver("DOUBLE"),
			[typeof(ICollection)] = new ICollectionResolver(),
			[typeof(Enumerable)] = new EnumerableResolver(),
			[typeof(Guid)] = new GuidResolver(),
			[typeof(Math)] = new MathResolver(),
			[typeof(Regex)] = new RegexResolver(),
			[typeof(ObjectId)] = new ObjectIdResolver(),
			[typeof(string)] = new StringResolver(),
			[typeof(Nullable)] = new NullableResolver()
		};

		private readonly BsonMapper _mapper;

		private readonly Expression _expr;

		private readonly ParameterExpression _rootParameter;

		private readonly BsonDocument _parameters = new BsonDocument();

		private int _paramIndex;

		private Type _dbRefType;

		private readonly StringBuilder _builder = new StringBuilder();

		private readonly Stack<Expression> _nodes = new Stack<Expression>();

		public LinqExpressionVisitor(BsonMapper mapper, Expression expr)
		{
			_mapper = mapper;
			_expr = expr;
			if (expr is LambdaExpression lambdaExpression)
			{
				_rootParameter = lambdaExpression.Parameters.First();
				return;
			}
			throw new NotSupportedException("Expression " + expr.ToString() + " must be a lambda expression");
		}

		public BsonExpression Resolve(bool predicate)
		{
			Visit(_expr);
			Constants.ENSURE(_nodes.Count == 0, "node stack must be empty when finish expression resolve");
			string text = _builder.ToString();
			try
			{
				BsonExpression bsonExpression = BsonExpression.Create(text, _parameters);
				if (predicate && (bsonExpression.Type == BsonExpressionType.Path || bsonExpression.Type == BsonExpressionType.Call || bsonExpression.Type == BsonExpressionType.Parameter))
				{
					text = "(" + text + " = true)";
					bsonExpression = BsonExpression.Create(text, _parameters);
				}
				return bsonExpression;
			}
			catch (Exception innerException)
			{
				throw new NotSupportedException("Invalid BsonExpression when converted from Linq expression: " + _expr.ToString() + " - `" + text + "`", innerException);
			}
		}

		protected override Expression VisitLambda<T>(Expression<T> node)
		{
			Expression result = base.VisitLambda(node);
			_builder.Length--;
			return result;
		}

		protected override Expression VisitInvocation(InvocationExpression node)
		{
			Expression result = base.VisitInvocation(node);
			_builder.Length--;
			return result;
		}

		protected override Expression VisitParameter(ParameterExpression node)
		{
			_builder.Append(_rootParameter.Equals(node) ? "$" : "@");
			return base.VisitParameter(node);
		}

		protected override Expression VisitMember(MemberExpression node)
		{
			bool flag = ParameterExpressionVisitor.Test(node);
			MemberInfo member = node.Member;
			if (TryGetResolver(member.DeclaringType, out var typeResolver))
			{
				string text = typeResolver.ResolveMember(member);
				if (text == null)
				{
					throw new NotSupportedException("Member " + member.Name + " are not support in " + member.DeclaringType.Name + " when convert to BsonExpression (" + node.ToString() + ").");
				}
				ResolvePattern(text, node.Expression, new Expression[0]);
			}
			else if (node.Expression != null)
			{
				_nodes.Push(node);
				base.Visit(node.Expression);
				if (flag)
				{
					string value = ResolveMember(member);
					_builder.Append(value);
				}
			}
			else
			{
				object value2 = Evaluate(node);
				base.Visit(Expression.Constant(value2));
			}
			if (_nodes.Count > 0)
			{
				_nodes.Pop();
			}
			return node;
		}

		protected override Expression VisitMethodCall(MethodCallExpression node)
		{
			if (IsMethodIndexEval(node, out var obj, out var idx))
			{
				Visit(obj);
				object obj2 = Evaluate(idx, typeof(string), typeof(int));
				if (obj2 is string)
				{
					_builder.Append(".");
					_builder.Append($"['{obj2}']");
				}
				else
				{
					_builder.Append($"[{obj2}]");
				}
				return node;
			}
			if (!TryGetResolver(node.Method.DeclaringType, out var typeResolver))
			{
				if (ParameterExpressionVisitor.Test(node))
				{
					throw new NotSupportedException("Method " + node.Method.Name + " not available to convert to BsonExpression (" + node.ToString() + ").");
				}
				object value = Evaluate(node);
				base.Visit(Expression.Constant(value));
				return node;
			}
			string text = typeResolver.ResolveMethod(node.Method);
			if (text == null)
			{
				throw new NotSupportedException("Method " + Reflection.MethodName(node.Method) + " in " + node.Method.DeclaringType.Name + " are not supported when convert to BsonExpression (" + node.ToString() + ").");
			}
			ResolvePattern(text, node.Object, node.Arguments);
			return node;
		}

		protected override Expression VisitConstant(ConstantExpression node)
		{
			object value = node.Value;
			while (_nodes.Count > 0 && _nodes.Peek() is MemberExpression memberExpression)
			{
				if (memberExpression.Member is FieldInfo fieldInfo)
				{
					value = fieldInfo.GetValue(value);
				}
				else if (memberExpression.Member is PropertyInfo propertyInfo)
				{
					value = propertyInfo.GetValue(value);
				}
				_nodes.Pop();
			}
			Constants.ENSURE(_nodes.Count == 0, "counter stack must be zero to eval all properties/field over object");
			string text = "p" + _paramIndex++;
			_builder.AppendFormat("@" + text);
			Type type = value?.GetType();
			BsonValue value2 = ((type == null) ? BsonValue.Null : ((type == typeof(string)) ? new BsonValue((string)value) : _mapper.Serialize(value.GetType(), value)));
			_parameters[text] = value2;
			return node;
		}

		protected override Expression VisitUnary(UnaryExpression node)
		{
			if (node.NodeType == ExpressionType.Not)
			{
				if (node.Operand.NodeType == ExpressionType.MemberAccess)
				{
					_builder.Append("(");
					Visit(node.Operand);
					_builder.Append(" = false)");
				}
				else
				{
					_builder.Append("(");
					Visit(node.Operand);
					_builder.Append(")");
					_builder.Append(" = false");
				}
			}
			else if (node.NodeType == ExpressionType.Convert)
			{
				Type fromType = node.Operand.Type;
				Type type = node.Type;
				if ((fromType == typeof(double) || fromType == typeof(decimal)) && (type == typeof(int) || type == typeof(long)))
				{
					string methodName = "To" + type.Name.ToString();
					MethodInfo methodInfo = (from x in typeof(Convert).GetMethods()
						where x.Name == methodName
						where x.GetParameters().Length == 1 && x.GetParameters().Any((ParameterInfo z) => z.ParameterType == fromType)
						select x).FirstOrDefault();
					if (methodInfo == null)
					{
						throw new NotSupportedException("Cast from " + fromType.Name + " are not supported when convert to BsonExpression");
					}
					MethodCallExpression node2 = Expression.Call(null, methodInfo, node.Operand);
					VisitMethodCall(node2);
				}
				else
				{
					base.VisitUnary(node);
				}
			}
			else if (node.NodeType == ExpressionType.ArrayLength)
			{
				_builder.Append("LENGTH(");
				Visit(node.Operand);
				_builder.Append(")");
			}
			else
			{
				base.VisitUnary(node);
			}
			return node;
		}

		protected override Expression VisitNew(NewExpression node)
		{
			if (node.Members == null)
			{
				if (!TryGetResolver(node.Type, out var typeResolver))
				{
					throw new NotSupportedException($"New instance are not supported for {node.Type} when convert to BsonExpression ({node.ToString()}).");
				}
				string text = typeResolver.ResolveCtor(node.Constructor);
				if (text == null)
				{
					throw new NotSupportedException("Constructor for " + node.Type.Name + " are not supported when convert to BsonExpression (" + node.ToString() + ").");
				}
				ResolvePattern(text, null, node.Arguments);
			}
			else
			{
				_builder.Append("{ ");
				for (int i = 0; i < node.Members.Count; i++)
				{
					MemberInfo memberInfo = node.Members[i];
					_builder.Append((i > 0) ? ", " : "");
					_builder.AppendFormat("'{0}': ", memberInfo.Name);
					Visit(node.Arguments[i]);
				}
				_builder.Append(" }");
			}
			return node;
		}

		protected override Expression VisitMemberInit(MemberInitExpression node)
		{
			if (node.NewExpression.Constructor.GetParameters().Length != 0)
			{
				throw new NotSupportedException($"New instance of {node.Type} are not supported because contains ctor with parameter. Try use only property initializers: `new {node.Type.Name} {{ PropA = 1, PropB == \"John\" }}`.");
			}
			_builder.Append("{");
			for (int i = 0; i < node.Bindings.Count; i++)
			{
				MemberAssignment memberAssignment = node.Bindings[i] as MemberAssignment;
				string text = ResolveMember(memberAssignment.Member);
				_builder.Append((i > 0) ? ", " : "");
				_builder.Append(text.Substring(1));
				_builder.Append(":");
				Visit(memberAssignment.Expression);
			}
			_builder.Append("}");
			return node;
		}

		protected override Expression VisitNewArray(NewArrayExpression node)
		{
			_builder.Append("[ ");
			for (int i = 0; i < node.Expressions.Count; i++)
			{
				_builder.Append((i > 0) ? ", " : "");
				Visit(node.Expressions[i]);
			}
			_builder.Append(" ]");
			return node;
		}

		protected override Expression VisitBinary(BinaryExpression node)
		{
			bool ensurePredicate = node.NodeType == ExpressionType.AndAlso || node.NodeType == ExpressionType.OrElse;
			if (node.NodeType == ExpressionType.Coalesce)
			{
				return VisitCoalesce(node);
			}
			if (node.NodeType == ExpressionType.ArrayIndex)
			{
				return VisitArrayIndex(node);
			}
			string @operator = GetOperator(node.NodeType);
			_builder.Append("(");
			VisitAsPredicate(node.Left, ensurePredicate);
			_builder.Append(@operator);
			if (!_mapper.EnumAsInteger && node.Left.NodeType == ExpressionType.Convert && node.Left is UnaryExpression unaryExpression && unaryExpression.Operand.Type.GetTypeInfo().IsEnum && unaryExpression.Type == typeof(int))
			{
				VisitAsPredicate(Expression.Constant(Enum.GetName(unaryExpression.Operand.Type, Evaluate(node.Right))), ensurePredicate);
			}
			else
			{
				VisitAsPredicate(node.Right, ensurePredicate);
			}
			_builder.Append(")");
			return node;
		}

		protected override Expression VisitConditional(ConditionalExpression node)
		{
			_builder.Append("IIF(");
			Visit(node.Test);
			_builder.Append(", ");
			Visit(node.IfTrue);
			_builder.Append(", ");
			Visit(node.IfFalse);
			_builder.Append(")");
			return node;
		}

		private Expression VisitCoalesce(BinaryExpression node)
		{
			_builder.Append("COALESCE(");
			Visit(node.Left);
			_builder.Append(", ");
			Visit(node.Right);
			_builder.Append(")");
			return node;
		}

		private Expression VisitArrayIndex(BinaryExpression node)
		{
			Visit(node.Left);
			_builder.Append("[");
			object value = Evaluate(node.Right, typeof(int));
			_builder.Append(value);
			_builder.Append("]");
			return node;
		}

		private void ResolvePattern(string pattern, Expression obj, IList<Expression> args)
		{
			Tokenizer tokenizer = new Tokenizer(pattern);
			while (!tokenizer.EOF)
			{
				Token token = tokenizer.ReadToken(eatWhitespace: false);
				if (token.Type == TokenType.Hashtag)
				{
					Visit(obj);
				}
				else if (token.Type == TokenType.At && tokenizer.LookAhead(eatWhitespace: false).Type == TokenType.Int)
				{
					int index = Convert.ToInt32(tokenizer.ReadToken(eatWhitespace: false).Expect(TokenType.Int).Value);
					Visit(args[index]);
				}
				else if (token.Type == TokenType.Percent)
				{
					VisitEnumerablePredicate(args[1] as LambdaExpression);
				}
				else
				{
					_builder.Append((token.Type == TokenType.String) ? ("'" + token.Value + "'") : token.Value);
				}
			}
		}

		private void VisitEnumerablePredicate(LambdaExpression lambda)
		{
			Expression body = lambda.Body;
			if (body is BinaryExpression binaryExpression)
			{
				if (binaryExpression.Left.NodeType != ExpressionType.Parameter)
				{
					throw new LiteException(0, "Any/All requires simple parameter on left side. Eg: `x => x.Phones.Select(p => p.Number).Any(n => n > 5)`");
				}
				string @operator = GetOperator(binaryExpression.NodeType);
				_builder.Append(@operator);
				VisitAsPredicate(binaryExpression.Right, ensurePredicate: false);
				return;
			}
			if (body is MethodCallExpression methodCallExpression)
			{
				if (methodCallExpression.Object.NodeType != ExpressionType.Parameter)
				{
					throw new NotSupportedException("Any/All requires simple parameter on left side. Eg: `x.Customers.Select(c => c.Name).Any(n => n.StartsWith('J'))`");
				}
				if (!TryGetResolver(methodCallExpression.Method.DeclaringType, out var typeResolver))
				{
					throw new NotSupportedException("Method " + methodCallExpression.Method.Name + " not available to convert to BsonExpression inside Any/All call.");
				}
				string text = typeResolver.ResolveMethod(methodCallExpression.Method);
				if (text == null || !text.StartsWith("#"))
				{
					throw new NotSupportedException("Method " + methodCallExpression.Method.Name + " not available to convert to BsonExpression inside Any/All call.");
				}
				ResolvePattern(text.Substring(1), methodCallExpression.Object, methodCallExpression.Arguments);
				return;
			}
			throw new LiteException(0, "When using Any/All method test do only simple predicate variable. Eg: `x => x.Phones.Select(p => p.Number).Any(n => n > 5)`");
		}

		private string GetOperator(ExpressionType nodeType)
		{
			return nodeType switch
			{
				ExpressionType.Add => " + ", 
				ExpressionType.Multiply => " * ", 
				ExpressionType.Subtract => " - ", 
				ExpressionType.Divide => " / ", 
				ExpressionType.Equal => " = ", 
				ExpressionType.NotEqual => " != ", 
				ExpressionType.GreaterThan => " > ", 
				ExpressionType.GreaterThanOrEqual => " >= ", 
				ExpressionType.LessThan => " < ", 
				ExpressionType.LessThanOrEqual => " <= ", 
				ExpressionType.And => " AND ", 
				ExpressionType.AndAlso => " AND ", 
				ExpressionType.Or => " OR ", 
				ExpressionType.OrElse => " OR ", 
				_ => throw new NotSupportedException($"Operator not supported {nodeType}"), 
			};
		}

		private string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			bool flag = _dbRefType != null && member.DeclaringType.IsAssignableFrom(_dbRefType);
			MemberMapper memberMapper = _mapper.GetEntityMapper(member.DeclaringType).Members.FirstOrDefault((MemberMapper x) => x.MemberName == name);
			if (memberMapper == null)
			{
				throw new NotSupportedException($"Member {name} not found on BsonMapper for type {member.DeclaringType}.");
			}
			_dbRefType = (memberMapper.IsDbRef ? memberMapper.UnderlyingType : null);
			return "." + ((flag && memberMapper.FieldName == "_id") ? "$id" : memberMapper.FieldName);
		}

		private bool IsMethodIndexEval(MethodCallExpression node, out Expression obj, out Expression idx)
		{
			MethodInfo method = node.Method;
			_ = method.DeclaringType;
			ParameterInfo[] parameters = method.GetParameters();
			if (method.Name == "get_Item" && parameters.Length == 1 && (parameters[0].ParameterType == typeof(int) || parameters[0].ParameterType == typeof(string)))
			{
				obj = node.Object;
				idx = node.Arguments[0];
				return true;
			}
			obj = null;
			idx = null;
			return false;
		}

		private void VisitAsPredicate(Expression expr, bool ensurePredicate)
		{
			ensurePredicate = ensurePredicate && (expr.NodeType == ExpressionType.MemberAccess || expr.NodeType == ExpressionType.Call || expr.NodeType == ExpressionType.Invoke || expr.NodeType == ExpressionType.Constant);
			if (ensurePredicate)
			{
				_builder.Append("(");
				_builder.Append("(");
				base.Visit(expr);
				_builder.Append(")");
				_builder.Append(" = true)");
			}
			else
			{
				base.Visit(expr);
			}
		}

		private object Evaluate(Expression expr, params Type[] validTypes)
		{
			object value = null;
			if (expr.NodeType == ExpressionType.Constant)
			{
				ConstantExpression constantExpression = (ConstantExpression)expr;
				value = constantExpression.Value;
			}
			else
			{
				Delegate @delegate = Expression.Lambda(expr).Compile();
				value = @delegate.DynamicInvoke();
			}
			if (validTypes.Length != 0 && value == null)
			{
				throw new NotSupportedException($"Expression {expr} can't return null value");
			}
			if (validTypes.Length != 0 && !validTypes.Any((Type x) => x == value.GetType()))
			{
				throw new NotSupportedException(string.Format("Expression {0} must return on of this types: {1}", expr, string.Join(", ", validTypes.Select((Type x) => "`" + x.Name + "`"))));
			}
			return value;
		}

		private bool TryGetResolver(Type declaringType, out ITypeResolver typeResolver)
		{
			bool num = Reflection.IsCollection(declaringType);
			bool flag = Reflection.IsEnumerable(declaringType);
			bool flag2 = Reflection.IsNullable(declaringType);
			Type key = (num ? typeof(ICollection) : (flag ? typeof(Enumerable) : (flag2 ? typeof(Nullable) : declaringType)));
			return _resolver.TryGetValue(key, out typeResolver);
		}
	}
	internal class ParameterExpressionVisitor : ExpressionVisitor
	{
		public bool IsParameter { get; private set; }

		protected override Expression VisitParameter(ParameterExpression node)
		{
			IsParameter = true;
			return base.VisitParameter(node);
		}

		public static bool Test(Expression node)
		{
			ParameterExpressionVisitor parameterExpressionVisitor = new ParameterExpressionVisitor();
			parameterExpressionVisitor.Visit(node);
			return parameterExpressionVisitor.IsParameter;
		}
	}
	internal class BsonValueResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			switch (member.Name)
			{
			case "AsInt32":
			case "AsInt64":
			case "AsArray":
			case "AsDateTime":
			case "AsDocument":
			case "AsObjectId":
			case "AsString":
			case "AsBinary":
			case "AsDouble":
			case "AsBoolean":
			case "AsDecimal":
			case "AsGuid":
				return "#";
			case "IsNull":
				return "IS_NULL(#)";
			case "IsArray":
				return "IS_ARRAY(#)";
			case "IsDocument":
				return "IS_DOCUMENT(#)";
			case "IsInt32":
				return "IS_INT32(#)";
			case "IsInt64":
				return "IS_INT64(#)";
			case "IsDouble":
				return "IS_DOUBLE(#)";
			case "IsDecimal":
				return "IS_DECIMAL(#)";
			case "IsNumber":
				return "IS_NUMBER(#)";
			case "IsBinary":
				return "IS_BINARY(#)";
			case "IsBoolean":
				return "IS_BOOLEAN(#)";
			case "IsString":
				return "IS_STRING(#)";
			case "IsObjectId":
				return "IS_OBJECTID(#)";
			case "IsGuid":
				return "IS_GUID(#)";
			case "IsDateTime":
				return "IS_DATETIME(#)";
			case "IsMinValue":
				return "IS_MINVALUE(#)";
			case "IsMaxValue":
				return "IS_MAXVALUE(#)";
			default:
				return null;
			}
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class ConvertResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return method.Name switch
			{
				"ToInt32" => "INT32(@0)", 
				"ToInt64" => "INT64(@0)", 
				"ToDouble" => "DOUBLE(@0)", 
				"ToDecimal" => "DECIMAL(@0)", 
				"ToDateTime" => "DATE(@0)", 
				"FromBase64String" => "BINARY(@0)", 
				"ToBoolean" => "BOOL(@0)", 
				"ToString" => "STRING(@0)", 
				_ => null, 
			};
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class DateTimeResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			switch (method.Name)
			{
			case "AddYears":
				return "DATEADD('y', @0, #)";
			case "AddMonths":
				return "DATEADD('M', @0, #)";
			case "AddDays":
				return "DATEADD('d', @0, #)";
			case "AddHours":
				return "DATEADD('h', @0, #)";
			case "AddMinutes":
				return "DATEADD('m', @0, #)";
			case "AddSeconds":
				return "DATEADD('s', @0, #)";
			case "ToString":
			{
				ParameterInfo[] parameters = method.GetParameters();
				if (parameters.Length == 0)
				{
					return "STRING(#)";
				}
				if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
				{
					return "FORMAT(#, @0)";
				}
				break;
			}
			case "ToUniversalTime":
				return "TO_UTC(#)";
			case "Parse":
				return "DATETIME(@0)";
			case "Equals":
				return "# = @0";
			}
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			return member.Name switch
			{
				"Now" => "NOW()", 
				"UtcNow" => "NOW_UTC()", 
				"Today" => "TODAY()", 
				"Year" => "YEAR(#)", 
				"Month" => "MONTH(#)", 
				"Day" => "DAY(#)", 
				"Hour" => "HOUR(#)", 
				"Minute" => "MINUTE(#)", 
				"Second" => "SECOND(#)", 
				"Date" => "DATETIME(YEAR(#), MONTH(#), DAY(#))", 
				"ToLocalTime" => "TO_LOCAL(#)", 
				"ToUniversalTime" => "TO_UTC(#)", 
				_ => null, 
			};
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			ParameterInfo[] parameters = ctor.GetParameters();
			if (parameters.Length == 3 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == typeof(int) && parameters[2].ParameterType == typeof(int))
			{
				return "DATETIME(@0, @1, @2)";
			}
			return null;
		}
	}
	internal class EnumerableResolver : ITypeResolver
	{
		public virtual string ResolveMethod(MethodInfo method)
		{
			switch (Reflection.MethodName(method, 1))
			{
			case "AsEnumerable()":
				return "@0[*]";
			case "get_Item(int)":
				return "#[@0]";
			case "ElementAt(int)":
				return "@0[@1]";
			case "Single()":
			case "First()":
			case "SingleOrDefault()":
			case "FirstOrDefault()":
				return "@0[0]";
			case "Last()":
			case "LastOrDefault()":
				return "@0[-1]";
			case "Single(Func<T,TResult>)":
			case "First(Func<T,TResult>)":
			case "SingleOrDefault(Func<T,TResult>)":
			case "FirstOrDefault(Func<T,TResult>)":
				return "FIRST(FILTER(@0 => @1))";
			case "Last(Func<T,TResult>)":
			case "LastOrDefault(Func<T,TResult>)":
				return "LAST(FILTER(@0 => @1))";
			case "Where(Func<T,TResult>)":
				return "FILTER(@0 => @1)";
			case "Select(Func<T,TResult>)":
				return "MAP(@0 => @1)";
			case "Count()":
				return "COUNT(@0)";
			case "Sum()":
				return "SUM(@0)";
			case "Average()":
				return "AVG(@0)";
			case "Max()":
				return "MAX(@0)";
			case "Min()":
				return "MIN(@0)";
			case "Count(Func<T,TResult>)":
				return "COUNT(FILTER(@0 => @1))";
			case "Sum(Func<T,TResult>)":
				return "SUM(MAP(@0 => @1))";
			case "Average(Func<T,TResult>)":
				return "AVG(MAP(@0 => @1))";
			case "Max(Func<T,TResult>)":
				return "MAX(MAP(@0 => @1))";
			case "Min(Func<T,TResult>)":
				return "MIN(MAP(@0 => @1))";
			case "ToList()":
			case "ToArray()":
				return "ARRAY(@0)";
			case "Any(Func<T,TResult>)":
				return "@0 ANY %";
			case "All(Func<T,TResult>)":
				return "@0 ALL %";
			case "Any()":
				return "COUNT(@0) > 0";
			default:
				if (method.Name == "Contains")
				{
					return "@0 ANY = @1";
				}
				return null;
			}
		}

		public virtual string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "Length"))
			{
				if (name == "Count")
				{
					return "COUNT(#)";
				}
				return null;
			}
			return "LENGTH(#)";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class GuidResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return method.Name switch
			{
				"ToString" => "STRING(#)", 
				"NewGuid" => "GUID()", 
				"Parse" => "GUID(@0)", 
				"TryParse" => throw new NotSupportedException("There is no TryParse translate. Use Guid.Parse()"), 
				"Equals" => "# = @0", 
				_ => null, 
			};
		}

		public string ResolveMember(MemberInfo member)
		{
			if (member.Name == "Empty")
			{
				return "GUID('00000000-0000-0000-0000-000000000000')";
			}
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			ParameterInfo[] parameters = ctor.GetParameters();
			if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
			{
				return "GUID(@0)";
			}
			return null;
		}
	}
	internal class ICollectionResolver : EnumerableResolver
	{
		public override string ResolveMethod(MethodInfo method)
		{
			if (method.Name == "Contains")
			{
				return "# ANY = @0";
			}
			return base.ResolveMethod(method);
		}
	}
	internal interface ITypeResolver
	{
		string ResolveMethod(MethodInfo method);

		string ResolveMember(MemberInfo member);

		string ResolveCtor(ConstructorInfo ctor);
	}
	internal class MathResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			int num = method.GetParameters().Length;
			switch (method.Name)
			{
			case "Abs":
				return "ABS(@0)";
			case "Pow":
				return "POW(@0, @1)";
			case "Round":
				if (num != 2)
				{
					throw new ArgumentOutOfRangeException("Method Round need 2 arguments when convert to BsonExpression");
				}
				return "ROUND(@0, @1)";
			default:
				return null;
			}
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class NullableResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "HasValue"))
			{
				if (name == "Value")
				{
					return "#";
				}
				return null;
			}
			return "(IS_NULL(#) = false)";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class NumberResolver : ITypeResolver
	{
		private readonly string _parseMethod;

		public NumberResolver(string parseMethod)
		{
			_parseMethod = parseMethod;
		}

		public string ResolveMethod(MethodInfo method)
		{
			switch (method.Name)
			{
			case "ToString":
			{
				ParameterInfo[] parameters = method.GetParameters();
				if (parameters.Length == 0)
				{
					return "STRING(#)";
				}
				if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
				{
					return "FORMAT(#, @0)";
				}
				break;
			}
			case "Parse":
				return _parseMethod + "(@0)";
			case "Equals":
				return "# = @0";
			}
			return null;
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class ObjectIdResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			string name = method.Name;
			if (!(name == "ToString"))
			{
				if (name == "Equals")
				{
					return "# = @0";
				}
				return null;
			}
			return "STRING(#)";
		}

		public string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "Empty"))
			{
				if (name == "CreationTime")
				{
					return "OID_CREATIONTIME(#)";
				}
				return null;
			}
			return "OBJECTID('000000000000000000000000')";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			ParameterInfo[] parameters = ctor.GetParameters();
			if (parameters.Length == 1 && parameters[0].ParameterType == typeof(string))
			{
				return "OBJECTID(@0)";
			}
			return null;
		}
	}
	internal class RegexResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			string name = method.Name;
			if (!(name == "Split"))
			{
				if (name == "IsMatch")
				{
					return "IS_MATCH(@0, @1)";
				}
				return null;
			}
			return "SPLIT(@0, @1, true)";
		}

		public string ResolveMember(MemberInfo member)
		{
			return null;
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	internal class StringResolver : ITypeResolver
	{
		public string ResolveMethod(MethodInfo method)
		{
			int num = method.GetParameters().Length;
			switch (method.Name)
			{
			case "Count":
				return "LENGTH(#)";
			case "Trim":
				return "TRIM(#)";
			case "TrimStart":
				return "LTRIM(#)";
			case "TrimEnd":
				return "RTRIM(#)";
			case "ToUpper":
				return "UPPER(#)";
			case "ToUpperInvariant":
				return "UPPER(#)";
			case "ToLower":
				return "LOWER(#)";
			case "ToLowerInvariant":
				return "LOWER(#)";
			case "Replace":
				return "REPLACE(#, @0, @1)";
			case "PadLeft":
				return "LPAD(#, @0, @1)";
			case "RightLeft":
				return "RPAD(#, @0, @1)";
			case "IndexOf":
				if (num != 1)
				{
					return "INDEXOF(#, @0, @1)";
				}
				return "INDEXOF(#, @0)";
			case "Substring":
				if (num != 1)
				{
					return "SUBSTRING(#, @0, @1)";
				}
				return "SUBSTRING(#, @0)";
			case "StartsWith":
				return "# LIKE (@0 + '%')";
			case "Contains":
				return "# LIKE ('%' + @0 + '%')";
			case "EndsWith":
				return "# LIKE ('%' + @0)";
			case "ToString":
				return "#";
			case "Equals":
				return "# = @0";
			case "IsNullOrEmpty":
				return "(LENGTH(@0) = 0)";
			case "IsNullOrWhiteSpace":
				return "(LENGTH(TRIM(@0)) = 0)";
			case "Format":
				throw new NotImplementedException();
			case "Join":
				throw new NotImplementedException();
			default:
				return null;
			}
		}

		public string ResolveMember(MemberInfo member)
		{
			string name = member.Name;
			if (!(name == "Length"))
			{
				if (name == "Empty")
				{
					return "''";
				}
				return null;
			}
			return "LENGTH(#)";
		}

		public string ResolveCtor(ConstructorInfo ctor)
		{
			return null;
		}
	}
	public class MemberMapper
	{
		public bool AutoId { get; set; }

		public string MemberName { get; set; }

		public Type DataType { get; set; }

		public string FieldName { get; set; }

		public GenericGetter Getter { get; set; }

		public GenericSetter Setter { get; set; }

		public Func<object, BsonMapper, BsonValue> Serialize { get; set; }

		public Func<BsonValue, BsonMapper, object> Deserialize { get; set; }

		public bool IsDbRef { get; set; }

		public bool IsEnumerable { get; set; }

		public Type UnderlyingType { get; set; }

		public bool IsIgnore { get; set; }
	}
	public delegate object CreateObject(BsonDocument value);
	public delegate void GenericSetter(object target, object value);
	public delegate object GenericGetter(object obj);
	internal class Reflection
	{
		private static readonly Dictionary<Type, CreateObject> _cacheCtor = new Dictionary<Type, CreateObject>();

		public static readonly Dictionary<Type, PropertyInfo> ConvertType = new Dictionary<Type, PropertyInfo>
		{
			[typeof(DateTime)] = typeof(BsonValue).GetProperty("AsDateTime"),
			[typeof(decimal)] = typeof(BsonValue).GetProperty("AsDecimal"),
			[typeof(double)] = typeof(BsonValue).GetProperty("AsDouble"),
			[typeof(long)] = typeof(BsonValue).GetProperty("AsInt64"),
			[typeof(int)] = typeof(BsonValue).GetProperty("AsInt32"),
			[typeof(bool)] = typeof(BsonValue).GetProperty("AsBoolean"),
			[typeof(byte[])] = typeof(BsonValue).GetProperty("AsBinary"),
			[typeof(BsonDocument)] = typeof(BsonValue).GetProperty("AsDocument"),
			[ty