@nymphjs/driver-sqlite3 1.0.0-beta.127 → 1.0.0-beta.129

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,19 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [1.0.0-beta.129](https://forge.sciactive.com/sciactive/nymphjs/compare/v1.0.0-beta.128...v1.0.0-beta.129) (2026-10-05)
7
+
8
+ ### Features
9
+
10
+ - add method to export a single entity ([dac08cb](https://forge.sciactive.com/sciactive/nymphjs/commits/dac08cb39c1fe4473337d2c41c45252f1ed13dae))
11
+ - migrate to built in node sqlite, target es2024 ([d7c78c0](https://forge.sciactive.com/sciactive/nymphjs/commits/d7c78c06072d785b228ff790eb005ab4f84529e9))
12
+
13
+ # [1.0.0-beta.128](https://forge.sciactive.com/sciactive/nymphjs/compare/v1.0.0-beta.127...v1.0.0-beta.128) (2026-09-29)
14
+
15
+ ### Features
16
+
17
+ - fix indexes to properly optimize queries, requires full reimport ([0a54f5b](https://forge.sciactive.com/sciactive/nymphjs/commits/0a54f5baa663163f6876d17c5ef6bebefa4cd9fa))
18
+
6
19
  # [1.0.0-beta.127](https://forge.sciactive.com/sciactive/nymphjs/compare/v1.0.0-beta.126...v1.0.0-beta.127) (2026-09-24)
7
20
 
8
21
  **Note:** Version bump only for package @nymphjs/driver-sqlite3
package/README.md CHANGED
@@ -31,7 +31,7 @@ const nymph = new Nymph({}, new SQLite3Driver(sqliteConfig));
31
31
 
32
32
  ## Options
33
33
 
34
- See the [config declaration file](src/conf/d.ts).
34
+ See the [config declaration file](src/conf/index.ts).
35
35
 
36
36
  # License
37
37
 
@@ -1,12 +1,12 @@
1
- import SQLite3 from 'better-sqlite3';
1
+ import { DatabaseSync } from 'node:sqlite';
2
2
  import { NymphDriver, type EntityConstructor, type EntityObjectType, type EntityInterface, type EntityInstanceType, type SerializedEntityData, type FormattedSelector, type Options, type Selector } from '@nymphjs/nymph';
3
3
  import { SQLite3DriverConfig } from './conf/index.js';
4
4
  declare class InternalStore {
5
- link: SQLite3.Database;
6
- linkWrite?: SQLite3.Database;
5
+ link: DatabaseSync;
6
+ linkWrite?: DatabaseSync;
7
7
  connected: boolean;
8
8
  transactionsStarted: number;
9
- constructor(link: SQLite3.Database);
9
+ constructor(link: DatabaseSync);
10
10
  }
11
11
  /**
12
12
  * The SQLite3 Nymph database driver.
@@ -80,6 +80,8 @@ export default class SQLite3Driver extends NymphDriver {
80
80
  type: 'comment' | 'uid' | 'entity';
81
81
  content: string;
82
82
  }, void, false | undefined>;
83
+ exportEntity(etype: string, guid: string): Promise<string>;
84
+ private exportEntityInternal;
83
85
  /**
84
86
  * Generate the SQLite3 query.
85
87
  * @param options The options array.
@@ -1,4 +1,4 @@
1
- import SQLite3 from 'better-sqlite3';
1
+ import { DatabaseSync } from 'node:sqlite';
2
2
  import { NymphDriver, EntityConflictError, EntityInvalidDataError, EntityUniqueConstraintError, InvalidParametersError, NotConfiguredError, QueryFailedError, UnableToConnectError, xor, } from '@nymphjs/nymph';
3
3
  import { makeTableSuffix } from '@nymphjs/guid';
4
4
  import { SQLite3DriverConfigDefaults as defaults, } from './conf/index.js';
@@ -64,53 +64,47 @@ export default class SQLite3Driver extends NymphDriver {
64
64
  return Promise.resolve(this.store.connected);
65
65
  }
66
66
  _connect(write) {
67
- const { filename, fileMustExist, timeout, explicitWrite, wal, verbose } = this.config;
67
+ const { filename, fileMustExist, timeout, explicitWrite, wal } = this.config;
68
68
  try {
69
69
  const setOptions = (link) => {
70
70
  // Set database and connection options.
71
71
  if (wal) {
72
- link.pragma('journal_mode = WAL;');
72
+ link.exec('PRAGMA journal_mode = WAL;');
73
73
  }
74
- link.pragma('encoding = "UTF-8";');
75
- link.pragma('foreign_keys = 1;');
76
- link.pragma('case_sensitive_like = 1;');
74
+ link.exec('PRAGMA encoding = "UTF-8";');
75
+ link.exec('PRAGMA foreign_keys = 1;');
76
+ link.exec('PRAGMA case_sensitive_like = 1;');
77
77
  for (let pragma of this.config.pragmas) {
78
- link.pragma(pragma);
78
+ link.exec(`PRAGMA ${pragma}`);
79
79
  }
80
80
  // Create the preg_match and regexp functions.
81
81
  link.function('regexp', { deterministic: true }, ((pattern, subject) => (this.posixRegexMatch(pattern, subject) ? 1 : 0)));
82
82
  };
83
83
  let link;
84
84
  try {
85
- link = new SQLite3(filename, {
86
- readonly: !explicitWrite && !write,
87
- fileMustExist,
85
+ link = new DatabaseSync(filename, {
86
+ readOnly: !explicitWrite && !write,
88
87
  timeout,
89
- verbose,
90
88
  });
91
89
  }
92
90
  catch (e) {
93
- if (e.code === 'SQLITE_CANTOPEN' &&
91
+ if (e.code === 'ERR_SQLITE_CANTOPEN' &&
94
92
  !explicitWrite &&
95
93
  !write &&
96
- !this.config.fileMustExist) {
94
+ !fileMustExist) {
97
95
  // This happens when the file doesn't exist and we attempt to open it
98
96
  // readonly.
99
97
  // First open it in write mode.
100
- const writeLink = new SQLite3(filename, {
101
- readonly: false,
102
- fileMustExist,
98
+ const writeLink = new DatabaseSync(filename, {
99
+ readOnly: false,
103
100
  timeout,
104
- verbose,
105
101
  });
106
102
  setOptions(writeLink);
107
103
  writeLink.close();
108
104
  // Now open in readonly.
109
- link = new SQLite3(filename, {
110
- readonly: true,
111
- fileMustExist,
105
+ link = new DatabaseSync(filename, {
106
+ readOnly: true,
112
107
  timeout,
113
- verbose,
114
108
  });
115
109
  }
116
110
  else {
@@ -209,31 +203,21 @@ export default class SQLite3Driver extends NymphDriver {
209
203
  createDataTable(etype) {
210
204
  // Create the data table.
211
205
  this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "value" CHARACTER(1) NOT NULL, "json" BLOB, "string" TEXT, "number" REAL, "truthy" INTEGER, PRIMARY KEY("guid", "name"));`);
212
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid");`);
213
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid_name`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid", "name");`);
214
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name");`);
215
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name_string`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name", "string");`);
216
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name_number`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name", "number");`);
217
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid_name_number`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "number");`);
218
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name_truthy`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name", "truthy");`);
219
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid_name_truthy`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "truthy");`);
206
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name", "guid");`);
207
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name_string_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name", "string", "guid");`);
208
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name_number_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name", "number", "guid");`);
209
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name_truthy_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name", "truthy", "guid");`);
210
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name_json_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name", "json", "guid")`);
220
211
  }
221
212
  createReferencesTable(etype) {
222
213
  // Create the references table.
223
214
  this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "reference" CHARACTER(24) NOT NULL, PRIMARY KEY("guid", "name", "reference"));`);
224
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid");`);
225
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("name");`);
226
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_name_reference`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("name", "reference");`);
227
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference");`);
228
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "name");`);
229
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid_name_reference`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "name", "reference");`);
230
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference_name_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference", "name", "guid");`);
231
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference_guid_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference", "guid", "name");`);
215
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_name_reference_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("name", "reference", "guid");`);
232
216
  }
233
217
  createTokensTable(etype) {
234
218
  // Create the tokens table.
235
219
  this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid") ON DELETE CASCADE, "name" TEXT NOT NULL, "token" INTEGER NOT NULL, "position" INTEGER NOT NULL, "stem" INTEGER NOT NULL, PRIMARY KEY("guid", "name", "token", "position"));`);
236
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}_id_name_token`)} ON ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("name", "token");`);
220
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}_id_name_token_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("name", "token", "guid");`);
237
221
  }
238
222
  createUniquesTable(etype) {
239
223
  // Create the unique strings table.
@@ -274,7 +258,7 @@ export default class SQLite3Driver extends NymphDriver {
274
258
  catch (e) {
275
259
  const errorCode = e?.code;
276
260
  const errorMsg = e?.message;
277
- if (errorCode === 'SQLITE_ERROR' &&
261
+ if (errorCode === 'ERR_SQLITE_ERROR' &&
278
262
  errorMsg.match(/^no such table: /) &&
279
263
  this.createTables()) {
280
264
  for (let etype of etypes) {
@@ -287,7 +271,7 @@ export default class SQLite3Driver extends NymphDriver {
287
271
  throw new QueryFailedError('Query failed: ' + e2?.code + ' - ' + e2?.message, query, e2?.code);
288
272
  }
289
273
  }
290
- else if (errorCode === 'SQLITE_CONSTRAINT_UNIQUE' &&
274
+ else if (errorCode === 'ERR_SQLITE_ERROR' &&
291
275
  errorMsg.match(/^UNIQUE constraint failed: /)) {
292
276
  throw new EntityUniqueConstraintError(`Unique constraint violation.`);
293
277
  }
@@ -396,9 +380,9 @@ export default class SQLite3Driver extends NymphDriver {
396
380
  async getIndexes(etype) {
397
381
  const indexes = [];
398
382
  for (let [scope, suffix] of [
399
- ['data', '_json'],
383
+ ['data', '_string_guid'],
400
384
  ['references', '_reference_guid'],
401
- ['tokens', '_token_position_stem'],
385
+ ['tokens', '_token_guid'],
402
386
  ]) {
403
387
  const indexDefinitions = this.queryArray(`SELECT "name", "sql" FROM "sqlite_master" WHERE "type"='index' AND "name" LIKE @pattern;`, {
404
388
  params: {
@@ -419,37 +403,37 @@ export default class SQLite3Driver extends NymphDriver {
419
403
  this.checkIndexName(definition.name);
420
404
  await this.deleteIndex(etype, definition.scope, definition.name);
421
405
  if (definition.scope === 'data') {
422
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_json`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("json") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
423
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_string`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("string") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
424
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_number`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("number") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
425
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_truthy`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("truthy") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
406
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_string_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("string", "guid") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
407
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_number_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("number", "guid") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
408
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_truthy_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("truthy", "guid") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
409
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${definition.name}_json_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("json", "guid") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
426
410
  }
427
411
  else if (definition.scope === 'references') {
428
412
  this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_custom_${definition.name}_reference_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference", "guid") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
429
413
  }
430
414
  else if (definition.scope === 'tokens') {
431
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}_id_custom_${definition.name}_token_position_stem`)} ON ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("token", "position", "stem") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
415
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}_id_custom_${definition.name}_token_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("token", "guid") WHERE "name"=${SQLite3Driver.escapeValue(definition.property)};`);
432
416
  }
433
417
  return true;
434
418
  }
435
419
  async deleteIndex(etype, scope, name) {
436
420
  this.checkIndexName(name);
437
421
  if (scope === 'data') {
438
- this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_json`)};`);
439
- this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_string`)};`);
440
- this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_number`)};`);
441
- this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_truthy`)};`);
422
+ this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_string_guid`)};`);
423
+ this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_number_guid`)};`);
424
+ this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_truthy_guid`)};`);
425
+ this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_custom_${name}_json_guid`)};`);
442
426
  }
443
427
  else if (scope === 'references') {
444
428
  this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_custom_${name}_reference_guid`)};`);
445
429
  }
446
430
  else if (scope === 'tokens') {
447
- this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}_id_custom_${name}_token_position_stem`)};`);
431
+ this.queryRun(`DROP INDEX IF EXISTS ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}_id_custom_${name}_token_guid`)};`);
448
432
  }
449
433
  return true;
450
434
  }
451
435
  async getEtypes() {
452
- const tables = this.queryArray("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix;", {
436
+ const tables = this.queryArray(`SELECT "name" FROM "sqlite_master" WHERE "type"='table' AND "name" LIKE @prefix;`, {
453
437
  params: {
454
438
  prefix: this.prefix + 'entities_' + '%',
455
439
  },
@@ -507,75 +491,90 @@ export default class SQLite3Driver extends NymphDriver {
507
491
  const etypes = await this.getEtypes();
508
492
  for (const etype of etypes) {
509
493
  // Export entities.
510
- const dataIterator = this.queryArray(`SELECT e."guid", e."tags", e."cdate", e."mdate", e."user", e."group", e."acUser", e."acGroup", e."acOther", e."acRead", e."acWrite", e."acFull", d."name", d."value", json(d."json") as "json", d."string", d."number" FROM ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} e LEFT JOIN ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} d USING ("guid") ORDER BY e."guid";`)[Symbol.iterator]();
511
- let datum = dataIterator.next();
512
- while (!datum.done) {
513
- const guid = datum.value.guid;
514
- const tags = datum.value.tags.slice(1, -1);
515
- const cdate = datum.value.cdate;
516
- const mdate = datum.value.mdate;
517
- const user = datum.value.user;
518
- const group = datum.value.group;
519
- const acUser = datum.value.acUser;
520
- const acGroup = datum.value.acGroup;
521
- const acOther = datum.value.acOther;
522
- const acRead = datum.value.acRead?.slice(1, -1).split(',');
523
- const acWrite = datum.value.acWrite?.slice(1, -1).split(',');
524
- const acFull = datum.value.acFull?.slice(1, -1).split(',');
525
- let currentEntityExport = [];
526
- currentEntityExport.push(`{${guid}}<${etype}>[${tags}]`);
527
- currentEntityExport.push(`\tcdate=${JSON.stringify(cdate)}`);
528
- currentEntityExport.push(`\tmdate=${JSON.stringify(mdate)}`);
529
- if (this.nymph.tilmeld != null) {
530
- if (user != null) {
531
- currentEntityExport.push(`\tuser=${JSON.stringify(['nymph_entity_reference', user, 'User'])}`);
532
- }
533
- if (group != null) {
534
- currentEntityExport.push(`\tgroup=${JSON.stringify(['nymph_entity_reference', group, 'Group'])}`);
535
- }
536
- if (acUser != null) {
537
- currentEntityExport.push(`\tacUser=${JSON.stringify(acUser)}`);
538
- }
539
- if (acGroup != null) {
540
- currentEntityExport.push(`\tacGroup=${JSON.stringify(acGroup)}`);
541
- }
542
- if (acOther != null) {
543
- currentEntityExport.push(`\tacOther=${JSON.stringify(acOther)}`);
544
- }
545
- if (acRead != null) {
546
- currentEntityExport.push(`\tacRead=${JSON.stringify(acRead)}`);
547
- }
548
- if (acWrite != null) {
549
- currentEntityExport.push(`\tacWrite=${JSON.stringify(acWrite)}`);
550
- }
551
- if (acFull != null) {
552
- currentEntityExport.push(`\tacFull=${JSON.stringify(acFull)}`);
553
- }
494
+ const entityIterator = this.exportEntityInternal(etype);
495
+ for await (let content of entityIterator) {
496
+ yield { type: 'entity', content };
497
+ }
498
+ }
499
+ }
500
+ async exportEntity(etype, guid) {
501
+ const entityIterator = this.exportEntityInternal(etype, guid);
502
+ let exportContent = '';
503
+ for await (let content of entityIterator) {
504
+ exportContent += content;
505
+ }
506
+ return exportContent;
507
+ }
508
+ async *exportEntityInternal(etype, guid) {
509
+ // Export entities.
510
+ const dataIterator = this.queryArray(`SELECT e."guid", e."tags", e."cdate", e."mdate", e."user", e."group", e."acUser", e."acGroup", e."acOther", e."acRead", e."acWrite", e."acFull", d."name", d."value", json(d."json") as "json", d."string", d."number" FROM ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} e LEFT JOIN ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} d USING ("guid")${guid == null ? '' : ` WHERE e."guid"=@guid`} ORDER BY e."guid";`, guid == null ? undefined : { params: { guid } })[Symbol.iterator]();
511
+ let datum = dataIterator.next();
512
+ while (!datum.done) {
513
+ const guid = datum.value.guid;
514
+ const tags = datum.value.tags.slice(1, -1);
515
+ const cdate = datum.value.cdate;
516
+ const mdate = datum.value.mdate;
517
+ const user = datum.value.user;
518
+ const group = datum.value.group;
519
+ const acUser = datum.value.acUser;
520
+ const acGroup = datum.value.acGroup;
521
+ const acOther = datum.value.acOther;
522
+ const acRead = datum.value.acRead?.slice(1, -1).split(',');
523
+ const acWrite = datum.value.acWrite?.slice(1, -1).split(',');
524
+ const acFull = datum.value.acFull?.slice(1, -1).split(',');
525
+ let currentEntityExport = [];
526
+ currentEntityExport.push(`{${guid}}<${etype}>[${tags}]`);
527
+ currentEntityExport.push(`\tcdate=${JSON.stringify(cdate)}`);
528
+ currentEntityExport.push(`\tmdate=${JSON.stringify(mdate)}`);
529
+ if (this.nymph.tilmeld != null) {
530
+ if (user != null) {
531
+ currentEntityExport.push(`\tuser=${JSON.stringify(['nymph_entity_reference', user, 'User'])}`);
554
532
  }
555
- if (datum.value.name != null) {
556
- // This do will keep going and adding the data until the
557
- // next entity is reached. datum will end on the next entity.
558
- do {
559
- const value = datum.value.value === 'N'
560
- ? JSON.stringify(datum.value.number)
561
- : datum.value.value === 'S'
562
- ? JSON.stringify(datum.value.string)
563
- : datum.value.value === 'J'
564
- ? datum.value.json
565
- : datum.value.value;
566
- currentEntityExport.push(`\t${datum.value.name}=${value}`);
567
- datum = dataIterator.next();
568
- } while (!datum.done && datum.value.guid === guid);
533
+ if (group != null) {
534
+ currentEntityExport.push(`\tgroup=${JSON.stringify(['nymph_entity_reference', group, 'Group'])}`);
569
535
  }
570
- else {
571
- // Make sure that datum is incremented :)
572
- datum = dataIterator.next();
536
+ if (acUser != null) {
537
+ currentEntityExport.push(`\tacUser=${JSON.stringify(acUser)}`);
573
538
  }
574
- currentEntityExport.push('');
575
- if (yield { type: 'entity', content: currentEntityExport.join('\n') }) {
576
- return;
539
+ if (acGroup != null) {
540
+ currentEntityExport.push(`\tacGroup=${JSON.stringify(acGroup)}`);
541
+ }
542
+ if (acOther != null) {
543
+ currentEntityExport.push(`\tacOther=${JSON.stringify(acOther)}`);
544
+ }
545
+ if (acRead != null) {
546
+ currentEntityExport.push(`\tacRead=${JSON.stringify(acRead)}`);
547
+ }
548
+ if (acWrite != null) {
549
+ currentEntityExport.push(`\tacWrite=${JSON.stringify(acWrite)}`);
550
+ }
551
+ if (acFull != null) {
552
+ currentEntityExport.push(`\tacFull=${JSON.stringify(acFull)}`);
577
553
  }
578
554
  }
555
+ if (datum.value.name != null) {
556
+ // This do will keep going and adding the data until the
557
+ // next entity is reached. datum will end on the next entity.
558
+ do {
559
+ const value = datum.value.value === 'N'
560
+ ? JSON.stringify(datum.value.number)
561
+ : datum.value.value === 'S'
562
+ ? JSON.stringify(datum.value.string)
563
+ : datum.value.value === 'J'
564
+ ? datum.value.json
565
+ : datum.value.value;
566
+ currentEntityExport.push(`\t${datum.value.name}=${value}`);
567
+ datum = dataIterator.next();
568
+ } while (!datum.done && datum.value.guid === guid);
569
+ }
570
+ else {
571
+ // Make sure that datum is incremented :)
572
+ datum = dataIterator.next();
573
+ }
574
+ currentEntityExport.push('');
575
+ if (yield currentEntityExport.join('\n')) {
576
+ return;
577
+ }
579
578
  }
580
579
  }
581
580
  /**
@@ -2464,13 +2463,13 @@ export default class SQLite3Driver extends NymphDriver {
2464
2463
  return true;
2465
2464
  }
2466
2465
  async needsMigration() {
2467
- const table = this.queryGet("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix LIMIT 1;", {
2466
+ const table = this.queryGet(`SELECT "name" FROM "sqlite_master" WHERE "type"='table' AND "name" LIKE @prefix LIMIT 1;`, {
2468
2467
  params: {
2469
2468
  prefix: this.prefix + 'data_' + '%',
2470
2469
  },
2471
2470
  });
2472
2471
  if (table?.name) {
2473
- const result = this.queryGet("SELECT 1 AS `exists` FROM pragma_table_info(@table) WHERE `name`='json';", {
2472
+ const result = this.queryGet(`SELECT 1 AS "exists" FROM pragma_table_info(@table) WHERE "name"='json';`, {
2474
2473
  params: {
2475
2474
  table: table.name,
2476
2475
  },
@@ -2479,7 +2478,7 @@ export default class SQLite3Driver extends NymphDriver {
2479
2478
  return 'json';
2480
2479
  }
2481
2480
  }
2482
- const table2 = this.queryGet("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @tokenTable LIMIT 1;", {
2481
+ const table2 = this.queryGet(`SELECT "name" FROM "sqlite_master" WHERE "type"='table' AND "name" LIKE @tokenTable LIMIT 1;`, {
2483
2482
  params: {
2484
2483
  tokenTable: this.prefix + 'tokens_' + '%',
2485
2484
  },
@@ -2487,13 +2486,13 @@ export default class SQLite3Driver extends NymphDriver {
2487
2486
  if (!table2 || !table2.name) {
2488
2487
  return 'tokens';
2489
2488
  }
2490
- const table3 = this.queryGet("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix LIMIT 1;", {
2489
+ const table3 = this.queryGet(`SELECT "name" FROM "sqlite_master" WHERE "type"='table' AND "name" LIKE @prefix LIMIT 1;`, {
2491
2490
  params: {
2492
2491
  prefix: this.prefix + 'entities_' + '%',
2493
2492
  },
2494
2493
  });
2495
2494
  if (table3?.name) {
2496
- const result = this.queryGet("SELECT 1 AS `exists` FROM pragma_table_info(@table) WHERE `name`='user';", {
2495
+ const result = this.queryGet(`SELECT 1 AS "exists" FROM pragma_table_info(@table) WHERE "name"='user';`, {
2497
2496
  params: {
2498
2497
  table: table3.name,
2499
2498
  },