public QueryStringParameterScopeParser(IResourceContextProvider resourceContextProvider, FieldChainRequirements chainRequirements, Action <ResourceFieldAttribute, ResourceContext, string> validateSingleFieldCallback = null) : base(resourceContextProvider) { _chainRequirements = chainRequirements; _validateSingleFieldCallback = validateSingleFieldCallback; }
protected QueryExpression ParseCountOrField(FieldChainRequirements chainRequirements) { CountExpression count = TryParseCount(); if (count != null) { return(count); } return(ParseFieldChain(chainRequirements, "Count function or field name expected.")); }
protected ResourceFieldChainExpression ParseFieldChain(FieldChainRequirements chainRequirements, string alternativeErrorMessage) { if (TokenStack.TryPop(out Token token) && token.Kind == TokenKind.Text) { var chain = OnResolveFieldChain(token.Value, chainRequirements); if (chain.Any()) { return(new ResourceFieldChainExpression(chain)); } } throw new QueryParseException(alternativeErrorMessage ?? "Field name expected."); }
protected QueryExpression ParseCountOrConstantOrNullOrField(FieldChainRequirements chainRequirements) { CountExpression count = TryParseCount(); if (count != null) { return(count); } IdentifierExpression constantOrNull = TryParseConstantOrNull(); if (constantOrNull != null) { return(constantOrNull); } return(ParseFieldChain(chainRequirements, "Count function, value between quotes, null or field name expected.")); }
protected ComparisonExpression ParseComparison(string operatorName) { var comparisonOperator = Enum.Parse <ComparisonOperator>(operatorName.Pascalize()); EatText(operatorName); EatSingleCharacterToken(TokenKind.OpenParen); // Allow equality comparison of a HasOne relationship with null. FieldChainRequirements leftChainRequirements = comparisonOperator == ComparisonOperator.Equals ? FieldChainRequirements.EndsInAttribute | FieldChainRequirements.EndsInToOne : FieldChainRequirements.EndsInAttribute; QueryExpression leftTerm = ParseCountOrField(leftChainRequirements); EatSingleCharacterToken(TokenKind.Comma); QueryExpression rightTerm = ParseCountOrConstantOrNullOrField(FieldChainRequirements.EndsInAttribute); EatSingleCharacterToken(TokenKind.CloseParen); if (leftTerm is ResourceFieldChainExpression leftChain) { if (leftChainRequirements.HasFlag(FieldChainRequirements.EndsInToOne) && !(rightTerm is NullConstantExpression)) { // Run another pass over left chain to have it fail when chain ends in relationship. OnResolveFieldChain(leftChain.ToString(), FieldChainRequirements.EndsInAttribute); } PropertyInfo leftProperty = leftChain.Fields.Last().Property; if (leftProperty.Name == nameof(Identifiable.Id) && rightTerm is LiteralConstantExpression rightConstant) { string id = DeObfuscateStringId(leftProperty.ReflectedType, rightConstant.Value); rightTerm = new LiteralConstantExpression(id); } } return(new ComparisonExpression(comparisonOperator, leftTerm, rightTerm)); }
/// <summary> /// Takes a dotted path and walks the resource graph to produce a chain of fields. /// </summary> protected abstract IReadOnlyCollection <ResourceFieldAttribute> OnResolveFieldChain(string path, FieldChainRequirements chainRequirements);
protected override IReadOnlyCollection <ResourceFieldAttribute> OnResolveFieldChain(string path, FieldChainRequirements chainRequirements) { var field = ChainResolver.GetField(path, _resourceContext, path); _validateSingleFieldCallback?.Invoke(field, _resourceContext, path); return(new[] { field }); }
protected override IReadOnlyCollection <ResourceFieldAttribute> OnResolveFieldChain(string path, FieldChainRequirements chainRequirements) { if (chainRequirements == FieldChainRequirements.EndsInToMany) { return(ChainResolver.ResolveToOneChainEndingInToMany(_resourceContextInScope, path, _validateSingleFieldCallback)); } if (chainRequirements == FieldChainRequirements.EndsInAttribute) { return(ChainResolver.ResolveToOneChainEndingInAttribute(_resourceContextInScope, path, _validateSingleFieldCallback)); } if (chainRequirements.HasFlag(FieldChainRequirements.EndsInAttribute) && chainRequirements.HasFlag(FieldChainRequirements.EndsInToOne)) { return(ChainResolver.ResolveToOneChainEndingInAttributeOrToOne(_resourceContextInScope, path, _validateSingleFieldCallback)); } throw new InvalidOperationException($"Unexpected combination of chain requirement flags '{chainRequirements}'."); }
protected override IReadOnlyCollection <ResourceFieldAttribute> OnResolveFieldChain(string path, FieldChainRequirements chainRequirements) { return(ChainResolver.ResolveToManyChain(_resourceContextInScope, path, _validateSingleFieldCallback)); }
protected override IReadOnlyCollection <ResourceFieldAttribute> OnResolveFieldChain(string path, FieldChainRequirements chainRequirements) { var attribute = ChainResolver.GetAttribute(path, _resourceContextInScope, path); _validateSingleAttributeCallback?.Invoke(attribute, _resourceContextInScope, path); return(new[] { attribute }); }
protected override IReadOnlyCollection <ResourceFieldAttribute> OnResolveFieldChain(string path, FieldChainRequirements chainRequirements) { if (chainRequirements == FieldChainRequirements.EndsInToMany) { // The mismatch here (ends-in-to-many being interpreted as entire-chain-must-be-to-many) is intentional. return(ChainResolver.ResolveToManyChain(_resourceContextInScope, path, _validateSingleFieldCallback)); } if (chainRequirements == FieldChainRequirements.IsRelationship) { return(ChainResolver.ResolveRelationshipChain(_resourceContextInScope, path, _validateSingleFieldCallback)); } throw new InvalidOperationException($"Unexpected combination of chain requirement flags '{chainRequirements}'."); }
protected override IReadOnlyCollection <ResourceFieldAttribute> OnResolveFieldChain(string path, FieldChainRequirements chainRequirements) { throw new NotSupportedException(); }