import { DataFactory } from "rdf-data-factory" ; import { ArgumentNode , FieldNode , ListValueNode , NamedTypeNode , NameNode , ValueNode } from "graphql/language" ; import { ContextParser , JsonLdContextNormalized } from "jsonld-context-parser" ; import * as RDF from "@rdfjs/types" ; import { Algebra , Factory } from "sparqlalgebrajs" ; import { IValueNodeHandlerOutput , NodeHandlerAdapter , NodeValueHandlerAdapter } from "./handler" ; import { IConvertContext } from "./IConvertContext" ; import { IConvertSettings } from "./IConvertSettings" ; import { DirectiveNodeHandlerAdapter , IDirectiveContext , IDirectiveNodeHandlerOutput } from "./handler/directivenode/DirectiveNodeHandlerAdapter" ; /**
 * Utilities for conversion.
 */ export class Util { public readonly dataFactory : RDF . DataFactory ; public readonly operationFactory : Factory ; public readonly contextParser : ContextParser ; protected readonly settings : IConvertSettings ; private readonly nodeHandlers : { [ kind ] : NodeHandlerAdapter < any > ; } = { } ; private readonly nodeValueHandlers : { [ kind ] : NodeValueHandlerAdapter < any > ; } = { } ; private readonly directiveNodeHandlers : { [ kind ] : DirectiveNodeHandlerAdapter ; } = { } ; constructor ( settings ) { this . settings = settings ; this . dataFactory = settings . dataFactory || new DataFactory ( ) ; this . operationFactory = new Factory ( this . dataFactory ) ; this . contextParser = new ContextParser ( ) ; } /**
     * Register a new  NodeHandlerAdapter .
     *  param { NodeHandlerAdapter < any > } nodeHandler public registerNodeHandler ( nodeHandler ) { this . nodeHandlers [ nodeHandler . targetKind ] = nodeHandler ; } /**
     * Register a new  NodeValueHandlerAdapter param { NodeValueHandlerAdapter < any > } nodeValueHandler public registerNodeValueHandler ( nodeValueHandler ) { this . nodeValueHandlers [ nodeValueHandler . targetKind ] = nodeValueHandler ; } /**
     * Register a new  DirectiveNodeHandlerAdapter param { DirectiveNodeHandlerAdapter } directiveNodeHandler public registerDirectiveNodeHandler ( directiveNodeHandler ) { this . directiveNodeHandlers [ directiveNodeHandler . targetKind ] = directiveNodeHandler ; } param { T } node param { IConvertContext } convertContext return { Operation } public handleNode < T extends { kind : string ; } > ( node , convertContext ) { const nodeHandler = this . nodeHandlers [ node . kind ] ; if ( ! nodeHandler ) { throw new Error ( `Unsupported GraphQL node '${ node . kind }'` ) ; } return nodeHandler . handle ( node , convertContext ) ; } param { T } node param { string } fieldName param { IConvertContext } convertContext return { IValueNodeHandlerOutput } public handleNodeValue < T extends ValueNode > ( node , fieldName , convertContext ) { const nodeValueHandler = this . nodeValueHandlers [ node . kind ] ; if ( ! nodeValueHandler ) { throw new Error ( `Unsupported GraphQL value node '${ node . kind }'` ) ; } return nodeValueHandler . handle ( node , fieldName , convertContext ) ; } param { IDirectiveContext } directiveContext param { IConvertContext } convertContext return { IDirectiveNodeHandlerOutput } public handleDirectiveNode ( directiveContext , convertContext ) { const directiveNodeHandler = this . directiveNodeHandlers [ directiveContext . directive . name . value ] ; if ( ! directiveNodeHandler ) { return null ; } return directiveNodeHandler . handle ( directiveContext , convertContext ) ; } param { Operation [ ] } operations return { Operation } public joinOperations ( operations ) { if ( operations . length === 1 ) { return operations [ 0 ] ; } const bgps = [ ] ; const nonBgps = [ ] ; for ( const operation of operations ) { if ( operation . type === 'bgp' ) { bgps . push ( operation ) ; } else { nonBgps . push ( operation ) ; } } if ( bgps . length === operations . length ) { return this . joinOperationsAsBgp ( bgps ) ; } else if ( bgps . length === operations . length - 1 && nonBgps [ 0 ] . type === 'leftjoin' && nonBgps [ 0 ] . input [ 0 ] . type === 'bgp' ) { const originalLeftJoin = < Algebra . LeftJoin > nonBgps [ 0 ] ; bgps . push ( originalLeftJoin . input [ 0 ] ) ; return this . operationFactory . createLeftJoin ( this . joinOperationsAsBgp ( bgps ) , originalLeftJoin . input [ 1 ] ) ; } else if ( nonBgps . length === operations . length ) { return this . joinOperationsAsNestedJoin ( nonBgps ) ; } else { return this . joinOperationsAsNestedJoin ( [ this . joinOperationsAsBgp ( bgps ) , this . joinOperationsAsNestedJoin ( nonBgps ) , ] ) ; } } public joinOperationsAsBgp ( operations ) { return this . operationFactory . createBgp ( ( < Algebra . Pattern [ ] > [ ] ) . concat . apply ( [ ] , operations . map ( ( op ) => ( < Algebra . Bgp > op ) . patterns ) ) ) ; } public joinOperationsAsNestedJoin ( operations ) { return this . operationFactory . createJoin ( operations ) ; } param { string [ ] } path param { string } fieldLabel return { string [ ] } public appendFieldToPath ( path , fieldLabel ) { return path . concat ( [ fieldLabel ] ) ; } param { FieldNode } field return { string } public getFieldLabel ( field ) { return ( field . alias ? field . alias : field . name ) . value ; } param { string } fieldLabel param { IConvertContext } convertContext param { string } variableDelimiter return { Variable } public nameToVariable ( fieldLabel , convertContext ) { return this . dataFactory . variable ! ( ( convertContext . path . length ? convertContext . path . join ( this . settings . variableDelimiter ) + this . settings . variableDelimiter : '' ) + fieldLabel ) ; } param { string } value param { IContext } context return { NamedNode } public valueToNamedNode ( value , context ) { const contextValue = context . expandTerm ( value , true ) ; if ( this . settings . requireContext && ! contextValue ) { throw new Error ( 'No context entry was found for ' + value ) ; } return this . dataFactory . namedNode ( contextValue || value ) ; } param { ReadonlyArray < ArgumentNode > } args param { string } name return { ArgumentNode } public getArgument ( args , name ) { if ( args ) { for ( const argument of args ) { if ( argument . name . value === name ) { return argument ; } } } } param { Term } subject param { NamedTypeNode } typeCondition param { IConvertContext } convertContext return { Pattern } public newTypePattern ( subject , typeCondition , convertContext ) { return this . operationFactory . createPattern ( subject , this . dataFactory . namedNode ( 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type' ) , this . valueToNamedNode ( typeCondition . name . value , convertContext . context ) , convertContext . graph ) ; } param { Term } subject param { NameNode } predicateName param { Term } object param { Term } graph param { IContext } context return { Pattern } public createQuadPattern ( subject , predicateName , object , graph , context ) { const predicate = this . valueToNamedNode ( predicateName . value , context ) ; if ( context && context . getContextRaw ( ) [ predicateName . value ] && ( < any > context . getContextRaw ( ) [ predicateName . value ] ) [ '@reverse' ] ) { return this . operationFactory . createPattern ( object , predicate , subject , graph ) ; } return this . operationFactory . createPattern ( subject , predicate , object , graph ) ; } param { Term } subject param { NameNode } predicateName param { Term } object param { Term } graph param { IContext } context return { Path } public createQuadPath ( subject , predicateName , predicateAlternatives , object , graph , context ) { const predicateInitial = this . valueToNamedNode ( predicateName . value , context ) ; let pathSymbol = this . operationFactory . createLink ( predicateInitial ) ; for ( const predicateAlternative of predicateAlternatives . values ) { if ( predicateAlternative . kind !== 'EnumValue' ) { throw new Error ( 'Invalid value type for \'alt\' argument, must be EnumValue, but got ' + predicateAlternative . kind ) ; } pathSymbol = this . operationFactory . createAlt ( [ pathSymbol , this . operationFactory . createLink ( this . valueToNamedNode ( predicateAlternative . value , context ) ) , ] ) ; } if ( context && context . getContextRaw ( ) [ predicateName . value ] && ( < any > context . getContextRaw ( ) [ predicateName . value ] ) [ '@reverse' ] ) { return this . operationFactory . createPath ( object , pathSymbol , subject , graph ) ; } return this . operationFactory . createPath ( subject , pathSymbol , object , graph ) ; } }