/// Given a syntax of someField { fields, to, selection, from, object } /// it will figure out if 'someField' is an IEnumerable or an istance of the object (not a collection) and build the correct select statement private DataApiNode BuildDynamicSelectForObjectGraph(string query, string name, EqlGrammerParser.EntityQueryContext context) { if (!_schemaProvider.TypeHasField(_selectContext.Type.Name, name)) { throw new EqlCompilerException($"Type {_selectContext.Type} does not have field or property {name}"); } name = _schemaProvider.GetActualFieldName(_selectContext.Type.Name, name); // Don't really like any of this, but... try { var result = EqlCompiler.CompileWith(query, _selectContext, _schemaProvider, _methodProvider); var exp = result.Expression; if (exp.Body.Type.IsEnumerable()) { return(BuildDynamicSelectOnCollection(exp, name, context, false)); } var oldContext = _selectContext; _selectContext = exp.Body; // visit child fields. Will be field or entityQueries again var fieldExpressions = context.fields.children.Select(c => Visit(c)).Where(n => n != null).ToList(); var relationsExps = fieldExpressions.Where(f => f.Expression.NodeType == ExpressionType.MemberInit || f.Expression.NodeType == ExpressionType.Call).ToList(); if (_relationHandler != null && relationsExps.Any()) { var parameterExpression = Expression.Parameter(_selectContext.Type); var relations = relationsExps.Select(r => (Expression)Expression.PropertyOrField(parameterExpression, r.Name)).ToList(); exp = _relationHandler.BuildNodeForSelect(relations, parameterExpression, exp, name, _schemaProvider); } var newExp = DataApiExpressionUtil.CreateNewExpression(_selectContext, fieldExpressions, _schemaProvider); _selectContext = oldContext; return(new DataApiNode(_schemaProvider.GetActualFieldName(_selectContext.Type.Name, name), newExp, exp.Parameters.Any() ? exp.Parameters.First() : null, exp.Body)); } catch (EqlCompilerException ex) { throw DataApiException.MakeFieldCompileError(query, ex.Message); } }
/// We compile each entityQuery with EqlCompiler and build a Select call from the fields public override DataApiNode VisitEntityQuery(EqlGrammerParser.EntityQueryContext context) { string name; string query; if (context.alias != null) { name = context.alias.name.GetText(); query = context.entity.GetText(); } else { query = context.entity.GetText(); name = query; if (name.IndexOf(".") > -1) { name = name.Substring(0, name.IndexOf(".")); } } try { if (_selectContext == null) { // top level are queries on the context var exp = EqlCompiler.Compile(query, _schemaProvider, _methodProvider).Expression; var topLevelSelect = BuildDynamicSelectOnCollection(exp, name, context, true); return(topLevelSelect); } // other levels are object selection. e.g. from the top level people query I am selecting all their children { field1, etc. } return(BuildDynamicSelectForObjectGraph(query, name, context)); } catch (EqlCompilerException ex) { //return DataApiNode.MakeError(name, $"Error compiling field or query '{query}'. {ex.Message}"); throw DataApiException.MakeFieldCompileError(query, ex.Message); } }