namespace Simple.Data { using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using QueryPolyfills; public partial class InMemoryAdapter : Adapter { private readonly Dictionary _autoIncrementColumns = new Dictionary(); private readonly Dictionary _keyColumns = new Dictionary(); private readonly Dictionary>> _tables = new Dictionary>>(); private readonly ICollection _joins = new Collection(); private List> GetTable(string tableName) { tableName = tableName.ToLowerInvariant(); if (!_tables.ContainsKey(tableName)) _tables.Add(tableName, new List>()); return _tables[tableName]; } public override IDictionary GetKey(string tableName, IDictionary record) { if (!_keyColumns.ContainsKey(tableName)) return null; return _keyColumns[tableName].ToDictionary(key => key, key => record.ContainsKey(key) ? record[key] : null); } public override IList GetKeyNames(string tableName) { if (!_keyColumns.ContainsKey(tableName)) return null; return _keyColumns[tableName]; } public override IDictionary Get(string tableName, params object[] keyValues) { if (!_keyColumns.ContainsKey(tableName)) throw new InvalidOperationException("No key specified for In-Memory table."); var keys = _keyColumns[tableName]; if (keys.Length != keyValues.Length) throw new ArgumentException("Incorrect number of values for key."); var expression = new ObjectReference(keys[0]) == keyValues[0]; for (int i = 1; i < keyValues.Length; i++) { expression = expression && new ObjectReference(keys[i]) == keyValues[i]; } return Find(tableName, expression).FirstOrDefault(); } public override IEnumerable> Find(string tableName, SimpleExpression criteria) { var whereClauseHandler = new WhereClauseHandler(new WhereClause(criteria)); return whereClauseHandler.Run(GetTable(tableName)); } public override IEnumerable> RunQuery(SimpleQuery query, out IEnumerable unhandledClauses) { unhandledClauses = query.Clauses.AsEnumerable(); return GetTable(query.TableName); } public override IDictionary Insert(string tableName, IDictionary data, bool resultRequired) { if (_autoIncrementColumns.ContainsKey(tableName)) { var table = GetTable(tableName); var autoIncrementColumn = _autoIncrementColumns[tableName]; if(!data.ContainsKey(autoIncrementColumn)) { data.Add(autoIncrementColumn, 0); } object nextVal = 0; if(table.Count > 0) { nextVal = table.Select(d => d[autoIncrementColumn]).Max(); ; } nextVal = ObjectMaths.Increment(nextVal); data[autoIncrementColumn] = nextVal; } GetTable(tableName).Add(data); AddAsDetail(tableName, data); AddAsMaster(tableName, data); return data; } private void AddAsDetail(string tableName, IDictionary data) { foreach (var @join in _joins.Where(j => j.DetailTableName.Equals(tableName, StringComparison.OrdinalIgnoreCase))) { if (!data.ContainsKey(@join.DetailKey)) continue; foreach ( var master in GetTable(@join.MasterTableName).Where( d => d.ContainsKey(@join.MasterKey) && d[@join.MasterKey].Equals(data[@join.DetailKey]))) { data[@join.MasterPropertyName] = master; if (!master.ContainsKey(@join.DetailPropertyName)) { master.Add(@join.DetailPropertyName, new List> {data}); } else { ((List>) master[@join.DetailPropertyName]).Add(data); } } } } private void AddAsMaster(string tableName, IDictionary data) { foreach (var @join in _joins.Where(j => j.MasterTableName.Equals(tableName, StringComparison.OrdinalIgnoreCase))) { if (!data.ContainsKey(@join.MasterKey)) continue; foreach ( var detail in GetTable(@join.DetailTableName).Where( d => d.ContainsKey(@join.DetailKey) && d[@join.DetailKey].Equals(data[@join.MasterKey]))) { detail[@join.MasterPropertyName] = data; if (!data.ContainsKey(@join.DetailPropertyName)) { data.Add(@join.DetailPropertyName, new List> {data}); } else { ((List>) data[@join.DetailPropertyName]).Add(data); } } } } public override int Update(string tableName, IDictionary data, SimpleExpression criteria) { int count = 0; foreach (var record in Find(tableName, criteria)) { UpdateRecord(data, record); ++count; } return count; } private static void UpdateRecord(IDictionary data, IDictionary record) { foreach (var kvp in data) { record[kvp.Key] = kvp.Value; } } public override int Delete(string tableName, SimpleExpression criteria) { List> deletions = Find(tableName, criteria).ToList(); foreach (var record in deletions) { GetTable(tableName).Remove(record); } return deletions.Count; } public override bool IsExpressionFunction(string functionName, params object[] args) { return (functionName.Equals("like", StringComparison.OrdinalIgnoreCase) || functionName.Equals("notlike", StringComparison.OrdinalIgnoreCase)) && args.Length == 1 && args[0] is string; } public void SetAutoIncrementColumn(string tableName, string columnName) { _autoIncrementColumns.Add(tableName, columnName); } public void SetKeyColumn(string tableName, string columnName) { _keyColumns[tableName] = new[] {columnName}; } public void SetAutoIncrementKeyColumn(string tableName, string columnName) { SetKeyColumn(tableName, columnName); SetAutoIncrementColumn(tableName, columnName); } public void SetKeyColumns(string tableName, params string[] columnNames) { _keyColumns[tableName] = columnNames; } /// /// Set up an implicit join between two tables. /// /// The name of the 'master' table /// The 'primary key' /// The name to give the lookup property in the detail objects /// The name of the 'master' table /// The 'foreign key' /// The name to give the collection property in the master object public void ConfigureJoin(string masterTableName, string masterKey, string masterPropertyName, string detailTableName, string detailKey, string detailPropertyName) { var join = new Join(masterTableName, masterKey, masterPropertyName, detailTableName, detailKey, detailPropertyName); _joins.Add(join); } public class Join { private readonly string _masterTableName; private readonly string _masterKey; private readonly string _masterPropertyName; private readonly string _detailTableName; private readonly string _detailKey; private readonly string _detailPropertyName; public Join(string masterTableName, string masterKey, string masterPropertyName, string detailTableName, string detailKey, string detailPropertyName) { _masterTableName = masterTableName; _masterKey = masterKey; _masterPropertyName = masterPropertyName; _detailTableName = detailTableName; _detailKey = detailKey; _detailPropertyName = detailPropertyName; } public string DetailPropertyName { get { return _detailPropertyName; } } public string DetailKey { get { return _detailKey; } } public string DetailTableName { get { return _detailTableName; } } public string MasterPropertyName { get { return _masterPropertyName; } } public string MasterKey { get { return _masterKey; } } public string MasterTableName { get { return _masterTableName; } } } public IDictionary Upsert(string tableName, IDictionary dict, SimpleExpression criteriaExpression, bool isResultRequired, IAdapterTransaction adapterTransaction) { return Upsert(tableName, dict, criteriaExpression, isResultRequired); } public IEnumerable> UpsertMany(string tableName, IList> list, IEnumerable keyFieldNames, IAdapterTransaction adapterTransaction, bool isResultRequired, Func,Exception,bool> errorCallback) { return UpsertMany(tableName, list, keyFieldNames, isResultRequired, errorCallback); } public IEnumerable> UpsertMany(string tableName, IList> list, IAdapterTransaction adapterTransaction, bool isResultRequired, Func, Exception, bool> errorCallback) { return UpsertMany(tableName, list, isResultRequired, errorCallback); } public IDictionary Get(string tableName, IAdapterTransaction transaction, params object[] parameterValues) { return Get(tableName, parameterValues); } } }