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
142 lines (116 loc) · 6.09 KB
/
DataStrategy.cs
File metadata and controls
142 lines (116 loc) · 6.09 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
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
{
using System.Reflection;
/// <summary>
/// This class supports the Simple.Data framework internally and should not be used in your code.
/// </summary>
public abstract class DataStrategy : DynamicObject, ICloneable
{
private readonly ConcurrentDictionary<string, dynamic> _members = new ConcurrentDictionary<string, dynamic>();
protected DataStrategy() {}
protected DataStrategy(DataStrategy copy)
{
_members = copy._members;
}
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 internal abstract bool ExecuteFunction(out object result, ExecuteFunctionCommand command);
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
{
if (TryInvokeFunction(binder.Name, () => binder.ArgumentsToDictionary(args), out result)) return true;
if (new AdapterMethodDynamicInvoker(GetAdapter()).TryInvokeMember(binder, 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 DataStrategy GetDatabase();
internal bool IsExpressionFunction(string name, object[] args)
{
return GetAdapter().IsExpressionFunction(name, args);
}
internal abstract RunStrategy Run { get; }
object ICloneable.Clone()
{
return Clone();
}
protected internal abstract DataStrategy Clone();
public dynamic WithOptions(OptionsBase options)
{
return new DataStrategyWithOptions(this, options);
}
public virtual dynamic ClearOptions()
{
return this;
}
}
}