@peerbit/indexer-sqlite3 2.1.0 → 2.1.1-2ed894b

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/src/schema.ts CHANGED
@@ -162,6 +162,92 @@ type SQLField = {
162
162
  describesExistenceOfAnother?: string;
163
163
  };
164
164
  type SQLConstraint = { name: string; definition: string };
165
+ type PrimaryFieldInfo = Pick<
166
+ SQLField,
167
+ "name" | "type" | "from" | "unwrappedType"
168
+ >;
169
+
170
+ const createScalarSQLField = (
171
+ path: string[],
172
+ field: Field,
173
+ type: FieldType,
174
+ primary: string | false,
175
+ isOptional: boolean,
176
+ ): SQLField => {
177
+ const name = getInlineTableFieldName(path.slice(1), field.key);
178
+ const isPrimary = primary !== false && name === primary;
179
+ const sqlType = toSQLType(type, isOptional);
180
+ return {
181
+ name,
182
+ key: field.key,
183
+ definition: `${escapeColumnName(name)} ${sqlType} ${isPrimary ? "PRIMARY KEY" : ""}`,
184
+ type: sqlType,
185
+ isPrimary,
186
+ from: field,
187
+ unwrappedType: unwrapNestedType(field.type),
188
+ path: [...path.slice(1), field.key],
189
+ };
190
+ };
191
+
192
+ const resolvePrimaryFieldInfoFromSchema = (
193
+ ctor: Constructor<any>,
194
+ path: string[],
195
+ primary: string,
196
+ ): PrimaryFieldInfo | undefined => {
197
+ const schema = getSchema(ctor);
198
+ if (!schema) {
199
+ return undefined;
200
+ }
201
+
202
+ for (const field of schema.fields) {
203
+ let fieldType: FieldType = field.type;
204
+
205
+ // option(T) is stored as T (nullable) in SQL.
206
+ if (fieldType instanceof OptionKind) {
207
+ fieldType = fieldType.elementType;
208
+ }
209
+
210
+ // fixedArray(u8, N) represents bytes and must map to BLOB in SQL. Note that
211
+ // FixedArrayKind is also a WrappedType, so unwrapNestedType() would otherwise
212
+ // turn it into the scalar "u8" and incorrectly treat it as INTEGER.
213
+ if (fieldType instanceof FixedArrayKind && fieldType.elementType === "u8") {
214
+ fieldType = Uint8Array;
215
+ } else {
216
+ fieldType = unwrapNestedType(fieldType);
217
+ }
218
+
219
+ // Arrays are always stored in separate tables.
220
+ if (fieldType instanceof VecKind) {
221
+ continue;
222
+ }
223
+
224
+ if (typeof fieldType === "string" || isUint8ArrayType(fieldType)) {
225
+ const sqlField = createScalarSQLField(path, field, fieldType, primary, true);
226
+ if (sqlField.isPrimary) {
227
+ return {
228
+ name: sqlField.name,
229
+ type: sqlField.type,
230
+ from: sqlField.from,
231
+ unwrappedType: sqlField.unwrappedType,
232
+ };
233
+ }
234
+ } else if (
235
+ typeof fieldType === "function" &&
236
+ clazzCanBeInlined(fieldType as Constructor<any>)
237
+ ) {
238
+ const nested = resolvePrimaryFieldInfoFromSchema(
239
+ fieldType as Constructor<any>,
240
+ [...path, field.key],
241
+ primary,
242
+ );
243
+ if (nested) {
244
+ return nested;
245
+ }
246
+ }
247
+ }
248
+
249
+ return undefined;
250
+ };
165
251
 
166
252
  export interface Table {
167
253
  name: string;
@@ -331,21 +417,30 @@ export const getSQLFields = (
331
417
 
332
418
  let foundPrimary = false;
333
419
 
420
+ // Resolve the primary field info independent of schema field order. This is
421
+ // needed because nested table generation can happen before the primary field
422
+ // has been processed and added to `sqlFields`.
423
+ const parentPrimaryFieldInfo: PrimaryFieldInfo =
424
+ primary === false || primary === CHILD_TABLE_ID
425
+ ? {
426
+ name: CHILD_TABLE_ID,
427
+ type: "INTEGER",
428
+ from: undefined,
429
+ unwrappedType: undefined,
430
+ }
431
+ : resolvePrimaryFieldInfoFromSchema(ctor, path, primary) || {
432
+ // Fallback: nested tables use synthetic integer ids, and we allow that
433
+ // primary to be unresolved here.
434
+ name: primary,
435
+ type: "INTEGER",
436
+ from: undefined,
437
+ unwrappedType: undefined,
438
+ };
439
+
334
440
  const addJoinFields =
335
441
  primary === false
336
442
  ? addJoinFieldFromParent
337
443
  : (fields: SQLField[], contstraints: SQLConstraint[]) => {
338
- // we resolve primary field here since it might be unknown until this point
339
- const parentPrimaryField =
340
- primary != null
341
- ? sqlFields.find((field) => field.name === primary)
342
- : undefined;
343
- const parentPrimaryFieldName =
344
- parentPrimaryField?.name || CHILD_TABLE_ID;
345
- const parentPrimaryFieldType = parentPrimaryField
346
- ? parentPrimaryField.type
347
- : "INTEGER";
348
-
349
444
  fields.unshift(
350
445
  {
351
446
  name: CHILD_TABLE_ID,
@@ -362,17 +457,17 @@ export const getSQLFields = (
362
457
  {
363
458
  name: PARENT_TABLE_ID,
364
459
  key: PARENT_TABLE_ID,
365
- definition: `${PARENT_TABLE_ID} ${parentPrimaryFieldType}`,
366
- type: parentPrimaryFieldType,
367
- from: parentPrimaryField?.from,
368
- unwrappedType: parentPrimaryField?.unwrappedType,
460
+ definition: `${PARENT_TABLE_ID} ${parentPrimaryFieldInfo.type}`,
461
+ type: parentPrimaryFieldInfo.type,
462
+ from: parentPrimaryFieldInfo.from,
463
+ unwrappedType: parentPrimaryFieldInfo.unwrappedType,
369
464
  isPrimary: false,
370
465
  path: [PARENT_TABLE_ID],
371
466
  },
372
467
  );
373
468
  contstraints.push({
374
469
  name: `${PARENT_TABLE_ID}_fk`,
375
- definition: `CONSTRAINT ${PARENT_TABLE_ID}_fk FOREIGN KEY(${PARENT_TABLE_ID}) REFERENCES ${tableName}(${parentPrimaryFieldName}) ON DELETE CASCADE`,
470
+ definition: `CONSTRAINT ${PARENT_TABLE_ID}_fk FOREIGN KEY(${PARENT_TABLE_ID}) REFERENCES ${tableName}(${parentPrimaryFieldInfo.name}) ON DELETE CASCADE`,
376
471
  });
377
472
  };
378
473
 
@@ -446,27 +541,13 @@ export const getSQLFields = (
446
541
  };
447
542
 
448
543
  const handleSimpleField = (
449
- key: string,
450
544
  field: Field,
451
545
  type: FieldType,
452
546
  isOptional: boolean,
453
547
  ) => {
454
- let keyString = getInlineTableFieldName(path.slice(1), key);
455
-
456
- const isPrimary = primary != null && keyString === primary;
457
- foundPrimary = foundPrimary || isPrimary;
458
-
459
- const fieldType = toSQLType(type, isOptional);
460
- sqlFields.push({
461
- name: keyString,
462
- key,
463
- definition: `${escapeColumnName(keyString)} ${fieldType} ${isPrimary ? "PRIMARY KEY" : ""}`,
464
- type: fieldType,
465
- isPrimary,
466
- from: field,
467
- unwrappedType: unwrapNestedType(field.type),
468
- path: [...path.slice(1), key],
469
- });
548
+ const sqlField = createScalarSQLField(path, field, type, primary, isOptional);
549
+ foundPrimary = foundPrimary || sqlField.isPrimary;
550
+ sqlFields.push(sqlField);
470
551
  };
471
552
 
472
553
  const handleField = (
@@ -480,7 +561,7 @@ export const getSQLFields = (
480
561
  }
481
562
 
482
563
  if (typeof type === "string" || type === Uint8Array) {
483
- handleSimpleField(key, field, type, true);
564
+ handleSimpleField(field, type, true);
484
565
  } else if (
485
566
  typeof type === "function" &&
486
567
  clazzCanBeInlined(type as Constructor<any>)