forked from ThatRendle/Simple.Data
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDataStrategy.cs
More file actions
173 lines (141 loc) · 10 KB
/
DataStrategy.cs
File metadata and controls
173 lines (141 loc) · 10 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using Simple.Data.Commands;
namespace Simple.Data
{
/// <summary>
/// This class supports the Simple.Data framework internally and should not be used in your code.
/// </summary>
public abstract class DataStrategy : DynamicObject
{
private readonly ConcurrentDictionary<string, dynamic> _members = new ConcurrentDictionary<string, dynamic>();
public abstract Adapter GetAdapter();
/// <summary>
/// Provides the implementation for operations that get member values. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for operations such as getting a value for a property.
/// </summary>
/// <param name="binder">Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive.</param>
/// <param name="result">The result of the get operation. For example, if the method is called for a property, you can assign the property value to <paramref name="result"/>.</param>
/// <returns>
/// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.)
/// </returns>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
return GetDynamicMember(binder, out result);
}
protected virtual bool GetDynamicMember(GetMemberBinder binder, out object result)
{
result = GetOrAddDynamicReference(binder.Name);
return true;
}
private dynamic GetOrAddDynamicReference(string name)
{
return _members.GetOrAdd(name, CreateDynamicReference);
}
internal bool TryInvokeFunction(String functionName, Func<IDictionary<String,Object>> getFunctionArguments, out object result)
{
var adapterWithFunctions = GetAdapter() as IAdapterWithFunctions;
if (adapterWithFunctions != null && adapterWithFunctions.IsValidFunction(functionName))
{
var command = new ExecuteFunctionCommand(GetDatabase(), adapterWithFunctions, functionName, getFunctionArguments());
return ExecuteFunction(out result, command);
}
result = null;
return false;
}
protected abstract bool ExecuteFunction(out object result, ExecuteFunctionCommand command);
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
if (this.TryInvokeFunction(binder.Name, () => binder.ArgumentsToDictionary(args), out result)) return true;
return base.TryInvokeMember(binder, args, out result);
}
public dynamic this[string name]
{
get { return GetOrAddDynamicReference(name); }
}
private ObjectReference CreateDynamicReference(string name)
{
return new ObjectReference(name, this);
}
internal DynamicTable SetMemberAsTable(ObjectReference reference)
{
if (reference == null) throw new ArgumentNullException("reference");
_members.TryUpdate(reference.GetName(), new DynamicTable(reference.GetName(), this), reference);
return (DynamicTable)_members[reference.GetName()];
}
internal DynamicTable SetMemberAsTable(ObjectReference reference, DynamicTable table)
{
if (reference == null) throw new ArgumentNullException("reference");
_members.TryUpdate(reference.GetName(), table, reference);
return (DynamicTable)_members[reference.GetName()];
}
internal DynamicSchema SetMemberAsSchema(ObjectReference reference)
{
if (reference == null) throw new ArgumentNullException("reference");
_members.TryUpdate(reference.GetName(), new DynamicSchema(reference.GetName(), this), reference);
return (DynamicSchema)_members[reference.GetName()];
}
internal DynamicSchema SetMemberAsSchema(ObjectReference reference, DynamicSchema schema)
{
if (reference == null) throw new ArgumentNullException("reference");
_members.TryUpdate(reference.GetName(), schema, reference);
return (DynamicSchema)_members[reference.GetName()];
}
protected internal abstract Database GetDatabase();
/// <summary>
/// Finds data from the specified "table".
/// </summary>
/// <param name="tableName">Name of the table.</param>
/// <param name="criteria">The criteria. This may be <c>null</c>, in which case all records should be returned.</param>
/// <returns>The list of records matching the criteria. If no records are found, return an empty list.</returns>
internal abstract IEnumerable<IDictionary<string, object>> Find(string tableName, SimpleExpression criteria);
/// <summary>
/// Inserts a record into the specified "table".
/// </summary><param name="tableName">Name of the table.</param><param name="data">The values to insert.</param><returns>If possible, return the newly inserted row, including any automatically-set values such as primary keys or timestamps.</returns>
internal abstract IEnumerable<IDictionary<string, object>> InsertMany(string tableName, IEnumerable<IDictionary<string, object>> enumerable, ErrorCallback onError, bool resultRequired);
/// <summary>
/// Inserts many records into the specified "table".
/// </summary><param name="tableName">Name of the table.</param><param name="data">The values to insert.</param><returns>If possible, return the newly inserted row, including any automatically-set values such as primary keys or timestamps.</returns>
internal abstract IDictionary<string, object> Insert(string tableName, IDictionary<string, object> data, bool resultRequired);
/// <summary>
/// Updates the specified "table" according to specified criteria.
/// </summary><param name="tableName">Name of the table.</param><param name="data">The new values.</param><param name="criteria">The expression to use as criteria for the update operation.</param><returns>The number of records affected by the update operation.</returns>
internal abstract int Update(string tableName, IDictionary<string, object> data, SimpleExpression criteria);
/// <summary>
/// Deletes from the specified table.
/// </summary><param name="tableName">Name of the table.</param><param name="criteria">The expression to use as criteria for the delete operation.</param><returns>The number of records which were deleted.</returns>
internal abstract int Delete(string tableName, SimpleExpression criteria);
internal abstract IDictionary<string, object> FindOne(string getQualifiedName, SimpleExpression criteriaExpression);
internal abstract int UpdateMany(string tableName, IList<IDictionary<string, object>> dataList);
internal bool IsExpressionFunction(string name, object[] args)
{
return GetAdapter().IsExpressionFunction(name, args);
}
internal abstract int UpdateMany(string tableName, IList<IDictionary<string, object>> dataList, IEnumerable<string> criteriaFieldNames);
internal abstract int UpdateMany(string tableName, IList<IDictionary<string, object>> newValuesList,
IList<IDictionary<string, object>> originalValuesList);
public abstract int Update(string tableName, IDictionary<string, object> newValuesDict, IDictionary<string, object> originalValuesDict);
protected static SimpleExpression CreateCriteriaFromOriginalValues(string tableName, IDictionary<string, object> newValuesDict, IDictionary<string, object> originalValuesDict)
{
var criteriaValues = originalValuesDict
.Where(originalKvp => newValuesDict.ContainsKey(originalKvp.Key) && !(Equals(newValuesDict[originalKvp.Key], originalKvp.Value)));
return ExpressionHelper.CriteriaDictionaryToExpression(tableName, criteriaValues);
}
protected static Dictionary<string, object> CreateChangedValuesDict(IEnumerable<KeyValuePair<string, object>> newValuesDict, IDictionary<string, object> originalValuesDict)
{
var changedValuesDict =
newValuesDict.Where(
kvp =>
(!originalValuesDict.ContainsKey(kvp.Key)) || !(Equals(kvp.Value, originalValuesDict[kvp.Key])))
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
return changedValuesDict;
}
public abstract IEnumerable<IDictionary<string, object>> UpsertMany(string tableName, IList<IDictionary<string, object>> list, IEnumerable<string> keyFieldNames, bool isResultRequired, ErrorCallback errorCallback);
public abstract IDictionary<string,object> Upsert(string tableName, IDictionary<string, object> dict, SimpleExpression criteriaExpression, bool isResultRequired);
public abstract IEnumerable<IDictionary<string, object>> UpsertMany(string tableName, IList<IDictionary<string, object>> list, bool isResultRequired, ErrorCallback errorCallback);
public abstract IDictionary<string,object> Get(string tableName, object[] args);
}
}