@apibara/plugin-drizzle 2.1.0-beta.2 → 2.1.0-beta.21

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/dist/index.cjs CHANGED
@@ -4,10 +4,21 @@ const indexer = require('@apibara/indexer');
4
4
  const plugins = require('@apibara/indexer/plugins');
5
5
  const internal = require('@apibara/indexer/internal');
6
6
  const plugins$1 = require('@apibara/indexer/internal/plugins');
7
+ const constants = require('./shared/plugin-drizzle.cae20704.cjs');
8
+ const pglite$1 = require('@electric-sql/pglite');
9
+ const nodePostgres = require('drizzle-orm/node-postgres');
10
+ const migrator$1 = require('drizzle-orm/node-postgres/migrator');
11
+ const pglite = require('drizzle-orm/pglite');
12
+ const migrator = require('drizzle-orm/pglite/migrator');
13
+ const pg = require('pg');
7
14
  const protocol = require('@apibara/protocol');
8
15
  const drizzleOrm = require('drizzle-orm');
9
16
  const pgCore = require('drizzle-orm/pg-core');
10
17
 
18
+ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
19
+
20
+ const pg__default = /*#__PURE__*/_interopDefaultCompat(pg);
21
+
11
22
  class DrizzleStorageError extends Error {
12
23
  constructor(message, options) {
13
24
  super(message, options);
@@ -35,16 +46,70 @@ function serialize(obj) {
35
46
  function sleep(ms) {
36
47
  return new Promise((resolve) => setTimeout(resolve, ms));
37
48
  }
49
+ const getIdColumnForTable = (tableName, idColumn) => {
50
+ if (idColumn[tableName]) {
51
+ return idColumn[tableName];
52
+ }
53
+ return idColumn["*"];
54
+ };
38
55
 
39
- const CHECKPOINTS_TABLE_NAME = "__indexer_checkpoints";
40
- const FILTERS_TABLE_NAME = "__indexer_filters";
41
- const SCHEMA_VERSION_TABLE_NAME = "__indexer_schema_version";
42
- const checkpoints = pgCore.pgTable(CHECKPOINTS_TABLE_NAME, {
56
+ function drizzle(options) {
57
+ const {
58
+ connectionString = process.env["POSTGRES_CONNECTION_STRING"] ?? "memory://",
59
+ schema,
60
+ type = "pglite",
61
+ config,
62
+ poolConfig
63
+ } = options ?? {};
64
+ if (isPostgresConnectionString(connectionString) || type === "node-postgres") {
65
+ const pool = new pg__default.Pool({
66
+ connectionString,
67
+ ...poolConfig || {}
68
+ });
69
+ return nodePostgres.drizzle(pool, { schema, ...config || {} });
70
+ }
71
+ if (type === "pglite") {
72
+ return pglite.drizzle({
73
+ schema,
74
+ connection: {
75
+ dataDir: connectionString || "memory://pglite"
76
+ },
77
+ ...config || {}
78
+ });
79
+ }
80
+ throw new Error("Invalid database type");
81
+ }
82
+ async function migrate(db, options) {
83
+ const isPglite = !!("$client" in db && db.$client instanceof pglite$1.PGlite);
84
+ try {
85
+ if (isPglite) {
86
+ await migrator.migrate(db, options);
87
+ } else {
88
+ await migrator$1.migrate(db, options);
89
+ }
90
+ } catch (error) {
91
+ throw new DrizzleStorageError(
92
+ "Failed to apply migrations! Please check if you have generated migrations using drizzle:generate",
93
+ {
94
+ cause: error
95
+ }
96
+ );
97
+ }
98
+ }
99
+ function isPostgresConnectionString(conn) {
100
+ return conn.startsWith("postgres://") || conn.startsWith("postgresql://");
101
+ }
102
+
103
+ const CHECKPOINTS_TABLE_NAME = "checkpoints";
104
+ const FILTERS_TABLE_NAME = "filters";
105
+ const SCHEMA_VERSION_TABLE_NAME = "schema_version";
106
+ const schema$1 = pgCore.pgSchema(constants.SCHEMA_NAME);
107
+ const checkpoints = schema$1.table(CHECKPOINTS_TABLE_NAME, {
43
108
  id: pgCore.text("id").notNull().primaryKey(),
44
109
  orderKey: pgCore.integer("order_key").notNull(),
45
110
  uniqueKey: pgCore.text("unique_key")
46
111
  });
47
- const filters = pgCore.pgTable(
112
+ const filters = schema$1.table(
48
113
  FILTERS_TABLE_NAME,
49
114
  {
50
115
  id: pgCore.text("id").notNull(),
@@ -58,7 +123,7 @@ const filters = pgCore.pgTable(
58
123
  }
59
124
  ]
60
125
  );
61
- const schemaVersion = pgCore.pgTable(SCHEMA_VERSION_TABLE_NAME, {
126
+ const schemaVersion = schema$1.table(SCHEMA_VERSION_TABLE_NAME, {
62
127
  k: pgCore.integer("k").notNull().primaryKey(),
63
128
  version: pgCore.integer("version").notNull()
64
129
  });
@@ -69,12 +134,19 @@ const MIGRATIONS = [
69
134
  // Add more migration arrays for future versions
70
135
  ];
71
136
  async function initializePersistentState(tx) {
72
- await tx.execute(`
73
- CREATE TABLE IF NOT EXISTS ${SCHEMA_VERSION_TABLE_NAME} (
137
+ await tx.execute(
138
+ drizzleOrm.sql.raw(`
139
+ CREATE SCHEMA IF NOT EXISTS ${constants.SCHEMA_NAME};
140
+ `)
141
+ );
142
+ await tx.execute(
143
+ drizzleOrm.sql.raw(`
144
+ CREATE TABLE IF NOT EXISTS ${constants.SCHEMA_NAME}.${SCHEMA_VERSION_TABLE_NAME} (
74
145
  k INTEGER PRIMARY KEY,
75
146
  version INTEGER NOT NULL
76
147
  );
77
- `);
148
+ `)
149
+ );
78
150
  const versionRows = await tx.select().from(schemaVersion).where(drizzleOrm.eq(schemaVersion.k, 0));
79
151
  const storedVersion = versionRows[0]?.version ?? -1;
80
152
  if (storedVersion > CURRENT_SCHEMA_VERSION) {
@@ -84,22 +156,26 @@ async function initializePersistentState(tx) {
84
156
  }
85
157
  try {
86
158
  if (storedVersion === -1) {
87
- await tx.execute(`
88
- CREATE TABLE IF NOT EXISTS ${CHECKPOINTS_TABLE_NAME} (
159
+ await tx.execute(
160
+ drizzleOrm.sql.raw(`
161
+ CREATE TABLE IF NOT EXISTS ${constants.SCHEMA_NAME}.${CHECKPOINTS_TABLE_NAME} (
89
162
  id TEXT PRIMARY KEY,
90
163
  order_key INTEGER NOT NULL,
91
164
  unique_key TEXT
92
165
  );
93
- `);
94
- await tx.execute(`
95
- CREATE TABLE IF NOT EXISTS ${FILTERS_TABLE_NAME} (
166
+ `)
167
+ );
168
+ await tx.execute(
169
+ drizzleOrm.sql.raw(`
170
+ CREATE TABLE IF NOT EXISTS ${constants.SCHEMA_NAME}.${FILTERS_TABLE_NAME} (
96
171
  id TEXT NOT NULL,
97
172
  filter TEXT NOT NULL,
98
173
  from_block INTEGER NOT NULL,
99
174
  to_block INTEGER DEFAULT NULL,
100
175
  PRIMARY KEY (id, from_block)
101
176
  );
102
- `);
177
+ `)
178
+ );
103
179
  await tx.insert(schemaVersion).values({
104
180
  k: 0,
105
181
  version: CURRENT_SCHEMA_VERSION
@@ -134,7 +210,9 @@ async function persistState(props) {
134
210
  target: checkpoints.id,
135
211
  set: {
136
212
  orderKey: Number(endCursor.orderKey),
137
- uniqueKey: endCursor.uniqueKey
213
+ // Explicitly set the unique key to `null` to indicate that it has been deleted
214
+ // Otherwise drizzle will not update its value.
215
+ uniqueKey: endCursor.uniqueKey ? endCursor.uniqueKey : null
138
216
  }
139
217
  });
140
218
  if (filter) {
@@ -213,11 +291,24 @@ async function finalizeState(props) {
213
291
  });
214
292
  }
215
293
  }
294
+ async function resetPersistence(props) {
295
+ const { tx, indexerId } = props;
296
+ try {
297
+ await tx.delete(checkpoints).where(drizzleOrm.eq(checkpoints.id, indexerId));
298
+ await tx.delete(filters).where(drizzleOrm.eq(filters.id, indexerId));
299
+ } catch (error) {
300
+ throw new DrizzleStorageError("Failed to reset persistence state", {
301
+ cause: error
302
+ });
303
+ }
304
+ }
216
305
 
306
+ const ROLLBACK_TABLE_NAME = "reorg_rollback";
307
+ const schema = pgCore.pgSchema(constants.SCHEMA_NAME);
217
308
  function getReorgTriggerName(table, indexerId) {
218
309
  return `${table}_reorg_${indexerId}`;
219
310
  }
220
- pgCore.pgTable("__reorg_rollback", {
311
+ schema.table(ROLLBACK_TABLE_NAME, {
221
312
  n: pgCore.serial("n").primaryKey(),
222
313
  op: pgCore.char("op", { length: 1 }).$type().notNull(),
223
314
  table_name: pgCore.text("table_name").notNull(),
@@ -228,9 +319,12 @@ pgCore.pgTable("__reorg_rollback", {
228
319
  });
229
320
  async function initializeReorgRollbackTable(tx, indexerId) {
230
321
  try {
322
+ await tx.execute(`
323
+ CREATE SCHEMA IF NOT EXISTS ${constants.SCHEMA_NAME};
324
+ `);
231
325
  await tx.execute(
232
326
  drizzleOrm.sql.raw(`
233
- CREATE TABLE IF NOT EXISTS __reorg_rollback(
327
+ CREATE TABLE IF NOT EXISTS ${constants.SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(
234
328
  n SERIAL PRIMARY KEY,
235
329
  op CHAR(1) NOT NULL,
236
330
  table_name TEXT NOT NULL,
@@ -243,7 +337,7 @@ async function initializeReorgRollbackTable(tx, indexerId) {
243
337
  );
244
338
  await tx.execute(
245
339
  drizzleOrm.sql.raw(`
246
- CREATE INDEX IF NOT EXISTS idx_reorg_rollback_indexer_id_cursor ON __reorg_rollback(indexer_id, cursor);
340
+ CREATE INDEX IF NOT EXISTS idx_reorg_rollback_indexer_id_cursor ON ${constants.SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(indexer_id, cursor);
247
341
  `)
248
342
  );
249
343
  } catch (error) {
@@ -254,7 +348,7 @@ async function initializeReorgRollbackTable(tx, indexerId) {
254
348
  try {
255
349
  await tx.execute(
256
350
  drizzleOrm.sql.raw(`
257
- CREATE OR REPLACE FUNCTION reorg_checkpoint()
351
+ CREATE OR REPLACE FUNCTION ${constants.SCHEMA_NAME}.reorg_checkpoint()
258
352
  RETURNS TRIGGER AS $$
259
353
  DECLARE
260
354
  id_col TEXT := TG_ARGV[0]::TEXT;
@@ -264,13 +358,13 @@ async function initializeReorgRollbackTable(tx, indexerId) {
264
358
  old_id_value TEXT := row_to_json(OLD.*)->>id_col;
265
359
  BEGIN
266
360
  IF (TG_OP = 'DELETE') THEN
267
- INSERT INTO __reorg_rollback(op, table_name, cursor, row_id, row_value, indexer_id)
361
+ INSERT INTO ${constants.SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)
268
362
  SELECT 'D', TG_TABLE_NAME, order_key, old_id_value, row_to_json(OLD.*), indexer_id;
269
363
  ELSIF (TG_OP = 'UPDATE') THEN
270
- INSERT INTO __reorg_rollback(op, table_name, cursor, row_id, row_value, indexer_id)
364
+ INSERT INTO ${constants.SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)
271
365
  SELECT 'U', TG_TABLE_NAME, order_key, new_id_value, row_to_json(OLD.*), indexer_id;
272
366
  ELSIF (TG_OP = 'INSERT') THEN
273
- INSERT INTO __reorg_rollback(op, table_name, cursor, row_id, row_value, indexer_id)
367
+ INSERT INTO ${constants.SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)
274
368
  SELECT 'I', TG_TABLE_NAME, order_key, new_id_value, null, indexer_id;
275
369
  END IF;
276
370
  RETURN NULL;
@@ -287,9 +381,10 @@ async function initializeReorgRollbackTable(tx, indexerId) {
287
381
  );
288
382
  }
289
383
  }
290
- async function registerTriggers(tx, tables, endCursor, idColumn, indexerId) {
384
+ async function registerTriggers(tx, tables, endCursor, idColumnMap, indexerId) {
291
385
  try {
292
386
  for (const table of tables) {
387
+ const tableIdColumn = getIdColumnForTable(table, idColumnMap);
293
388
  await tx.execute(
294
389
  drizzleOrm.sql.raw(
295
390
  `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`
@@ -300,7 +395,7 @@ async function registerTriggers(tx, tables, endCursor, idColumn, indexerId) {
300
395
  CREATE CONSTRAINT TRIGGER ${getReorgTriggerName(table, indexerId)}
301
396
  AFTER INSERT OR UPDATE OR DELETE ON ${table}
302
397
  DEFERRABLE INITIALLY DEFERRED
303
- FOR EACH ROW EXECUTE FUNCTION reorg_checkpoint('${idColumn}', ${`${Number(endCursor.orderKey)}`}, '${indexerId}');
398
+ FOR EACH ROW EXECUTE FUNCTION ${constants.SCHEMA_NAME}.reorg_checkpoint('${tableIdColumn}', ${Number(endCursor.orderKey)}, '${indexerId}');
304
399
  `)
305
400
  );
306
401
  }
@@ -325,11 +420,11 @@ async function removeTriggers(db, tables, indexerId) {
325
420
  });
326
421
  }
327
422
  }
328
- async function invalidate(tx, cursor, idColumn, indexerId) {
423
+ async function invalidate(tx, cursor, idColumnMap, indexerId) {
329
424
  const { rows: result } = await tx.execute(
330
425
  drizzleOrm.sql.raw(`
331
426
  WITH deleted AS (
332
- DELETE FROM __reorg_rollback
427
+ DELETE FROM ${constants.SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}
333
428
  WHERE cursor > ${Number(cursor.orderKey)}
334
429
  AND indexer_id = '${indexerId}'
335
430
  RETURNING *
@@ -343,6 +438,7 @@ async function invalidate(tx, cursor, idColumn, indexerId) {
343
438
  );
344
439
  }
345
440
  for (const op of result) {
441
+ const tableIdColumn = getIdColumnForTable(op.table_name, idColumnMap);
346
442
  switch (op.op) {
347
443
  case "I":
348
444
  try {
@@ -352,7 +448,7 @@ async function invalidate(tx, cursor, idColumn, indexerId) {
352
448
  await tx.execute(
353
449
  drizzleOrm.sql.raw(`
354
450
  DELETE FROM ${op.table_name}
355
- WHERE ${idColumn} = '${op.row_id}'
451
+ WHERE ${tableIdColumn} = '${op.row_id}'
356
452
  `)
357
453
  );
358
454
  } catch (error) {
@@ -392,7 +488,9 @@ async function invalidate(tx, cursor, idColumn, indexerId) {
392
488
  );
393
489
  }
394
490
  const rowValue = typeof op.row_value === "string" ? JSON.parse(op.row_value) : op.row_value;
395
- const nonIdKeys = Object.keys(rowValue).filter((k) => k !== idColumn);
491
+ const nonIdKeys = Object.keys(rowValue).filter(
492
+ (k) => k !== tableIdColumn
493
+ );
396
494
  const fields = nonIdKeys.map((c) => `${c} = prev.${c}`).join(", ");
397
495
  const query = drizzleOrm.sql.raw(`
398
496
  UPDATE ${op.table_name}
@@ -400,7 +498,7 @@ async function invalidate(tx, cursor, idColumn, indexerId) {
400
498
  FROM (
401
499
  SELECT * FROM json_populate_record(null::${op.table_name}, '${JSON.stringify(op.row_value)}'::json)
402
500
  ) as prev
403
- WHERE ${op.table_name}.${idColumn} = '${op.row_id}'
501
+ WHERE ${op.table_name}.${tableIdColumn} = '${op.row_id}'
404
502
  `);
405
503
  await tx.execute(query);
406
504
  } catch (error) {
@@ -422,7 +520,7 @@ async function finalize(tx, cursor, indexerId) {
422
520
  try {
423
521
  await tx.execute(
424
522
  drizzleOrm.sql.raw(`
425
- DELETE FROM __reorg_rollback
523
+ DELETE FROM ${constants.SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}
426
524
  WHERE cursor <= ${Number(cursor.orderKey)}
427
525
  AND indexer_id = '${indexerId}'
428
526
  `)
@@ -433,52 +531,124 @@ async function finalize(tx, cursor, indexerId) {
433
531
  });
434
532
  }
435
533
  }
534
+ async function cleanupStorage(tx, tables, indexerId) {
535
+ try {
536
+ for (const table of tables) {
537
+ await tx.execute(
538
+ drizzleOrm.sql.raw(
539
+ `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`
540
+ )
541
+ );
542
+ }
543
+ await tx.execute(
544
+ drizzleOrm.sql.raw(`
545
+ DELETE FROM ${constants.SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}
546
+ WHERE indexer_id = '${indexerId}'
547
+ `)
548
+ );
549
+ for (const table of tables) {
550
+ try {
551
+ await tx.execute(drizzleOrm.sql.raw(`TRUNCATE TABLE ${table} CASCADE;`));
552
+ } catch (error) {
553
+ throw new DrizzleStorageError(`Failed to truncate table ${table}`, {
554
+ cause: error
555
+ });
556
+ }
557
+ }
558
+ } catch (error) {
559
+ throw new DrizzleStorageError("Failed to clean up storage", {
560
+ cause: error
561
+ });
562
+ }
563
+ }
436
564
 
437
- const DRIZZLE_PROPERTY = "_drizzle";
438
565
  const MAX_RETRIES = 5;
439
566
  function useDrizzleStorage(_db) {
440
567
  const context = indexer.useIndexerContext();
441
- if (!context[DRIZZLE_PROPERTY]) {
568
+ if (!context[constants.DRIZZLE_PROPERTY]) {
442
569
  throw new DrizzleStorageError(
443
570
  "drizzle storage is not available. Did you register the plugin?"
444
571
  );
445
572
  }
446
- return context[DRIZZLE_PROPERTY];
573
+ return context[constants.DRIZZLE_PROPERTY];
447
574
  }
448
575
  function drizzleStorage({
449
576
  db,
450
577
  persistState: enablePersistence = true,
451
578
  indexerName: identifier = "default",
452
- schema,
453
- idColumn = "id"
579
+ schema: _schema,
580
+ idColumn,
581
+ migrate: migrateOptions
454
582
  }) {
455
- return plugins.defineIndexerPlugin((indexer) => {
583
+ return plugins.defineIndexerPlugin((indexer$1) => {
456
584
  let tableNames = [];
457
585
  let indexerId = "";
586
+ const alwaysReindex = process.env["APIBARA_ALWAYS_REINDEX"] === "true";
587
+ let prevFinality;
588
+ const schema = _schema ?? db._.schema ?? {};
589
+ const idColumnMap = {
590
+ "*": typeof idColumn === "string" ? idColumn : "id",
591
+ ...typeof idColumn === "object" ? idColumn : {}
592
+ };
458
593
  try {
459
- tableNames = Object.values(schema ?? db._.schema ?? {}).map(
460
- (table) => table.dbName
461
- );
594
+ tableNames = Object.values(schema).map((table) => table.dbName);
462
595
  } catch (error) {
463
596
  throw new DrizzleStorageError("Failed to get table names from schema", {
464
597
  cause: error
465
598
  });
466
599
  }
467
- indexer.hooks.hook("run:before", async () => {
468
- const { indexerName: indexerFileName, availableIndexers } = plugins$1.useInternalContext();
600
+ for (const table of Object.values(schema)) {
601
+ const columns = table.columns;
602
+ const tableIdColumn = getIdColumnForTable(table.dbName, idColumnMap);
603
+ const columnExists = Object.values(columns).some(
604
+ (column) => column.name === tableIdColumn
605
+ );
606
+ if (!columnExists) {
607
+ throw new DrizzleStorageError(
608
+ `Column \`"${tableIdColumn}"\` does not exist in table \`"${table.dbName}"\`. Make sure the table has the specified column or provide a valid \`idColumn\` mapping to \`drizzleStorage\`.`
609
+ );
610
+ }
611
+ }
612
+ indexer$1.hooks.hook("run:before", async () => {
613
+ const internalContext = plugins$1.useInternalContext();
614
+ const context = indexer.useIndexerContext();
615
+ const logger = plugins.useLogger();
616
+ context[constants.DRIZZLE_STORAGE_DB_PROPERTY] = db;
617
+ const { indexerName: indexerFileName, availableIndexers } = internalContext;
469
618
  indexerId = internal.generateIndexerId(indexerFileName, identifier);
470
619
  let retries = 0;
620
+ let migrationsApplied = false;
621
+ let cleanupApplied = false;
471
622
  while (retries <= MAX_RETRIES) {
472
623
  try {
624
+ if (migrateOptions && !migrationsApplied) {
625
+ await migrate(db, migrateOptions);
626
+ migrationsApplied = true;
627
+ logger.success("Migrations applied");
628
+ }
473
629
  await withTransaction(db, async (tx) => {
474
630
  await initializeReorgRollbackTable(tx, indexerId);
475
631
  if (enablePersistence) {
476
632
  await initializePersistentState(tx);
477
633
  }
634
+ if (alwaysReindex && !cleanupApplied) {
635
+ logger.warn(
636
+ `Reindexing: Deleting all data from tables - ${tableNames.join(", ")}`
637
+ );
638
+ await cleanupStorage(tx, tableNames, indexerId);
639
+ if (enablePersistence) {
640
+ await resetPersistence({ tx, indexerId });
641
+ }
642
+ cleanupApplied = true;
643
+ logger.success("Tables have been cleaned up for reindexing");
644
+ }
478
645
  });
479
646
  break;
480
647
  } catch (error) {
481
648
  if (retries === MAX_RETRIES) {
649
+ if (error instanceof DrizzleStorageError) {
650
+ throw error;
651
+ }
482
652
  throw new DrizzleStorageError(
483
653
  "Initialization failed after 5 retries",
484
654
  {
@@ -491,7 +661,7 @@ function drizzleStorage({
491
661
  }
492
662
  }
493
663
  });
494
- indexer.hooks.hook("connect:before", async ({ request }) => {
664
+ indexer$1.hooks.hook("connect:before", async ({ request }) => {
495
665
  if (!enablePersistence) {
496
666
  return;
497
667
  }
@@ -508,19 +678,19 @@ function drizzleStorage({
508
678
  }
509
679
  });
510
680
  });
511
- indexer.hooks.hook("connect:after", async ({ request }) => {
681
+ indexer$1.hooks.hook("connect:after", async ({ request }) => {
512
682
  const cursor = request.startingCursor;
513
683
  if (!cursor) {
514
684
  return;
515
685
  }
516
686
  await withTransaction(db, async (tx) => {
517
- await invalidate(tx, cursor, idColumn, indexerId);
687
+ await invalidate(tx, cursor, idColumnMap, indexerId);
518
688
  if (enablePersistence) {
519
689
  await invalidateState({ tx, cursor, indexerId });
520
690
  }
521
691
  });
522
692
  });
523
- indexer.hooks.hook("connect:factory", async ({ request, endCursor }) => {
693
+ indexer$1.hooks.hook("connect:factory", async ({ request, endCursor }) => {
524
694
  if (!enablePersistence) {
525
695
  return;
526
696
  }
@@ -534,7 +704,7 @@ function drizzleStorage({
534
704
  });
535
705
  }
536
706
  });
537
- indexer.hooks.hook("message:finalize", async ({ message }) => {
707
+ indexer$1.hooks.hook("message:finalize", async ({ message }) => {
538
708
  const { cursor } = message.finalize;
539
709
  if (!cursor) {
540
710
  throw new DrizzleStorageError("Finalized Cursor is undefined");
@@ -546,45 +716,49 @@ function drizzleStorage({
546
716
  }
547
717
  });
548
718
  });
549
- indexer.hooks.hook("message:invalidate", async ({ message }) => {
719
+ indexer$1.hooks.hook("message:invalidate", async ({ message }) => {
550
720
  const { cursor } = message.invalidate;
551
721
  if (!cursor) {
552
722
  throw new DrizzleStorageError("Invalidate Cursor is undefined");
553
723
  }
554
724
  await withTransaction(db, async (tx) => {
555
- await invalidate(tx, cursor, idColumn, indexerId);
725
+ await invalidate(tx, cursor, idColumnMap, indexerId);
556
726
  if (enablePersistence) {
557
727
  await invalidateState({ tx, cursor, indexerId });
558
728
  }
559
729
  });
560
730
  });
561
- indexer.hooks.hook("handler:middleware", async ({ use }) => {
731
+ indexer$1.hooks.hook("handler:middleware", async ({ use }) => {
562
732
  use(async (context, next) => {
563
733
  try {
564
- const { endCursor, finality } = context;
734
+ const { endCursor, finality, cursor } = context;
565
735
  if (!endCursor) {
566
736
  throw new DrizzleStorageError("End Cursor is undefined");
567
737
  }
568
738
  await withTransaction(db, async (tx) => {
569
- context[DRIZZLE_PROPERTY] = { db: tx };
739
+ context[constants.DRIZZLE_PROPERTY] = { db: tx };
740
+ if (prevFinality === "pending") {
741
+ await invalidate(tx, cursor, idColumnMap, indexerId);
742
+ }
570
743
  if (finality !== "finalized") {
571
744
  await registerTriggers(
572
745
  tx,
573
746
  tableNames,
574
747
  endCursor,
575
- idColumn,
748
+ idColumnMap,
576
749
  indexerId
577
750
  );
578
751
  }
579
752
  await next();
580
- delete context[DRIZZLE_PROPERTY];
581
- if (enablePersistence) {
753
+ delete context[constants.DRIZZLE_PROPERTY];
754
+ if (enablePersistence && finality !== "pending") {
582
755
  await persistState({
583
756
  tx,
584
757
  endCursor,
585
758
  indexerId
586
759
  });
587
760
  }
761
+ prevFinality = finality;
588
762
  });
589
763
  if (finality !== "finalized") {
590
764
  await removeTriggers(db, tableNames, indexerId);
@@ -600,5 +774,7 @@ function drizzleStorage({
600
774
  });
601
775
  }
602
776
 
777
+ exports.drizzle = drizzle;
603
778
  exports.drizzleStorage = drizzleStorage;
779
+ exports.migrate = migrate;
604
780
  exports.useDrizzleStorage = useDrizzleStorage;