3using System.Threading.Tasks;
45 KeyValuePair<VariableReference, bool>[] Order,
ScriptNode Node)
48 KeyValuePair<VariableReference, bool>[] LeftOrder = await
Reduce(this.
Left, Order);
54 e =
new LeftOuterJoinEnumerator(e, this.
Left.
Name,
this.Right,
this.Right.Name, Generic, RightWhere,
Variables,
this.Flipped);
62 if (Top !=
int.MaxValue)
74 private readonly
string leftName;
75 private readonly
string rightName;
76 private readonly
bool hasLeftName;
77 private readonly
bool flipped;
78 private readonly
bool generic;
79 private bool rightFirst;
89 this.leftName = LeftName;
90 this.rightName = RightName;
91 this.rightSource = RightSource;
92 this.generic = Generic;
95 this.hasLeftName = !
string.IsNullOrEmpty(this.leftName);
99 public object Current => this.current;
101 public void Dispose()
106 public bool MoveNext()
108 return this.MoveNextAsync().Result;
111 public async Task<bool> MoveNextAsync()
115 if (!(this.right is
null))
117 bool First = this.rightFirst;
118 this.rightFirst =
false;
123 this.current =
new JoinedObject(this.right.Current,
this.rightName,
this.left.Current,
this.leftName);
125 this.current =
new JoinedObject(this.left.Current,
this.leftName,
this.right.Current,
this.rightName);
135 if (this.defaultRight is
null)
137 this.defaultRight =
new GenericObject(this.rightSource.CollectionName,
138 typeof(
GenericObject).FullName, Guid.Empty, Array.Empty<KeyValuePair<string, object>>());
142 this.current =
new JoinedObject(this.defaultRight, this.rightName, this.left.Current,
this.leftName);
144 this.current =
new JoinedObject(this.left.Current,
this.leftName,
this.defaultRight,
this.rightName);
151 if (!await this.left.MoveNextAsync())
154 if (this.leftVariables is
null)
155 this.leftVariables =
new ObjectProperties(this.left.Current,
this.variables);
157 this.leftVariables.Object = this.left.Current;
159 if (this.hasLeftName)
160 this.leftVariables[this.leftName] = this.left.Current;
162 this.right = await this.rightSource.Find(0,
int.MaxValue, this.
generic, this.conditions, this.leftVariables,
163 null, this.conditions);
165 this.rightFirst =
true;
195 KeyValuePair<VariableReference, bool>[] LeftOrder = await
Reduce(this.Left, Order);
198 RightWhere = this.
Combine(RightWhere, this.Conditions);
200 if (Top !=
int.MaxValue)
206 if (!(Where is
null))
209 Processor =
new OuterJoinLeftProcessor(Processor, this.Left.Name,
this.Right,
210 this.Right.Name, Generic, RightWhere,
Variables,
this.Flipped);
212 return await this.Left.Process(Processor, 0,
int.MaxValue, Generic,
216 internal class OuterJoinLeftProcessor :
IProcessor<object>
218 private readonly OuterJoinRightProcessor rightProcessor;
222 private readonly
string leftName;
223 private readonly
bool hasLeftName;
224 private readonly
bool generic;
228 IDataSource RightSource,
string RightName,
bool Generic,
231 this.rightProcessor =
new OuterJoinRightProcessor(Processor, LeftName,
232 RightSource, RightName,
Flipped);
234 this.leftName = LeftName;
235 this.rightSource = RightSource;
236 this.generic = Generic;
239 this.hasLeftName = !
string.IsNullOrEmpty(this.leftName);
242 public bool IsAsynchronous =>
true;
243 public bool Process(
object Object) => this.ProcessAsync(Object).Result;
244 public bool Flush() => this.rightProcessor.Flush();
245 public Task<bool> FlushAsync() => this.rightProcessor.FlushAsync();
247 public async Task<bool> ProcessAsync(
object Object)
249 if (this.leftVariables is
null)
252 this.leftVariables.Object = Object;
254 if (this.hasLeftName)
255 this.leftVariables[this.leftName] = Object;
257 this.rightProcessor.CurrentLeft = Object;
259 return await this.rightSource.Process(this.rightProcessor, 0,
int.MaxValue,
260 this.
generic, this.conditions, this.leftVariables,
null, this.conditions);
264 private class OuterJoinRightProcessor :
IProcessor<object>
268 private readonly
string leftName;
269 private readonly
string rightName;
270 private readonly
bool flipped;
272 private object currentLeft =
null;
273 private bool firstRight =
true;
278 this.processor = Processor;
279 this.leftName = LeftName;
280 this.rightSource = RightSource;
281 this.rightName = RightName;
285 public object CurrentLeft
287 get => this.currentLeft;
290 this.currentLeft = value;
291 this.firstRight =
true;
295 public bool IsAsynchronous => this.processor.IsAsynchronous;
297 public bool Process(
object Object)
299 this.firstRight =
false;
303 return this.processor.Process(
new JoinedObject(Object, this.rightName,
304 this.CurrentLeft, this.leftName));
308 return this.processor.Process(
new JoinedObject(this.CurrentLeft,
309 this.leftName, Object, this.rightName));
315 this.firstRight =
false;
319 return this.processor.ProcessAsync(
new JoinedObject(Object, this.rightName,
320 this.CurrentLeft, this.leftName));
324 return this.processor.ProcessAsync(
new JoinedObject(this.CurrentLeft,
325 this.leftName, Object, this.rightName));
333 if (this.defaultRight is
null)
335 this.defaultRight =
new GenericObject(this.rightSource.CollectionName,
337 Array.Empty<KeyValuePair<string, object>>());
340 this.
Process(this.defaultRight);
343 return this.processor.Flush();
346 public async Task<bool> FlushAsync()
350 if (this.defaultRight is
null)
352 this.defaultRight =
new GenericObject(this.rightSource.CollectionName,
354 Array.Empty<KeyValuePair<string, object>>());
360 return await this.processor.FlushAsync();
Generic object. Contains a sequence of properties.
Base class for all nodes in a parsed script tree.
Enumerator that only returns elements matching a set of conditions.
Enumerator that limits the return set to a maximum number of records.
Enumerator that skips a given number of result records.
Processor that only processes elements matching a set of conditions.
Processor that limits the return set to a maximum number of records.
Processor that skips a given number of result records.
Represents a joined object.
Abstract base classes of joined sources.
ScriptNode Conditions
Conditions for join.
ScriptNode Combine(ScriptNode Where, ScriptNode On)
Combines one or two restrictions.
IDataSource Left
Left source
static async Task< ScriptNode > Reduce(IDataSource Source, ScriptNode Where)
Reduces a where clause to fit the current data source.
IDataSource Right
Right source
Data source formed through an LEFT [OUTER] JOIN of two sources.
LeftOuterJoinedSource(IDataSource Left, IDataSource Right, ScriptNode Conditions)
Data source formed through an LEFT [OUTER] JOIN of two sources.
override async Task< bool > Process(IProcessor< object > Processor, int Offset, int Top, bool Generic, ScriptNode Where, Variables Variables, KeyValuePair< VariableReference, bool >[] Order, ScriptNode Node)
Processes objects matching filter conditions in Where .
override async Task< IResultSetEnumerator > Find(int Offset, int Top, bool Generic, ScriptNode Where, Variables Variables, KeyValuePair< VariableReference, bool >[] Order, ScriptNode Node)
Finds objects matching filter conditions in Where .
virtual bool Flipped
If sources should be flipped in the JoinedObject instances created.
Task< bool > MoveNextAsync()
Advances the enumerator to the next element of the collection.
Interface for processors of objects.
bool Process(T Object)
Processes an object synchronously.
Task< bool > ProcessAsync(T Object)
Processes an object asynchronously.
Interface for result-set enumerators.
Interface for data sources that can be used in SQL statements.
Task< IResultSetEnumerator > Find(int Offset, int Top, bool Generic, ScriptNode Where, Variables Variables, KeyValuePair< VariableReference, bool >[] Order, ScriptNode Node)
Finds objects matching filter conditions in Where .
string Name
Collection name or alias.