diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 00000000..a211ef17 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,334 @@ +// Type definitions for sparqljs 3.1 +// Project: https://github.com/RubenVerborgh/SPARQL.js +// Definitions by: Alexey Morozov +// Ruben Taelman +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.1 + +import * as RdfJs from '@rdfjs/types'; + +//type RdfJs = import('').RdfJs; + +export const Parser: { + new (options?: ParserOptions): SparqlParser; +}; + +export interface ParserOptions { + prefixes?: { [prefix: string]: string } | undefined; + baseIRI?: string | undefined; + factory?: RdfJs.DataFactory | undefined; + sparqlStar?: boolean | undefined; +} + +export const Generator: { + new (options?: GeneratorOptions): SparqlGenerator; +}; + +export interface GeneratorOptions { + allPrefixes?: boolean | undefined; + prefixes?: { [prefix: string]: string } | undefined; + indent?: string | undefined; + newline?: string | undefined; + sparqlStar?: boolean | undefined; +} + +export interface SparqlParser { + parse(query: string): SparqlQuery; +} + +export interface SparqlGenerator { + stringify(query: SparqlQuery): string; + createGenerator(): any; +} + +export class Wildcard { + readonly termType: 'Wildcard'; + readonly value: '*'; + equals(other: RdfJs.Term | null | undefined): boolean; +} + +export type Term = VariableTerm | IriTerm | LiteralTerm | BlankTerm | QuadTerm; + +export type VariableTerm = RdfJs.Variable; +export type IriTerm = RdfJs.NamedNode; +export type LiteralTerm = RdfJs.Literal; +export type BlankTerm = RdfJs.BlankNode; +export type QuadTerm = RdfJs.Quad; + +export type SparqlQuery = Query | Update; + +export type Query = SelectQuery | ConstructQuery | AskQuery | DescribeQuery | PathsQuery; + +export interface BaseQuery { + type: 'query'; + base?: string | undefined; + prefixes: { [prefix: string]: string; }; + where?: Pattern[] | undefined; + values?: ValuePatternRow[] | undefined; +} + +export interface SelectQuery extends BaseQuery { + queryType: 'SELECT'; + variables: Variable[] | [Wildcard]; + distinct?: boolean | undefined; + from?: { + default: IriTerm[]; + named: IriTerm[]; + } | undefined; + reduced?: boolean | undefined; + group?: Grouping[] | undefined; + having?: Expression[] | undefined; + order?: Ordering[] | undefined; + limit?: number | undefined; + offset?: number | undefined; +} + +export interface Grouping { + expression: Expression; +} + +export interface Ordering { + expression: Expression; + descending?: boolean | undefined; +} + +export interface ConstructQuery extends BaseQuery { + queryType: 'CONSTRUCT'; + template?: Triple[] | undefined; +} + +export interface AskQuery extends BaseQuery { + queryType: 'ASK'; +} + +export interface DescribeQuery extends BaseQuery { + queryType: 'DESCRIBE'; + variables: Variable[] | [Wildcard]; +} + +export interface PathsQuery extends BaseQuery { + queryType: "PATHS"; + shortest: boolean; + cyclic: boolean; + start: PathEndpoint; + end: PathEndpoint; + via: PathVia; + maxLength?: number; + limit?: number; + offset?: number; +} + +export interface PathEndpoint { + variable: VariableTerm; + input?: { type: 'NamedNode', value: IriTerm } | { type: 'Pattern', value: GroupPattern }; +} + +export type PathVia = + { type: 'Variable', value: VariableTerm } | + { type: 'Path', value: IriTerm | PropertyPath } | + { type: 'Pattern', value: GroupPattern } + +export interface Update { + type: 'update'; + prefixes: { [prefix: string]: string; }; + updates: UpdateOperation[]; +} + +export type UpdateOperation = InsertDeleteOperation | ManagementOperation; + +export interface InsertDeleteOperation { + updateType: 'insert' | 'delete' | 'deletewhere' | 'insertdelete'; + graph?: IriTerm | undefined; + insert?: Quads[] | undefined; + delete?: Quads[] | undefined; + where?: Pattern[] | undefined; +} + +export type Quads = BgpPattern | GraphQuads; + +export type ManagementOperation = + | CopyMoveAddOperation + | LoadOperation + | CreateOperation + | ClearDropOperation; + +export interface CopyMoveAddOperation { + type: 'copy' | 'move' | 'add'; + silent: boolean; + source: GraphOrDefault; + destination: GraphOrDefault; +} + +export interface LoadOperation { + type: 'load'; + silent: boolean; + source: IriTerm; + destination: IriTerm | false; +} + +export interface CreateOperation { + type: 'create'; + silent: boolean; + graph: IriTerm; +} + +export interface ClearDropOperation { + type: 'clear' | 'drop'; + silent: boolean; + graph: GraphReference; +} + +export interface GraphOrDefault { + type: 'graph'; + name?: IriTerm | undefined; + default?: boolean | undefined; +} + +export interface GraphReference extends GraphOrDefault { + named?: boolean | undefined; + all?: boolean | undefined; +} + +/** + * Examples: '?var', '*', + * SELECT (?a as ?b) ... ==> { expression: '?a', variable: '?b' } + */ +export type Variable = VariableExpression | VariableTerm; + +export interface VariableExpression { + expression: Expression; + variable: VariableTerm; +} + +export type Pattern = + | BgpPattern + | BlockPattern + | FilterPattern + | BindPattern + | ValuesPattern + | SelectQuery; + //| PathsQuery; + +/** + * Basic Graph Pattern + */ +export interface BgpPattern { + type: 'bgp'; + triples: Triple[]; +} + +export interface GraphQuads { + type: 'graph'; + name: IriTerm; + triples: Triple[]; +} + +export type BlockPattern = + | OptionalPattern + | UnionPattern + | GroupPattern + | GraphPattern + | MinusPattern + | ServicePattern; + +export interface OptionalPattern { + type: 'optional'; + patterns: Pattern[]; +} + +export interface UnionPattern { + type: 'union'; + patterns: Pattern[]; +} + +export interface GroupPattern { + type: 'group'; + patterns: Pattern[]; +} + +export interface GraphPattern { + type: 'graph'; + name: IriTerm; + patterns: Pattern[]; +} + +export interface MinusPattern { + type: 'minus'; + patterns: Pattern[]; +} + +export interface ServicePattern { + type: 'service'; + name: IriTerm; + silent: boolean; + patterns: Pattern[]; +} + +export interface FilterPattern { + type: 'filter'; + expression: Expression; +} + +export interface BindPattern { + type: 'bind'; + expression: Expression; + variable: VariableTerm; +} + +export interface ValuesPattern { + type: 'values'; + values: ValuePatternRow[]; +} + +export interface ValuePatternRow { + [variable: string]: IriTerm | BlankTerm | LiteralTerm | undefined; +} + +export interface Triple { + subject: IriTerm | BlankTerm | VariableTerm | QuadTerm; + predicate: IriTerm | VariableTerm | PropertyPath; + object: Term; +} + +export interface PropertyPath { + type: 'path'; + pathType: '|' | '/' | '^' | '+' | '*' | '!'; + items: Array; +} + +export type Expression = + | OperationExpression + | FunctionCallExpression + | AggregateExpression + | BgpPattern + | GraphPattern + | GroupPattern + | Tuple + | Term; + +// allow Expression circularly reference itself +export interface Tuple extends Array {} + +export interface BaseExpression { + type: string; + distinct?: boolean | undefined; +} + +export interface OperationExpression extends BaseExpression { + type: 'operation'; + operator: string; + args: Expression[]; +} + +export interface FunctionCallExpression extends BaseExpression { + type: 'functionCall'; + function: string; + args: Expression[]; +} + +export interface AggregateExpression extends BaseExpression { + type: 'aggregate'; + expression: Expression; + aggregation: string; + separator?: string | undefined; +} \ No newline at end of file diff --git a/lib/SparqlGenerator.js b/lib/SparqlGenerator.js index 92d933ed..1ed1c82b 100644 --- a/lib/SparqlGenerator.js +++ b/lib/SparqlGenerator.js @@ -23,12 +23,51 @@ function Generator(options) { this._explicitDatatype = Boolean(options.explicitDatatype); } +// Add a new function to handle PATHS queries +Generator.prototype.toPathsQuery = function (q) { + let query = 'PATHS '; + + if (q.start) { + query += `START = ${this.toEntity(q.start)} `; + } + if (q.end) { + query += `END = ${this.toEntity(q.end)} `; + } + if (q.via) { + query += `VIA = ${this.toEntity(q.via)} `; + } + if (q.maxLength !== undefined) { + query += `MAXLENGTH = ${q.maxLength} `; + } + if (q.shortest) { + query += 'SHORTEST '; + } + if (q.cyclic) { + query += 'CYCLIC '; + } + if (q.limit !== undefined) { + query += `LIMIT ${q.limit} `; + } + if (q.offset !== undefined) { + query += `OFFSET ${q.offset} `; + } + + return query.trim(); +}; + // Converts the parsed query object into a SPARQL query Generator.prototype.toQuery = function (q) { var query = ''; - if (q.queryType) - query += q.queryType.toUpperCase() + ' '; + if (q.queryType) { + switch (q.queryType.toUpperCase()) { + case "PATHS" : + return this.toPathsQuery(q); + default: + query += q.queryType.toUpperCase() + ' '; + } + } + if (q.reduced) query += 'REDUCED '; if (q.distinct) diff --git a/lib/sparql.jison b/lib/sparql.jison index d981ab06..7c19d345 100644 --- a/lib/sparql.jison +++ b/lib/sparql.jison @@ -462,6 +462,7 @@ } return operations; } + module.exports = parser; %} %lex @@ -666,6 +667,14 @@ SPACES_COMMENTS (\s+|{COMMENT}\n\r?)+ {ANON} return 'ANON' <> return 'EOF' . return 'INVALID' +"PATHS" return 'PATHS' +"START" return 'START' +"END" return 'END' +"VIA" return 'VIA' +"ALL" return 'ALL' +"MAX LENGTH" return 'MAXLENGTH' +"SHORTEST" return 'SHORTEST' +"CYCLIC" return 'CYCLIC' /lex @@ -804,6 +813,34 @@ Qry | 'DESCRIBE' ( VarOrIri+ | '*' ) DatasetClause* WhereClause? SolutionModifier -> extend({ queryType: 'DESCRIBE', variables: $2 === '*' ? [new Wildcard()] : $2 }, groupDatasets($3), $4, $5) // [12] AskQuery | 'ASK' DatasetClause* WhereClause SolutionModifier -> extend({ queryType: 'ASK' }, groupDatasets($2), $3, $4) + | 'PATHS' ShortestModifier? 'CYCLIC'? 'START' PathEndpoint 'END' PathEndpoint 'VIA' PathVia MaxLengthModifier? LimitOffsetClauses? -> extend({ queryType: 'PATHS', shortest: ($2 !== undefined ? $2 : true), cyclic: ($3 !== undefined), start: $5, end: $7, via: $9 }, $10, $11) + ; + +ShortestModifier + : 'SHORTEST' -> true + | 'ALL' -> false + ; + +PathEndpoint + : Var ( ConstantEndpoint | GraphPatternEndpoint )? -> { variable: $1, input: $2 } + ; + +ConstantEndpoint + : '=' iri -> { type: 'NamedNode', value: $2 } + ; + +GraphPatternEndpoint + : GroupGraphPattern -> { type: 'Pattern', value: { type: 'group', patterns: $1.patterns }} + ; + +PathVia + : Var -> { type: 'Variable', value: $1 } + | GroupGraphPattern -> { type: 'Pattern', value: { type: 'group', patterns: $1.patterns }} + | Path -> { type: 'Path', value: $1 } + ; + +MaxLengthModifier + : 'MAXLENGTH' INTEGER -> { maxLength: toInt($2) } ; SelectClauseWildcard diff --git a/package.json b/package.json index 9119ad76..f610f261 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "sparqljs", - "version": "3.7.3", + "version": "3.7.300", "description": "A parser for the SPARQL query language", "author": "Ruben Verborgh ", "keywords": [ @@ -18,11 +18,13 @@ "url": "https://github.com/RubenVerborgh/SPARQL.js/issues" }, "main": "sparql.js", + "types": "index.d.ts", "bin": { "sparqljs": "bin/sparql-to-json" }, "files": [ "sparql.js", + "index.d.ts", "lib/*.js", "bin/*" ], diff --git a/queries/paths_keyword/all_max_len.sparql b/queries/paths_keyword/all_max_len.sparql new file mode 100644 index 00000000..6f218436 --- /dev/null +++ b/queries/paths_keyword/all_max_len.sparql @@ -0,0 +1,3 @@ +PREFIX ex: + +PATHS ALL START ?s = ex:Alice END ?e = ex:Bob VIA ?v MAX LENGTH 7 diff --git a/queries/paths_keyword/base.sparql b/queries/paths_keyword/base.sparql new file mode 100644 index 00000000..64139b46 --- /dev/null +++ b/queries/paths_keyword/base.sparql @@ -0,0 +1 @@ +PATHS START ?s = End ?e = VIA diff --git a/queries/paths_keyword/cycoff.sparql b/queries/paths_keyword/cycoff.sparql new file mode 100644 index 00000000..a9025d69 --- /dev/null +++ b/queries/paths_keyword/cycoff.sparql @@ -0,0 +1,7 @@ +PREFIX ex: + +PATHS CYCLIC +START ?s = ex:Node1 +END ?e = ex:Node2 +VIA ?v +OFFSET 10 diff --git a/queries/paths_keyword/limoffshor.sparql b/queries/paths_keyword/limoffshor.sparql new file mode 100644 index 00000000..ba7e4361 --- /dev/null +++ b/queries/paths_keyword/limoffshor.sparql @@ -0,0 +1,8 @@ +PREFIX ex: + +PATHS SHORTEST +START ?s = ex:Source +END ?e = ex:Target +VIA ex:leadsTo +OFFSET 2 +LIMIT 8 \ No newline at end of file diff --git a/queries/paths_keyword/prefix.sparql b/queries/paths_keyword/prefix.sparql new file mode 100644 index 00000000..6cb5e614 --- /dev/null +++ b/queries/paths_keyword/prefix.sparql @@ -0,0 +1,6 @@ +PREFIX ex: + +PATHS +START ?s = ex:PersonA +END ?e = ex:PersonB +VIA ex:knows \ No newline at end of file diff --git a/queries/paths_keyword/short_gp.sparql b/queries/paths_keyword/short_gp.sparql new file mode 100644 index 00000000..77908838 --- /dev/null +++ b/queries/paths_keyword/short_gp.sparql @@ -0,0 +1,6 @@ +PREFIX ex: + +PATHS SHORTEST +START ?s { ?s ex:hasAge 30 } +END ?e { ?e ex:hasAge 40 } +VIA ex:knows diff --git a/queries/paths_keyword/via_pattern.sparql b/queries/paths_keyword/via_pattern.sparql new file mode 100644 index 00000000..bc9ddadd --- /dev/null +++ b/queries/paths_keyword/via_pattern.sparql @@ -0,0 +1 @@ +PATHS START ?s = End ?e = VIA { ?s ?e } diff --git a/test/SparqlParser-test.js b/test/SparqlParser-test.js index 1e5a62c7..3c61217c 100644 --- a/test/SparqlParser-test.js +++ b/test/SparqlParser-test.js @@ -26,6 +26,10 @@ describe('A SPARQL parser', function () { testQueries('sparqlstar-spec', { mustError: true }); }); + describe('Testing the paths keyword', () => { + testQueries('paths_keyword', {mustError:false}); + }); + describe('in SPARQL mode with skipValidation', () => { testQueries('sparql', { skipValidation: true }); testQueries('sparqlstar', { skipValidation: true, mustError: true }); @@ -128,6 +132,48 @@ describe('A SPARQL parser', function () { expect(error.message).toContain("Target id of 'AS' (?X) already used in subquery"); }); + it('should throw an error because end has = missing was left empty', function () { + var query = 'PATHS START ?s = END ?e VIA ?v'; + try { parser.parse(query); } + catch (e) { error = e; } + + expect(error).not.toBeUndefined(); + expect(error).toBeInstanceOf(Error); + expect(error.message).toContain("Parse error"); + }); + + it('should throw an error because start was left empty', function () { + var query = 'PATHS START END ?e = VIA '; + try { parser.parse(query); } + catch (e) { error = e; } + + expect(error).not.toBeUndefined(); + expect(error).toBeInstanceOf(Error); + expect(error.message).toContain("Expecting 'VAR', got 'END'"); + }); + + it('should throw an error because start was not assigned a variable', function () { + var query = 'PATHS START = END ?e = VIA ?v'; + try { parser.parse(query); } + catch (e) { error = e; } + + expect(error).not.toBeUndefined(); + expect(error).toBeInstanceOf(Error); + expect(error.message).toContain("Expecting 'VAR'"); + }); + + it('should throw an error because end was not assigned a variable', function () { + var query = 'PATHS START ?s = END = VIA '; + try { parser.parse(query); } + catch (e) { error = e; } + + expect(error).not.toBeUndefined(); + expect(error).toBeInstanceOf(Error); + expect(error.message).toContain("Expecting 'VAR'"); + }); + + + it('should preserve BGP and filter pattern order', function () { var query = 'SELECT * { ?s ?p "1" . FILTER(true) . ?s ?p "2" }'; var groups = parser.parse(query).where; @@ -464,6 +510,10 @@ function testQueries(directory, settings) { var parsedQuery = parseJSON(fs.readFileSync(parsedQueryFile, 'utf8')); const parsed = parser.parse(sparql); + if (directory === 'paths_keyword'){ + console.log('expected', parsedQuery); + console.log('the sparql is ', sparql); + console.log('parsed', parsed);}; expect(parsed).toEqualParsedQuery(parsedQuery); }); } diff --git a/test/parsedQueries/paths_keyword/all_max_len.json b/test/parsedQueries/paths_keyword/all_max_len.json new file mode 100644 index 00000000..a76706cb --- /dev/null +++ b/test/parsedQueries/paths_keyword/all_max_len.json @@ -0,0 +1,43 @@ +{ + "queryType": "PATHS", + "type": "query", + "shortest": false, + "cyclic": false, + "start": { + "variable": { + "termType": "Variable", + "value": "s" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/Alice" + } + } + }, + "end": { + "variable": { + "termType": "Variable", + "value": "e" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/Bob" + } + } + }, + "via": { + "type": "Variable", + "value": { + "termType": "Variable", + "value": "v" + } + }, + "maxLength": 7, + "prefixes": { + "ex": "http://example.org/" + } +} diff --git a/test/parsedQueries/paths_keyword/base.json b/test/parsedQueries/paths_keyword/base.json new file mode 100644 index 00000000..01a56415 --- /dev/null +++ b/test/parsedQueries/paths_keyword/base.json @@ -0,0 +1,40 @@ +{ + "queryType": "PATHS", + "type": "query", + "shortest": true, + "cyclic": false, + "start": { + "variable": { + "termType": "Variable", + "value": "s" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/start" + } + } + }, + "end": { + "variable": { + "termType": "Variable", + "value": "e" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/end" + } + } + }, + "via": { + "type": "Path", + "value": { + "termType": "NamedNode", + "value": "http://example.org/via" + } + }, + "prefixes": {} +} diff --git a/test/parsedQueries/paths_keyword/cycoff.json b/test/parsedQueries/paths_keyword/cycoff.json new file mode 100644 index 00000000..726b84e0 --- /dev/null +++ b/test/parsedQueries/paths_keyword/cycoff.json @@ -0,0 +1,43 @@ +{ + "queryType": "PATHS", + "type": "query", + "shortest": true, + "cyclic": true, + "start": { + "variable": { + "termType": "Variable", + "value": "s" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/Node1" + } + } + }, + "end": { + "variable": { + "termType": "Variable", + "value": "e" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/Node2" + } + } + }, + "via": { + "type": "Variable", + "value": { + "termType": "Variable", + "value": "v" + } + }, + "offset": 10, + "prefixes": { + "ex": "http://example.org/" + } +} diff --git a/test/parsedQueries/paths_keyword/limoffshor.json b/test/parsedQueries/paths_keyword/limoffshor.json new file mode 100644 index 00000000..b0ddbf1a --- /dev/null +++ b/test/parsedQueries/paths_keyword/limoffshor.json @@ -0,0 +1,44 @@ +{ + "queryType": "PATHS", + "type": "query", + "shortest": true, + "cyclic": false, + "start": { + "variable": { + "termType": "Variable", + "value": "s" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/Source" + } + } + }, + "end": { + "variable": { + "termType": "Variable", + "value": "e" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/Target" + } + } + }, + "via": { + "type": "Path", + "value": { + "termType": "NamedNode", + "value": "http://example.org/leadsTo" + } + }, + "limit": 8, + "offset": 2, + "prefixes": { + "ex": "http://example.org/" + } +} diff --git a/test/parsedQueries/paths_keyword/prefix.json b/test/parsedQueries/paths_keyword/prefix.json new file mode 100644 index 00000000..0397dc66 --- /dev/null +++ b/test/parsedQueries/paths_keyword/prefix.json @@ -0,0 +1,42 @@ +{ + "queryType": "PATHS", + "type": "query", + "shortest": true, + "cyclic": false, + "start": { + "variable": { + "termType": "Variable", + "value": "s" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/PersonA" + } + } + }, + "end": { + "variable": { + "termType": "Variable", + "value": "e" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/PersonB" + } + } + }, + "via": { + "type": "Path", + "value": { + "termType": "NamedNode", + "value": "http://example.org/knows" + } + }, + "prefixes": { + "ex": "http://example.org/" + } +} diff --git a/test/parsedQueries/paths_keyword/short_gp.json b/test/parsedQueries/paths_keyword/short_gp.json new file mode 100644 index 00000000..0c79e916 --- /dev/null +++ b/test/parsedQueries/paths_keyword/short_gp.json @@ -0,0 +1,92 @@ +{ + "queryType": "PATHS", + "type": "query", + "shortest": true, + "cyclic": false, + "start": { + "variable": { + "termType": "Variable", + "value": "s" + }, + "input": { + "type": "Pattern", + "value": { + "patterns": [ + { + "triples": [ + { + "object": { + "datatype": { + "termType": "NamedNode", + "value": "http://www.w3.org/2001/XMLSchema#integer" + }, + "language": "", + "termType": "Literal", + "value": "30" + }, + "predicate": { + "termType": "NamedNode", + "value": "http://example.org/hasAge" + }, + "subject": { + "termType": "Variable", + "value": "s" + } + } + ], + "type": "bgp" + } + ], + "type": "group" + } + } + }, + "end": { + "variable": { + "termType": "Variable", + "value": "e" + }, + "input": { + "type": "Pattern", + "value": { + "patterns": [ + { + "triples": [ + { + "object": { + "datatype": { + "termType": "NamedNode", + "value": "http://www.w3.org/2001/XMLSchema#integer" + }, + "language": "", + "termType": "Literal", + "value": "40" + }, + "predicate": { + "termType": "NamedNode", + "value": "http://example.org/hasAge" + }, + "subject": { + "termType": "Variable", + "value": "e" + } + } + ], + "type": "bgp" + } + ], + "type": "group" + } + } + }, + "via": { + "type": "Path", + "value": { + "termType": "NamedNode", + "value": "http://example.org/knows" + } + }, + "prefixes": { + "ex": "http://example.org/" + } +} diff --git a/test/parsedQueries/paths_keyword/via_pattern.json b/test/parsedQueries/paths_keyword/via_pattern.json new file mode 100644 index 00000000..7eab8e84 --- /dev/null +++ b/test/parsedQueries/paths_keyword/via_pattern.json @@ -0,0 +1,60 @@ +{ + "queryType": "PATHS", + "type": "query", + "shortest": true, + "cyclic": false, + "start": { + "variable": { + "termType": "Variable", + "value": "s" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/start" + } + } + }, + "end": { + "variable": { + "termType": "Variable", + "value": "e" + }, + "input": { + "type": "NamedNode", + "value": { + "termType": "NamedNode", + "value": "http://example.org/end" + } + } + }, + "via": { + "type": "Pattern", + "value": { + "type": "group", + "patterns": [ + { + "triples": [ + { + "object": { + "termType": "Variable", + "value": "e" + }, + "predicate": { + "termType": "NamedNode", + "value": "http://example.org/via" + }, + "subject": { + "termType": "Variable", + "value": "s" + } + } + ], + "type": "bgp" + } + ] + } + }, + "prefixes": {} +}