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());
                }
            }
        }
Example #2
0
        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);
            }
        }