public override async IAsyncEnumerable <Path> ComputeSelect(EvaluationContext ctx) { if (ListCandidate != null && Template != null) { // Expression select var select = ListCandidate.ComputeSelect(ctx); await foreach (var atom in select) { yield return(atom); } // Expression paths var paths = ListCandidate.ComputePaths(ctx); await foreach (var path in paths) { yield return(path.Append("Id")); } // Inner template select var scopedCtx = ctx.Clone(); scopedCtx.SetLocalVariable(IteratorVariableName, new EvaluationVariable( eval: TemplateUtil.VariableThatThrows(IteratorVariableName), selectResolver: () => select, pathsResolver: () => paths )); await foreach (var atom in Template.ComputeSelect(scopedCtx)) { yield return(atom); } } }
public override async Task GenerateOutputs(EvaluationContext ctx) { _listCandidate ??= TemplexBase.Parse(ListExpression); if (_listCandidate != null) { var listObj = (await _listCandidate.Evaluate(ctx)) ?? new List <object>(); if (listObj is IList list) { foreach (var listItem in list) { // Initialize new evaluation context with the new variable in it var scopedCtx = ctx.Clone(); scopedCtx.SetLocalVariable(IteratorVariableName, new EvaluationVariable( evalAsync: () => Task.FromResult(listItem), selectResolver: () => AsyncUtil.Empty <Path>(), // It doesn't matter when generating output pathsResolver: () => AsyncUtil.Empty <Path>() // It doesn't matter when generating output )); // Run the template again on that context await Inner.GenerateOutputs(scopedCtx); } } else { throw new TemplateException($"Expression does not evaluate to a list ({_listCandidate})."); } } }
public override async Task GenerateOutputs(EvaluationContext ctx) { if (ctx.TryGetApiResult(QueryInfo, out object result)) { ctx = ctx.Clone(); ctx.SetLocalVariable(VariableName, new EvaluationVariable(value: result)); } await Inner.GenerateOutputs(ctx); }
/// <summary> /// Clones the <see cref="EvaluationContext"/> and returns a new one that contains the new variable. /// </summary> private EvaluationContext GetScopeLocalContext(EvaluationContext ctx) { var variable = new EvaluationVariable( evalAsync: () => Value.Evaluate(ctx), selectResolver: () => Value.ComputeSelect(ctx), pathsResolver: () => Value.ComputePaths(ctx)); var ctxClone = ctx.Clone(); ctxClone.SetLocalVariable(VariableName, variable); return(ctxClone); }
public override async IAsyncEnumerable <Path> ComputeSelect(EvaluationContext ctx) { var ctxClone = ctx.Clone(); ctxClone.SetLocalVariable(VariableName, new EvaluationVariable( eval: TemplateUtil.VariableThatThrows(varName: VariableName), // This is what makes it a "static" context pathsResolver: () => AsyncUtil.Singleton(Path.Empty(QueryInfo)) )); await foreach (var path in Inner.ComputeSelect(ctxClone)) { yield return(path); } }
/// <summary> /// Clones the <see cref="EvaluationContext"/> and returns a new one that contains the new variable. /// </summary> private EvaluationContext GetScopeLocalContext(EvaluationContext ctx) { _varExpression ??= TemplexBase.Parse(VariableExpression); var variable = new EvaluationVariable( evalAsync: () => _varExpression.Evaluate(ctx), selectResolver: () => _varExpression.ComputeSelect(ctx), pathsResolver: () => _varExpression.ComputePaths(ctx)); var ctxClone = ctx.Clone(); ctxClone.SetLocalVariable(VariableName, variable); return(ctxClone); }
public override async Task GenerateOutput(StringBuilder builder, EvaluationContext ctx, Func <string, string> encodeFunc = null) { if (ListCandidate != null && Template != null) { var listObj = (await ListCandidate.Evaluate(ctx)) ?? new List <object>(); if (listObj is IList list) { int index = 0; foreach (var listItem in list) { // Initialize new evaluation context with the new variable in it var scopedCtx = ctx.Clone(); scopedCtx.SetLocalVariable(IteratorVariableName, new EvaluationVariable( evalAsync: () => Task.FromResult(listItem), selectResolver: () => AsyncUtil.Empty <Path>(), // It doesn't matter when generating output pathsResolver: () => AsyncUtil.Empty <Path>() // It doesn't matter when generating output )); // Index, useful for setting line numbers scopedCtx.SetLocalVariable(IteratorVariableName + "_index", new EvaluationVariable( evalAsync: () => Task.FromResult <object>(index), selectResolver: () => AsyncUtil.Empty <Path>(), // It doesn't matter when generating output pathsResolver: () => AsyncUtil.Empty <Path>() // It doesn't matter when generating output )); // Run the template again on that context await Template.GenerateOutput(builder, scopedCtx, encodeFunc); index++; } } else { throw new TemplateException($"Foreach expression could not be applied. Expression ({ListCandidate}) does not evaluate to a list."); } } }