using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using ServiceStack.Text;
namespace ServiceStack.Script
{
///
/// Handlebars.js like each block
/// Usages: {{#each customers}} {{Name}} {{/each}}
/// {{#each customers}} {{it.Name}} {{/each}}
/// {{#each num in numbers}} {{num}} {{/each}}
/// {{#each num in [1,2,3]}} {{num}} {{/each}}
/// {{#each numbers}} {{it}} {{else}} no numbers {{/each}}
/// {{#each numbers}} {{it}} {{else if letters != null}} has letters {{else}} no numbers {{/each}}
/// {{#each n in numbers where n > 5}} {{it}} {{else}} no numbers > 5 {{/each}}
/// {{#each n in numbers where n > 5 orderby n skip 1 take 2}} {{it}} {{else}} no numbers > 5 {{/each}}
///
public class EachScriptBlock : ScriptBlock
{
public override string Name => "each";
public override async Task WriteAsync(ScriptScopeContext scope, PageBlockFragment block, CancellationToken token)
{
if (block.Argument.IsNullOrEmpty())
throw new NotSupportedException("'each' block requires the collection to iterate");
var cache = (EachArg)scope.Context.Cache.GetOrAdd(block.ArgumentString, _ => ParseArgument(scope, block));
var collection = cache.Source.Evaluate(scope, out var syncResult, out var asyncResult)
? (IEnumerable)syncResult
: (IEnumerable)(await asyncResult.ConfigAwait());
var index = 0;
if (collection != null)
{
if (cache.Where != null || cache.OrderBy != null || cache.OrderByDescending != null ||
cache.Skip != null || cache.Take != null)
{
var filteredResults = new List>();
foreach (var element in collection)
{
// Add all properties into scope if called without explicit in argument
var scopeArgs = !cache.HasExplicitBinding && CanExportScopeArgs(element)
? element.ToObjectDictionary()
: new Dictionary();
scopeArgs[cache.Binding] = element;
scopeArgs[nameof(index)] = AssertWithinMaxQuota(index++);
var itemScope = scope.ScopeWithParams(scopeArgs);
if (cache.Where != null)
{
var result = await cache.Where.EvaluateToBoolAsync(itemScope).ConfigAwait();
if (!result)
continue;
}
filteredResults.Add(scopeArgs);
}
IEnumerable> selectedResults = filteredResults;
var comparer = (IComparer