public void FilterNotRegex(MemberExpression expression, string pattern, bool ignoreCase) { SparqlVariable s = VariableGenerator.TryGetSubjectVariable(expression) ?? SubjectVariable; SparqlVariable o = VariableGenerator.TryGetObjectVariable(expression) ?? VariableGenerator.CreateObjectVariable(expression); BuildMemberAccess(expression); FilterNotRegex(o, pattern, ignoreCase); }
public override void OnBeforeFromClauseVisited(Expression expression) { SparqlVariable s = null; SparqlVariable o = null; if (expression is MemberExpression) { QuerySourceReferenceExpression sourceExpression = expression.TryGetQuerySourceReference(); s = VariableGenerator.TryGetSubjectVariable(sourceExpression) ?? VariableGenerator.TryGetObjectVariable(sourceExpression); o = VariableGenerator.CreateObjectVariable(expression); // The from clause is parsed first when handling a query. This allows us to detect if the // query source is a subquery and proceed with implementing it _before_ hanlding its results. MemberExpression memberExpression = expression as MemberExpression; if (s.IsGlobal()) { Type type = memberExpression.Member.DeclaringType; if (type.IsSubclassOf(typeof(Resource))) { WhereResourceOfType(s, type); } } // If the query model has a numeric result operator, we make all the following // expressions optional in order to also allow to count zero occurences. if (QueryModel.HasNumericResultOperator()) { GraphPatternBuilder optionalBuilder = new GraphPatternBuilder(GraphPatternType.Optional); Child(optionalBuilder); PatternBuilder = optionalBuilder; } } else { s = VariableGenerator.TryGetSubjectVariable(expression); o = VariableGenerator.TryGetObjectVariable(expression); } if (s != null && o != null) { // Set the variable name of the query source reference as subject of the current query. SetSubjectVariable(s, true); SetObjectVariable(o, true); } }
public void WhereResourceNotOfType(SparqlVariable s, Type type) { RdfClassAttribute t = type.TryGetCustomAttribute <RdfClassAttribute>(); if (t != null) { Uri a = new Uri("http://www.w3.org/1999/02/22-rdf-syntax-ns#type"); SparqlVariable o = VariableGenerator.CreateObjectVariable(); ConstantExpression c = Expression.Constant(t.MappedUri); PatternBuilder.Where(e => e.Subject(s).PredicateUri(a).Object(o)); PatternBuilder.Filter(e => e.Variable(o.Name) != c.AsIriExpression() || !e.Bound(o.Name)); } }
public override void SetObjectOperator(ResultOperatorBase resultOperator) { base.SetObjectOperator(resultOperator); if (ObjectVariable != null) { if (resultOperator is AnyResultOperator) { // When using x.Any(), we add a LIMIT 1 the query results in the SparqlQueryGenerator. // When using .Any(x => ..), the variable x is locally scoped and cannot be // used in outer queries. Therefore do not need to actually select it. // This avoids issues with Stardog: // https://community.stardog.com/t/sparql-union-only-working-with-inferencing-enabled/1040/9 } else if (resultOperator is AverageResultOperator) { var aggregate = new AverageAggregate(new VariableTerm(ObjectVariable.Name)); SetObjectVariable(aggregate.AsSparqlVariable(), true); } else if (resultOperator is CountResultOperator) { var aggregate = new CountDistinctAggregate(new VariableTerm(ObjectVariable.Name)); SetObjectVariable(aggregate.AsSparqlVariable(), true); } else if (resultOperator is FirstResultOperator) { // "Using LIMIT and OFFSET to select different subsets of the query solutions // will not be useful unless the order is made predictable by using ORDER BY." // Source: https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#modOffset // Therefore, if no ordering exists we add an ordering on the current subject // to make the query result predictable. if (!QueryModel.BodyClauses.OfType <OrderByClause>().Any()) { OrderBy(SubjectVariable); } else { // In case the order was make explicit, we have to do nothing. } Limit(1); } else if (resultOperator is LastResultOperator) { // "Using LIMIT and OFFSET to select different subsets of the query solutions // will not be useful unless the order is made predictable by using ORDER BY." // Source: https://www.w3.org/TR/2013/REC-sparql11-query-20130321/#modOffset // Therefore, if no ordering exists we add an ordering on the current subject // to make the query result predictable. if (!QueryModel.BodyClauses.OfType <OrderByClause>().Any()) { OrderByDescending(SubjectVariable); } else { // Inverting the direction of the first ordering is handled in SparqlQueryModelVisitor.VisitOrdering(). // This is because the orderings are not necessarily processed *before* the result operators.. } Limit(1); } else if (resultOperator is MaxResultOperator) { var aggregate = new MaxAggregate(new VariableTerm(ObjectVariable.Name)); SetObjectVariable(aggregate.AsSparqlVariable(), true); } else if (resultOperator is MinResultOperator) { var aggregate = new MinAggregate(new VariableTerm(ObjectVariable.Name)); SetObjectVariable(aggregate.AsSparqlVariable(), true); } else if (resultOperator is SumResultOperator) { var aggregate = new SumAggregate(new VariableTerm(ObjectVariable.Name)); SetObjectVariable(aggregate.AsSparqlVariable(), true); } else if (resultOperator is OfTypeResultOperator) { OfTypeResultOperator ofType = resultOperator as OfTypeResultOperator; RdfClassAttribute type = ofType.SearchedItemType.TryGetCustomAttribute <RdfClassAttribute>(); if (type == null) { throw new ArgumentException("No RdfClass attrribute declared on type: " + ofType.SearchedItemType); } SparqlVariable s = ObjectVariable; SparqlVariable p = VariableGenerator.CreatePredicateVariable(); SparqlVariable o = VariableGenerator.CreateObjectVariable(); WhereResource(s, p, o); WhereResourceOfType(o, ofType.SearchedItemType); } else if (resultOperator is SkipResultOperator) { SkipResultOperator op = resultOperator as SkipResultOperator; Offset(int.Parse(op.Count.ToString())); } else if (resultOperator is TakeResultOperator) { TakeResultOperator op = resultOperator as TakeResultOperator; Limit(int.Parse(op.Count.ToString())); } else { throw new NotImplementedException(resultOperator.ToString()); } } }
private SparqlVariable BuildMemberAccess(MemberExpression memberExpression, IGraphPatternBuilder patternBuilder) { MemberInfo member = memberExpression.Member; // If we do access a member of a system type, like string.Length we actually select the // the declaring member and invoke a SPARQL built in call to get the value. if (member.IsBuiltInCall()) { MemberExpression parentMember = memberExpression.Expression as MemberExpression; return(BuildMemberAccess(parentMember, patternBuilder)); } else if (memberExpression.Expression is MemberExpression) { MemberExpression parentMember = memberExpression.Expression as MemberExpression; // Note: When we build an optional property path, we consider the relation to the // parent properties of the accessed property to be non-optional. IGraphPatternBuilder builder = member.IsUriType() ? patternBuilder : PatternBuilder; // We might encounter property paths (i.e. contact.Organization.Name). Therefore, // implement the parent expression of the current member recursively.. SparqlVariable po = BuildMemberAccess(parentMember, builder); // If we are building a node on a property path (parentExpression != null), we associate // the object variable with the parent expression so that it becomes the subject of the parent. VariableGenerator.SetSubjectVariable(memberExpression, po); } if (member.IsUriType()) { // When we access the .Uri member of a resource we do not need a property mapping and return the subject as the bound variable. // We create a triple pattern describing the resource in the local scope just in case it has not been described yet. // Todo: Improve. Check if triples actually need to be asserted. SparqlVariable s = VariableGenerator.TryGetSubjectVariable(memberExpression) ?? SubjectVariable; SparqlVariable p = VariableGenerator.CreatePredicateVariable(); SparqlVariable o = VariableGenerator.CreateObjectVariable(memberExpression); patternBuilder.Where(t => t.Subject(s).Predicate(p).Object(o)); VariableGenerator.SetSubjectVariable(memberExpression, s); return(s); } else if (memberExpression.Expression is QuerySourceReferenceExpression) { QuerySourceReferenceExpression querySource = memberExpression.Expression as QuerySourceReferenceExpression; if (VariableGenerator.TryGetSubjectVariable(memberExpression) == VariableGenerator.GlobalSubject) { // In case the accessed member is the global query subject (i.e. from x select x.Y).. SparqlVariable s = VariableGenerator.TryGetSubjectVariable(querySource); SparqlVariable o = VariableGenerator.GlobalSubject; if (s == null) { s = VariableGenerator.CreateSubjectVariable(querySource); BuildMemberAccess(memberExpression, patternBuilder, member, s, o); } return(o); } else { // Otherwise we are accessing a member of the globale query subject (i.e. from x where x.Y select x) SparqlVariable s = VariableGenerator.TryGetSubjectVariable(querySource) ?? VariableGenerator.GlobalSubject; SparqlVariable o = VariableGenerator.TryGetObjectVariable(memberExpression) ?? VariableGenerator.CreateObjectVariable(memberExpression); BuildMemberAccess(memberExpression, patternBuilder, member, s, o); return(o); } } else { SparqlVariable s = VariableGenerator.TryGetSubjectVariable(memberExpression) ?? VariableGenerator.CreateSubjectVariable(memberExpression); SparqlVariable o = VariableGenerator.TryGetObjectVariable(memberExpression) ?? VariableGenerator.CreateObjectVariable(memberExpression); BuildMemberAccess(memberExpression, patternBuilder, member, s, o); return(o); } }
public override void OnBeforeSelectClauseVisited(Expression selector) { base.OnBeforeSelectClauseVisited(selector); QuerySourceReferenceExpression sourceExpression = selector.TryGetQuerySourceReference(); if (sourceExpression != null) { // Register the query source with the global variable for sub-queries. SparqlVariable s = VariableGenerator.TryGetSubjectVariable(sourceExpression) ?? VariableGenerator.GlobalSubject; // Assert the object type. if (sourceExpression.Type.IsSubclassOf(typeof(Resource))) { WhereResourceOfType(s, sourceExpression.Type); } if (selector is MemberExpression) { MemberExpression memberExpression = selector as MemberExpression; SparqlVariable o = VariableGenerator.CreateObjectVariable(memberExpression); // Select all triples having the resource as subject. SetSubjectVariable(s); SetObjectVariable(o, true); // If the member expression is not selected in the WHERE block, we add it here. // Scenarios: // - from x in Model.AsQueryable<X>() select x.B // - from x in Model.AsQueryable<X>() where x.A select x.B string e = memberExpression.ToString(); if (!QueryModel.BodyClauses.OfType <WhereClause>().Any(c => c.Predicate.ToString().Contains(e))) { // We select the member without a constraint on its value. QueryModel.BodyClauses.Add(new WhereClause(memberExpression)); // Since there is no constraint on the member, we also need to select the ones that are not bound. Type memberType = memberExpression.Member.GetMemberType(); // TODO: There might be a different default value on the member using the DefaultValue() attribute. object defaultValue = TypeHelper.GetDefaultValue(memberType); if (defaultValue != null && memberType != typeof(string)) { ConstantExpression coalescedValue = Expression.Constant(defaultValue); // Mark the variable to be coalesced with the default value when selected. CoalescedVariables[o] = coalescedValue.AsLiteralExpression(); } } } else if (QueryModel.HasNumericResultOperator()) { // If we have a numeric result operator on the root query, make the // subject variable known so that the model visitor can handle it. SetSubjectVariable(s); } } }