@nymphjs/driver-sqlite3 1.0.0-beta.98 → 1.0.0-beta.99

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.
@@ -174,6 +174,53 @@ export default class SQLite3Driver extends NymphDriver {
174
174
  isConnected() {
175
175
  return this.store.connected;
176
176
  }
177
+ createEntitiesTable(etype) {
178
+ // Create the entity table.
179
+ this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid" CHARACTER(24) PRIMARY KEY, "tags" TEXT, "cdate" REAL NOT NULL, "mdate" REAL NOT NULL);`);
180
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_cdate`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("cdate");`);
181
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_mdate`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("mdate");`);
182
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_tags`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("tags");`);
183
+ }
184
+ createDataTable(etype) {
185
+ // Create the data table.
186
+ 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"));`);
187
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid");`);
188
+ 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");`);
189
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name");`);
190
+ 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");`);
191
+ 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");`);
192
+ 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");`);
193
+ 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");`);
194
+ 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");`);
195
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acuserread`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'acUser\' AND "number" >= 1;`);
196
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acgroupread`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'acGroup\' AND "number" >= 1;`);
197
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acotherread`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'acOther\' AND "number" >= 1;`);
198
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acuser`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'user\';`);
199
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acgroup`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'group\';`);
200
+ }
201
+ createReferencesTable(etype) {
202
+ // Create the references table.
203
+ 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"));`);
204
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid");`);
205
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("name");`);
206
+ 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");`);
207
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference");`);
208
+ 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");`);
209
+ 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");`);
210
+ 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");`);
211
+ 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");`);
212
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid_reference_nameuser`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "reference") WHERE "name"=\'user\';`);
213
+ this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid_reference_namegroup`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "reference") WHERE "name"=\'group\';`);
214
+ }
215
+ createTokensTable(etype) {
216
+ // Create the tokens table.
217
+ 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"));`);
218
+ 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");`);
219
+ }
220
+ createUniquesTable(etype) {
221
+ // Create the unique strings table.
222
+ this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid") ON DELETE CASCADE, "unique" TEXT NOT NULL UNIQUE, PRIMARY KEY("guid", "unique"));`);
223
+ }
177
224
  /**
178
225
  * Create entity tables in the database.
179
226
  *
@@ -183,40 +230,11 @@ export default class SQLite3Driver extends NymphDriver {
183
230
  this.startTransaction('nymph-tablecreation');
184
231
  try {
185
232
  if (etype != null) {
186
- // Create the entity table.
187
- this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid" CHARACTER(24) PRIMARY KEY, "tags" TEXT, "cdate" REAL NOT NULL, "mdate" REAL NOT NULL);`);
188
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_cdate`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("cdate");`);
189
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_mdate`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("mdate");`);
190
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}entities_${etype}_id_tags`)} ON ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("tags");`);
191
- // Create the data table.
192
- 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"));`);
193
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid");`);
194
- 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");`);
195
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("name");`);
196
- 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");`);
197
- 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");`);
198
- 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");`);
199
- 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");`);
200
- 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");`);
201
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acuserread`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'acUser\' AND "number" >= 1;`);
202
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acgroupread`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'acGroup\' AND "number" >= 1;`);
203
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acotherread`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'acOther\' AND "number" >= 1;`);
204
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acuser`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'user\';`);
205
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}data_${etype}_id_acgroup`)} ON ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid") WHERE "name"=\'group\';`);
206
- // Create the references table.
207
- 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"));`);
208
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid");`);
209
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_name`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("name");`);
210
- 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");`);
211
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_reference`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("reference");`);
212
- 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");`);
213
- 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");`);
214
- 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");`);
215
- 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");`);
216
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid_reference_nameuser`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "reference") WHERE "name"=\'user\';`);
217
- this.queryRun(`CREATE INDEX IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}references_${etype}_id_guid_reference_namegroup`)} ON ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "reference") WHERE "name"=\'group\';`);
218
- // Create the unique strings table.
219
- this.queryRun(`CREATE TABLE IF NOT EXISTS ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} ("guid" CHARACTER(24) NOT NULL REFERENCES ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid") ON DELETE CASCADE, "unique" TEXT NOT NULL UNIQUE, PRIMARY KEY("guid", "unique"));`);
233
+ this.createEntitiesTable(etype);
234
+ this.createDataTable(etype);
235
+ this.createReferencesTable(etype);
236
+ this.createTokensTable(etype);
237
+ this.createUniquesTable(etype);
220
238
  }
221
239
  else {
222
240
  // Create the UID table.
@@ -319,6 +337,12 @@ export default class SQLite3Driver extends NymphDriver {
319
337
  guid,
320
338
  },
321
339
  });
340
+ this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} WHERE "guid"=@guid;`, {
341
+ etypes: [etype],
342
+ params: {
343
+ guid,
344
+ },
345
+ });
322
346
  this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=@guid;`, {
323
347
  etypes: [etype],
324
348
  params: {
@@ -351,6 +375,18 @@ export default class SQLite3Driver extends NymphDriver {
351
375
  await this.commit('nymph-delete-uid');
352
376
  return true;
353
377
  }
378
+ async getEtypes() {
379
+ const tables = this.queryArray("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix;", {
380
+ params: {
381
+ prefix: this.prefix + 'entities_' + '%',
382
+ },
383
+ });
384
+ const etypes = [];
385
+ for (const table of tables) {
386
+ etypes.push(table.name.substr((this.prefix + 'entities_').length));
387
+ }
388
+ return etypes;
389
+ }
354
390
  async *exportDataIterator() {
355
391
  if (yield {
356
392
  type: 'comment',
@@ -395,15 +431,7 @@ export default class SQLite3Driver extends NymphDriver {
395
431
  return;
396
432
  }
397
433
  // Get the etypes.
398
- const tables = this.queryArray("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @prefix;", {
399
- params: {
400
- prefix: this.prefix + 'entities_' + '%',
401
- },
402
- });
403
- const etypes = [];
404
- for (const table of tables) {
405
- etypes.push(table.name.substr((this.prefix + 'entities_').length));
406
- }
434
+ const etypes = await this.getEtypes();
407
435
  for (const etype of etypes) {
408
436
  // Export entities.
409
437
  const dataIterator = this.queryArray(`SELECT e.*, 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]();
@@ -720,6 +748,124 @@ export default class SQLite3Driver extends NymphDriver {
720
748
  params[value] = svalue;
721
749
  }
722
750
  break;
751
+ case 'search':
752
+ case '!search':
753
+ if (curValue[0] === 'cdate' || curValue[0] === 'mdate') {
754
+ if (curQuery) {
755
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
756
+ }
757
+ curQuery += (xor(typeIsNot, clauseNot) ? 'NOT ' : '') + '(0)';
758
+ break;
759
+ }
760
+ else {
761
+ if (curQuery) {
762
+ curQuery += typeIsOr ? ' OR ' : ' AND ';
763
+ }
764
+ const name = `param${++count.i}`;
765
+ const queryPartToken = (term) => {
766
+ const value = `param${++count.i}`;
767
+ params[value] = term.token;
768
+ return ('EXISTS (SELECT "guid" FROM ' +
769
+ SQLite3Driver.escape(this.prefix + 'tokens_' + etype) +
770
+ ' WHERE "guid"=' +
771
+ ieTable +
772
+ '."guid" AND "name"=@' +
773
+ name +
774
+ ' AND "token"=@' +
775
+ value +
776
+ (term.nostemmed ? ' AND "stem"=0' : '') +
777
+ ')');
778
+ };
779
+ const queryPartSeries = (series) => {
780
+ const tokenTableSuffix = makeTableSuffix();
781
+ const tokenParts = series.tokens.map((token, i) => {
782
+ const value = `param${++count.i}`;
783
+ params[value] = token.token;
784
+ return {
785
+ fromClause: i === 0
786
+ ? 'FROM ' +
787
+ SQLite3Driver.escape(this.prefix + 'tokens_' + etype) +
788
+ ' t' +
789
+ tokenTableSuffix +
790
+ '0'
791
+ : 'JOIN ' +
792
+ SQLite3Driver.escape(this.prefix + 'tokens_' + etype) +
793
+ ' t' +
794
+ tokenTableSuffix +
795
+ i +
796
+ ' ON t' +
797
+ tokenTableSuffix +
798
+ i +
799
+ '."guid" = t' +
800
+ tokenTableSuffix +
801
+ '0."guid" AND t' +
802
+ tokenTableSuffix +
803
+ i +
804
+ '."name" = t' +
805
+ tokenTableSuffix +
806
+ '0."name" AND t' +
807
+ tokenTableSuffix +
808
+ i +
809
+ '."position" = t' +
810
+ tokenTableSuffix +
811
+ '0."position" + ' +
812
+ i,
813
+ whereClause: 't' +
814
+ tokenTableSuffix +
815
+ i +
816
+ '."token"=@' +
817
+ value +
818
+ (token.nostemmed
819
+ ? ' AND t' + tokenTableSuffix + i + '."stem"=0'
820
+ : ''),
821
+ };
822
+ });
823
+ return ('EXISTS (SELECT t' +
824
+ tokenTableSuffix +
825
+ '0."guid" ' +
826
+ tokenParts.map((part) => part.fromClause).join(' ') +
827
+ ' WHERE t' +
828
+ tokenTableSuffix +
829
+ '0."guid"=' +
830
+ ieTable +
831
+ '."guid" AND t' +
832
+ tokenTableSuffix +
833
+ '0."name"=@' +
834
+ name +
835
+ ' AND ' +
836
+ tokenParts.map((part) => part.whereClause).join(' AND ') +
837
+ ')');
838
+ };
839
+ const queryPartTerm = (term) => {
840
+ if (term.type === 'series') {
841
+ return queryPartSeries(term);
842
+ }
843
+ else if (term.type === 'not') {
844
+ return 'NOT ' + queryPartTerm(term.operand);
845
+ }
846
+ else if (term.type === 'or') {
847
+ let queryParts = [];
848
+ for (let operand of term.operands) {
849
+ queryParts.push(queryPartTerm(operand));
850
+ }
851
+ return '(' + queryParts.join(' OR ') + ')';
852
+ }
853
+ return queryPartToken(term);
854
+ };
855
+ const parsedFTSQuery = this.tokenizer.parseSearchQuery(curValue[1]);
856
+ // Run through the query and add terms.
857
+ let termStrings = [];
858
+ for (let term of parsedFTSQuery) {
859
+ termStrings.push(queryPartTerm(term));
860
+ }
861
+ curQuery +=
862
+ (xor(typeIsNot, clauseNot) ? 'NOT ' : '') +
863
+ '(' +
864
+ termStrings.join(' AND ') +
865
+ ')';
866
+ params[name] = curValue[0];
867
+ }
868
+ break;
723
869
  case 'match':
724
870
  case '!match':
725
871
  if (curValue[0] === 'cdate') {
@@ -1430,95 +1576,158 @@ export default class SQLite3Driver extends NymphDriver {
1430
1576
  });
1431
1577
  return result?.cur_uid ?? null;
1432
1578
  }
1433
- async importEntity({ guid, cdate, mdate, tags, sdata, etype, }) {
1579
+ async importEntity(entity) {
1580
+ return await this.importEntityInternal(entity, false);
1581
+ }
1582
+ async importEntityTokens(entity) {
1583
+ return await this.importEntityInternal(entity, true);
1584
+ }
1585
+ async importEntityInternal({ guid, cdate, mdate, tags, sdata, etype, }, onlyTokens) {
1434
1586
  try {
1435
- this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} WHERE "guid"=@guid;`, {
1436
- etypes: [etype],
1437
- params: {
1438
- guid,
1439
- },
1440
- });
1441
- this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} WHERE "guid"=@guid;`, {
1442
- etypes: [etype],
1443
- params: {
1444
- guid,
1445
- },
1446
- });
1447
- this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=@guid;`, {
1448
- etypes: [etype],
1449
- params: {
1450
- guid,
1451
- },
1452
- });
1453
- this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=@guid;`, {
1454
- etypes: [etype],
1455
- params: {
1456
- guid,
1457
- },
1458
- });
1459
- this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid", "tags", "cdate", "mdate") VALUES (@guid, @tags, @cdate, @mdate);`, {
1587
+ if (!onlyTokens) {
1588
+ this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} WHERE "guid"=@guid;`, {
1589
+ etypes: [etype],
1590
+ params: {
1591
+ guid,
1592
+ },
1593
+ });
1594
+ this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} WHERE "guid"=@guid;`, {
1595
+ etypes: [etype],
1596
+ params: {
1597
+ guid,
1598
+ },
1599
+ });
1600
+ this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} WHERE "guid"=@guid;`, {
1601
+ etypes: [etype],
1602
+ params: {
1603
+ guid,
1604
+ },
1605
+ });
1606
+ }
1607
+ this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} WHERE "guid"=@guid;`, {
1460
1608
  etypes: [etype],
1461
1609
  params: {
1462
1610
  guid,
1463
- tags: ',' + tags.join(',') + ',',
1464
- cdate,
1465
- mdate,
1466
1611
  },
1467
1612
  });
1468
- for (const name in sdata) {
1469
- const value = sdata[name];
1470
- const uvalue = JSON.parse(value);
1471
- if (value === undefined) {
1472
- continue;
1473
- }
1474
- const storageValue = typeof uvalue === 'number'
1475
- ? 'N'
1476
- : typeof uvalue === 'string'
1477
- ? 'S'
1478
- : 'J';
1479
- const jsonValue = storageValue === 'J' ? value : null;
1480
- this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "value", "json", "string", "number", "truthy") VALUES (@guid, @name, @storageValue, jsonb(@jsonValue), @string, @number, @truthy);`, {
1613
+ if (!onlyTokens) {
1614
+ this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=@guid;`, {
1481
1615
  etypes: [etype],
1482
1616
  params: {
1483
1617
  guid,
1484
- name,
1485
- storageValue,
1486
- jsonValue,
1487
- string: storageValue === 'J' ? null : `${uvalue}`,
1488
- number: Number(uvalue),
1489
- truthy: uvalue ? 1 : 0,
1490
1618
  },
1491
1619
  });
1492
- const references = this.findReferences(value);
1493
- for (const reference of references) {
1494
- this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "name", "reference") VALUES (@guid, @name, @reference);`, {
1620
+ }
1621
+ if (!onlyTokens) {
1622
+ this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}entities_${etype}`)} ("guid", "tags", "cdate", "mdate") VALUES (@guid, @tags, @cdate, @mdate);`, {
1623
+ etypes: [etype],
1624
+ params: {
1625
+ guid,
1626
+ tags: ',' + tags.join(',') + ',',
1627
+ cdate,
1628
+ mdate,
1629
+ },
1630
+ });
1631
+ for (const name in sdata) {
1632
+ const value = sdata[name];
1633
+ const uvalue = JSON.parse(value);
1634
+ if (value === undefined) {
1635
+ continue;
1636
+ }
1637
+ const storageValue = typeof uvalue === 'number'
1638
+ ? 'N'
1639
+ : typeof uvalue === 'string'
1640
+ ? 'S'
1641
+ : 'J';
1642
+ const jsonValue = storageValue === 'J' ? value : null;
1643
+ this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}data_${etype}`)} ("guid", "name", "value", "json", "string", "number", "truthy") VALUES (@guid, @name, @storageValue, jsonb(@jsonValue), @string, @number, @truthy);`, {
1495
1644
  etypes: [etype],
1496
1645
  params: {
1497
1646
  guid,
1498
1647
  name,
1499
- reference,
1648
+ storageValue,
1649
+ jsonValue,
1650
+ string: storageValue === 'J' ? null : `${uvalue}`,
1651
+ number: Number(uvalue),
1652
+ truthy: uvalue ? 1 : 0,
1500
1653
  },
1501
1654
  });
1655
+ const references = this.findReferences(value);
1656
+ for (const reference of references) {
1657
+ this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}references_${etype}`)} ("guid", "name", "reference") VALUES (@guid, @name, @reference);`, {
1658
+ etypes: [etype],
1659
+ params: {
1660
+ guid,
1661
+ name,
1662
+ reference,
1663
+ },
1664
+ });
1665
+ }
1502
1666
  }
1503
1667
  }
1504
- const uniques = await this.nymph
1505
- .getEntityClassByEtype(etype)
1506
- .getUniques({ guid, cdate, mdate, tags, data: {}, sdata });
1507
- for (const unique of uniques) {
1668
+ const EntityClass = this.nymph.getEntityClassByEtype(etype);
1669
+ for (let name in sdata) {
1670
+ let tokenString = null;
1508
1671
  try {
1509
- this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} ("guid", "unique") VALUES (@guid, @unique);`, {
1510
- etypes: [etype],
1511
- params: {
1512
- guid,
1513
- unique,
1514
- },
1515
- });
1672
+ tokenString = EntityClass.getFTSText(name, JSON.parse(sdata[name]));
1516
1673
  }
1517
1674
  catch (e) {
1518
- if (e instanceof EntityUniqueConstraintError) {
1519
- this.nymph.config.debugError('sqlite3', `Import entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`);
1675
+ // Ignore error.
1676
+ }
1677
+ if (tokenString != null) {
1678
+ const tokens = this.tokenizer.tokenize(tokenString);
1679
+ while (tokens.length) {
1680
+ const currentTokens = tokens.splice(0, 100);
1681
+ const params = {
1682
+ guid,
1683
+ name,
1684
+ };
1685
+ const values = [];
1686
+ for (let i = 0; i < currentTokens.length; i++) {
1687
+ const token = currentTokens[i];
1688
+ params['token' + i] = token.token;
1689
+ params['position' + i] = token.position;
1690
+ params['stem' + i] = token.stem ? 1 : 0;
1691
+ values.push('(@guid, @name, @token' +
1692
+ i +
1693
+ ', @position' +
1694
+ i +
1695
+ ', @stem' +
1696
+ i +
1697
+ ')');
1698
+ }
1699
+ this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("guid", "name", "token", "position", "stem") VALUES ${values.join(', ')};`, {
1700
+ etypes: [etype],
1701
+ params,
1702
+ });
1703
+ }
1704
+ }
1705
+ }
1706
+ if (!onlyTokens) {
1707
+ const uniques = await EntityClass.getUniques({
1708
+ guid,
1709
+ cdate,
1710
+ mdate,
1711
+ tags,
1712
+ data: {},
1713
+ sdata,
1714
+ });
1715
+ for (const unique of uniques) {
1716
+ try {
1717
+ this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} ("guid", "unique") VALUES (@guid, @unique);`, {
1718
+ etypes: [etype],
1719
+ params: {
1720
+ guid,
1721
+ unique,
1722
+ },
1723
+ });
1724
+ }
1725
+ catch (e) {
1726
+ if (e instanceof EntityUniqueConstraintError) {
1727
+ this.nymph.config.debugError('sqlite3', `Import entity unique constraint violation for GUID "${guid}" on etype "${etype}": "${unique}"`);
1728
+ }
1729
+ throw e;
1520
1730
  }
1521
- throw e;
1522
1731
  }
1523
1732
  }
1524
1733
  }
@@ -1623,6 +1832,7 @@ export default class SQLite3Driver extends NymphDriver {
1623
1832
  }
1624
1833
  async saveEntity(entity) {
1625
1834
  const insertData = (guid, data, sdata, uniques, etype) => {
1835
+ const EntityClass = this.nymph.getEntityClassByEtype(etype);
1626
1836
  const runInsertQuery = (name, value, svalue) => {
1627
1837
  if (value === undefined) {
1628
1838
  return;
@@ -1656,6 +1866,41 @@ export default class SQLite3Driver extends NymphDriver {
1656
1866
  },
1657
1867
  });
1658
1868
  }
1869
+ let tokenString = null;
1870
+ try {
1871
+ tokenString = EntityClass.getFTSText(name, value);
1872
+ }
1873
+ catch (e) {
1874
+ // Ignore error.
1875
+ }
1876
+ if (tokenString != null) {
1877
+ const tokens = this.tokenizer.tokenize(tokenString);
1878
+ while (tokens.length) {
1879
+ const currentTokens = tokens.splice(0, 100);
1880
+ const params = {
1881
+ guid,
1882
+ name,
1883
+ };
1884
+ const values = [];
1885
+ for (let i = 0; i < currentTokens.length; i++) {
1886
+ const token = currentTokens[i];
1887
+ params['token' + i] = token.token;
1888
+ params['position' + i] = token.position;
1889
+ params['stem' + i] = token.stem ? 1 : 0;
1890
+ values.push('(@guid, @name, @token' +
1891
+ i +
1892
+ ', @position' +
1893
+ i +
1894
+ ', @stem' +
1895
+ i +
1896
+ ')');
1897
+ }
1898
+ this.queryRun(`INSERT INTO ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} ("guid", "name", "token", "position", "stem") VALUES ${values.join(', ')};`, {
1899
+ etypes: [etype],
1900
+ params,
1901
+ });
1902
+ }
1903
+ }
1659
1904
  };
1660
1905
  for (const unique of uniques) {
1661
1906
  try {
@@ -1726,6 +1971,12 @@ export default class SQLite3Driver extends NymphDriver {
1726
1971
  guid,
1727
1972
  },
1728
1973
  });
1974
+ this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}tokens_${etype}`)} WHERE "guid"=@guid;`, {
1975
+ etypes: [etype],
1976
+ params: {
1977
+ guid,
1978
+ },
1979
+ });
1729
1980
  this.queryRun(`DELETE FROM ${SQLite3Driver.escape(`${this.prefix}uniques_${etype}`)} WHERE "guid"=@guid;`, {
1730
1981
  etypes: [etype],
1731
1982
  params: {
@@ -1805,9 +2056,25 @@ export default class SQLite3Driver extends NymphDriver {
1805
2056
  table: table.name,
1806
2057
  },
1807
2058
  });
1808
- return !result?.exists;
2059
+ if (!result?.exists) {
2060
+ return 'json';
2061
+ }
2062
+ }
2063
+ const table2 = this.queryGet("SELECT `name` FROM `sqlite_master` WHERE `type`='table' AND `name` LIKE @tokenTable LIMIT 1;", {
2064
+ params: {
2065
+ tokenTable: this.prefix + 'tokens_' + '%',
2066
+ },
2067
+ });
2068
+ if (!table2 || !table2.name) {
2069
+ return 'tokens';
1809
2070
  }
1810
2071
  return false;
1811
2072
  }
2073
+ async liveMigration(_migrationType) {
2074
+ const etypes = await this.getEtypes();
2075
+ for (let etype of etypes) {
2076
+ this.createTokensTable(etype);
2077
+ }
2078
+ }
1812
2079
  }
1813
2080
  //# sourceMappingURL=SQLite3Driver.js.map