Skip to content

Commit 5d9949c

Browse files
committed
commit
ready for tests to pass after regenerating changed asts
1 parent 43e4979 commit 5d9949c

13 files changed

Lines changed: 90 additions & 53 deletions

File tree

packages/algebra-transformer-1-1/lib/algebraToAst/sparql.ts

Lines changed: 48 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ import type {
5656
Term,
5757
Sparql11Nodes,
5858
Quads,
59+
60+
DatasetClauses,
61+
PatternFilter,
5962
} from '@traqula/rules-sparql-1-1';
6063
import { isomorphic } from 'rdf-isomorphic';
6164
import * as Algebra from '../algebra';
@@ -258,7 +261,7 @@ class Translator {
258261
return this.astFactory.wildcard(this.astFactory.gen());
259262
}
260263

261-
private arrayToPattern(input: Pattern[]): Pattern {
264+
private arrayToPattern(input: Pattern[]): PatternGroup {
262265
if (!Array.isArray(input)) {
263266
return this.astFactory.patternGroup([ input ], this.astFactory.gen());
264267
}
@@ -314,6 +317,14 @@ class Translator {
314317
]);
315318
}
316319

320+
private translateDatasetClauses(_default: RDF.NamedNode[], named: RDF.NamedNode[]): DatasetClauses {
321+
const F = this.astFactory;
322+
return F.datasetClauses([
323+
..._default.map(x => (<const>{ clauseType: 'default', value: this.translateTerm(x) })),
324+
...named.map(x => (<const>{ clauseType: 'named', value: this.translateTerm(x) })),
325+
], F.gen());
326+
}
327+
317328
/**
318329
* Input of from is for example a project
319330
*/
@@ -326,10 +337,7 @@ class Translator {
326337
} else {
327338
query = result;
328339
}
329-
query.datasets = F.datasetClauses([
330-
...op.default.map(x => (<const>{ clauseType: 'default', value: this.translateTerm(x) })),
331-
...op.named.map(x => (<const>{ clauseType: 'named', value: this.translateTerm(x) })),
332-
], F.gen());
340+
query.datasets = this.translateDatasetClauses(op.default, op.named);
333341
return <PatternGroup> result;
334342
}
335343

@@ -395,6 +403,7 @@ class Translator {
395403
}
396404

397405
private translateMinus(op: Algebra.Minus): Pattern[] {
406+
const F = this.astFactory;
398407
let patterns = this.translateOperation(op.input[1]);
399408
if (patterns.type === 'group') {
400409
patterns = patterns.patterns;
@@ -404,10 +413,7 @@ class Translator {
404413
}
405414
return Util.flatten([
406415
this.translateOperation(op.input[0]),
407-
{
408-
type: 'minus',
409-
patterns,
410-
},
416+
F.patternMinus(patterns, F.gen()),
411417
]);
412418
}
413419

@@ -578,15 +584,14 @@ class Translator {
578584
// Convert filter to 'having' if it contains an aggregator variable
579585
// could always convert, but is nicer to use filter when possible
580586
if (result.where && F.isPatternFilter(result.where.patterns.at(-1) ?? {})) {
581-
// TODO: jitsy: inspect closer
582-
// const filter = <PatternFilter> result.where.patterns.at(-1);
583-
// if (this.objectContainsValues(filter, Object.keys(aggregators))) {
584-
// select.solutionModifiers.having = F.solutionModifierHaving(
585-
// Util.flatten([ this.replaceAggregatorVariables((<any> filter).expression, aggregators) ]),
586-
// F.gen(),
587-
// );
588-
// result.where.patterns.splice(-1);
589-
// }
587+
const filter = <PatternFilter> result.where.patterns.at(-1);
588+
if (this.objectContainsVariable(filter, Object.keys(aggregators))) {
589+
select.solutionModifiers.having = F.solutionModifierHaving(
590+
Util.flatten([ this.replaceAggregatorVariables(filter.expression, aggregators) ]),
591+
F.gen(),
592+
);
593+
result.where.patterns.splice(-1);
594+
}
590595
}
591596

592597
this.extend = extend;
@@ -598,6 +603,21 @@ class Translator {
598603
return F.patternGroup([ select ], F.gen());
599604
}
600605

606+
private objectContainsVariable(o: any, vals: string[]): boolean {
607+
const F = this.astFactory;
608+
const casted = <Sparql11Nodes> o;
609+
if (F.isTermVariable(casted)) {
610+
return vals.includes(casted.value);
611+
}
612+
if (Array.isArray(o)) {
613+
return o.some(e => this.objectContainsVariable(e, vals));
614+
}
615+
if (o === Object(o)) {
616+
return Object.keys(o).some(key => this.objectContainsVariable(o[key], vals));
617+
}
618+
return false;
619+
}
620+
601621
private translateReduced(op: Algebra.Reduced): Pattern {
602622
const result = this.translateOperation(op.input);
603623
// Project is nested in group object
@@ -646,7 +666,7 @@ class Translator {
646666

647667
private translateUnion(op: Algebra.Union): PatternUnion {
648668
return this.astFactory.patternUnion(
649-
<PatternGroup[]> op.input.map(x => this.translateOperation(x)).map(x => this.arrayToPattern(x)),
669+
op.input.map(x => this.translateOperation(x)).map(x => this.arrayToPattern(x)),
650670
this.astFactory.gen(),
651671
);
652672
}
@@ -768,33 +788,26 @@ F.gen(),
768788
if (where && where.type === types.FROM) {
769789
const from = where;
770790
where = from.input;
771-
use = { default: from.default, named: from.named };
791+
use = this.translateDatasetClauses(from.default, from.named);
772792
}
773793

774794
const updates = <[UpdateOperationModify & { where?: unknown; delete?: unknown; insert?: unknown }]> [{
775795
type: 'updateOperation',
776796
subType: 'modify',
777797
delete: this.convertUpdatePatterns(op.delete ?? []),
778798
insert: this.convertUpdatePatterns(op.insert ?? []),
779-
from: F.datasetClauses([], F.gen()),
799+
where: F.patternGroup([], F.gen()),
800+
from: use ?? F.datasetClauses([], F.gen()),
780801
loc: F.gen(),
781802
}];
782-
// Typings don't support 'using' yet
783-
if (use) {
784-
(<any> updates[0]).from = use;
785-
}
786803

787804
// Corresponds to empty array in SPARQL.js
788805
if (!where || (where.type === types.BGP && where.patterns.length === 0)) {
789-
updates[0].where = [];
806+
updates[0].where = F.patternGroup([], F.gen());
790807
} else {
791808
const graphs: RDF.NamedNode[] = [];
792-
const result = this.translateOperation(this.removeQuadsRecursive(where, graphs));
793-
if (result.type === 'group') {
794-
updates[0].where = result.patterns;
795-
} else {
796-
updates[0].where = [ result ];
797-
}
809+
const result = <Pattern[]> this.translateOperation(this.removeQuadsRecursive(where, graphs));
810+
updates[0].where = this.arrayToPattern(result);
798811
// Graph might not be applied yet since there was no project
799812
// this can only happen if there was a single graph
800813
if (graphs.length > 0) {
@@ -803,7 +816,9 @@ F.gen(),
803816
}
804817
// Ignore if default graph
805818
if (graphs[0]?.value !== '') {
806-
updates[0].where = [ F.patternGraph(this.translateTerm(graphs[0]), updates[0].where, F.gen()) ];
819+
updates[0].where.patterns = [
820+
F.patternGraph(this.translateTerm(graphs[0]), updates[0].where.patterns, F.gen()),
821+
];
807822
}
808823
}
809824
}

packages/algebra-transformer-1-1/lib/sparqlAlgebra.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,7 @@ class QueryTranslator {
538538
const contained = predicate.items[0];
539539
let items: (TermIri | PathNegatedElt)[];
540540
if (this.astFactory.isPathPure(contained) && contained.subType === '|') {
541-
items = <(TermIri | PathNegatedElt)[]> contained.items;
541+
items = contained.items;
542542
} else {
543543
items = [ contained ];
544544
}
@@ -1071,8 +1071,8 @@ class QueryTranslator {
10711071
this.translateUpdateTriplesBlock(quad, op.graph ? this.translateTerm(op.graph) : op.graph)));
10721072
insertTriples.push(...op.insert.flatMap(quad =>
10731073
this.translateUpdateTriplesBlock(quad, op.graph ? this.translateTerm(op.graph) : op.graph)));
1074-
if (op.where.length > 0) {
1075-
where = this.translateGraphPattern(F.patternGroup(op.where, F.sourceLocation(...op.where)));
1074+
if (op.where.patterns.length > 0) {
1075+
where = this.translateGraphPattern(op.where);
10761076
const use: { default: RDF.NamedNode[]; named: RDF.NamedNode[] } = this.translateDatasetClause(op.from);
10771077
if (use.default.length > 0 || use.named.length > 0) {
10781078
where = this.factory.createFrom(where, use.default, use.named);

packages/algebra-transformer-1-1/test/sparql/sparql11-query/update/sparql-update-3-1-3-2b-quads.sparql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,9 @@ WHERE
1313
?person foaf:name ?name .
1414
OPTIONAL { ?person foaf:mbox ?email }
1515
} }
16+
17+
INSERT{
18+
GRAPH <http://example/addresses> {
19+
?person <http://xmlns.com/foaf/0.1/name> ?name .
20+
?person <http://xmlns.com/foaf/0.1/mbox> ?email . } } WHERE {
21+
GRAPH <http://example/people> { } } ;

packages/core/lib/generator-builder/dynamicGenerator.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export class DynamicGenerator<Context, Names extends string, RuleDefs extends Ge
4848
const generate = (): void => def.gImpl({
4949
SUBRULE: this.subrule,
5050
PRINT: this.print,
51+
PRINT_SPACE_LEFT: this.printSpaceLeft,
5152
PRINT_WORD: this.printWord,
5253
PRINT_WORDS: this.printWords,
5354
CATCHUP: this.catchup,
@@ -119,6 +120,11 @@ export class DynamicGenerator<Context, Names extends string, RuleDefs extends Ge
119120
this.expectsSpace = true;
120121
};
121122

123+
private readonly printSpaceLeft: RuleDefArg['PRINT_WORD'] = (...args) => {
124+
this.expectsSpace = true;
125+
this.print(...args);
126+
};
127+
122128
private readonly printWords: RuleDefArg['PRINT_WORD'] = (...args) => {
123129
for (const arg of args) {
124130
this.printWord(arg);

packages/core/lib/generator-builder/generatorTypes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export type GeneratorRule<
3232
export interface RuleDefArg {
3333
SUBRULE: <T, U>(cstDef: GeneratorRule<any, any, T, U>, input: T, arg: U) => void;
3434
PRINT: (...args: string[]) => void;
35+
PRINT_SPACE_LEFT: (...args: string[]) => void;
3536
PRINT_WORD: (...args: string[]) => void;
3637
PRINT_WORDS: (...args: string[]) => void;
3738
HANDLE_LOC: <T>(loc: Localized, nodeHandle: () => T) => T | undefined;

packages/rules-sparql-1-1/lib/RoundTripTypes.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ export type UpdateOperationModify = UpdateOperationBase & {
8888
insert: Quads[];
8989
delete: Quads[];
9090
from: DatasetClauses;
91-
where: Pattern[];
91+
where: PatternGroup;
9292
};
9393
export type UpdateOperation =
9494
| UpdateOperationLoad

packages/rules-sparql-1-1/lib/factoryMixins/UpdateOperationFactory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import type {
44
GraphRef,
55
GraphRefDefault,
66
GraphRefSpecific,
7-
Pattern,
7+
Pattern, PatternGroup,
88
Quads,
99
TermIri,
1010
UpdateOperationAdd,
@@ -254,7 +254,7 @@ export function UpdateOperationFactoryMixin<TBase extends Constructor<CoreFactor
254254
loc: SourceLocation,
255255
insert: Quads[] | undefined,
256256
del: Quads[] | undefined,
257-
where: Pattern[],
257+
where: PatternGroup,
258258
from: DatasetClauses,
259259
graph?: TermIri | undefined,
260260
): UpdateOperationModify {

packages/rules-sparql-1-1/lib/grammar/dataSetClause.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ export const usingClause = datasetClauseUsing('usingClause', l.usingClause);
5151
export function datasetClauseUsingStar<RuleName extends string>(
5252
name: RuleName,
5353
subRule: ReturnType<typeof datasetClauseUsing<any>>,
54+
fromUsing: 'FROM' | 'USING',
5455
): SparqlRule<RuleName, DatasetClauses> {
5556
return {
5657
name,
@@ -69,7 +70,7 @@ export function datasetClauseUsingStar<RuleName extends string>(
6970
},
7071
gImpl: ({ SUBRULE, PRINT_WORD }) => (ast, { factory: F }) => {
7172
for (const clause of ast.clauses) {
72-
PRINT_WORD('FROM');
73+
PRINT_WORD(fromUsing);
7374
if (clause.clauseType === 'named') {
7475
F.printFilter(ast, () => PRINT_WORD('NAMED'));
7576
}
@@ -79,8 +80,8 @@ export function datasetClauseUsingStar<RuleName extends string>(
7980
};
8081
}
8182

82-
export const datasetClauseStar = datasetClauseUsingStar(<const> 'datasetClauses', datasetClause);
83-
export const usingClauseStar = datasetClauseUsingStar(<const> 'usingClauses', usingClause);
83+
export const datasetClauseStar = datasetClauseUsingStar(<const> 'datasetClauses', datasetClause, 'FROM');
84+
export const usingClauseStar = datasetClauseUsingStar(<const> 'usingClauses', usingClause, 'USING');
8485

8586
/**
8687
* [[15]](https://www.w3.org/TR/sparql11-query/#rNamedGraphClause)

packages/rules-sparql-1-1/lib/grammar/expression.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,9 @@ export const argList: SparqlRule<'argList', Wrap<IArgList>> = <const> {
7070
}
7171
});
7272
const [ head, ...tail ] = ast.val.args;
73-
SUBRULE(expression, head, undefined);
73+
if (head) {
74+
SUBRULE(expression, head, undefined);
75+
}
7476
for (const expr of tail) {
7577
F.printFilter(ast, () => PRINT_WORD(','));
7678
SUBRULE(expression, expr, undefined);
@@ -104,7 +106,7 @@ export const expressionList: SparqlGrammarRule<'expressionList', Wrap<Expression
104106
]),
105107
};
106108

107-
const infixOperators = new Set([ '||', '&&', '=', '!=', '<', '>', '<=', '>=', '+', '-', '*', '/' ]);
109+
const infixOperators = new Set([ 'in', 'notin', '||', '&&', '=', '!=', '<', '>', '<=', '>=', '+', '-', '*', '/' ]);
108110
const prefixOperator = new Set([ '!', 'UPLUS', 'UMINUS' ]);
109111

110112
/**
@@ -118,7 +120,7 @@ export const expression: SparqlRule<'expression', Expression> = <const> {
118120
SUBRULE(varOrTerm, ast, undefined);
119121
} else if (F.isExpressionOperator(ast)) {
120122
if (infixOperators.has(ast.operator)) {
121-
const [ left, right ] = <[Expression, Expression]>ast.args;
123+
const [ left, ...right ] = ast.args;
122124
F.printFilter(ast, () => PRINT_WORD('('));
123125
SUBRULE(expression, left, undefined);
124126
F.printFilter(ast, () => {
@@ -130,7 +132,11 @@ export const expression: SparqlRule<'expression', Expression> = <const> {
130132
PRINT_WORD(ast.operator);
131133
}
132134
});
133-
SUBRULE(expression, right, undefined);
135+
if (right.length === 1) {
136+
SUBRULE(expression, right[0], undefined);
137+
} else {
138+
SUBRULE(argList, F.wrap({ args: right, distinct: false }, ast.loc), undefined);
139+
}
134140
F.printFilter(ast, () => PRINT_WORD(')'));
135141
} else if (prefixOperator.has(ast.operator)) {
136142
const [ expr ] = <[Expression]>ast.args;

packages/rules-sparql-1-1/lib/grammar/literals.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,8 @@ export const rdfLiteral: SparqlRule<'rdfLiteral', TermLiteral> = <const> {
6464
} },
6565
])) ?? value;
6666
},
67-
gImpl: ({ SUBRULE, PRINT }) => (ast, { factory }) => {
68-
factory.printFilter(ast, () => PRINT(stringEscapedLexical(ast.value)));
67+
gImpl: ({ SUBRULE, PRINT, PRINT_SPACE_LEFT }) => (ast, { factory }) => {
68+
factory.printFilter(ast, () => PRINT_SPACE_LEFT(stringEscapedLexical(ast.value)));
6969

7070
if (ast.langOrIri) {
7171
if (typeof ast.langOrIri === 'string') {
@@ -240,8 +240,8 @@ export const iriFull: SparqlRule<'iriFull', TermIriFull> = <const> {
240240
const iriToken = CONSUME(l.terminals.iriRef);
241241
return ACTION(() => C.factory.namedNode(C.factory.sourceLocation(iriToken), iriToken.image.slice(1, -1)));
242242
},
243-
gImpl: ({ PRINT_WORD }) => (ast, { factory }) => {
244-
factory.printFilter(ast, () => PRINT_WORD('<', ast.value, '>'));
243+
gImpl: ({ PRINT }) => (ast, { factory }) => {
244+
factory.printFilter(ast, () => PRINT('<', ast.value, '>'));
245245
},
246246
};
247247

0 commit comments

Comments
 (0)