@@ -56,6 +56,9 @@ import type {
5656 Term ,
5757 Sparql11Nodes ,
5858 Quads ,
59+
60+ DatasetClauses ,
61+ PatternFilter ,
5962} from '@traqula/rules-sparql-1-1' ;
6063import { isomorphic } from 'rdf-isomorphic' ;
6164import * 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 }
0 commit comments