private async Task ProcessIncludes(List <IEntity> results, CancellationToken ct) { if (!Includes.Any()) { return; } //TODO: optimize / parallel processing foreach (var propertyDefinition in Includes) { var targetEntityDefinition = (IEntityDefinition)propertyDefinition.PropertyType.GetTargetValueType(propertyDefinition); var foreignIds = results .Select(x => x[propertyDefinition.Name]) .Where(x => x != null) .Cast <IEntity>() .Select(x => _repository.GetDocumentId(targetEntityDefinition, x.Id)) .Distinct(); var foreignQuery = new DocumentDbQuery(_repository, targetEntityDefinition) .Add(Criterion.In(MetaConstants.IdProperty, foreignIds.Cast <object>().ToArray())); var foreignEntities = (await foreignQuery.ToEnumerable <IEntity>(ct)).ToDictionary(x => x.Id); results.ForEach(x => { var foreignId = ((IEntity)x[propertyDefinition.Name])?.Id; if (foreignId != null && foreignEntities.ContainsKey(foreignId)) { x[propertyDefinition.Name] = foreignEntities[foreignId]; } }); } }
private async Task <SqlQuerySpec> BuildQuerySpec(DocumentDbQuery query, CancellationToken ct) { if (!query.FullQuery.IsNullOrEmpty()) { return(new SqlQuerySpec(query.FullQuery)); } var parameters = new SqlParameterCollection(); return(new SqlQuerySpec($"SELECT {BuildSelect(query)} FROM ROOT {await BuildWhere(query, parameters, ct)} {BuildOrder(query)}", parameters)); }
private static string BuildSelect(DocumentDbQuery query) { if (query.Projection == null) { return("VALUE ROOT"); } if (query.Projection.PropertyNames.Safe().Any()) { return(string.Join(", ", query.Projection.PropertyNames.Select(x => $"ROOT.{x}"))); } throw new NotSupportedException(); }
private static string BuildOrder(DocumentDbQuery query) { if (!query.Orders.Any()) { return(null); } if (query.Orders.Count > 1) { throw new QueryException(query, "Document db does not support multiple order by."); } var order = query.Orders[0]; return($"ORDER BY ROOT.{order.PropertyName} {(order.Ascending ? "ASC" : "DESC")}"); }
private static async Task <string> BuildWhere(DocumentDbQuery query, SqlParameterCollection parameters, CancellationToken ct) { var joins = new List <string>(); var whereConditions = new List <string> { "ROOT." + DocumentDbConstants.EntityDefinitionProperty + " = @" + DocumentDbConstants.EntityDefinitionProperty }; parameters.Add(new SqlParameter("@" + DocumentDbConstants.EntityDefinitionProperty, query.EntityDefinition.FullName)); foreach (var criterion in query.Criterions) { string remaining; var leading = criterion.PropertyName.SplitFirst('.', out remaining); var propertyDefinition = query.EntityDefinition.Properties.SafeGet(leading); if (propertyDefinition == null) { throw new QueryException(query, $"Unable to find a property named {leading} on {query.EntityDefinition}"); } var criteria = $"ROOT.{criterion.PropertyName}"; if (propertyDefinition.PropertyType is ArrayValueType) { var prefix = GetPrefixName(propertyDefinition.Name); joins.Add($" JOIN {prefix} IN ROOT.{propertyDefinition.Name}"); criteria = $"{prefix}.{remaining}"; } switch (criterion.Operator) { case Operators.Eq: var parameterName = GetParameterName(criterion.PropertyName); whereConditions.Add($"{criteria} = @{parameterName}"); parameters.Add(new SqlParameter($"@{parameterName}", criterion.Value)); break; case Operators.In: whereConditions.Add($"{criteria} IN ({string.Join(", ", GetInValues(criterion.Value))})"); break; default: throw new QueryException(query, $"Unsupported operator {criterion.Operator}."); } } foreach (var subQuery in query.SubQueries) { if (subQuery.Value.IsIdQuery) { whereConditions.Add($"ROOT.{subQuery.Key}.{MetaConstants.IdProperty} = @{subQuery.Key}"); parameters.Add(new SqlParameter($"@{subQuery.Key}", ((DocumentDbQuery)subQuery.Value).Criterions[0].Value)); } else { // We actually need to run the subquery at that point var subEntities = await((DocumentDbQuery)subQuery.Value).ToEnumerable <IEntity>(ct); var subEntitiesIds = subEntities.Safe().Select(x => x.Id); whereConditions.Add( $"ROOT.{subQuery.Key}.{MetaConstants.IdProperty} IN ({string.Join(", ", GetInValues(subEntitiesIds))})"); } } return($"{string.Join(" ", joins)} WHERE {string.Join(" AND ", whereConditions)}"); }