/// <summary> /// Analyzes a lambda expression to check whether it can be satisfied with /// $select and client-side materialization. /// </summary> /// <param name="le">Lambda expression.</param> /// <param name="re">Resource expression in scope.</param> /// <param name="matchMembers">Whether member accesses are matched as top-level projections.</param> /// <param name="context">Context of expression to analyze.</param> /// <returns>true if the lambda is a client-side projection; false otherwise.</returns> internal static bool Analyze(LambdaExpression le, ResourceExpression re, bool matchMembers, DataServiceContext context) { Debug.Assert(le != null, "le != null"); if (le.Body.NodeType == ExpressionType.Constant) { if (ClientTypeUtil.TypeOrElementTypeIsEntity(le.Body.Type)) { throw new NotSupportedException(Strings.ALinq_CannotCreateConstantEntity); } re.Projection = new ProjectionQueryOptionExpression(le.Body.Type, le, new List <string>()); return(true); } if (le.Body.NodeType == ExpressionType.MemberInit || le.Body.NodeType == ExpressionType.New) { AnalyzeResourceExpression(le, re, context); return(true); } if (matchMembers) { // Members can be projected standalone or type-casted. Expression withoutConverts = SkipConverts(le.Body); if (withoutConverts.NodeType == ExpressionType.MemberAccess) { AnalyzeResourceExpression(le, re, context); return(true); } } return(false); }
/// <summary> /// Visit an <see cref="InputReferenceExpression"/>, producing a new InputReferenceExpression /// based on the visited form of the <see cref="QueryableResourceExpression"/> that is referenced by /// the InputReferenceExpression argument, <paramref name="ire"/>. /// </summary> /// <param name="ire">InputReferenceExpression expression to visit</param> /// <returns>Visited InputReferenceExpression expression</returns> internal virtual Expression VisitInputReferenceExpression(InputReferenceExpression ire) { Debug.Assert(ire != null, "ire != null -- otherwise caller never should have visited here"); ResourceExpression re = (ResourceExpression)this.Visit(ire.Target); return(re.CreateReference()); }
/// <summary>Builds the Uri for the expression passed in.</summary> /// <param name="e">The expression to translate into a Uri</param> /// <returns>Query components</returns> internal QueryComponents Translate(Expression e) { Uri uri; Version version; bool addTrailingParens = false; Dictionary <Expression, Expression> normalizerRewrites = null; // short cut analysis if just a resource set or singleton resource. // note - to be backwards compatible with V1, will only append trailing () for queries // that include more then just a resource set. if (!(e is QueryableResourceExpression)) { normalizerRewrites = new Dictionary <Expression, Expression>(ReferenceEqualityComparer <Expression> .Instance); e = Evaluator.PartialEval(e); e = ExpressionNormalizer.Normalize(e, normalizerRewrites); e = ResourceBinder.Bind(e, this.Context); addTrailingParens = true; } UriWriter.Translate(this.Context, addTrailingParens, e, out uri, out version); ResourceExpression re = e as ResourceExpression; Type lastSegmentType = re.Projection == null ? re.ResourceType : re.Projection.Selector.Parameters[0].Type; LambdaExpression selector = re.Projection == null ? null : re.Projection.Selector; return(new QueryComponents(uri, version, lastSegmentType, selector, normalizerRewrites)); }
/// <summary> /// Retargets this input reference to point to the resource set specified by <paramref name="newTarget"/>. /// </summary> /// <param name="newTarget">The <see cref="QueryableResourceExpression"/> that this input reference should use as its target</param> internal void OverrideTarget(QueryableResourceExpression newTarget) { Debug.Assert(newTarget != null, "Resource set cannot be null"); Debug.Assert(newTarget.ResourceType.Equals(this.Type), "Cannot reference a resource set with a different resource type"); this.target = newTarget; }
/// <summary> /// Analyzes the specified <paramref name="lambda"/> for selection and updates /// <paramref name="resource"/>. /// </summary> /// <param name="lambda">Lambda expression to analyze.</param> /// <param name="resource">Resource expression to update.</param> /// <param name="context">Context of expression to analyze.</param> private static void AnalyzeResourceExpression(LambdaExpression lambda, ResourceExpression resource, DataServiceContext context) { SelectExpandPathBuilder pb = new SelectExpandPathBuilder(); ProjectionAnalyzer.Analyze(lambda, pb, context); resource.Projection = new ProjectionQueryOptionExpression(lambda.Body.Type, lambda, pb.ProjectionPaths.ToList()); resource.ExpandPaths = pb.ExpandPaths.Union(resource.ExpandPaths, StringComparer.Ordinal).ToList(); resource.RaiseUriVersion(pb.UriVersion); }
protected virtual Expression VisitResource(ResourceExpression e) { var fields = VisitFieldDeclarations(e.Fields); var filter = Visit(e.Filter); return(Equals(fields, e.Fields) && filter == e.Filter ? e : new ResourceExpression(e.Type, e.Name, fields, filter)); }
/// <summary> /// Replaces Lambda parameter references or transparent scope property accesses over those Lambda /// parameter references with <see cref="InputReferenceExpression"/>s to the appropriate corresponding /// <see cref="QueryableResourceExpression"/>s, based on the 'input' QueryableResourceExpression to which the /// Lambda is logically applied and any enclosing transparent scope applied to that input resource. /// </summary> /// <param name="e">The expression to rebind</param> /// <param name="currentInput"> /// The 'current input' resource - either the root resource or the /// rightmost resource in the navigation chain.</param> /// <param name="inputParameter">The Lambda parameter that represents a reference to the 'input'</param> /// <param name="referencedInputs">A list that will be populated with the resources that were referenced by the rebound expression</param> /// <returns> /// The rebound version of <paramref name="e"/> where MemberExpression/ParameterExpressions that /// represent resource references have been replaced with appropriate InputReferenceExpressions. /// </returns> internal static Expression Bind(Expression e, ResourceExpression currentInput, ParameterExpression inputParameter, List <ResourceExpression> referencedInputs) { Debug.Assert(e != null, "Expression cannot be null"); Debug.Assert(currentInput != null, "A current input resource is required"); Debug.Assert(inputParameter != null, "The input lambda parameter is required"); Debug.Assert(referencedInputs != null, "The referenced inputs list is required"); InputBinder binder = new InputBinder(currentInput, inputParameter); Expression result = binder.Visit(e); referencedInputs.AddRange(binder.referencedInputs); return(result); }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) { output.Write("using ("); Variable.WriteTo(output); output.Write(" = "); ResourceExpression.WriteTo(output, options); output.WriteLine(") {"); output.Indent(); Body.WriteTo(output, options); output.Unindent(); output.WriteLine(); output.Write("}"); }
protected override Expression VisitResource(ResourceExpression resource) { _stringBuilder.Append(_root); Visit(resource.Name); if (resource.Fields.Any()) { AppendParameterSeparator(); _stringBuilder.Append("fields="); VisitFieldDeclarations(resource.Fields); } Visit(resource.Filter); return(resource); }
internal LambdaExpression Rebind(LambdaExpression lambda, ResourceExpression source) { this.successfulRebind = true; this.oldLambdaParameter = lambda.Parameters[0]; this.projectionSource = source; Expression body = this.Visit(lambda.Body); if (this.successfulRebind) { Type delegateType = typeof(Func <,>).MakeGenericType(new Type[] { newLambdaParameter.Type, lambda.Body.Type }); return(Expression.Lambda(delegateType, body, new ParameterExpression[] { this.newLambdaParameter })); } else { throw new NotSupportedException(Strings.ALinq_CanOnlyProjectTheLeaf); } }
internal static LambdaExpression TryToRewrite(LambdaExpression le, ResourceExpression source) { Type proposedParameterType = source.ResourceType; LambdaExpression result; if (!ResourceBinder.PatternRules.MatchSingleArgumentLambda(le, out le) || // can only rewrite single parameter Lambdas. ClientTypeUtil.TypeOrElementTypeIsEntity(le.Parameters[0].Type) || // only attempt to rewrite if lambda parameter is not an entity type !(le.Parameters[0].Type.GetProperties().Any(p => p.PropertyType == proposedParameterType))) // lambda parameter must have public property that is same as proposed type. { result = le; } else { ProjectionRewriter rewriter = new ProjectionRewriter(proposedParameterType); result = rewriter.Rebind(le, source); } return(result); }
public override void WriteTo(ITextOutput output, ILAstWritingOptions options) { WriteILRange(output, options); output.Write("using"); if (IsAsync) { output.Write(".async"); } if (IsRefStruct) { output.Write(".ref"); } output.Write(" ("); Variable.WriteTo(output); output.Write(" = "); ResourceExpression.WriteTo(output, options); output.WriteLine(") {"); output.Indent(); Body.WriteTo(output, options); output.Unindent(); output.WriteLine(); output.Write("}"); }
/// <summary> /// Constructs a new input reference expression that refers to the specified resource set /// </summary> /// <param name="target">The target resource set that the new expression will reference</param> internal InputReferenceExpression(ResourceExpression target) { Debug.Assert(target != null, "Target resource set cannot be null"); this.target = target; }
/// <summary> /// Resolves member accesses that represent transparent scope property accesses to the corresponding resource, /// iff the input resource is enclosed in a transparent scope and the specified MemberExpression represents /// such a property access. /// </summary> /// <param name="m">MemberExpression expression to visit</param> /// <returns> /// An InputReferenceExpression if the member access represents a transparent scope property /// access that can be resolved to a resource in the path that produces the input resource; /// otherwise the same MemberExpression is returned. /// </returns> internal override Expression VisitMemberAccess(MemberExpression m) { // If the current input resource is not enclosed in a transparent scope, then this // MemberExpression cannot represent a valid transparent scope access based on the input parameter. if (this.inputResource == null || !this.inputResource.HasTransparentScope) { return(base.VisitMemberAccess(m)); } ParameterExpression innerParamRef = null; Stack <PropertyInfo> nestedAccesses = new Stack <PropertyInfo>(); MemberExpression memberRef = m; while (memberRef != null && PlatformHelper.IsProperty(memberRef.Member) && memberRef.Expression != null) { nestedAccesses.Push((PropertyInfo)memberRef.Member); if (memberRef.Expression.NodeType == ExpressionType.Parameter) { innerParamRef = (ParameterExpression)memberRef.Expression; } memberRef = memberRef.Expression as MemberExpression; } // Only continue if the inner non-MemberExpression is the input reference ParameterExpression and // at least one property reference is present - otherwise this cannot be a transparent scope access. if (innerParamRef != this.inputParameter || nestedAccesses.Count == 0) { return(m); } ResourceExpression target = this.input; QueryableResourceExpression targetResource = this.inputResource; bool transparentScopeTraversed = false; // Process all the traversals through transparent scopes. while (nestedAccesses.Count > 0) { if (targetResource == null || !targetResource.HasTransparentScope) { break; } // Peek the property; pop it once it's consumed // (it could be a non-transparent-identifier access). PropertyInfo currentProp = nestedAccesses.Peek(); // If this is the accessor for the target, then the member // refers to the target itself. if (currentProp.Name.Equals(targetResource.TransparentScope.Accessor, StringComparison.Ordinal)) { target = targetResource; nestedAccesses.Pop(); transparentScopeTraversed = true; continue; } // This member could also be one of the in-scope sources of the target. Expression source; if (!targetResource.TransparentScope.SourceAccessors.TryGetValue(currentProp.Name, out source)) { break; } transparentScopeTraversed = true; nestedAccesses.Pop(); Debug.Assert(source != null, "source != null -- otherwise ResourceBinder created an accessor to nowhere"); InputReferenceExpression sourceReference = source as InputReferenceExpression; if (sourceReference == null) { targetResource = source as QueryableResourceExpression; if (targetResource == null || !targetResource.HasTransparentScope) { target = (ResourceExpression)source; } } else { targetResource = sourceReference.Target as QueryableResourceExpression; target = targetResource; } } // If no traversals were made, the original expression is OK. if (!transparentScopeTraversed) { return(m); } // Process traversals after the transparent scope. Expression result = this.CreateReference(target); while (nestedAccesses.Count > 0) { result = Expression.Property(result, nestedAccesses.Pop()); } return(result); }
public void Preprocess(List <XmlAttribute> expressionAttributes, List <Resource> resources, List <IdViewObject> viewElements) { // Create all properties for viewElements foreach (IdViewObject viewElement in viewElements) { Tuple <CodeMemberField, CodeMemberProperty> result = CodeGeneratorHelper.GenerateProxyProperty(viewElement.Id, viewElement.TypeName, new CodeMethodInvokeExpression(GetFindViewByIdReference(viewElement.TypeName), CodeGeneratorHelper.GetAndroidResourceReference(ResourcePart.Id, viewElement.Id))); Fields.Add(result.Item1); Properties.Add(result.Item2); } // Generate property for ILocalizationService LocalizationService CodePropertyReferenceExpression localizationServiceReference = CreateLocalizationServiceProperty(); // Eval all expressions List <ExpressionContainer> expressions = (from attribute in expressionAttributes let expressionResult = EvaluateExpression(attribute.Value) where expressionResult != null select new ExpressionContainer { Expression = expressionResult, TargetObject = attribute.AttachedId, TargetField = attribute.LocalName, IsTargetingResource = false, }).ToList(); // Affect a property name to all resources and check if some has expression as attribute value foreach (Resource res in resources) { res.PropertyName = NameGeneratorHelper.GetResourceName(); foreach (KeyValuePair <string, string> propertyItem in res.Properties.Where(propertyItem => ParsingHelper.IsExpressionValue(propertyItem.Value)).ToList()) { res.Properties.Remove(propertyItem.Key); Expression expr = EvaluateExpression(propertyItem.Value); if (expr != null) { if (CheckCorrectExpressionInResource(expr)) { Log.LogError("Expression {0} is invalid in a resource context (you cannot use binding)", propertyItem.Value); } else { expressions.Add(new ExpressionContainer { Expression = expr, TargetObject = res.PropertyName, TargetField = propertyItem.Key, IsTargetingResource = true, }); } } } } // Check if all resources are declared and filter those we need Dictionary <string, Resource> neededResource = new Dictionary <string, Resource>(); List <string> resourceKeys = expressions.SelectMany(x => GetUsedResources(x.Expression)).Distinct().ToList(); foreach (string key in resourceKeys) { Resource res = resources.FirstOrDefault(x => key.Equals(x.Key, StringComparison.InvariantCultureIgnoreCase)); if (res == null) { Log.LogError("Resource with key {0} does not exists", key); } else { neededResource.Add(key, res); } } // Go through all binding expression and find those where we need to declare implicit resources // Will also remove all Template & TemplateSelector fields in BindingExpression // to only have a fully prepared adapter foreach (Expression bindingExpression in expressions.SelectMany(expression => GetBindingExpressions(expression.Expression)).ToList()) { if (bindingExpression.Has(BindingExpression.TEMPLATE)) { // create a template selector string templateSelectorKey = NameGeneratorHelper.GetResourceKey(); string templateSelectorPropertyName = NameGeneratorHelper.GetResourceName(); neededResource.Add(templateSelectorKey, new Resource(templateSelectorKey) { PropertyName = templateSelectorPropertyName, ResourceElement = null, Type = Configuration.DefaultTemplateSelector }); expressions.Add(new ExpressionContainer { Expression = bindingExpression[BindingExpression.TEMPLATE], TargetField = Configuration.DefaultTemplateSelectorField, TargetObject = templateSelectorPropertyName, IsTargetingResource = true, }); bindingExpression.Remove(BindingExpression.TEMPLATE); ResourceExpression templateSelectorResourceExpression = new ResourceExpression(); templateSelectorResourceExpression.Add(ResourceExpression.KEY, new TextExpression { Value = templateSelectorKey }); bindingExpression.Add(BindingExpression.TEMPLATE_SELECTOR, templateSelectorResourceExpression); } if (bindingExpression.Has(BindingExpression.TEMPLATE_SELECTOR)) { // create an adapter string adapterKey = NameGeneratorHelper.GetResourceKey(); string adapterName = NameGeneratorHelper.GetResourceName(); neededResource.Add(adapterKey, new Resource(adapterKey) { PropertyName = adapterName, ResourceElement = null, Type = Configuration.DefaultAdapter }); expressions.Add(new ExpressionContainer { Expression = bindingExpression[BindingExpression.TEMPLATE_SELECTOR], TargetField = Configuration.DefaultAdapterField, TargetObject = adapterName, IsTargetingResource = true, }); bindingExpression.Remove(BindingExpression.TEMPLATE_SELECTOR); ResourceExpression adapterResourceExpression = new ResourceExpression(); adapterResourceExpression.Add(ResourceExpression.KEY, new TextExpression { Value = adapterKey }); bindingExpression.Add(BindingExpression.ADAPTER, adapterResourceExpression); } } // In order to check if all adapter are not used more than once since we need them to be unique target Dictionary <string, bool> usedAdapter = new Dictionary <string, bool>(); foreach (ExpressionContainer expression in expressions.Where(x => x.Expression.IsOfType(ExpressionType.Binding)).ToList()) { Expression bindingExpression = expression.Expression; if (bindingExpression.Has(BindingExpression.ADAPTER)) { // expression in Adapter could only be Resource (since it's an android platform specific things, a binding expression would not have any sense) Expression resourceExpression = bindingExpression[BindingExpression.ADAPTER]; string adapterKey = resourceExpression.GetValue(ResourceExpression.KEY); Resource adapterResource = neededResource[adapterKey]; if (usedAdapter.ContainsKey(adapterKey)) { Log.LogError("The adapter with key {0} is used more than once which could lead to issue, you need one adapter per use !", adapterKey); } else { usedAdapter.Add(adapterKey, true); } // remove the adapter property bindingExpression.Remove(BindingExpression.ADAPTER); // store old target info string oldTargetField = expression.TargetField; string oldTargetObject = expression.TargetObject; bool oldTargetType = expression.IsTargetingResource; // retarget the binding expression to be targeted to Adapter.Collection expression.TargetField = "Collection"; expression.TargetObject = adapterResource.PropertyName; expression.IsTargetingResource = false; //TODO : false for debug mode only, need to see what we can do about that ? // add a new expression to target the old object/field couple and affect the adapter with the resource expression expressions.Add(new ExpressionContainer { IsTargetingResource = oldTargetType, TargetField = oldTargetField, TargetObject = oldTargetObject, Expression = resourceExpression, }); } } // Create all properties for resources Dictionary <string, CodePropertyReferenceExpression> resourceReferences = CreatePropertiesForResources(neededResource.Values); // Generate all properties to handle CommandParameter and retarget all expressions if needed GenerateCommandParameterProperties(expressions); // Create a setup resources method to initalize resources with all {Resource ...} and {Translation ...} expressions List <ExpressionContainer> translationExpressions = expressions.Where(x => x.Expression.IsOfType(ExpressionType.Translation)).ToList(); List <ExpressionContainer> expressionsTargetingResources = expressions.Where(x => x.IsTargetingResource && x.Expression.IsOfType(ExpressionType.Resource)).ToList(); List <ExpressionContainer> resourceExpressions = expressions.Where(x => !x.IsTargetingResource && x.Expression.IsOfType(ExpressionType.Resource)).ToList(); List <ExpressionContainer> bindingExpressions = expressions.Where(x => !x.IsTargetingResource && x.Expression.IsOfType(ExpressionType.Binding)).ToList(); CodeMethodReferenceExpression assignTranslationMethodReference = CreateAssignTranslationMethod(translationExpressions, localizationServiceReference); CodeMethodReferenceExpression setupResourcesReference = CreateSetupResourcesMethod(expressionsTargetingResources, resourceReferences); CodeMethodReferenceExpression setupResourceForViewElement = CreateSetupResourceForViewElementMethod(resourceExpressions, resourceReferences); CreateBindingOverrideMethod(bindingExpressions, localizationServiceReference, resourceReferences, assignTranslationMethodReference, setupResourcesReference, setupResourceForViewElement); }
/// <summary> /// Visit Query options for Resource /// </summary> /// <param name="re">Resource Expression with query options</param> internal void VisitQueryOptions(ResourceExpression re) { if (re.HasQueryOptions) { this.uriBuilder.Append(UriHelper.QUESTIONMARK); QueryableResourceExpression rse = re as QueryableResourceExpression; if (rse != null) { IEnumerator options = rse.SequenceQueryOptions.GetEnumerator(); while (options.MoveNext()) { Expression e = ((Expression)options.Current); ResourceExpressionType et = (ResourceExpressionType)e.NodeType; switch (et) { case ResourceExpressionType.SkipQueryOption: this.VisitQueryOptionExpression((SkipQueryOptionExpression)e); break; case ResourceExpressionType.TakeQueryOption: this.VisitQueryOptionExpression((TakeQueryOptionExpression)e); break; case ResourceExpressionType.OrderByQueryOption: this.VisitQueryOptionExpression((OrderByQueryOptionExpression)e); break; case ResourceExpressionType.FilterQueryOption: this.VisitQueryOptionExpression((FilterQueryOptionExpression)e); break; case ResourceExpressionType.ApplyQueryOption: this.VisitQueryOptionExpression((ApplyQueryOptionExpression)e); break; default: Debug.Assert(false, "Unexpected expression type " + ((int)et).ToString(CultureInfo.InvariantCulture)); break; } } } if (re.ExpandPaths.Count > 0) { this.VisitExpandOptions(re.ExpandPaths); } if (re.Projection != null && re.Projection.Paths.Count > 0) { this.VisitProjectionPaths(re.Projection.Paths); } if (re.CountOption == CountOption.CountQueryTrue) { this.VisitCountQueryOptions(true); } if (re.CountOption == CountOption.CountQueryFalse) { this.VisitCountQueryOptions(false); } if (re.CustomQueryOptions.Count > 0) { this.VisitCustomQueryOptions(re.CustomQueryOptions); } this.AppendCachedQueryOptionsToUriBuilder(); } }
/// <summary> /// Populates the analyser type for column. /// </summary> /// <param name="report">The report.</param> /// <param name="entityType">The resource type returned if the analyser refers to a resource expression.</param> /// <param name="reportExpression">The report expression.</param> /// <param name="reportAnalyserColumn">The report analyser column.</param> private static void PopulateAnalyserTypeForColumn(Report report, EntityType entityType, ReportExpression reportExpression, ReportAnalyserColumn reportAnalyserColumn) { reportAnalyserColumn.AnalyserType = reportAnalyserColumn.Type.GetDisplayName(); if (reportExpression.Is <StructureViewExpression>()) { reportAnalyserColumn.AnalyserType = StructureLevelsType.DisplayName; reportAnalyserColumn.DefaultOperator = Structured.ConditionType.AnyBelowStructureLevel; var expression = reportExpression.As <StructureViewExpression>(); var resReportNode = expression.StructureViewExpressionSourceNode.As <ResourceReportNode>(); var eType = resReportNode.ResourceReportNodeType; reportAnalyserColumn.TypeId = eType.Id; return; } if (!reportExpression.Is <NodeExpression>()) { return; } NodeExpression nodeExpression = reportExpression.As <NodeExpression>(); if (!nodeExpression.SourceNode.Is <ResourceReportNode>()) { return; } bool isNameColumnForType = false; if (reportExpression.Is <FieldExpression>()) { var fieldExpression = reportExpression.As <FieldExpression>(); if (fieldExpression.FieldExpressionField.Alias != "core:name") { return; } long sourceId = fieldExpression.SourceNode != null ? fieldExpression.SourceNode.Id : 0; long rootId = report.RootNode != null ? report.RootNode.Id : 0; isNameColumnForType = (sourceId == rootId) && (sourceId != 0); } reportAnalyserColumn.IsNameColumnForType = isNameColumnForType; ResourceReportNode resourceReportNode = nodeExpression.SourceNode.As <ResourceReportNode>( ); RelationshipReportNode relationshipReportNode = nodeExpression.SourceNode.As <RelationshipReportNode>( ); if (entityType == null) { // Need to be able accept entityType as an argument, e.g. if it is from a script column // But also need to be able to read it from the node, e.g. if it is the root name column. Messed up. entityType = resourceReportNode.ResourceReportNodeType; if (entityType == null) { return; } } ResourceExpression resourceExpression = reportExpression.As <ResourceExpression>(); // Handle "Type" types //if the resource type is "Type", add current parent node type and descendant types' id as filtered entity ids (bug 24859) //Update: only the forward relationship is "isOfType", the "type" list will be restricted. (bug 27862) if (entityType.Alias == "core:type" && relationshipReportNode?.FollowRelationship?.Alias == "core:isOfType" ) { AggregateReportNode parentAggregatedNode = resourceReportNode.ParentAggregatedNode; ReportNode parentReportNode = parentAggregatedNode != null ? parentAggregatedNode.GroupedNode : resourceReportNode.ParentReportNode; ResourceReportNode parentResourceReportNode = parentReportNode != null?parentReportNode.As <ResourceReportNode>() : null; if (parentResourceReportNode != null && parentResourceReportNode.ResourceReportNodeType != null) { reportAnalyserColumn.FilteredEntityIds = PerTenantEntityTypeCache.Instance.GetDescendantsAndSelf( parentResourceReportNode.ResourceReportNodeType.Id).ToArray(); } } // Handle "User" and "Person" types if (PerTenantEntityTypeCache.Instance.IsDerivedFrom(entityType.Id, "core:person") || PerTenantEntityTypeCache.Instance.IsDerivedFrom(entityType.Id, "core:userAccount")) { // If this is a relationship or calc then make it as a user inline relationship otherwise a simple user string. reportAnalyserColumn.AnalyserType = nodeExpression.SourceNode.Is <FieldExpression>( ) ? "UserString" : "UserInlineRelationship"; return; } // Treat the root 'Name' column like a lookup, so we get the 'Any Of', 'Any Except' options. if (isNameColumnForType) { reportAnalyserColumn.AnalyserType = "InlineRelationship"; reportAnalyserColumn.TypeId = entityType.Id; } }
/// <summary> /// Returns an <see cref="InputReferenceExpression"/> that references the specified resource, /// and also adds the the resource to the hashset of resources that were referenced by the /// expression that is being rebound. /// </summary> /// <param name="resource">The resource for which a reference was found</param> /// <returns>An InputReferenceExpression that represents a reference to the specified resource</returns> private Expression CreateReference(ResourceExpression resource) { this.referencedInputs.Add(resource); return(resource.CreateReference()); }
/// <summary> /// Constructs a new InputBinder based on the specified input resources, which is represented by the specified ParameterExpression. /// </summary> /// <param name="resource">The current input resource from which valid references must start</param> /// <param name="setReferenceParam">The parameter that must be referenced in order to refer to the specified input resources</param> private InputBinder(ResourceExpression resource, ParameterExpression setReferenceParam) { this.input = resource; this.inputResource = resource as QueryableResourceExpression; this.inputParameter = setReferenceParam; }
/// <summary> /// TODO: Refactor /// </summary> internal static void CaptureMetadata(StructuredQuery query, QuerySettings settings, QueryResult result, DataTable dataTable) { if (settings.SupportClientAggregate) { int totalGroupedColumns = settings.ClientAggregate.GroupedColumns?.Count ?? 0; int totalColumns = totalGroupedColumns + settings.ClientAggregate.AggregatedColumns.Count; for (int index = 0; index < totalColumns; index++) { int columnIndex; DataColumn tableColumn = dataTable.Columns[index]; if (index < totalGroupedColumns) { columnIndex = index; if (settings.ClientAggregate.GroupedColumns != null) { tableColumn.ExtendedProperties["ColumnId"] = settings.ClientAggregate.GroupedColumns[columnIndex].ReportColumnId; } } else { columnIndex = index - totalGroupedColumns; if (settings.ClientAggregate.AggregatedColumns != null) { tableColumn.ExtendedProperties["ColumnId"] = settings.ClientAggregate.AggregatedColumns[columnIndex].ReportColumnId; } } tableColumn.ExtendedProperties["ColumnIndex"] = columnIndex; } result.AggregateDataTable = dataTable; } else { int index = 0; foreach (SelectColumn selectColumn in query.SelectColumns) { // Set column ID into data table column object (why??) DataColumn tableColumn = dataTable.Columns[index]; tableColumn.ExtendedProperties["ColumnId"] = selectColumn.ColumnId; // Set data type into result column info, for columns (e.g. calculated) where we can only determine it dynamically at the moment ResultColumn resultColumn = result.Columns[index]; if (resultColumn.ColumnType == null) { if (selectColumn.Expression is AggregateExpression && ((AggregateExpression)selectColumn.Expression).Expression is ResourceExpression) { if (((AggregateExpression)selectColumn.Expression).AggregateMethod == AggregateMethod.Count || ((AggregateExpression)selectColumn.Expression).AggregateMethod == AggregateMethod.CountUniqueItems || ((AggregateExpression)selectColumn.Expression).AggregateMethod == AggregateMethod.CountUniqueNotBlanks || ((AggregateExpression)selectColumn.Expression).AggregateMethod == AggregateMethod.CountWithValues) { resultColumn.ColumnType = new EDC.Database.Types.Int32Type(); } else { resultColumn.ColumnType = ((ResourceExpression)((AggregateExpression)selectColumn.Expression).Expression).CastType; resultColumn.IsResource = true; if (resultColumn.ColumnType == null) { resultColumn.ColumnType = new EDC.Database.Types.ChoiceRelationshipType(); } } } else if (selectColumn.Expression is AggregateExpression && ((AggregateExpression)selectColumn.Expression).Expression is ResourceDataColumn) { if (((AggregateExpression)selectColumn.Expression).AggregateMethod == AggregateMethod.Count || ((AggregateExpression)selectColumn.Expression).AggregateMethod == AggregateMethod.CountUniqueItems || ((AggregateExpression)selectColumn.Expression).AggregateMethod == AggregateMethod.CountUniqueNotBlanks || ((AggregateExpression)selectColumn.Expression).AggregateMethod == AggregateMethod.CountWithValues) { resultColumn.ColumnType = new EDC.Database.Types.Int32Type(); } else { resultColumn.ColumnType = ((ResourceDataColumn)((AggregateExpression)selectColumn.Expression).Expression).CastType; //resultColumn.IsResource = true; } } else if (selectColumn.Expression is StructureViewExpression) { resultColumn.ColumnType = new EDC.Database.Types.StructureLevelsType(); } else { ResourceExpression resourceExpression = selectColumn.Expression as ResourceExpression; if (resourceExpression != null) { resultColumn.ColumnType = resourceExpression.CastType; resultColumn.IsResource = true; } else { resultColumn.ColumnType = DatabaseType.ConvertFromType(tableColumn.DataType); } } } index++; } result.DataTable = dataTable; } }