• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rubensworks / graphql-to-sparql.js / 20781762490

07 Jan 2026 12:38PM UTC coverage: 92.605% (-0.05%) from 92.659%
20781762490

push

github

rubensworks
Update to Traqula v1

328 of 363 branches covered (90.36%)

Branch coverage included in aggregate %.

511 of 543 relevant lines covered (94.11%)

312.82 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.16
/lib/handler/NodeHandlerDocument.ts
1
import {DocumentNode} from "graphql";
2
import {DefinitionNode} from "graphql/language";
3
import * as RDF from "@rdfjs/types";
4
import {Algebra} from "@traqula/algebra-transformations-1-2";
48✔
5
import {AlgebraFactory, algebraUtils} from "@traqula/algebra-transformations-1-2";
48✔
6
import {IConvertContext} from "../IConvertContext";
7
import {IConvertSettings} from "../IConvertSettings";
8
import {Util} from "../Util";
9
import {INodeQuadContext, NodeHandlerAdapter} from "./NodeHandlerAdapter";
48✔
10

11
/**
12
 * Converts GraphQL documents to joined operations for all its definitions.
13
 */
14
export class NodeHandlerDocument extends NodeHandlerAdapter<DocumentNode> {
48✔
15
  constructor(util: Util, settings: IConvertSettings) {
16
    super('Document', util, settings);
318✔
17
  }
18

19
  public handle(document: DocumentNode, convertContext: IConvertContext): Algebra.Operation {
20
    const definitionOperations = document.definitions
210✔
21
      .map((definition) => {
22
        const subjectOutput = this.getNodeQuadContextDefinitionNode(definition,
210✔
23
          {...convertContext, ignoreUnknownVariables: true});
24
        const queryParseContext: IConvertContext = {
210✔
25
          ...convertContext,
26
          graph: subjectOutput.graph || convertContext.graph,
204✔
27
          subject: subjectOutput.subject || this.util.dataFactory.blankNode(),
198✔
28
        };
29
        let definitionOperation = this.util.handleNode(definition, queryParseContext);
210✔
30
        if (subjectOutput && subjectOutput.auxiliaryPatterns) {
198!
31
          definitionOperation = this.util.joinOperations([
×
32
            definitionOperation,
33
            this.util.operationFactory.createBgp(subjectOutput.auxiliaryPatterns),
34
          ]);
35
        }
36
        return definitionOperation;
198✔
37
      });
38
    const operation = this.util.operationFactory.createProject(
198✔
39
      definitionOperations.length === 1 ? definitionOperations[0] : this.util.operationFactory.createUnion(definitionOperations),
99!
40
      convertContext.terminalVariables);
41

42
    // Convert blank nodes to variables
43
    return this.translateBlankNodesToVariables(operation);
198✔
44
  }
45

46
  /**
47
   * Get the quad context of a definition node that should be used for the whole definition node.
48
   * @param {DefinitionNode} definition A definition node.
49
   * @param {IConvertContext} convertContext A convert context.
50
   * @return {INodeQuadContext} The subject and optional auxiliary patterns.
51
   */
52
  public getNodeQuadContextDefinitionNode(definition: DefinitionNode, convertContext: IConvertContext)
53
    : INodeQuadContext {
54
    if (definition.kind === 'OperationDefinition') {
210!
55
      return this.getNodeQuadContextSelectionSet(definition.selectionSet,
210✔
56
        definition.name ? definition.name.value : '', convertContext);
105✔
57
    }
58
    throw new Error(`Unsupported definition: ${definition.kind}`);
×
59
  }
60

61
  /**
62
   * Translates blank nodes inside the query to variables.
63
   * @param {Project} operation The operation to translate.
64
   * @return {Operation} The transformed operation.
65
   */
66
  public translateBlankNodesToVariables(operation: Algebra.Project): Algebra.Operation {
67
    const blankToVariableMapping: {[bLabel: string]: RDF.Variable} = {};
198✔
68
    const variablesRaw = new Set(operation.variables.map(x => x.value));
336✔
69

70
    const uniqueVar = (label: string, variables: Set<string>): RDF.Variable => {
198✔
71
      let counter = 0;
186✔
72
      let labelLoop = label;
186✔
73
      while (variablesRaw.has(labelLoop)) {
186✔
74
        labelLoop = `${label}${counter++}`;
×
75
      }
76
      return this.util.dataFactory.variable!(labelLoop);
186✔
77
    }
78

79
    const blankToVariable = (term: RDF.Term): RDF.Term => {
198✔
80
      if (term.termType === 'BlankNode') {
2,628✔
81
        let variable = blankToVariableMapping[term.value];
198✔
82
        if (!variable) {
198✔
83
          variable = uniqueVar(term.value, variablesRaw);
186✔
84
          variablesRaw.add(variable.value)
186✔
85
          blankToVariableMapping[term.value] = variable;
186✔
86
        }
87
        return variable;
198✔
88
      }
89
      return term;
2,430✔
90
    }
91

92
    return algebraUtils.mapOperation<'unsafe', typeof operation>(operation, {
198✔
93
      [Algebra.Types.PATH]: {
94
        preVisitor: () => ({continue: false}),
12✔
95
        transform: (op: Algebra.Path) => this.util.operationFactory.createPath(
12✔
96
          blankToVariable(op.subject),
97
          op.predicate,
98
          blankToVariable(op.object),
99
          blankToVariable(op.graph),
100
        )
101
      },
102
      [Algebra.Types.PATTERN]: {
103
        preVisitor: () => ({continue: false}),
648✔
104
        transform: (op: Algebra.Pattern) => this.util.operationFactory.createPattern(
648✔
105
            blankToVariable(op.subject),
106
            blankToVariable(op.predicate),
107
            blankToVariable(op.object),
108
            blankToVariable(op.graph),
109
          ),
110
      },
111
    });
112
  }
113
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc