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

terminusdb / terminusdb-client-js / 20754335327

06 Jan 2026 04:12PM UTC coverage: 58.218% (-0.5%) from 58.679%
20754335327

push

github

web-flow
Merge pull request #357 from hoijnet/rdf-list-operator-library

Rdf list operator library

2475 of 4796 branches covered (51.61%)

Branch coverage included in aggregate %.

54 of 159 new or added lines in 3 files covered. (33.96%)

7 existing lines in 1 file now uncovered.

4283 of 6812 relevant lines covered (62.87%)

43.2 hits per line

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

80.04
/lib/query/woqlQuery.js
1
/* eslint-disable class-methods-use-this */
2
/* eslint-disable no-redeclare */
3
/* eslint-disable block-scoped-var */
4
/* eslint-disable no-var */
5
/* eslint-disable vars-on-top */
6
/* eslint-disable no-param-reassign */
7
/* eslint-disable no-unused-vars */
8
/* eslint-disable camelcase */
9
/* eslint-disable no-plusplus */
10
/* eslint-disable prefer-destructuring */
11
/* eslint-disable guard-for-in */
12
/* eslint-disable no-restricted-syntax */
13

14
/// /@ts-check
15
// WOQLQuery
16
/**
17
 * defines the internal functions of the woql query object - the
18
 * language API is defined in WOQLQuery
19
 * @module WOQLQuery
20
 * @constructor
21
 * @param {object} [query] json-ld query for initialisation
22
 * @returns {WOQLQuery}
23
 */
24

25
const WOQLCore = require('./woqlCore');
1✔
26
const {
27
  Var, Vars, Doc, VarsUnique,
1✔
28
} = require('./woqlDoc');
1✔
29
// eslint-disable-next-line no-unused-vars
30
const typedef = require('../typedef');
1✔
31

32
// I HAVE TO REVIEW THE Inheritance and the prototype chain
33
class WOQLQuery extends WOQLCore {
2✔
34
  /**
35
   * defines the internal functions of the woql query object - the
36
   * language API is defined in WOQLQuery
37
   * @module WOQLQuery
38
   * @constructor
39
   * @param {object} [query] json-ld query for initialisation
40
   * @returns {WOQLQuery}
41
   */
42

43
  /**
44
 * Update a pattern matching rule for the triple (Subject, Predicate, oldObjValue) with the
45
 * new one (Subject, Predicate, newObjValue)
46
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
47
 * @param {string|Var} predicate - The IRI of a property or a variable
48
 * @param {string|Var} newObjValue - The value to update or a literal
49
 * @param {string|Var} oldObjValue - The old value of the object
50
 * @returns {WOQLQuery} A WOQLQuery which contains the a Update Triple Statement
51
 */
52
  update_triple(subject, predicate, newObjValue, oldObjValue) { return this; }
×
53

54
  /**
55
 * Generates a query that by default matches all triples in a graph identified by "graph"
56
 * or in all the current terminusDB's graph
57
 * @param {string | boolean} [graph] - false or the resource identifier of a graph possible
58
 * value are schema/{main - myschema - *} | instance/{main - myschema - *}  |
59
 * inference/{main - myschema - *}
60
 * @param {string|Var} [subject] - The IRI of a triple’s subject or a variable,
61
 * default value "v:Subject"
62
 * @param {string|Var} [predicate] - The IRI of a property or a variable,
63
 *  default value "v:Predicate"
64
 * @param {string|Var} [object] - The IRI of a node or a variable, or a literal,
65
 * default value "v:Object"
66
 * @returns {WOQLQuery} A WOQLQuery which contains the pattern matching expression
67
 */
68
  star(graph, subject, predicate, object) { return this; }
×
69

70
  /**
71
  * Update a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate, Object, Graph)
72
  * @param {string|Var} subject - The IRI of a triple’s subject or a variable
73
  * @param {string|Var} predicate - The IRI of a property or a variable
74
  * @param {string|Var} newObject - The value to update or a literal
75
  * @param {typedef.GraphRef} graphRef - A valid graph resource identifier string
76
  * @returns {WOQLQuery} A WOQLQuery which contains the a Update Quad Statement
77
  */
78
  update_quad(subject, predicate, newObject, graphRef) { return this; }
×
79

80
  /**
81
   * @param {string|Var} id - IRI string or variable containing
82
   * @param {string|Var} type  -  IRI string or variable containing the IRI of the
83
   * @param {typedef.GraphRef} [refGraph] - Optional Graph resource identifier
84
   * @returns {WOQLQuery} A WOQLQuery which contains the insert expression
85
   */
86
  insert(id, type, refGraph) { return this; }
×
87

88
  /**
89
  * Sets the graph resource ID that will be used for subsequent chained function calls
90
  * @param {typedef.GraphRef} [graphRef] Resource String identifying the graph which will
91
  * be used for subsequent chained schema calls
92
  * @returns {WOQLQuery} A WOQLQuery which contains the partial Graph pattern matching expression
93
  */
94
  graph(graphRef) { return this; }
×
95

96
  /**
97
   * Specifies the identity of a node that can then be used in subsequent builder functions.
98
   * Note that node() requires subsequent chained functions to complete the triples / quads
99
   * that it produces - by itself it only generates the subject.
100
   * @param {string|Var} nodeid -  The IRI of a node or a variable containing an IRI which will
101
   * be the subject of the builder functions
102
   * @param {typedef.FuntionType} [chainType] - Optional type of builder function to build
103
   * (default is triple)
104
   * @returns {WOQLQuery} - A WOQLQuery which contains the partial Node pattern matching expression
105
   */
106
  node(nodeid, chainType) { return this; }
×
107

108
  /**
109
   * Deletes all triples in the passed graph (defaults to instance/main)
110
   * @param {typedef.GraphRef} [graphRef] - Resource String identifying the graph from
111
   * which all triples will be removed
112
   * @returns {WOQLQuery} - A WOQLQuery which contains the deletion expression
113
   * @example
114
   * nuke("schema/main")
115
   * //will delete everything from the schema/main graph
116
   */
117
  nuke(graphRef) { return this; }
×
118

119
  /**
120
   * @param {string|Var} [Subj] - The IRI of a triple’s subject or a variable
121
   * @param {string|Var} [Pred] - The IRI of a property or a variable
122
   * @param {string|Var} [Obj] - The IRI of a node or a variable, or a literal
123
   * @param {typedef.GraphRef} [Graph] - the resource identifier of a graph possible
124
   * @returns {WOQLQuery} - A WOQLQuery which contains the pattern matching expression
125
   */
126
  all(Subj, Pred, Obj, Graph) { return this; }
×
127

128
  /**
129
   * @param {boolean} tf
130
   * @returns {object}
131
   */
132
  boolean(tf) { return {}; }
×
133

134
  /**
135
   * @param {string} s
136
   * @returns {object}
137
   */
138
  string(s) { return {}; }
×
139

140
  /**
141
 * @param {any} s
142
 * @param {string} t
143
 * @returns {object}
144

145
 */
146
  literal(s, t) { return {}; }
×
147

148
  /**
149
   * @param {string} s
150
   * @returns {object}
151
   */
152
  iri(s) { return {}; }
×
153

154
  // eslint-disable-next-line no-underscore-dangle
155
  _set_context(ctxt) { return this; }
×
156

157
  /**
158
   * @param {WOQLQuery} Subq
159
   * @returns {WOQLQuery}
160
   */
161
  addSubQuery(Subq) {
162
    super.addSubQuery(Subq);
206✔
163
    return this;
206✔
164
  }
165

166
  /**
167
   * @param {string} msg
168
   * @returns {WOQLQuery}
169
   */
170
  parameterError(msg) {
171
    super.parameterError(msg);
3✔
172
    return this;
3✔
173
  }
174

175
  /**
176
   * @returns {WOQLQuery}
177
   */
178
  updated() {
179
    super.updated();
39✔
180
    return this;
39✔
181
  }
1✔
182

183
  // eslint-disable-next-line no-useless-constructor
184
  constructor(query) {
789✔
185
    super(query);
186
  }
1✔
187
}
188

189
/**
190
 * Read a node identified by an IRI as a JSON-LD document
191
 * @param {string} IRI -  The document id  or a variable to read
192
 * @param {string} output - Variable which will be bound to the document.
193
 * @return {WOQLQuery} WOQLQuery
194
 */
195
WOQLQuery.prototype.read_document = function (IRI, output) {
1✔
196
  if (this.cursor['@type']) this.wrapCursorWithAnd();
4!
197
  this.cursor['@type'] = 'ReadDocument';
4✔
198
  this.cursor.identifier = this.cleanNodeValue(IRI);
4✔
199
  this.cursor.document = this.expandValueVariable(output);
4✔
200
  return this;
4✔
201
};
202

203
/**
204
 * Insert a document in the graph.
205
 * @param {object} docjson -  The document to insert. Must either have an '@id' or
206
 * have a class specified key.
207
 * @param {string} [IRI] - An optional identifier specifying the document location.
208
 * @return {WOQLQuery} WOQLQuery
209
 */
210

211
WOQLQuery.prototype.insert_document = function (docjson, IRI) {
1✔
212
  if (this.cursor['@type']) this.wrapCursorWithAnd();
4!
213
  this.cursor['@type'] = 'InsertDocument';
4✔
214
  if (typeof IRI !== 'undefined') this.cursor.identifier = this.cleanNodeValue(IRI);
4✔
215

216
  this.cursor.document = this.cleanObject(docjson);
4✔
217

218
  return this.updated();
4✔
219
};
220

221
/**
222
 * Update a document identified by an IRI
223
 * @param {object} docjson -  The document to update. Must either have an '@id' or
224
 * have a class specified key.
225
 * @param {string} [IRI] - An optional identifier specifying the document location.
226
 * @return {WOQLQuery} WOQLQuery
227
 */
228

229
WOQLQuery.prototype.update_document = function (docjson, IRI) {
1✔
230
  if (this.cursor['@type']) this.wrapCursorWithAnd();
6!
231
  this.cursor['@type'] = 'UpdateDocument';
6✔
232
  if (typeof IRI !== 'undefined') this.cursor.identifier = this.cleanNodeValue(IRI);
6✔
233

234
  this.cursor.document = this.cleanObject(docjson);
6✔
235

236
  return this.updated();
6✔
237
};
238

239
/**
240
 * Delete a document from the graph.
241
 * @param {string} IRI -  The document id  or a variable
242
 * @return {WOQLQuery} WOQLQuery
243
 */
244

245
WOQLQuery.prototype.delete_document = function (IRI) {
1✔
246
  if (this.cursor['@type']) this.wrapCursorWithAnd();
3!
247
  this.cursor['@type'] = 'DeleteDocument';
3✔
248
  this.cursor.identifier = this.cleanNodeValue(IRI);
3✔
249
  return this.updated();
3✔
250
};
251

252
/**
253
 * Contains definitions of the WOQL functions which map directly to JSON-LD types
254
 * All other calls and queries can be composed from these
255
 */
256

257
// moved from woqlCore
258
WOQLQuery.prototype.wrapCursorWithAnd = function () {
1✔
259
  if (this.cursor && this.cursor['@type'] === 'And') {
154✔
260
    const newby = this.cursor.and.length;
2✔
261
    this.and({});
2✔
262
    this.cursor = this.cursor.and[newby];
2✔
263
  } else {
264
    const nj = new WOQLQuery().json(this.cursor);
152✔
265
    for (const k in this.cursor) delete this.cursor[k];
628✔
266
    // create an empty json for the new query
267
    this.and(nj, {});
152✔
268
    this.cursor = this.cursor.and[1];
152✔
269
  }
270
};
271

272
/**
273
 * Query running against any specific commit Id
274
 * @param {string}  refPath  - path to specific reference Id or commit Id
275
 * @param {WOQLQuery} [subquery] - subquery for the specific commit point
276
 * @returns {WOQLQuery}
277
 */
278

279
WOQLQuery.prototype.using = function (refPath, subquery) {
1✔
280
  if (this.cursor['@type']) this.wrapCursorWithAnd();
49!
281
  this.cursor['@type'] = 'Using';
49✔
282
  if (!refPath || typeof refPath !== 'string') {
49✔
283
    return this.parameterError('The first parameter to using must be a Collection ID (string)');
1✔
284
  }
285
  this.cursor.collection = refPath;
48✔
286
  return this.addSubQuery(subquery);
48✔
287
};
288

289
/**
290
 * Adds a text comment to a query - can also be used to wrap any part of a query to turn it off
291
 * @param {string} comment - text comment
292
 * @param {WOQLQuery} [subquery]  - query that is "commented out"
293
 * @returns {WOQLQuery}
294
 */
295

296
WOQLQuery.prototype.comment = function (comment, subquery) {
1✔
297
  // if (comment && comment === 'args')
298
  // return ['comment', 'query']
299
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
300
  this.cursor['@type'] = 'Comment';
2✔
301
  this.cursor.comment = this.jlt(comment);
2✔
302
  return this.addSubQuery(subquery);
2✔
303
};
304

305
/**
306
 * Filters the query so that only the variables included in [V1...Vn] are returned in the bindings
307
 * @param {...string|...Var} varNames - only these variables are returned
308
 * @returns {WOQLQuery}
309
 */
310

311
WOQLQuery.prototype.select = function (...varNames) {
161✔
312
  if (this.cursor['@type']) this.wrapCursorWithAnd();
48!
313
  this.cursor['@type'] = 'Select';
48✔
314
  if (!varNames || varNames.length <= 0) {
48!
315
    return this.parameterError('Select must be given a list of variable names');
×
316
  }
317
  const last = varNames[varNames.length - 1];
48✔
318
  /**
319
  *@type {any}
320
  */
321
  let embedquery = false;
48✔
322
  if (typeof last === 'object' && !(last instanceof Var) && last.json) {
48✔
323
    embedquery = varNames.pop();
3✔
324
  } // else var embedquery = false
325
  this.cursor.variables = this.rawVarList(varNames);
48✔
326
  return this.addSubQuery(embedquery);
48✔
327
};
328

329
/**
330
 * Build a localized scope for variables to prevent leaking local variables to outer scope.
331
 * Returns a tuple [localized, v] where:
332
 * - localized: function that wraps queries with select("") and eq() bindings
333
 * - v: object with unique variable names for use in the inner query
334
 *
335
 * Parameters with non-null values are bound from outer scope via eq().
336
 * Parameters with null values are local-only variables.
337
 *
338
 * @param {object} paramSpec - Object mapping parameter names to values (or null for local vars)
339
 * @returns {[function, object]} Tuple of [localized function, variables object]
340
 * @example
341
 * const [localized, v] = WOQL.localize({ consSubject, valueVar, last_cell: null });
342
 * return localized(
343
 *   WOQL.and(
344
 *     WOQL.triple(v.consSubject, 'rdf:type', 'rdf:List'),
345
 *     WOQL.triple(v.last_cell, 'rdf:rest', 'rdf:nil')
346
 *   )
347
 * );
348
 */
349
WOQLQuery.prototype.localize = function (paramSpec) {
1✔
350
  // Generate unique variable names for all parameters
351
  const paramNames = Object.keys(paramSpec);
10✔
352
  const v = VarsUnique(...paramNames);
10✔
353

354
  const localized = (queryOrUndefined) => {
10✔
355
    // CRITICAL: Create eq bindings for outer parameters OUTSIDE select("")
356
    // This ensures outer parameters are visible in query results
357
    const outerEqBindings = [];
7✔
358
    for (const paramName of paramNames) {
12✔
359
      const outerValue = paramSpec[paramName];
12✔
360
      if (outerValue !== null) {
12✔
361
        // If the outer value is a variable, add eq(var, var) to register it in outer scope
362
        if (typeof outerValue === 'string' && outerValue.startsWith('v:')) {
7!
363
          outerEqBindings.push(new WOQLQuery().eq(outerValue, outerValue));
7✔
364
        }
365
        // Bind the unique variable to the outer parameter OUTSIDE the select("")
366
        outerEqBindings.push(new WOQLQuery().eq(v[paramName], outerValue));
7✔
367
      }
368
    }
369

370
    if (queryOrUndefined) {
7✔
371
      // Functional mode: wrap query in select(""), then add outer eq bindings
372
      const localizedQuery = new WOQLQuery().select('').and(queryOrUndefined);
6✔
373

374
      if (outerEqBindings.length > 0) {
6✔
375
        // Wrap: eq(outer) AND select("") { query }
376
        return new WOQLQuery().and(...outerEqBindings, localizedQuery);
3✔
377
      }
378
      return localizedQuery;
3✔
379
    }
380

381
    // Fluent mode: return wrapper that applies pattern on and()
382
    const fluentWrapper = new WOQLQuery();
1✔
383
    // eslint-disable-next-line no-underscore-dangle
384
    fluentWrapper._localizeOuterEq = outerEqBindings;
1✔
385

386
    // Override and() to apply the localize pattern
387
    fluentWrapper.and = function (...args) {
1✔
388
      const innerQuery = new WOQLQuery().and(...args);
1✔
389
      const localizedQuery = new WOQLQuery().select('').and(innerQuery);
1✔
390

391
      // eslint-disable-next-line no-underscore-dangle
392
      if (fluentWrapper._localizeOuterEq.length > 0) {
1!
393
        // eslint-disable-next-line no-underscore-dangle
394
        return new WOQLQuery().and(...fluentWrapper._localizeOuterEq, localizedQuery);
1✔
395
      }
NEW
396
      return localizedQuery;
×
397
    };
398

399
    return fluentWrapper;
1✔
400
  };
401

402
  return [localized, v];
10✔
403
};
404

405
/**
406
 * Filter the query to return only results that are distinct in the given variables
407
 * @param {...string|...Var} varNames - these variables are guaranteed to be unique as a tuple
408
 * @returns {WOQLQuery}
409
 */
410

411
WOQLQuery.prototype.distinct = function (...varNames) {
4✔
412
  // if (list && list[0] === 'args')
413
  // return ['variable_list', 'query']
414
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
415
  this.cursor['@type'] = 'Distinct';
2✔
416
  if (!varNames || varNames.length <= 0) {
2!
417
    return this.parameterError('Distinct must be given a list of variable names');
×
418
  }
419
  const last = varNames[varNames.length - 1];
2✔
420
  /**
421
     * @type {any}
422
     */
423
  let embedquery = false;
2✔
424
  if (typeof last === 'object' && !(last instanceof Var) && last.json) {
2✔
425
    embedquery = varNames.pop();
1✔
426
  } // else var embedquery = false
427
  this.cursor.variables = this.rawVarList(varNames);
2✔
428
  return this.addSubQuery(embedquery);
2✔
429
};
430

431
/**
432
* Logical conjunction of the contained queries - all queries must match or the entire clause fails
433
* @param {...WOQLQuery} subqueries - A list of one or more woql queries to execute as a conjunction
434
* @returns {WOQLQuery} - A WOQLQuery object containing the conjunction of queries
435
*/
436

437
WOQLQuery.prototype.and = function (...subqueries) {
527✔
438
  if (this.cursor['@type'] && this.cursor['@type'] !== 'And') {
227✔
439
    const nj = new WOQLQuery().json(this.cursor);
3✔
440
    for (const k in this.cursor) delete this.cursor[k];
11✔
441
    subqueries.unshift(nj);
3✔
442
  }
443
  this.cursor['@type'] = 'And';
227✔
444
  if (typeof this.cursor.and === 'undefined') this.cursor.and = [];
227✔
445
  for (let i = 0; i < subqueries.length; i++) {
227✔
446
    const onevar = this.jobj(subqueries[i]);
530✔
447
    if (
530✔
448
      onevar['@type'] === 'And'
579✔
449
      && onevar.and
450
    ) {
451
      for (let j = 0; j < onevar.and.length; j++) {
49✔
452
        const qjson = onevar.and[j];
152✔
453
        if (qjson) {
152!
454
          const subvar = this.jobj(qjson);
152✔
455
          this.cursor.and.push(subvar);
152✔
456
        }
457
      }
458
    } else {
459
      this.cursor.and.push(onevar);
481✔
460
    }
461
  }
462
  return this;
227✔
463
};
464

465
/**
466
 * Creates a logical OR of the arguments
467
 * @param {...WOQLQuery} subqueries - A list of one or more woql queries
468
 * to execute as alternatives
469
 * @returns {WOQLQuery} - A WOQLQuery object containing the logical Or of the subqueries
470
 */
471

472
WOQLQuery.prototype.or = function (...subqueries) {
1✔
473
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
474
  this.cursor['@type'] = 'Or';
2✔
475
  if (typeof this.cursor.or === 'undefined') this.cursor.or = [];
2!
476
  for (let i = 0; i < subqueries.length; i++) {
2✔
477
    const onevar = this.jobj(subqueries[i]);
3!
478
    this.cursor.or.push(onevar);
3✔
479
  }
480
  return this;
2✔
481
};
482
/**
483
 * Specifies the database URL that will be the default database for the enclosed query
484
 * @param {typedef.GraphRef} graphRef- A valid graph resource identifier string
485
 * @param {WOQLQuery} [query] - The query
486
 * @returns {WOQLQuery} A WOQLQuery object containing the from expression
487
 */
488

489
/**
490
 * Specifies the database URL that will be the default database for the enclosed query
491
 * @param {typedef.GraphRef} graphRef- A valid graph resource identifier string
492
 * @param {WOQLQuery} [query] - The query
493
 * @returns {WOQLQuery} A WOQLQuery object containing the from expression
494
 */
495

496
WOQLQuery.prototype.from = function (graphRef, query) {
1✔
497
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
498
  this.cursor['@type'] = 'From';
2✔
499
  if (!graphRef || typeof graphRef !== 'string') {
2!
500
    return this.parameterError(
×
501
      'The first parameter to from must be a Graph Filter Expression (string)',
502
    );
503
  }
504
  this.cursor.graph = this.jlt(graphRef);
2✔
505
  return this.addSubQuery(query);
2✔
506
};
507

508
/**
509
 * Specifies the graph resource to write the contained query into
510
 * @param {typedef.GraphRef} graphRef- A valid graph resource identifier string
511
 * @param {WOQLQuery} [subquery] - The query which will be written into the graph
512
 * @returns {WOQLQuery} A WOQLQuery which will be written into the graph in question
513
 */
514

515
WOQLQuery.prototype.into = function (graphRef, subquery) {
1✔
516
  // if (graph_descriptor && graph_descriptor === 'args')
517
  // return ['graph', 'query']
518
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
519
  this.cursor['@type'] = 'Into';
2✔
520
  if (!graphRef || typeof graphRef !== 'string') {
2!
521
    return this.parameterError(
×
522
      'The first parameter to from must be a Graph Filter Expression (string)',
523
    );
524
  }
525
  this.cursor.graph = this.jlt(graphRef);
2✔
526
  return this.addSubQuery(subquery);
2✔
527
};
528

529
/**
530
 * Creates a triple pattern matching rule for the triple [S, P, O] (Subject, Predicate, Object)
531
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
532
 * @param {string|Var} predicate - The IRI of a property or a variable
533
 * @param {string|Var} object - The IRI of a node or a variable, or a literal
534
 * @returns {WOQLQuery}
535
 */
536

537
WOQLQuery.prototype.triple = function (subject, predicate, object) {
1✔
538
  // if (a && a === 'args')
539
  // return ['subject', 'predicate', 'object']
540
  if (this.cursor['@type']) this.wrapCursorWithAnd();
393✔
541
  this.cursor['@type'] = 'Triple';
393✔
542
  this.cursor.subject = this.cleanSubject(subject);
393✔
543
  this.cursor.predicate = this.cleanPredicate(predicate);
393✔
544
  this.cursor.object = this.cleanObject(object);
393✔
545
  return this;
393✔
546
};
547

548
/**
549
 * Creates a triple pattern matching rule for the triple [S, P, O] (Subject, Predicate,
550
 * Object) added in the current layer
551
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
552
 * @param {string|Var} predicate - The IRI of a property or a variable
553
 * @param {string|Var} object - The IRI of a node or a variable, or a literal
554
 * @returns {WOQLQuery}
555
 */
556

557
WOQLQuery.prototype.added_triple = function (subject, predicate, object) {
1✔
558
  // if (a && a === 'args')
559
  // return ['subject', 'predicate', 'object']
560
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
561
  this.cursor['@type'] = 'AddedTriple';
2✔
562
  this.cursor.subject = this.cleanSubject(subject);
2✔
563
  this.cursor.predicate = this.cleanPredicate(predicate);
2✔
564
  this.cursor.object = this.cleanObject(object);
2✔
565
  return this;
2✔
566
};
567

568
/**
569
 * Creates a triple pattern matching rule for the triple [S, P, O] (Subject, Predicate,
570
 * Object) added in the current commit
571
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
572
 * @param {string|Var} predicate - The IRI of a property or a variable
573
 * @param {string|Var} object - The IRI of a node or a variable, or a literal
574
 * @returns {WOQLQuery}
575
 */
576

577
WOQLQuery.prototype.removed_triple = function (subject, predicate, object) {
1✔
578
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
579
  this.cursor['@type'] = 'DeletedTriple';
2✔
580
  this.cursor.subject = this.cleanSubject(subject);
2✔
581
  this.cursor.predicate = this.cleanPredicate(predicate);
2✔
582
  this.cursor.object = this.cleanObject(object);
2✔
583
  return this;
2✔
584
};
585

586
/**
587
 * Creates a pattern matching rule for triple [Subject, Predicate, Object]
588
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
589
 * @param {string|Var} predicate - The IRI of a property or a variable
590
 * @param {string|Var} object - The IRI of a node or a variable, or a literal
591
 * @returns {WOQLQuery} A WOQLQuery which contains the a quad or a triple Statement
592
 */
593

594
WOQLQuery.prototype.link = function (subject, predicate, object) {
1✔
595
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
596
  this.cursor['@type'] = 'Triple';
2✔
597
  this.cursor.subject = this.cleanSubject(subject);
2✔
598
  this.cursor.predicate = this.cleanPredicate(predicate);
2✔
599
  this.cursor.object = this.cleanSubject(object);
2✔
600
  return this;
2✔
601
};
602

603
/**
604
 * Creates a pattern matching rule for triple [Subject, Predicate, Object]
605
 * add extra information about the type of the value object
606
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
607
 * @param {string|Var} predicate - The IRI of a property or a variable
608
 * @param {string | number | boolean | Var} objValue - an specific value
609
 * @returns {WOQLQuery} A WOQLQuery which contains the a quad or a triple Statement
610
 */
611

612
WOQLQuery.prototype.value = function (subject, predicate, objValue) {
1✔
613
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
614
  this.cursor['@type'] = 'Triple';
2✔
615
  this.cursor.subject = this.cleanSubject(subject);
2✔
616
  this.cursor.predicate = this.cleanPredicate(predicate);
2✔
617
  this.cursor.object = this.cleanDataValue(objValue, 'xsd:string');
2✔
618
  return this;
2✔
619
};
620

621
/**
622
 * Creates a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate, Object, Graph)
623
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
624
 * @param {string|Var} predicate - The IRI of a property or a variable
625
 * @param {string|Var} object - The IRI of a node or a variable, or a literal
626
 * @param {typedef.GraphRef} graphRef - A valid graph resource identifier string
627
 * @returns {WOQLQuery}
628
 */
629

630
WOQLQuery.prototype.quad = function (subject, predicate, object, graphRef) {
1✔
631
  if (this.cursor['@type']) this.wrapCursorWithAnd();
8!
632
  const args = this.triple(subject, predicate, object);
8✔
633
  // if (a && a === 'args')
634
  // return args.concat(['graph'])
635
  if (!graphRef) return this.parameterError('Quad takes four parameters, the last should be a graph filter');
8!
636
  this.cursor['@type'] = 'Triple';
8✔
637
  this.cursor.graph = this.cleanGraph(graphRef);
8✔
638
  return this;
8✔
639
};
640

641
/**
642
 * Creates a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate,
643
 * Object, Graph) removed from the current commit
644
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
645
 * @param {string|Var} predicate - The IRI of a property or a variable
646
 * @param {string|Var} object - The IRI of a node or a variable, or a literal
647
 * @param {typedef.GraphRef} graphRef- A valid graph resource identifier string
648
 * @returns {WOQLQuery}
649
 */
650

651
WOQLQuery.prototype.added_quad = function (subject, predicate, object, graphRef) {
1✔
652
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
653
  const args = this.triple(subject, predicate, object);
2✔
654
  // if (a && a === 'args')
655
  // return args.concat(['graph'])
656
  if (!graphRef) return this.parameterError('Quad takes four parameters, the last should be a graph filter');
2!
657
  this.cursor['@type'] = 'AddedQuad';
2✔
658
  this.cursor.graph = this.cleanGraph(graphRef);
2✔
659
  return this;
2✔
660
};
661

662
/**
663
 * Creates a pattern matching rule for the quad [S, P, O, G] (Subject, Predicate,
664
 * Object, Graph) removed from the current commit
665
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
666
 * @param {string|Var} predicate - The IRI of a property or a variable
667
 * @param {string|Var} object - The IRI of a node or a variable, or a literal
668
 * @param {typedef.GraphRef} graphRef- A valid graph resource identifier string
669
 * @returns {WOQLQuery}
670
 */
671

672
WOQLQuery.prototype.removed_quad = function (subject, predicate, object, graphRef) {
1✔
673
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
674
  const args = this.triple(subject, predicate, object);
2✔
675
  // if (a && a === 'args')
676
  // return args.concat(['graph'])
677
  if (!graphRef) return this.parameterError('Quad takes four parameters, the last should be a graph filter');
2!
678
  this.cursor['@type'] = 'DeletedQuad';
2✔
679
  this.cursor.graph = this.cleanGraph(graphRef);
2✔
680
  return this;
2✔
681
};
682

683
/**
684
 * Returns true if ClassA subsumes ClassB, according to the current DB schema
685
 * @param {string} classA - ClassA
686
 * @param {string} classB - ClassB
687
 * @returns {boolean} WOQLQuery
688
 */
689
WOQLQuery.prototype.sub = function (classA, classB) {
1✔
690
  if (!classA || !classB) return this.parameterError('Subsumption takes two parameters, both URIs');
6✔
691
  if (this.cursor['@type']) this.wrapCursorWithAnd();
5!
692
  this.cursor['@type'] = 'Subsumption';
5✔
693
  this.cursor.parent = this.cleanNodeValue(classA);
5✔
694
  this.cursor.child = this.cleanNodeValue(classB);
5✔
695
  return this;
5✔
696
};
697

698
WOQLQuery.prototype.subsumption = WOQLQuery.prototype.sub;
1✔
699

700
/**
701
 * Matches if a is equal to b
702
 * @param {string|number|boolean|array|Var} varName - literal, variable, array, or id
703
 * @param {string|number|boolean|array|Var} varValue - literal, variable, array, or id
704
 * @returns {WOQLQuery}
705
 */
706
WOQLQuery.prototype.eq = function (varName, varValue) {
1✔
707
  // if (a && a === 'args') return ['left', 'right']
708
  if (typeof varName === 'undefined' || typeof varValue === 'undefined') return this.parameterError('Equals takes two parameters');
22✔
709
  if (this.cursor['@type']) this.wrapCursorWithAnd();
21!
710
  this.cursor['@type'] = 'Equals';
21✔
711
  this.cursor.left = this.cleanObject(varName);
21✔
712
  this.cursor.right = this.cleanObject(varValue);
21✔
713
  return this;
21✔
714
};
715

716
WOQLQuery.prototype.equals = WOQLQuery.prototype.eq;
1✔
717

718
/**
719
 * Substring
720
 * @param {string|Var} string - String or variable
721
 * @param {number|Var} before - integer or variable (characters from start to begin)
722
 * @param {number|Var} [length] - integer or variable (length of substring)
723
 * @param {number|Var} [after] - integer or variable (number of characters after substring)
724
 * @param {string|Var} [subString] - String or variable
725
 * @returns {WOQLQuery}
726
 */
727
WOQLQuery.prototype.substr = function (string, before, length, after, subString) {
1✔
728
  // if (String && String === 'args')
729
  // return ['string', 'before', 'length', 'after', 'substring']
730
  if (!subString) {
4!
731
    subString = after;
×
732
    after = 0;
×
733
  }
734
  if (!subString) {
4!
735
    subString = length;
×
736
    length = subString.length + before;
×
737
  }
738
  if (!string || !subString || typeof subString !== 'string') {
4!
739
    return this.parameterError(
×
740
      'Substr - the first and last parameters must be strings representing the full and substring variables / literals',
741
    );
742
  }
743
  if (this.cursor['@type']) this.wrapCursorWithAnd();
4!
744
  this.cursor['@type'] = 'Substring';
4✔
745
  this.cursor.string = this.cleanDataValue(string, 'xsd:string');
4✔
746
  this.cursor.before = this.cleanDataValue(before, 'xsd:nonNegativeInteger');
4✔
747
  this.cursor.length = this.cleanDataValue(length, 'xsd:nonNegativeInteger');
4✔
748
  this.cursor.after = this.cleanDataValue(after, 'xsd:nonNegativeInteger');
4✔
749
  this.cursor.substring = this.cleanDataValue(subString, 'xsd:string');
4✔
750
  return this;
4✔
751
};
752

753
WOQLQuery.prototype.substring = WOQLQuery.prototype.substr;
1✔
754

755
/**
756
 * Use the document inteface to import documents
757
 * @deprecated
758
 * Retrieves the exernal resource defined by QueryResource and copies values
759
 * from it into variables defined in AsVars
760
 * @param {Vars | array<Var>} asvars - an array of AsVar variable mappings (see as for format below)
761
 * @param {WOQLQuery} queryResource - an external resource (remote, file, post) to query
762
 * @returns {WOQLQuery} A WOQLQuery which contains the get expression
763
 */
764
WOQLQuery.prototype.get = function (asvars, queryResource) {
1✔
765
  this.cursor['@type'] = 'Get';
3✔
766
  this.cursor.columns = asvars.json ? asvars.json() : new WOQLQuery().as(...asvars).json();
3✔
767
  if (queryResource) {
3✔
768
    this.cursor.resource = this.jobj(queryResource);
2✔
769
  } else {
770
    this.cursor.resource = {};
1✔
771
  }
772
  this.cursor = this.cursor.resource;
3✔
773
  return this;
3✔
774
};
775

776
/**
777
 * Use the document inteface to import documents
778
 * @deprecated
779
 * @put Outputs the results of a query to a file
780
 * @param {Vars | array<Var>} varsToExp - an array of AsVar variable
781
 * mappings (see as for format below)
782
 * @param {WOQLQuery} query - The query which will be executed to produce the results
783
 * @param {string} fileResource - an file resource local to the server
784
 * @returns {WOQLQuery} A WOQLQuery which contains the put expression
785
 */
786
WOQLQuery.prototype.put = function (varsToExp, query, fileResource) {
1✔
787
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
788
  this.cursor['@type'] = 'Put';
1✔
789
  if (Array.isArray(varsToExp) && typeof varsToExp[0] !== 'object') {
1!
790
    const nasvars = [];
×
791
    for (let i = 0; i < varsToExp.length; i++) {
×
792
      const iasv = this.asv(i, varsToExp[i]);
×
793
      nasvars.push(iasv);
×
794
      this.cursor.columns = nasvars;
×
795
    }
796
  } else {
797
    this.cursor.columns = varsToExp.json
1!
798
      ? varsToExp.json()
799
      : new WOQLQuery().as(...varsToExp).json();
800
  }
801
  this.cursor.query = this.jobj(query);
1✔
802
  if (fileResource) {
1!
803
    this.cursor.resource = this.jobj(fileResource);
1✔
804
  } else {
805
    this.cursor.resource = {};
×
806
  }
807
  this.cursor = this.cursor.resource;
1✔
808
  return this;
1✔
809
};
810

811
/**
812
 * @param {...(array|string|Var)} varList variable number of arguments
813
 * @returns WOQLQuery
814
 */
815
WOQLQuery.prototype.as = function (...varList) {
15✔
816
  // if (varList && varList[0] == 'args')
817
  // return [['indexed_as_var', 'named_as_var']]
818
  if (!Array.isArray(this.query)) this.query = [];
5!
819
  if (Array.isArray(varList[0])) {
5!
820
    if (!varList[1]) {
×
821
      // indexed as vars
822
      for (var i = 0; i < varList[0].length; i++) {
×
823
        const iasv = this.asv(i, varList[0][i]);
×
824
        this.query.push(iasv);
×
825
      }
826
    } else {
827
      for (var i = 0; i < varList.length; i++) {
×
828
        const onemap = varList[i];
×
829
        if (Array.isArray(onemap) && onemap.length >= 2) {
×
830
          const type = onemap && onemap.length > 2 ? onemap[2] : false;
×
831
          const oasv = this.asv(onemap[0], onemap[1], type);
×
832
          this.query.push(oasv);
×
833
        }
834
      }
835
    }
836
  } else if (typeof varList[0] === 'number' || typeof varList[0] === 'string') {
5!
837
    if (varList[2] && typeof varList[2] === 'string') {
5✔
838
      var oasv = this.asv(varList[0], varList[1], varList[2]);
1✔
839
    } else if (varList[1] && varList[1] instanceof Var) {
4!
840
      var oasv = this.asv(varList[0], varList[1]);
×
841
    } else if (varList[1] && typeof varList[1] === 'string') {
4!
842
      if (varList[1].substring(0, 4) === 'xsd:' || varList[1].substring(0, 4) === 'xdd:') {
4!
843
        var oasv = this.asv(this.query.length, varList[0], varList[1]);
×
844
      } else {
845
        var oasv = this.asv(varList[0], varList[1]);
4✔
846
      }
847
    } else {
848
      var oasv = this.asv(this.query.length, varList[0]);
×
849
    }
850
    this.query.push(oasv);
5✔
851
  } else if (typeof varList[0] === 'object') {
×
852
    // check if it is an class object with an json method
853
    this.query.push(varList[0].json ? varList[0].json() : varList[0]);
×
854
  }
855
  return this;
5✔
856
};
857

858
/**
859
 * Identifies a remote resource by URL and specifies the format of the resource through the options
860
 * @param {object} remoteObj - The URL at which the remote resource can be accessed
861
 * @param {typedef.DataFormatObj} [formatObj] - The format of the resource data {}
862
 * @returns {WOQLQuery} A WOQLQuery which contains the remote resource identifier
863
 */
864

865
WOQLQuery.prototype.remote = function (remoteObj, formatObj) {
1✔
866
  if (this.cursor['@type']) this.wrapCursorWithAnd();
3!
867
  this.cursor['@type'] = 'QueryResource';
3✔
868
  this.cursor.source = { '@type': 'Source', url: remoteObj };
3✔
869
  this.cursor.format = 'csv'; // hard coded for now
3✔
870
  if (typeof opts !== 'undefined') this.cursor.options = formatObj;
3!
871
  return this;
3✔
872
};
873

874
/**
875
 * Identifies a resource as a local path on the client, to be sent to the server through a
876
 * HTTP POST request, with the format defined through the options
877
 * @param {string} url - The Path on the server at which the file resource can be accessed
878
 * @param {typedef.DataFormatObj} [formatObj] - imput options, optional
879
 * @param {string} [source] - It defines the source of the file, it can be 'url','post'
880
 * @returns {WOQLQuery} A WOQLQuery which contains the Post resource identifier
881
 */
882

883
WOQLQuery.prototype.post = function (url, formatObj, source = 'post') {
1!
884
  // if (fpath && fpath == 'args') return ['file', 'format']
885
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
886
  this.cursor['@type'] = 'QueryResource';
1✔
887
  this.cursor.source = { '@type': 'Source', [source]: url };
1✔
888
  this.cursor.format = 'csv'; // hard coded for now
1✔
889
  this.cursor.options = formatObj;
1✔
890
  if (typeof formatObj !== 'undefined') this.cursor.options = formatObj;
1!
891
  return this;
1✔
892
};
893

894
/**
895
 * Deletes a single triple from the default graph of the database
896
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
897
 * @param {string|Var} predicate - The IRI of a property or a variable
898
 * @param {string|Var} object - The IRI of a node or a variable, or a literal
899
 * @returns {WOQLQuery} - A WOQLQuery which contains the Triple Deletion statement
900
 */
901

902
WOQLQuery.prototype.delete_triple = function (subject, predicate, object) {
1✔
903
  if (this.cursor['@type']) this.wrapCursorWithAnd();
6✔
904
  const args = this.triple(subject, predicate, object);
6✔
905
  this.cursor['@type'] = 'DeleteTriple';
6✔
906
  return this.updated();
6✔
907
};
908

909
/**
910
 * Adds triples according to the the pattern [subject,predicate,object]
911
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
912
 * @param {string|Var} predicate - The IRI of a property or a variable
913
 * @param {string|Var} object - The IRI of a node or a variable, or a literal
914
 * @returns {WOQLQuery}
915
 */
916

917
WOQLQuery.prototype.add_triple = function (subject, predicate, object) {
1✔
918
  if (this.cursor['@type']) this.wrapCursorWithAnd();
9!
919
  const args = this.triple(subject, predicate, object);
9✔
920
  this.cursor['@type'] = 'AddTriple';
9✔
921
  return this.updated();
9✔
922
};
923

924
/**
925
 * Deletes a single triple from the graph [Subject, Predicate, Object, Graph]
926
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
927
 * @param {string|Var} predicate - The IRI of a property or a variable
928
 * @param {string|Var} object - The IRI of a node or a variable, or a literal
929
 * @param {typedef.GraphRef} graphRef - A valid graph resource identifier string
930
 * @returns {WOQLQuery} - A WOQLQuery which contains the Delete Quad Statement
931
 */
932
WOQLQuery.prototype.delete_quad = function (subject, predicate, object, graphRef) {
1✔
933
  if (this.cursor['@type']) this.wrapCursorWithAnd();
6✔
934
  const args = this.triple(subject, predicate, object);
6✔
935
  // if (a && a == 'args') return args.concat(['graph'])
936
  if (!graphRef) {
6!
937
    return this.parameterError(
×
938
      'Delete Quad takes four parameters, the last should be a graph id',
939
    );
940
  }
941
  this.cursor['@type'] = 'DeleteTriple';
6✔
942
  this.cursor.graph = this.cleanGraph(graphRef);
6✔
943
  return this.updated();
6✔
944
};
945

946
/**
947
 * Adds quads according to the pattern [S,P,O,G]
948
 * @param {string|Var} subject - The IRI of a triple’s subject or a variable
949
 * @param {string|Var} predicate - The IRI of a property or a variable
950
 * @param {string|Var} object - The IRI of a node or a variable, or a literal
951
 * @param {typedef.GraphRef} graphRef - A valid graph resource identifier string
952
 * @returns {WOQLQuery}
953
 */
954

955
WOQLQuery.prototype.add_quad = function (subject, predicate, object, graphRef) {
1✔
956
  if (this.cursor['@type']) this.wrapCursorWithAnd();
5!
957
  const args = this.triple(subject, predicate, object);
5✔
958
  if (!graphRef) return this.parameterError('Add Quad takes four parameters, the last should be a graph id');
5!
959
  this.cursor['@type'] = 'AddTriple';
5✔
960
  this.cursor.graph = this.cleanGraph(graphRef);
5✔
961
  return this.updated();
5✔
962
};
963

964
/**
965
 * Remove whitespace from both sides of a string:
966
 * @param {string|Var} inputStr - A string or variable containing
967
 * the untrimmed version of the string
968
 * @param {string|Var} resultVarName - A string or variable
969
 * containing the trimmed version of the string
970
 * @returns {WOQLQuery} A WOQLQuery which contains the Trim pattern matching expression
971
 */
972

973
WOQLQuery.prototype.trim = function (inputStr, resultVarName) {
1✔
974
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
975
  this.cursor['@type'] = 'Trim';
2✔
976
  this.cursor.untrimmed = this.cleanDataValue(inputStr);
2✔
977
  this.cursor.trimmed = this.cleanDataValue(resultVarName);
2✔
978
  return this;
2✔
979
};
980

981
/**
982
 * Evaluates the passed arithmetic expression and generates or matches the result value
983
 * @param {object| WOQLQuery | string} arithExp - query or JSON-LD representing the query
984
 * @param {string|Var} resultVarName - output variable
985
 * @returns {WOQLQuery}
986
 */
987

988
WOQLQuery.prototype.eval = function (arithExp, resultVarName) {
1✔
989
  if (this.cursor['@type']) this.wrapCursorWithAnd();
10!
990
  this.cursor['@type'] = 'Eval';
10✔
991
  this.cursor.expression = arithExp.json ? arithExp.json() : arithExp;
10✔
992
  this.cursor.result = this.cleanArithmeticValue(resultVarName);
10✔
993
  return this;
10✔
994
};
995

996
/**
997
 * Evaluates the passed arithmetic expression and generates or matches the result value.
998
 * Alias for eval() to support both naming conventions in fluent/chained style.
999
 * @param {object|WOQLQuery|string} arithExp - A WOQL query containing a valid arithmetic expression
1000
 * @param {string|number|Var} resultVarName - Either a variable to store the result, or a numeric
1001
 * literal to test against the evaluated expression
1002
 * @returns {WOQLQuery}
1003
 */
1004

1005
WOQLQuery.prototype.evaluate = function (arithExp, resultVarName) {
1✔
1006
  return this.eval(arithExp, resultVarName);
2✔
1007
};
1008

1009
/**
1010
 * Adds the numbers together
1011
 * @param {...(string|number|Var)} args - a variable or numeric containing the values to add
1012
 * @returns {WOQLQuery} A WOQLQuery which contains the addition expression
1013
 */
1014

1015
WOQLQuery.prototype.plus = function (...args) {
10✔
1016
  // if (args && args[0] == 'args') return ['first', 'second']
1017
  if (this.cursor['@type']) this.wrapCursorWithAnd();
5!
1018
  this.cursor['@type'] = 'Plus';
5✔
1019
  this.cursor.left = this.arop(args.shift());
5✔
1020
  if (args.length > 1) {
5!
1021
    this.cursor.right = this.jobj(new WOQLQuery().plus(...args.map(this.arop)));
×
1022
  } else {
1023
    this.cursor.right = this.arop(args[0]);
5✔
1024
  }
1025
  return this;
5✔
1026
};
1027

1028
/**
1029
 *
1030
 * Subtracts Numbers N1..Nn
1031
 * @param {...(string|number|Var)} args - variable or numeric containing the value that will be
1032
 * subtracted from
1033
 * @returns {WOQLQuery} A WOQLQuery which contains the subtraction expression
1034
 */
1035
WOQLQuery.prototype.minus = function (...args) {
4✔
1036
  // if (args && args[0] === 'args') return ['first', 'right']
1037
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
1038
  this.cursor['@type'] = 'Minus';
2✔
1039
  this.cursor.left = this.arop(args.shift());
2✔
1040
  if (args.length > 1) {
2!
1041
    this.cursor.right = this.jobj(new WOQLQuery().minus(...args.map(this.arop)));
×
1042
  } else {
1043
    this.cursor.right = this.arop(args[0]);
2✔
1044
  }
1045
  return this;
2✔
1046
};
1047

1048
/**
1049
 *
1050
 * Multiplies numbers N1...Nn together
1051
 * @param {...(string|number|Var)} args - a variable or numeric containing the value
1052
 * @returns {WOQLQuery} A WOQLQuery which contains the multiplication expression
1053
 */
1054
WOQLQuery.prototype.times = function (...args) {
14✔
1055
  // if (args && args[0] === 'args') return ['first', 'right']
1056
  if (this.cursor['@type']) this.wrapCursorWithAnd();
7!
1057
  this.cursor['@type'] = 'Times';
7✔
1058
  this.cursor.left = this.arop(args.shift());
7✔
1059
  if (args.length > 1) {
7!
1060
    this.cursor.right = this.jobj(new WOQLQuery().times(...args.map(this.arop)));
×
1061
  } else {
1062
    this.cursor.right = this.arop(args[0]);
7✔
1063
  }
1064
  return this;
7✔
1065
};
1066

1067
/**
1068
 * Divides numbers N1...Nn by each other left, to right precedence
1069
 * @param {...(string|number|Var )} args - numbers to tbe divided
1070
 * @returns {WOQLQuery} A WOQLQuery which contains the division expression
1071
 */
1072
WOQLQuery.prototype.divide = function (...args) {
4✔
1073
  // if (args && args[0] === 'args') return ['left', 'right']
1074
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
1075
  this.cursor['@type'] = 'Divide';
2✔
1076
  this.cursor.left = this.arop(args.shift());
2✔
1077
  if (args.length > 1) {
2!
1078
    this.cursor.right = this.jobj(new WOQLQuery().divide(...args.map(this.arop)));
×
1079
  } else {
1080
    this.cursor.right = this.arop(args[0]);
2✔
1081
  }
1082
  return this;
2✔
1083
};
1084

1085
/**
1086
 * Division - integer division - args are divided left to right
1087
 * @param {...(string|number|Var)} args - numbers for division
1088
 * @returns {WOQLQuery} A WOQLQuery which contains the division expression
1089
 */
1090

1091
WOQLQuery.prototype.div = function (...args) {
6✔
1092
  // if (args && args[0] === 'args') return ['left', 'right']
1093
  if (this.cursor['@type']) this.wrapCursorWithAnd();
3!
1094
  this.cursor['@type'] = 'Div';
3✔
1095
  this.cursor.left = this.arop(args.shift());
3✔
1096
  if (args.length > 1) {
3!
1097
    this.cursor.right = this.jobj(new WOQLQuery().div(...args.map(this.arop)));
×
1098
  } else {
1099
    this.cursor.right = this.arop(args[0]);
3✔
1100
  }
1101
  return this;
3✔
1102
};
1103

1104
/**
1105
 * Exponent - raises varNum01 to the power of varNum02
1106
 * @param {string|number|Var} varNum -  a variable or numeric containing the number to be
1107
 * raised to the power of the second number
1108
 * @param {number} expNum -  a variable or numeric containing the exponent
1109
 * @returns {WOQLQuery} A WOQLQuery which contains the exponent expression
1110
 */
1111
WOQLQuery.prototype.exp = function (varNum, expNum) {
1✔
1112
  // if (a && a === 'args') return ['left', 'right']
1113
  if (this.cursor['@type']) this.wrapCursorWithAnd();
3!
1114
  this.cursor['@type'] = 'Exp';
3✔
1115
  this.cursor.left = this.arop(varNum);
3✔
1116
  this.cursor.right = this.arop(expNum);
3✔
1117
  return this;
3✔
1118
};
1119

1120
/**
1121
 * Generates the nearest lower integer to the passed number
1122
 * @param {string|number|Var} varNum - Variable or numeric containing the number to be floored
1123
 * @returns {WOQLQuery} A WOQLQuery which contains the floor expression
1124
 */
1125
WOQLQuery.prototype.floor = function (varNum) {
1✔
1126
  // if (a && a === 'args') return ['argument']
1127
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
1128
  this.cursor['@type'] = 'Floor';
2✔
1129
  this.cursor.argument = this.arop(varNum);
2✔
1130
  return this;
2✔
1131
};
1132

1133
/**
1134
 * Tests whether a given instance IRI has type Class, according to the current state of the DB
1135
 * @param {string|Var} instanceIRI - A string IRI or a variable that identify the class instance
1136
 * @param {string|Var} classId - A Class IRI or a variable
1137
 * @returns {WOQLQuery} A WOQLQuery object containing the type test
1138
 */
1139
WOQLQuery.prototype.isa = function (instanceIRI, classId) {
1✔
1140
  // if (a && a === 'args') return ['element', 'of_type']
1141
  if (this.cursor['@type']) this.wrapCursorWithAnd();
4!
1142
  this.cursor['@type'] = 'IsA';
4✔
1143
  this.cursor.element = this.cleanNodeValue(instanceIRI);
4✔
1144
  this.cursor.type = this.cleanNodeValue(classId);
4✔
1145
  return this;
4✔
1146
};
1147

1148
/**
1149
 * Generates a string Leverstein distance measure between stringA and stringB
1150
 * @param {string|Var} stringA - string literal or variable representing a string to be compared
1151
 * @param {string|Var } stringB - string literal or variable
1152
 * representing the other string to be compared
1153
 * @param {number|string|Var} distance - variable representing the distance between the variables
1154
 * @returns {WOQLQuery} A WOQLQuery which contains the Like pattern matching expression
1155
 */
1156
WOQLQuery.prototype.like = function (stringA, stringB, distance) {
1✔
1157
  // if (a && a === 'args')
1158
  // return ['left', 'right', 'like_similarity']
1159
  if (this.cursor['@type']) this.wrapCursorWithAnd();
3!
1160
  this.cursor['@type'] = 'Like';
3✔
1161
  this.cursor.left = this.cleanDataValue(stringA, 'xsd:string');
3✔
1162
  this.cursor.right = this.cleanDataValue(stringB, 'xsd:string');
3✔
1163
  if (distance) {
3✔
1164
    this.cursor.similarity = this.cleanDataValue(distance, 'xsd:decimal');
2✔
1165
  }
1166
  return this;
3✔
1167
};
1168

1169
/**
1170
 * Compares the value of v1 against v2 and returns true if v1 is less than v2
1171
 * @param {string|number|Var} varNum01 - a variable or numeric containing
1172
 * the number to be compared
1173
 * @param {string|number|Var} varNum02 - a variable or numeric containing the second comporator
1174
 * @returns {WOQLQuery} A WOQLQuery which contains the comparison expression
1175
 */
1176
WOQLQuery.prototype.less = function (varNum01, varNum02) {
1✔
1177
  if (this.cursor['@type']) this.wrapCursorWithAnd();
4!
1178
  this.cursor['@type'] = 'Less';
4✔
1179
  this.cursor.left = this.cleanDataValue(varNum01);
4✔
1180
  this.cursor.right = this.cleanDataValue(varNum02);
4✔
1181
  return this;
4✔
1182
};
1183

1184
/**
1185
 * Compares the value of v1 against v2 and returns true if v1 is greater than v2
1186
 * @param {string|number|Var} varNum01 - a variable or numeric containing the number to be compared
1187
 * @param {string|number|Var} varNum02 - a variable or numeric containing the second comporator
1188
 * @returns {WOQLQuery} A WOQLQuery which contains the comparison expression
1189
 */
1190
WOQLQuery.prototype.greater = function (varNum01, varNum02) {
1✔
1191
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
1192
  this.cursor['@type'] = 'Greater';
2✔
1193
  this.cursor.left = this.cleanDataValue(varNum01);
2✔
1194
  this.cursor.right = this.cleanDataValue(varNum02);
2✔
1195
  return this;
2✔
1196
};
1197

1198
/**
1199
 * Specifies that the Subquery is optional - if it does not match the query will not fail
1200
 * @param {WOQLQuery} [subquery] - A subquery which will be optionally matched
1201
 * @returns {WOQLQuery} A WOQLQuery object containing the optional sub Query
1202
 */
1203
WOQLQuery.prototype.opt = function (subquery) {
1✔
1204
  if (this.cursor['@type']) this.wrapCursorWithAnd();
42✔
1205
  this.cursor['@type'] = 'Optional';
42✔
1206
  this.addSubQuery(subquery);
42✔
1207
  return this;
42✔
1208
};
1209

1210
WOQLQuery.prototype.optional = WOQLQuery.prototype.opt;
1✔
1211

1212
/**
1213
 * Generate a new IRI from the prefix and a hash of the variables which will be unique for any
1214
 * given combination of variables
1215
 * @param {string} prefix - A prefix for the IRI - typically formed of the doc prefix and the
1216
 * classtype of the entity (“doc:Person”)
1217
 * @param {array|string|Var} inputVarList - An array of variables and / or strings from which the
1218
 * unique hash will be generated
1219
 * @param {string|Var} resultVarName - Variable in which the unique ID is stored
1220
 * @returns {WOQLQuery} A WOQLQuery object containing the unique ID generating function
1221
 */
1222
WOQLQuery.prototype.unique = function (prefix, inputVarList, resultVarName) {
1✔
1223
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
1224
  this.cursor['@type'] = 'HashKey';
2✔
1225
  this.cursor.base = this.cleanDataValue(prefix, 'xsd:string');
2✔
1226
  this.cursor.key_list = this.cleanDataValue(inputVarList);
2✔
1227
  this.cursor.uri = this.cleanNodeValue(resultVarName);
2✔
1228
  return this;
2✔
1229
};
1230

1231
/**
1232
 * Generates the node's ID combined the variable list with a specific prefix (URL base).
1233
 * If the input variables's values are the same, the output value will be the same.
1234
 * @param {string} prefix
1235
 * @param {string |array}  inputVarList the variable input list for generate the id
1236
 * @param {string} outputVar  the output variable name
1237
 */
1238

1239
WOQLQuery.prototype.idgen = function (prefix, inputVarList, outputVar) {
1✔
1240
  if (this.cursor['@type']) this.wrapCursorWithAnd();
3!
1241
  this.cursor['@type'] = 'LexicalKey';
3✔
1242
  this.cursor.base = this.cleanDataValue(prefix, 'xsd:string');
3✔
1243
  // this.cursor['base'] = this.cleanObject(this.string(prefix))
1244
  this.cursor.key_list = this.dataValueList(inputVarList);
3✔
1245
  this.cursor.uri = this.cleanNodeValue(outputVar);
3✔
1246
  return this;
3✔
1247
};
1248

1249
WOQLQuery.prototype.idgenerator = WOQLQuery.prototype.idgen;
1✔
1250

1251
/**
1252
 * Generates a random ID with a specified prefix
1253
 * Uses cryptographically secure random base64 encoding to generate unique identifiers
1254
 * @param {string} prefix - prefix for the generated ID
1255
 * @param {string} outputVar - variable that stores the generated ID
1256
 * @returns {WOQLQuery} A WOQLQuery which contains the random ID generation pattern
1257
 * idgen_random("Person/", "v:person_id")
1258
 */
1259
WOQLQuery.prototype.idgen_random = function (prefix, outputVar) {
1✔
1260
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
1261
  this.cursor['@type'] = 'RandomKey';
1✔
1262
  this.cursor.base = this.cleanDataValue(prefix, 'xsd:string');
1✔
1263
  this.cursor.uri = this.cleanNodeValue(outputVar);
1✔
1264
  return this;
1✔
1265
};
1266

1267
/**
1268
 * Backward-compatible alias for idgen_random
1269
 * @deprecated Use idgen_random instead
1270
 */
1271
WOQLQuery.prototype.random_idgen = WOQLQuery.prototype.idgen_random;
1✔
1272

1273
/**
1274
 * Changes a string to upper-case
1275
 * @param {string|Var} inputVarName - string or variable representing the uncapitalized string
1276
 * @param {string|Var} resultVarName -  variable that stores the capitalized string output
1277
 * @returns {WOQLQuery} A WOQLQuery which contains the Upper case pattern matching expression
1278
 */
1279
WOQLQuery.prototype.upper = function (inputVarName, resultVarName) {
1✔
1280
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
1281
  this.cursor['@type'] = 'Upper';
1✔
1282
  this.cursor.mixed = this.cleanDataValue(inputVarName);
1✔
1283
  this.cursor.upper = this.cleanDataValue(resultVarName);
1✔
1284
  return this;
1✔
1285
};
1286

1287
/**
1288
 * Changes a string to lower-case
1289
 * @param {string|Var} inputVarName -  string or variable representing the non-lowercased string
1290
 * @param {string|Var} resultVarName - variable that stores the lowercased string output
1291
 * @returns {WOQLQuery} A WOQLQuery which contains the Lower case pattern matching expression
1292
 */
1293

1294
WOQLQuery.prototype.lower = function (inputVarName, resultVarName) {
1✔
1295
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
1296
  this.cursor['@type'] = 'Lower';
1✔
1297
  this.cursor.mixed = this.cleanDataValue(inputVarName);
1✔
1298
  this.cursor.lower = this.cleanDataValue(resultVarName);
1✔
1299
  return this;
1✔
1300
};
1301

1302
/**
1303
 * Pads out the string input to be exactly len long by appending the pad character pad to
1304
 * form output
1305
 * @param {string|Var} inputVarName - The input string or variable in unpadded state
1306
 * @param {string|Var} pad - The characters to use to pad the string or a variable representing them
1307
 * @param {number | string | Var} len - The variable or integer value representing the length of
1308
 * the output string
1309
 * @param {string|Var} resultVarName - stores output
1310
 * @returns {WOQLQuery} A WOQLQuery which contains the Pad pattern matching expression
1311
 */
1312

1313
WOQLQuery.prototype.pad = function (inputVarName, pad, len, resultVarName) {
1✔
1314
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
1315
  this.cursor['@type'] = 'Pad';
1✔
1316
  this.cursor.string = this.cleanDataValue(inputVarName);
1✔
1317
  this.cursor.char = this.cleanDataValue(pad);
1✔
1318
  this.cursor.times = this.cleanDataValue(len, 'xsd:integer');
1✔
1319
  this.cursor.result = this.cleanDataValue(resultVarName);
1✔
1320
  return this;
1✔
1321
};
1322

1323
/**
1324
 * Splits a string (Input) into a list strings (Output) by removing separator
1325
 * @param {string|Var} inputVarName - A string or variable representing the unsplit string
1326
 * @param {string|Var} separator - A string or variable containing a sequence of charatcters
1327
 * to use as a separator
1328
 * @param {string|Var} resultVarName - variable that stores output list
1329
 * @returns {WOQLQuery} A WOQLQuery which contains the Split pattern matching expression
1330
 */
1331

1332
WOQLQuery.prototype.split = function (inputVarName, separator, resultVarName) {
1✔
1333
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
1334
  this.cursor['@type'] = 'Split';
2✔
1335
  this.cursor.string = this.cleanDataValue(inputVarName);
2✔
1336
  this.cursor.pattern = this.cleanDataValue(separator);
2✔
1337
  this.cursor.list = this.cleanDataValue(resultVarName);
2✔
1338
  return this;
2✔
1339
};
1340

1341
/**
1342
 * Matches if List includes Element
1343
 * @param {string|object|Var} element - Either a variable, IRI or any simple datatype
1344
 * @param {string|array|Var} list - List ([string, literal] or string*) Either a variable
1345
 * representing a list or a list of variables or literals
1346
 * @returns {WOQLQuery} A WOQLQuery which contains the List inclusion pattern matching expression
1347
 */
1348
WOQLQuery.prototype.member = function (element, list) {
1✔
1349
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
1350
  this.cursor['@type'] = 'Member';
2✔
1351
  this.cursor.member = this.cleanObject(element);
2✔
1352
  this.cursor.list = this.valueList(list);
2✔
1353
  return this;
2✔
1354
};
1355

1356
/**
1357
 * Computes the set difference between two lists (elements in listA but not in listB)
1358
 * @param {string|Var|array} listA - First list or variable
1359
 * @param {string|Var|array} listB - Second list or variable
1360
 * @param {string|Var} result - Variable to store the result
1361
 * @returns {WOQLQuery} A WOQLQuery which contains the SetDifference expression
1362
 */
1363
WOQLQuery.prototype.set_difference = function (listA, listB, result) {
1✔
1364
  if (this.cursor['@type']) this.wrapCursorWithAnd();
×
1365
  this.cursor['@type'] = 'SetDifference';
×
1366
  this.cursor.list_a = this.valueList(listA);
×
1367
  this.cursor.list_b = this.valueList(listB);
×
1368
  this.cursor.result = this.valueList(result);
×
1369
  return this;
×
1370
};
1371

1372
/**
1373
 * Computes the set intersection of two lists (elements in both listA and listB)
1374
 * @param {string|Var|array} listA - First list or variable
1375
 * @param {string|Var|array} listB - Second list or variable
1376
 * @param {string|Var} result - Variable to store the result
1377
 * @returns {WOQLQuery} A WOQLQuery which contains the SetIntersection expression
1378
 */
1379
WOQLQuery.prototype.set_intersection = function (listA, listB, result) {
1✔
1380
  if (this.cursor['@type']) this.wrapCursorWithAnd();
×
1381
  this.cursor['@type'] = 'SetIntersection';
×
1382
  this.cursor.list_a = this.valueList(listA);
×
1383
  this.cursor.list_b = this.valueList(listB);
×
1384
  this.cursor.result = this.valueList(result);
×
1385
  return this;
×
1386
};
1387

1388
/**
1389
 * Computes the set union of two lists (all unique elements from both lists)
1390
 * @param {string|Var|array} listA - First list or variable
1391
 * @param {string|Var|array} listB - Second list or variable
1392
 * @param {string|Var} result - Variable to store the result
1393
 * @returns {WOQLQuery} A WOQLQuery which contains the SetUnion expression
1394
 */
1395
WOQLQuery.prototype.set_union = function (listA, listB, result) {
1✔
1396
  if (this.cursor['@type']) this.wrapCursorWithAnd();
×
1397
  this.cursor['@type'] = 'SetUnion';
×
1398
  this.cursor.list_a = this.valueList(listA);
×
1399
  this.cursor.list_b = this.valueList(listB);
×
1400
  this.cursor.result = this.valueList(result);
×
1401
  return this;
×
1402
};
1403

1404
/**
1405
 * Checks if an element is a member of a set (efficient O(log n) lookup)
1406
 * @param {string|Var|any} element - Element to check
1407
 * @param {string|Var|array} set - Set (list) to check membership in
1408
 * @returns {WOQLQuery} A WOQLQuery which contains the SetMember expression
1409
 */
1410
WOQLQuery.prototype.set_member = function (element, set) {
1✔
1411
  if (this.cursor['@type']) this.wrapCursorWithAnd();
×
1412
  this.cursor['@type'] = 'SetMember';
×
1413
  this.cursor.element = this.cleanObject(element);
×
1414
  this.cursor.set = this.valueList(set);
×
1415
  return this;
×
1416
};
1417

1418
/**
1419
 * Converts a list to a set (removes duplicates and sorts)
1420
 * @param {string|Var|array} list - Input list or variable
1421
 * @param {string|Var} set - Variable to store the resulting set
1422
 * @returns {WOQLQuery} A WOQLQuery which contains the ListToSet expression
1423
 */
1424
WOQLQuery.prototype.list_to_set = function (list, set) {
1✔
1425
  if (this.cursor['@type']) this.wrapCursorWithAnd();
×
1426
  this.cursor['@type'] = 'ListToSet';
×
1427
  this.cursor.list = this.valueList(list);
×
1428
  this.cursor.set = this.valueList(set);
×
1429
  return this;
×
1430
};
1431

1432
/**
1433
 * takes a variable number of string arguments and concatenates them into a single string
1434
 * @param {array|string|Var} varList -  a variable representing a list or a list of variables or
1435
 * strings - variables can be embedded in the string if they do not contain spaces
1436
 * @param {string|Var}  resultVarName - A variable or string containing the output string
1437
 * @returns {WOQLQuery} A WOQLQuery which contains the Concatenation pattern matching expression
1438
 */
1439

1440
WOQLQuery.prototype.concat = function (varList, resultVarName) {
1✔
1441
  if (typeof varList === 'string') {
2✔
1442
    const slist = varList.split(/(v:)/);
1✔
1443
    const nlist = [];
1✔
1444
    if (slist[0]) nlist.push(slist[0]);
1!
1445
    for (let i = 1; i < slist.length; i += 2) {
1✔
1446
      if (slist[i]) {
2!
1447
        if (slist[i] === 'v:') {
2!
1448
          const slist2 = slist[i + 1].split(/([^\w_])/);
2✔
1449
          const x = slist2.shift();
2✔
1450
          nlist.push(`v:${x}`);
2✔
1451
          const rest = slist2.join('');
2✔
1452
          if (rest) nlist.push(rest);
2✔
1453
        }
1454
      }
1455
    }
1456
    varList = nlist;
1✔
1457
  }
1458
  if (Array.isArray(varList)) {
2!
1459
    if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
1460
    this.cursor['@type'] = 'Concatenate';
2✔
1461
    this.cursor.list = this.cleanDataValue(varList, true);
2✔
1462
    this.cursor.result = this.cleanDataValue(resultVarName);
2✔
1463
  }
1464
  return this;
2✔
1465
};
1466

1467
WOQLQuery.prototype.concatenate = WOQLQuery.prototype.concat;
1✔
1468

1469
/**
1470
 * Joins a list variable together (Input) into a string variable (Output) by glueing the strings
1471
 * together with Glue
1472
 * @param {string|array|Var} varList - a variable representing a list or a list of strings
1473
 * and / or variables
1474
 * @param {string|Var} glue - A variable (v:glue) or (glue) string representing the characters
1475
 * to put in between the joined strings in input
1476
 * @param {string|Var} resultVarName - A variable or string containing the output string
1477
 * @returns {WOQLQuery} A WOQLQuery which contains the Join pattern matching expression
1478
 */
1479
WOQLQuery.prototype.join = function (varList, glue, resultVarName) {
1✔
1480
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
1481
  this.cursor['@type'] = 'Join';
2✔
1482
  this.cursor.list = this.cleanDataValue(varList);
2✔
1483
  this.cursor.separator = this.cleanDataValue(glue);
2✔
1484
  this.cursor.result = this.cleanDataValue(resultVarName);
2✔
1485
  return this;
2✔
1486
};
1487

1488
/**
1489
 * computes the sum of the List of values passed. In contrast to other arithmetic functions,
1490
 * sum self-evaluates - it does not have to be passed to evaluate()
1491
 * @param {WOQLQuery} subquery -  a subquery or ([string or numeric]) - a list variable, or a
1492
 * list of variables or numeric literals
1493
 * @param {string|Var} total - the variable name with the sum result of the values in List
1494
 * @returns {WOQLQuery} - A WOQLQuery which contains the Sum expression
1495
 */
1496
WOQLQuery.prototype.sum = function (subquery, total) {
1✔
1497
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
1498
  this.cursor['@type'] = 'Sum';
1✔
1499
  this.cursor.list = this.cleanDataValue(subquery);
1✔
1500
  this.cursor.result = this.cleanObject(total);
1✔
1501
  return this;
1✔
1502
};
1503

1504
/**
1505
 *
1506
 * Specifies an offset position in the results to start listing results from
1507
 * @param {number|string|Var} start - A variable that refers to an interger or an integer literal
1508
 * @param {WOQLQuery} [subquery] - WOQL Query object, you can pass a subquery as an argument
1509
 * or a chained query
1510
 * @returns {WOQLQuery} A WOQLQuery whose results will be returned starting from
1511
 * the specified offset
1512
 */
1513

1514
WOQLQuery.prototype.start = function (start, subquery) {
1✔
1515
  // if (start && start === 'args') return ['start', 'query']
1516
  if (this.cursor['@type']) this.wrapCursorWithAnd();
4!
1517
  this.cursor['@type'] = 'Start';
4✔
1518
  this.cursor.start = start;
4✔
1519
  return this.addSubQuery(subquery);
4✔
1520
};
1521

1522
/**
1523
 * Specifies a maximum number of results that will be returned from the subquery
1524
 * @param {number|string} limit - A variable that refers to an non-negative integer or a
1525
 * non-negative integer
1526
 * @param {WOQLQuery} [subquery] - A subquery whose results will be limited
1527
 * @returns {WOQLQuery} A WOQLQuery whose results will be returned starting from
1528
 * the specified offset
1529
 */
1530

1531
WOQLQuery.prototype.limit = function (limit, subquery) {
1✔
1532
  if (this.cursor['@type']) this.wrapCursorWithAnd();
22!
1533
  this.cursor['@type'] = 'Limit';
22✔
1534
  this.cursor.limit = limit;
22✔
1535
  return this.addSubQuery(subquery);
22✔
1536
};
1537

1538
/**
1539
 * Matches the regular expression defined in Patern against the Test string, to produce
1540
 * the matched patterns in Matches
1541
 * @param {string} pattern - string or variable using normal PCRE regular expression syntax with
1542
 * the exception that special characters have to be escaped twice (to enable transport in JSONLD)
1543
 * @param {string|Var} inputVarName - string or variable containing the string to be tested for
1544
 * patterns with the regex
1545
 * @param {string|array|object|Var} resultVarList - variable representing the list of matches
1546
 * or a list of strings or variables
1547
 * @returns {WOQLQuery} A WOQLQuery which contains the Regular Expression pattern
1548
 * matching expression
1549
 */
1550

1551
WOQLQuery.prototype.re = function (pattern, inputVarName, resultVarList) {
1✔
1552
  if (this.cursor['@type']) this.wrapCursorWithAnd();
3!
1553
  this.cursor['@type'] = 'Regexp';
3✔
1554
  this.cursor.pattern = this.cleanDataValue(pattern);
3✔
1555
  this.cursor.string = this.cleanDataValue(inputVarName);
3✔
1556
  this.cursor.result = this.cleanDataValue(resultVarList);
3✔
1557
  return this;
3✔
1558
};
1559

1560
WOQLQuery.prototype.regexp = WOQLQuery.prototype.re;
1✔
1561

1562
/**
1563
 * Calculates the length of the list in va and stores it in vb
1564
 * @param {string|array} inputVarList - Either a variable representing a list or a list of
1565
 * variables or literals
1566
 * @param {string|Var} resultVarName -  A variable in which the length of the list is stored or
1567
 * the length of the list as a non-negative integer
1568
 * @returns {WOQLQuery} A WOQLQuery which contains the Length pattern matching expression
1569
 */
1570
WOQLQuery.prototype.length = function (inputVarList, resultVarName) {
1✔
1571
  if (this.cursor['@type']) this.wrapCursorWithAnd();
2!
1572
  this.cursor['@type'] = 'Length';
2✔
1573
  this.cursor.list = this.cleanDataValue(inputVarList);
2✔
1574
  if (resultVarName !== undefined && resultVarName !== null) {
2!
1575
    if (typeof resultVarName === 'number') {
2!
NEW
1576
      this.cursor.length = this.cleanObject(resultVarName, 'xsd:nonNegativeInteger');
×
1577
    } else {
1578
      // Handle string, Var instances, or any other variable representation
1579
      this.cursor.length = this.varj(resultVarName);
2✔
1580
    }
1581
  }
1582
  return this;
2✔
1583
};
1584

1585
/**
1586
 * Extracts a contiguous subsequence from a list, following JavaScript's slice() semantics
1587
 * @param {string|array|Var} inputList - Either a variable representing a list or a list of
1588
 * variables or literals
1589
 * @param {string|Var} resultVarName - A variable in which the sliced list is stored
1590
 * @param {number|string|Var} start - The start index (0-based, supports negative indices)
1591
 * @param {number|string|Var} [end] - The end index (exclusive, optional - defaults to list length)
1592
 * @returns {WOQLQuery} A WOQLQuery which contains the Slice pattern matching expression
1593
 * let [result] = vars("result")
1594
 * slice(["a", "b", "c", "d"], result, 1, 3)  // result = ["b", "c"]
1595
 * slice(["a", "b", "c", "d"], result, -2)    // result = ["c", "d"]
1596
 */
1597
WOQLQuery.prototype.slice = function (inputList, resultVarName, start, end) {
1✔
1598
  if (this.cursor['@type']) this.wrapCursorWithAnd();
10✔
1599
  this.cursor['@type'] = 'Slice';
10✔
1600
  this.cursor.list = this.cleanDataValue(inputList);
10✔
1601
  this.cursor.result = this.cleanDataValue(resultVarName);
10✔
1602
  if (typeof start === 'number') {
10✔
1603
    this.cursor.start = this.cleanObject(start, 'xsd:integer');
9✔
1604
  } else {
1605
    this.cursor.start = this.cleanDataValue(start);
1✔
1606
  }
1607
  // end is optional - only set if provided
1608
  if (end !== undefined) {
10✔
1609
    if (typeof end === 'number') {
9✔
1610
      this.cursor.end = this.cleanObject(end, 'xsd:integer');
8✔
1611
    } else {
1612
      this.cursor.end = this.cleanDataValue(end);
1✔
1613
    }
1614
  }
1615
  return this;
10✔
1616
};
1617

1618
/**
1619
 *
1620
 * Logical negation of the contained subquery - if the subquery matches, the query
1621
 * will fail to match
1622
 * @param {string | WOQLQuery} [subquery] -  A subquery which will be negated
1623
 * @returns {WOQLQuery} A WOQLQuery object containing the negated sub Query
1624
 */
1625
WOQLQuery.prototype.not = function (subquery) {
1✔
1626
  if (this.cursor['@type']) this.wrapCursorWithAnd();
20✔
1627
  this.cursor['@type'] = 'Not';
20✔
1628
  return this.addSubQuery(subquery);
20✔
1629
};
1630

1631
/**
1632
 * Results in one solution of the subqueries
1633
 * @param {string| WOQLQuery } [subquery] - WOQL Query objects
1634
 * @returns {WOQLQuery} A WOQLQuery object containing the once sub Query
1635
 */
1636
WOQLQuery.prototype.once = function (subquery) {
1✔
1637
  // if (query && query === 'args') return ['query']
1638
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
1639
  this.cursor['@type'] = 'Once';
1✔
1640
  return this.addSubQuery(subquery);
1✔
1641
};
1642

1643
/**
1644
 * Runs the query without backtracking on side-effects
1645
 * @param {string| WOQLQuery } [subquery] - WOQL Query objects
1646
 * @returns {WOQLQuery} A WOQLQuery object containing the immediately sub Query
1647
 */
1648
WOQLQuery.prototype.immediately = function (query) {
1✔
1649
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
1650
  this.cursor['@type'] = 'Immediately';
1✔
1651
  return this.addSubQuery(query);
1✔
1652
};
1653

1654
/**
1655
 * Creates a count of the results of the query
1656
 * @param {string|number|Var} countVarName - variable or integer count
1657
 * @param {WOQLQuery} [subquery]
1658
 * @returns {WOQLQuery} A WOQLQuery object containing the count sub Query
1659
 */
1660
WOQLQuery.prototype.count = function (countVarName, subquery) {
1✔
1661
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
1662
  this.cursor['@type'] = 'Count';
1✔
1663
  this.cursor.count = this.cleanObject(countVarName);
1✔
1664
  return this.addSubQuery(subquery);
1✔
1665
};
1666

1667
/**
1668
 * Casts the value of Input to a new value of type Type and stores the result in CastVar
1669
 * @param {string|number|object|Var} varName - Either a single variable or a
1670
 * literal of any basic type
1671
 * @param {string|Var} varType - Either a variable or a basic datatype (xsd / xdd)
1672
 * @param {string|Var} resultVarName - save the return variable
1673
 * @returns {WOQLQuery} A WOQLQuery which contains the casting expression
1674
 */
1675

1676
WOQLQuery.prototype.typecast = function (varName, varType, resultVarName) {
1✔
1677
  if (this.cursor['@type']) this.wrapCursorWithAnd();
4!
1678
  this.cursor['@type'] = 'Typecast';
4✔
1679
  this.cursor.value = this.cleanObject(varName);
4✔
1680
  this.cursor.type = this.cleanNodeValue(varType);
4✔
1681
  this.cursor.result = this.cleanObject(resultVarName);
4✔
1682
  return this;
4✔
1683
};
1684

1685
WOQLQuery.prototype.cast = WOQLQuery.prototype.typecast;
1✔
1686

1687
/**
1688
 * Orders the results of the contained subquery by a precedence list of variables
1689
 * @param  {...string|...Var|...array} orderedVarlist - A sequence of variables,
1690
 * by which to order the results,
1691
 * each optionally followed by either “asc” or “desc” to represent order as a list, by default
1692
 * it will sort the variable in ascending order
1693
 * @returns  {WOQLQuery} A WOQLQuery which contains the ordering expression
1694
 */
1695
WOQLQuery.prototype.order_by = function (...orderedVarlist) {
14✔
1696
  // if (orderedVarlist && orderedVarlist[0] === 'args')
1697
  // return ['variable_ordering', 'query']
1698
  if (this.cursor['@type']) this.wrapCursorWithAnd();
7!
1699
  this.cursor['@type'] = 'OrderBy';
7✔
1700
  this.cursor.ordering = [];
7✔
1701

1702
  if (!orderedVarlist || orderedVarlist.length === 0) {
7!
1703
    return this.parameterError(
×
1704
      'Order by must be passed at least one variables to order the query',
1705
    );
1706
  }
1707
  const embedquery = typeof orderedVarlist[orderedVarlist.length - 1] === 'object'
7✔
1708
    && orderedVarlist[orderedVarlist.length - 1].json
1709
    ? orderedVarlist.pop()
1710
    : false;
1711

1712
  for (let i = 0; i < orderedVarlist.length; i++) {
7✔
1713
    let obj;
12✔
1714
    if ((typeof orderedVarlist[i] === 'string' || orderedVarlist[i] instanceof Var) && orderedVarlist[i] !== '') {
12✔
1715
      obj = {
9✔
1716
        '@type': 'OrderTemplate',
1717
        variable: this.rawVar(orderedVarlist[i]),
1718
        order: 'asc',
1719
      };
1720
    } else if (orderedVarlist[i].length === 2 && orderedVarlist[i][1] === 'asc') {
3✔
1721
      obj = {
1✔
1722
        '@type': 'OrderTemplate',
1723
        variable: this.rawVar(orderedVarlist[i][0]),
1724
        order: 'asc',
1725
      };
1726
    } else if (orderedVarlist[i].length === 2 && orderedVarlist[i][1] === 'desc') {
2!
1727
      obj = {
2✔
1728
        '@type': 'OrderTemplate',
1729
        variable: this.rawVar(orderedVarlist[i][0]),
1730
        order: 'desc',
1731
      };
1732
    }
1733

1734
    if (obj) this.cursor.ordering.push(obj);
12!
1735
  }
1736
  return this.addSubQuery(embedquery);
7✔
1737
};
1738

1739
/**
1740
 *
1741
 * Groups the results of the contained subquery on the basis of identical values for Groupvars,
1742
 * extracts the patterns defined in PatternVars and stores the results in GroupedVar
1743
 * @param {array|string|Var} gvarlist - Either a single variable or an array of variables
1744
 * @param {array|string|Var} groupedvar - Either a single variable or an array of variables
1745
 * @param {string|Var} output - output variable name
1746
 * @param {WOQLQuery} [groupquery] - The query whose results will be grouped
1747
 * @returns {WOQLQuery} A WOQLQuery which contains the grouping expression
1748
 */
1749

1750
WOQLQuery.prototype.group_by = function (gvarlist, groupedvar, output, groupquery) {
1✔
1751
  // if (gvarlist && gvarlist === 'args')
1752
  // return ['group_by', 'group_template', 'grouped', 'query']
1753
  if (this.cursor['@type']) this.wrapCursorWithAnd();
4!
1754
  this.cursor['@type'] = 'GroupBy';
4✔
1755
  this.cursor.group_by = [];
4✔
1756

1757
  if (typeof gvarlist === 'string' || gvarlist instanceof Var) gvarlist = [gvarlist];
4✔
1758
  this.cursor.group_by = this.rawVarList(gvarlist);
4✔
1759
  if (typeof groupedvar === 'string' || groupedvar instanceof Var) groupedvar = [groupedvar];
4✔
1760
  this.cursor.template = this.rawVarList(groupedvar);
4✔
1761
  this.cursor.grouped = this.varj(output);
4✔
1762
  return this.addSubQuery(groupquery);
4✔
1763
};
1764

1765
/**
1766
 * A function that always matches, always returns true
1767
 * @returns {WOQLQuery} A WOQLQuery object containing the true value that will match any pattern
1768
 */
1769
WOQLQuery.prototype.true = function () {
1✔
1770
  this.cursor['@type'] = 'True';
1✔
1771
  return this;
1✔
1772
};
1773

1774
/**
1775
 * Performs a path regular expression match on the graph
1776
 * @param {string|Var} subject -  An IRI or variable that refers to an IRI representing the subject,
1777
 * i.e. the starting point of the path
1778
 * @param {string} pattern -(string) - A path regular expression describing a pattern through
1779
 * multiple edges of the graph (see: https://terminusdb.com/docs/path-query-reference-guide)
1780
 * @param {string|Var} object - An IRI or variable that refers to an IRI representing the object,
1781
 * i.e. ending point of the path
1782
 * @param {string|Var} [resultVarName] - A variable in which the actual paths
1783
 * traversed will be stored
1784
 * @returns {WOQLQuery} - A WOQLQuery which contains the path regular expression matching expression
1785
 */
1786

1787
WOQLQuery.prototype.path = function (subject, pattern, object, resultVarName) {
1✔
1788
  if (this.cursor['@type']) this.wrapCursorWithAnd();
40✔
1789
  this.cursor['@type'] = 'Path';
40✔
1790
  this.cursor.subject = this.cleanSubject(subject);
40✔
1791
  if (typeof pattern === 'string') pattern = this.compilePathPattern(pattern);
40!
1792
  this.cursor.pattern = pattern;
40✔
1793
  this.cursor.object = this.cleanObject(object);
40✔
1794
  if (typeof resultVarName !== 'undefined') {
40✔
1795
    this.cursor.path = this.varj(resultVarName);
38✔
1796
  }
1797
  return this;
40✔
1798
};
1799

1800
/**
1801
 * Extract the value of a key in a bound document.
1802
 * @param {string|Var} document - Document which is being accessed.
1803
 * @param {string|Var} field - The field from which the document which is being accessed.
1804
 * @param {string|Var} value - The value for the document and field.
1805
 * @returns {WOQLQuery} A WOQLQuery which contains the a dot Statement
1806
 */
1807

1808
WOQLQuery.prototype.dot = function (document, field, value) {
1✔
1809
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
1810
  this.cursor['@type'] = 'Dot';
1✔
1811
  this.cursor.document = this.expandValueVariable(document);
1✔
1812
  this.cursor.field = this.cleanDataValue(field, 'xsd:string');
1✔
1813
  this.cursor.value = this.expandValueVariable(value);
1✔
1814
  return this;
1✔
1815
};
1816

1817
/**
1818
 * Calculates the size in bytes of the contents of the resource identified in ResourceID
1819
 * @param {string|Var} resourceId - A valid resource identifier string (can refer to any graph /
1820
 * branch / commit / db)
1821
 * @param {string|Var} resultVarName - The variable name
1822
 */
1823

1824
WOQLQuery.prototype.size = function (resourceId, resultVarName) {
1✔
1825
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
1826
  this.cursor['@type'] = 'Size';
1✔
1827
  this.cursor.resource = this.cleanGraph(resourceId);
1✔
1828
  this.cursor.size = this.varj(resultVarName);
1✔
1829
  return this;
1✔
1830
};
1831

1832
/**
1833
 *
1834
 * Calculates the number of triples of the contents of the resource identified in ResourceID
1835
 * @param {string|Var} resourceId - A valid resource identifier string (can refer to any graph /
1836
 * branch / commit / db)
1837
 * @param {string|number|Var} tripleCount - An integer literal with the size in bytes or a
1838
 * variable containing that integer
1839
 * @returns {WOQLQuery} A WOQLQuery which contains the size expression
1840
 */
1841
WOQLQuery.prototype.triple_count = function (resourceId, TripleCount) {
1✔
1842
  if (this.cursor['@type']) this.wrapCursorWithAnd();
1!
1843
  this.cursor['@type'] = 'TripleCount';
1✔
1844
  this.cursor.resource = this.cleanGraph(resourceId);
1✔
1845
  this.cursor.count = this.varj(TripleCount);
1✔
1846
  return this;
1✔
1847
};
1848

1849
/**
1850
 * Returns true if 'elementId' is of type 'elementType', according to the current DB schema
1851
 * @param {string|Var} elementId - the id of a schema graph element
1852
 * @param {string|Var} elementType - the element type
1853
 * @returns {WOQLQuery} A WOQLQuery object containing the type_of pattern matching rule
1854
 */
1855

1856
WOQLQuery.prototype.type_of = function (elementId, elementType) {
1✔
1857
  if (!elementId || !elementType) return this.parameterError('type_of takes two parameters, both values');
4!
1858
  if (this.cursor['@type']) this.wrapCursorWithAnd();
4!
1859
  this.cursor['@type'] = 'TypeOf';
4✔
1860
  this.cursor.value = this.cleanObject(elementId);
4✔
1861
  this.cursor.type = this.cleanSubject(elementType);
4✔
1862
  return this;
4✔
1863
};
1864

1865
module.exports = WOQLQuery;
1✔
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