@apibara/plugin-drizzle 2.1.0-beta.40 → 2.1.0-beta.41

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
@@ -132,6 +132,15 @@ const filters = schema$1.table(
132
132
  }
133
133
  ]
134
134
  );
135
+ const chainReorganizations = schema$1.table("chain_reorganizations", {
136
+ id: pgCore.serial("id").primaryKey(),
137
+ indexerId: pgCore.text("indexer_id").notNull(),
138
+ oldHeadOrderKey: pgCore.integer("old_head_order_key"),
139
+ oldHeadUniqueKey: pgCore.text("old_head_unique_key").$type().default(null),
140
+ newHeadOrderKey: pgCore.integer("new_head_order_key").notNull(),
141
+ newHeadUniqueKey: pgCore.text("new_head_unique_key").$type().default(null),
142
+ recordedAt: pgCore.timestamp("recorded_at").defaultNow().notNull()
143
+ });
135
144
  const schemaVersion = schema$1.table(SCHEMA_VERSION_TABLE_NAME, {
136
145
  k: pgCore.integer("k").notNull().primaryKey(),
137
146
  version: pgCore.integer("version").notNull()
@@ -156,6 +165,25 @@ async function initializePersistentState(tx) {
156
165
  );
157
166
  `)
158
167
  );
168
+ await tx.execute(
169
+ drizzleOrm.sql.raw(`
170
+ CREATE TABLE IF NOT EXISTS ${constants.SCHEMA_NAME}.chain_reorganizations (
171
+ id SERIAL PRIMARY KEY,
172
+ indexer_id TEXT NOT NULL,
173
+ old_head_order_key INTEGER,
174
+ old_head_unique_key TEXT DEFAULT NULL,
175
+ new_head_order_key INTEGER NOT NULL,
176
+ new_head_unique_key TEXT DEFAULT NULL,
177
+ recorded_at TIMESTAMP NOT NULL DEFAULT NOW()
178
+ );
179
+ `)
180
+ );
181
+ await tx.execute(
182
+ drizzleOrm.sql.raw(`
183
+ CREATE INDEX IF NOT EXISTS idx_chain_reorgs_indexer_id
184
+ ON ${constants.SCHEMA_NAME}.chain_reorganizations(indexer_id);
185
+ `)
186
+ );
159
187
  const versionRows = await tx.select().from(schemaVersion).where(drizzleOrm.eq(schemaVersion.k, 0));
160
188
  const storedVersion = versionRows[0]?.version ?? -1;
161
189
  if (storedVersion > CURRENT_SCHEMA_VERSION) {
@@ -207,6 +235,22 @@ async function initializePersistentState(tx) {
207
235
  );
208
236
  }
209
237
  }
238
+ async function recordChainReorganization(props) {
239
+ const { tx, indexerId, oldHead, newHead } = props;
240
+ try {
241
+ await tx.insert(chainReorganizations).values({
242
+ indexerId,
243
+ oldHeadOrderKey: oldHead ? Number(oldHead.orderKey) : null,
244
+ oldHeadUniqueKey: oldHead?.uniqueKey ? oldHead.uniqueKey : null,
245
+ newHeadOrderKey: Number(newHead.orderKey),
246
+ newHeadUniqueKey: newHead.uniqueKey ? newHead.uniqueKey : null
247
+ });
248
+ } catch (error) {
249
+ throw new DrizzleStorageError("Failed to record chain reorganization", {
250
+ cause: error
251
+ });
252
+ }
253
+ }
210
254
  async function persistState(props) {
211
255
  const { tx, endCursor, filter, indexerId } = props;
212
256
  try {
@@ -267,6 +311,10 @@ async function getState(props) {
267
311
  async function invalidateState(props) {
268
312
  const { tx, cursor, indexerId } = props;
269
313
  try {
314
+ await tx.update(checkpoints).set({
315
+ orderKey: Number(cursor.orderKey),
316
+ uniqueKey: cursor.uniqueKey ? cursor.uniqueKey : null
317
+ }).where(drizzleOrm.eq(checkpoints.id, indexerId));
270
318
  await tx.delete(filters).where(
271
319
  drizzleOrm.and(
272
320
  drizzleOrm.eq(filters.id, indexerId),
@@ -597,7 +645,8 @@ function drizzleStorage({
597
645
  indexerName: identifier = "default",
598
646
  schema: _schema,
599
647
  idColumn,
600
- migrate: migrateOptions
648
+ migrate: migrateOptions,
649
+ recordChainReorganizations = false
601
650
  }) {
602
651
  return plugins.defineIndexerPlugin((indexer$1) => {
603
652
  let tableNames = [];
@@ -741,6 +790,20 @@ function drizzleStorage({
741
790
  throw new DrizzleStorageError("Invalidate Cursor is undefined");
742
791
  }
743
792
  await withTransaction(db, async (tx) => {
793
+ let oldHead;
794
+ if (recordChainReorganizations) {
795
+ const { cursor: currentCursor } = await getState({
796
+ tx,
797
+ indexerId
798
+ });
799
+ oldHead = currentCursor;
800
+ await recordChainReorganization({
801
+ tx,
802
+ indexerId,
803
+ oldHead,
804
+ newHead: cursor
805
+ });
806
+ }
744
807
  await invalidate(tx, cursor, idColumnMap, indexerId);
745
808
  if (enablePersistence) {
746
809
  await invalidateState({ tx, cursor, indexerId });
@@ -784,9 +847,7 @@ function drizzleStorage({
784
847
  }
785
848
  } catch (error) {
786
849
  await removeTriggers(db, tableNames, indexerId);
787
- throw new DrizzleStorageError("Failed to run handler:middleware", {
788
- cause: error
789
- });
850
+ throw error;
790
851
  }
791
852
  });
792
853
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/utils.ts","../src/helper.ts","../src/persistence.ts","../src/storage.ts","../src/index.ts"],"sourcesContent":["import type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\nimport type {\n PgDatabase,\n PgQueryResultHKT,\n PgTransaction,\n} from \"drizzle-orm/pg-core\";\n\nexport class DrizzleStorageError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"DrizzleStorageError\";\n }\n}\n\nexport async function withTransaction<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n cb: (db: PgTransaction<TQueryResult, TFullSchema, TSchema>) => Promise<void>,\n) {\n return await db.transaction(async (txnDb) => {\n return await cb(txnDb);\n });\n}\n\nexport function deserialize<T>(str: string): T {\n return JSON.parse(str, (_, value) =>\n typeof value === \"string\" && value.match(/^\\d+n$/)\n ? BigInt(value.slice(0, -1))\n : value,\n ) as T;\n}\n\nexport function serialize<T>(obj: T): string {\n return JSON.stringify(\n obj,\n (_, value) => (typeof value === \"bigint\" ? `${value.toString()}n` : value),\n \"\\t\",\n );\n}\n\nexport function sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport interface IdColumnMap extends Record<string, string> {\n /**\n * Wildcard mapping for all tables.\n */\n \"*\": string;\n}\n\nexport const getIdColumnForTable = (\n tableName: string,\n idColumn: IdColumnMap,\n): string => {\n // If there's a specific mapping for this table, use it\n if (idColumn[tableName]) {\n return idColumn[tableName];\n }\n // Default fallback\n return idColumn[\"*\"];\n};\n","import type { PGlite, PGliteOptions } from \"@electric-sql/pglite\";\nimport type { DrizzleConfig } from \"drizzle-orm\";\nimport { entityKind } from \"drizzle-orm\";\nimport type { MigrationConfig } from \"drizzle-orm/migrator\";\nimport type { NodePgDatabase as OriginalNodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport type { PgliteDatabase as OriginalPgliteDatabase } from \"drizzle-orm/pglite\";\nimport type pg from \"pg\";\nimport { DrizzleStorageError } from \"./utils\";\n\n/**\n * Union type of all possible drizzle database options\n */\nexport type DrizzleOptions = PgliteDrizzleOptions | NodePgDrizzleOptions;\n\n/**\n * Configuration options for Node-Postgres database connection\n */\nexport type NodePgDrizzleOptions = {\n /**\n * Type of database to use -\n * - \"pglite\" - PGLite database\n * - \"node-postgres\" - Node-Postgres database\n * @default \"pglite\"\n */\n type: \"node-postgres\";\n /**\n * Connection string to use for the database\n * @default \"\"\n */\n connectionString?: string;\n /**\n * Pool configuration options for Node-Postgres\n */\n poolConfig?: pg.PoolConfig;\n /**\n * Additional drizzle configuration options\n */\n config?: Omit<DrizzleConfig, \"schema\">;\n};\n\n/**\n * Configuration options for PGLite database connection\n */\nexport type PgliteDrizzleOptions = {\n /**\n * Type of database to use -\n * - \"pglite\" - PGLite database\n * - \"node-postgres\" - Node-Postgres database\n */\n type?: \"pglite\";\n /**\n * Connection string to use for the database\n * @default process.env[\"POSTGRES_CONNECTION_STRING\"] ?? \"memory://pglite\"\n */\n connectionString?: string;\n /**\n * Pool configuration is not supported for PGLite\n */\n poolConfig?: never;\n /**\n * Additional drizzle configuration options with PGLite specific connection options\n */\n config?: Omit<DrizzleConfig, \"schema\"> & {\n connection?:\n | (PGliteOptions & {\n dataDir?: string;\n })\n | string;\n };\n};\n\n/**\n * Extended PGLite database type with client information\n */\nexport type PgliteDatabase<TSchema extends Record<string, unknown>> =\n OriginalPgliteDatabase<TSchema> & {\n $client: PGlite;\n };\n\n/**\n * Extended Node-Postgres database type with client information\n */\nexport type NodePgDatabase<TSchema extends Record<string, unknown>> =\n OriginalNodePgDatabase<TSchema> & {\n $client: pg.Pool;\n };\n\nexport type Database<\n TOptions extends DrizzleOptions,\n TSchema extends Record<string, unknown>,\n> = TOptions extends PgliteDrizzleOptions\n ? PgliteDatabase<TSchema>\n : NodePgDatabase<TSchema>;\n\n/**\n * Creates a new Drizzle database instance based on the provided options\n *\n * @important connectionString defaults to process.env[\"POSTGRES_CONNECTION_STRING\"], if not set, it defaults to \"memory://\" (in-memory pglite)\n *\n * @param options - Configuration options for the database connection\n * @returns A configured Drizzle database instance\n * @throws {Error} If an invalid database type is specified\n */\nexport function drizzle<\n TSchema extends Record<string, unknown>,\n TOptions extends DrizzleOptions,\n>(\n options?: TOptions & {\n /**\n * Schema to use for the database\n * @default {}\n */\n schema?: TSchema;\n },\n): Database<TOptions, TSchema> {\n const {\n connectionString = process.env[\"POSTGRES_CONNECTION_STRING\"] ?? \"memory://\",\n schema,\n type = \"pglite\",\n config,\n poolConfig,\n } = options ?? {};\n\n if (isPgliteConnectionString(connectionString) && type === \"pglite\") {\n const { drizzle: drizzlePGLite } = require(\"drizzle-orm/pglite\");\n\n return drizzlePGLite({\n schema: schema as TSchema,\n connection: {\n dataDir: connectionString || \"memory://pglite\",\n },\n ...(config || {}),\n }) as Database<TOptions, TSchema>;\n }\n\n const { Pool } = require(\"pg\");\n const { drizzle: drizzleNode } = require(\"drizzle-orm/node-postgres\");\n const pool = new Pool({\n connectionString,\n ...(poolConfig || {}),\n });\n return drizzleNode(pool, { schema, ...(config || {}) }) as Database<\n TOptions,\n TSchema\n >;\n}\n\n/**\n * Options for database migration\n */\nexport type MigrateOptions = MigrationConfig;\n\n/**\n * Performs database migration based on the provided configuration\n * @param db - The database instance to migrate\n * @param options - Migration configuration options\n *\n * @important This function runs migrations on the database instance provided to the `drizzleStorage` plugin.\n * It automatically detects the type of database and runs the appropriate migrate function\n * (PGLite or Node-Postgres).\n *\n * @example\n * ```ts\n * await migrate(db, { migrationsFolder: \"./drizzle\" });\n * ```\n */\nexport async function migrate<TSchema extends Record<string, unknown>>(\n db: PgliteDatabase<TSchema> | NodePgDatabase<TSchema>,\n options: MigrateOptions,\n) {\n const isPglite = isDrizzleKind(db, \"PgliteDatabase\");\n\n try {\n if (isPglite) {\n const { migrate: migratePGLite } = require(\"drizzle-orm/pglite/migrator\");\n await migratePGLite(db as PgliteDatabase<TSchema>, options);\n } else {\n const {\n migrate: migrateNode,\n } = require(\"drizzle-orm/node-postgres/migrator\");\n await migrateNode(db as NodePgDatabase<TSchema>, options);\n }\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to apply migrations! Please check if you have generated migrations using drizzle:generate\",\n {\n cause: error,\n },\n );\n }\n}\n\nfunction isPgliteConnectionString(conn: string) {\n return (\n conn.startsWith(\"memory://\") ||\n conn.startsWith(\"file://\") ||\n conn.startsWith(\"idb://\")\n );\n}\n\nfunction isDrizzleKind(value: unknown, entityKindValue: string) {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n // https://github.com/drizzle-team/drizzle-orm/blob/f39f885779800982e90dd3c89aba6df3217a6fd2/drizzle-orm/src/entity.ts#L29-L41\n let cls = Object.getPrototypeOf(value).constructor;\n if (cls) {\n // Traverse the prototype chain to find the entityKind\n while (cls) {\n // https://github.com/drizzle-team/drizzle-orm/blob/f39f885779800982e90dd3c89aba6df3217a6fd2/drizzle-orm/src/pglite/driver.ts#L41\n if (entityKind in cls && cls[entityKind] === entityKindValue) {\n return true;\n }\n cls = Object.getPrototypeOf(cls);\n }\n }\n\n return false;\n}\n","import { type Cursor, normalizeCursor } from \"@apibara/protocol\";\nimport { and, eq, gt, isNull, lt, sql } from \"drizzle-orm\";\nimport type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\nimport type { PgQueryResultHKT, PgTransaction } from \"drizzle-orm/pg-core\";\nimport { integer, pgSchema, primaryKey, text } from \"drizzle-orm/pg-core\";\nimport { SCHEMA_NAME } from \"./constants\";\nimport { DrizzleStorageError, deserialize, serialize } from \"./utils\";\n\nconst CHECKPOINTS_TABLE_NAME = \"checkpoints\";\nconst FILTERS_TABLE_NAME = \"filters\";\nconst SCHEMA_VERSION_TABLE_NAME = \"schema_version\";\n\nconst schema = pgSchema(SCHEMA_NAME);\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const checkpoints = schema.table(CHECKPOINTS_TABLE_NAME, {\n id: text(\"id\").notNull().primaryKey(),\n orderKey: integer(\"order_key\").notNull(),\n uniqueKey: text(\"unique_key\"),\n});\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const filters = schema.table(\n FILTERS_TABLE_NAME,\n {\n id: text(\"id\").notNull(),\n filter: text(\"filter\").notNull(),\n fromBlock: integer(\"from_block\").notNull(),\n toBlock: integer(\"to_block\").$type<number | null>().default(null),\n },\n (table) => [\n {\n pk: primaryKey({ columns: [table.id, table.fromBlock] }),\n },\n ],\n);\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const schemaVersion = schema.table(SCHEMA_VERSION_TABLE_NAME, {\n k: integer(\"k\").notNull().primaryKey(),\n version: integer(\"version\").notNull(),\n});\n\nexport const CURRENT_SCHEMA_VERSION = 0;\n\n// migrations for future schema updates\nconst MIGRATIONS: string[][] = [\n // migrations[0]: v0 -> v1 (for future use)\n [],\n // Add more migration arrays for future versions\n];\n\nexport async function initializePersistentState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(tx: PgTransaction<TQueryResult, TFullSchema, TSchema>) {\n // Create schema if it doesn't exist\n await tx.execute(\n sql.raw(`\n CREATE SCHEMA IF NOT EXISTS ${SCHEMA_NAME};\n `),\n );\n\n // Create schema version table\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${SCHEMA_VERSION_TABLE_NAME} (\n k INTEGER PRIMARY KEY,\n version INTEGER NOT NULL\n );\n `),\n );\n\n // Get current schema version\n const versionRows = await tx\n .select()\n .from(schemaVersion)\n .where(eq(schemaVersion.k, 0));\n\n const storedVersion = versionRows[0]?.version ?? -1;\n\n // Check for incompatible version\n if (storedVersion > CURRENT_SCHEMA_VERSION) {\n throw new DrizzleStorageError(\n `Database Persistence schema version v${storedVersion} is newer than supported version v${CURRENT_SCHEMA_VERSION}`,\n );\n }\n\n // Begin schema updates\n try {\n if (storedVersion === -1) {\n // First time initialization\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${CHECKPOINTS_TABLE_NAME} (\n id TEXT PRIMARY KEY,\n order_key INTEGER NOT NULL,\n unique_key TEXT\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${FILTERS_TABLE_NAME} (\n id TEXT NOT NULL,\n filter TEXT NOT NULL,\n from_block INTEGER NOT NULL,\n to_block INTEGER DEFAULT NULL,\n PRIMARY KEY (id, from_block)\n );\n `),\n );\n\n // Set initial schema version\n await tx.insert(schemaVersion).values({\n k: 0,\n version: CURRENT_SCHEMA_VERSION,\n });\n } else {\n // Run any necessary migrations\n let currentVersion = storedVersion;\n while (currentVersion < CURRENT_SCHEMA_VERSION) {\n const migrationStatements = MIGRATIONS[currentVersion];\n for (const statement of migrationStatements) {\n await tx.execute(statement);\n }\n currentVersion++;\n }\n\n // Update schema version\n await tx\n .update(schemaVersion)\n .set({ version: CURRENT_SCHEMA_VERSION })\n .where(eq(schemaVersion.k, 0));\n }\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to initialize or migrate database schema\",\n { cause: error },\n );\n }\n}\n\nexport async function persistState<\n TFilter,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n endCursor: Cursor;\n filter?: TFilter;\n indexerId: string;\n}) {\n const { tx, endCursor, filter, indexerId } = props;\n\n try {\n if (endCursor) {\n await tx\n .insert(checkpoints)\n .values({\n id: indexerId,\n orderKey: Number(endCursor.orderKey),\n uniqueKey: endCursor.uniqueKey,\n })\n .onConflictDoUpdate({\n target: checkpoints.id,\n set: {\n orderKey: Number(endCursor.orderKey),\n // Explicitly set the unique key to `null` to indicate that it has been deleted\n // Otherwise drizzle will not update its value.\n uniqueKey: endCursor.uniqueKey ? endCursor.uniqueKey : null,\n },\n });\n\n if (filter) {\n await tx\n .update(filters)\n .set({ toBlock: Number(endCursor.orderKey) })\n .where(and(eq(filters.id, indexerId), isNull(filters.toBlock)));\n\n await tx\n .insert(filters)\n .values({\n id: indexerId,\n filter: serialize(filter),\n fromBlock: Number(endCursor.orderKey),\n toBlock: null,\n })\n .onConflictDoUpdate({\n target: [filters.id, filters.fromBlock],\n set: {\n filter: serialize(filter),\n fromBlock: Number(endCursor.orderKey),\n toBlock: null,\n },\n });\n }\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to persist state\", {\n cause: error,\n });\n }\n}\n\nexport async function getState<\n TFilter,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n indexerId: string;\n}): Promise<{ cursor?: Cursor; filter?: TFilter }> {\n const { tx, indexerId } = props;\n\n try {\n const checkpointRows = await tx\n .select()\n .from(checkpoints)\n .where(eq(checkpoints.id, indexerId));\n\n const cursor = checkpointRows[0]\n ? normalizeCursor({\n orderKey: BigInt(checkpointRows[0].orderKey),\n uniqueKey: checkpointRows[0].uniqueKey,\n })\n : undefined;\n\n const filterRows = await tx\n .select()\n .from(filters)\n .where(and(eq(filters.id, indexerId), isNull(filters.toBlock)));\n\n const filter = filterRows[0]\n ? deserialize<TFilter>(filterRows[0].filter)\n : undefined;\n\n return { cursor, filter };\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to get persistent state\", {\n cause: error,\n });\n }\n}\n\nexport async function invalidateState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n cursor: Cursor;\n indexerId: string;\n}) {\n const { tx, cursor, indexerId } = props;\n\n try {\n await tx\n .delete(filters)\n .where(\n and(\n eq(filters.id, indexerId),\n gt(filters.fromBlock, Number(cursor.orderKey)),\n ),\n );\n\n await tx\n .update(filters)\n .set({ toBlock: null })\n .where(\n and(\n eq(filters.id, indexerId),\n gt(filters.toBlock, Number(cursor.orderKey)),\n ),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to invalidate state\", {\n cause: error,\n });\n }\n}\n\nexport async function finalizeState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n cursor: Cursor;\n indexerId: string;\n}) {\n const { tx, cursor, indexerId } = props;\n\n try {\n await tx\n .delete(filters)\n .where(\n and(\n eq(filters.id, indexerId),\n lt(filters.toBlock, Number(cursor.orderKey)),\n ),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to finalize state\", {\n cause: error,\n });\n }\n}\n\nexport async function resetPersistence<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n indexerId: string;\n}) {\n const { tx, indexerId } = props;\n\n try {\n await tx.delete(checkpoints).where(eq(checkpoints.id, indexerId));\n await tx.delete(filters).where(eq(filters.id, indexerId));\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to reset persistence state\", {\n cause: error,\n });\n }\n}\n","import type { Cursor } from \"@apibara/protocol\";\nimport {\n type ExtractTablesWithRelations,\n type TablesRelationalConfig,\n sql,\n} from \"drizzle-orm\";\nimport {\n type PgDatabase,\n type PgQueryResultHKT,\n type PgTransaction,\n char,\n integer,\n jsonb,\n pgSchema,\n serial,\n text,\n} from \"drizzle-orm/pg-core\";\nimport { SCHEMA_NAME } from \"./constants\";\nimport {\n DrizzleStorageError,\n type IdColumnMap,\n getIdColumnForTable,\n} from \"./utils\";\n\nconst ROLLBACK_TABLE_NAME = \"reorg_rollback\";\n\nconst schema = pgSchema(SCHEMA_NAME);\n\nfunction getReorgTriggerName(table: string, indexerId: string) {\n return `${table}_reorg_${indexerId}`;\n}\n\nexport type ReorgOperation = \"I\" | \"U\" | \"D\";\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const reorgRollbackTable = schema.table(ROLLBACK_TABLE_NAME, {\n n: serial(\"n\").primaryKey(),\n op: char(\"op\", { length: 1 }).$type<ReorgOperation>().notNull(),\n table_name: text(\"table_name\").notNull(),\n cursor: integer(\"cursor\").notNull(),\n row_id: text(\"row_id\"),\n row_value: jsonb(\"row_value\"),\n indexer_id: text(\"indexer_id\").notNull(),\n});\n\nexport type ReorgRollbackRow = typeof reorgRollbackTable.$inferSelect;\n\nexport async function initializeReorgRollbackTable<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(tx: PgTransaction<TQueryResult, TFullSchema, TSchema>, indexerId: string) {\n try {\n // Create schema if it doesn't exist\n await tx.execute(`\n CREATE SCHEMA IF NOT EXISTS ${SCHEMA_NAME};\n `);\n // Create the audit log table\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(\n n SERIAL PRIMARY KEY,\n op CHAR(1) NOT NULL,\n table_name TEXT NOT NULL,\n cursor INTEGER NOT NULL,\n row_id TEXT,\n row_value JSONB,\n indexer_id TEXT NOT NULL\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE INDEX IF NOT EXISTS idx_reorg_rollback_indexer_id_cursor ON ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(indexer_id, cursor);\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to initialize reorg rollback table\", {\n cause: error,\n });\n }\n\n try {\n // Create the trigger function\n await tx.execute(\n sql.raw(`\n CREATE OR REPLACE FUNCTION ${SCHEMA_NAME}.reorg_checkpoint()\n RETURNS TRIGGER AS $$\n DECLARE\n table_name TEXT := TG_ARGV[0]::TEXT;\n id_col TEXT := TG_ARGV[1]::TEXT;\n order_key INTEGER := TG_ARGV[2]::INTEGER;\n indexer_id TEXT := TG_ARGV[3]::TEXT;\n new_id_value TEXT := row_to_json(NEW.*)->>id_col;\n old_id_value TEXT := row_to_json(OLD.*)->>id_col;\n BEGIN\n IF (TG_OP = 'DELETE') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'D', table_name, order_key, old_id_value, row_to_json(OLD.*), indexer_id;\n ELSIF (TG_OP = 'UPDATE') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'U', table_name, order_key, new_id_value, row_to_json(OLD.*), indexer_id;\n ELSIF (TG_OP = 'INSERT') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'I', table_name, order_key, new_id_value, null, indexer_id;\n END IF;\n RETURN NULL;\n END;\n $$ LANGUAGE plpgsql;\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to create reorg checkpoint function\",\n {\n cause: error,\n },\n );\n }\n}\n\nexport async function registerTriggers<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n endCursor: Cursor,\n idColumnMap: IdColumnMap,\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n // Determine the column ID for this specific table\n const tableIdColumn = getIdColumnForTable(table, idColumnMap);\n\n await tx.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n await tx.execute(\n sql.raw(`\n CREATE CONSTRAINT TRIGGER ${getReorgTriggerName(table, indexerId)}\n AFTER INSERT OR UPDATE OR DELETE ON ${table}\n DEFERRABLE INITIALLY DEFERRED\n FOR EACH ROW EXECUTE FUNCTION ${SCHEMA_NAME}.reorg_checkpoint('${table}', '${tableIdColumn}', ${Number(endCursor.orderKey)}, '${indexerId}');\n `),\n );\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to register triggers\", {\n cause: error,\n });\n }\n}\n\nexport async function removeTriggers<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n await db.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to remove triggers\", {\n cause: error,\n });\n }\n}\n\nexport async function invalidate<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n cursor: Cursor,\n idColumnMap: IdColumnMap,\n indexerId: string,\n) {\n // Get and delete operations after cursor in one query, ordered by newest first\n const { rows: result } = (await tx.execute(\n sql.raw(`\n WITH deleted AS (\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE cursor > ${Number(cursor.orderKey)}\n AND indexer_id = '${indexerId}'\n RETURNING *\n )\n SELECT * FROM deleted ORDER BY n DESC;\n `),\n )) as { rows: ReorgRollbackRow[] };\n\n if (!Array.isArray(result)) {\n throw new DrizzleStorageError(\n \"Invalid result format from reorg_rollback query\",\n );\n }\n\n // Process each operation in reverse order\n for (const op of result) {\n // Determine the column ID for this specific table\n const tableIdColumn = getIdColumnForTable(op.table_name, idColumnMap);\n\n switch (op.op) {\n case \"I\":\n try {\n if (!op.row_id) {\n throw new DrizzleStorageError(\"Insert operation has no row_id\");\n }\n\n await tx.execute(\n sql.raw(`\n DELETE FROM ${op.table_name}\n WHERE ${tableIdColumn} = '${op.row_id}'\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - I\",\n {\n cause: error,\n },\n );\n }\n\n break;\n\n case \"D\":\n try {\n // For deletes, reinsert the row using json_populate_record\n if (!op.row_value) {\n throw new DrizzleStorageError(\"Delete operation has no row_value\");\n }\n\n await tx.execute(\n sql.raw(`\n INSERT INTO ${op.table_name}\n SELECT * FROM json_populate_record(null::${op.table_name}, '${JSON.stringify(op.row_value)}'::json)\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - D\",\n {\n cause: error,\n },\n );\n }\n\n break;\n\n case \"U\":\n try {\n if (!op.row_value || !op.row_id) {\n throw new DrizzleStorageError(\n \"Update operation has no row_value or row_id\",\n );\n }\n\n // For updates, restore previous values\n\n const rowValue =\n typeof op.row_value === \"string\"\n ? JSON.parse(op.row_value)\n : op.row_value;\n\n const nonIdKeys = Object.keys(rowValue).filter(\n (k) => k !== tableIdColumn,\n );\n\n const fields = nonIdKeys.map((c) => `${c} = prev.${c}`).join(\", \");\n\n const query = sql.raw(`\n UPDATE ${op.table_name}\n SET ${fields}\n FROM (\n SELECT * FROM json_populate_record(null::${op.table_name}, '${JSON.stringify(op.row_value)}'::json)\n ) as prev\n WHERE ${op.table_name}.${tableIdColumn} = '${op.row_id}'\n `);\n\n await tx.execute(query);\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - U\",\n {\n cause: error,\n },\n );\n }\n break;\n\n default: {\n throw new DrizzleStorageError(`Unknown operation: ${op.op}`);\n }\n }\n }\n}\n\nexport async function finalize<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n cursor: Cursor,\n indexerId: string,\n) {\n try {\n await tx.execute(\n sql.raw(`\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE cursor <= ${Number(cursor.orderKey)}\n AND indexer_id = '${indexerId}'\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to finalize\", {\n cause: error,\n });\n }\n}\n\nexport async function cleanupStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n await tx.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n }\n\n await tx.execute(\n sql.raw(`\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE indexer_id = '${indexerId}'\n `),\n );\n\n for (const table of tables) {\n try {\n await tx.execute(sql.raw(`TRUNCATE TABLE ${table} CASCADE;`));\n } catch (error) {\n throw new DrizzleStorageError(`Failed to truncate table ${table}`, {\n cause: error,\n });\n }\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to clean up storage\", {\n cause: error,\n });\n }\n}\n","import { useIndexerContext } from \"@apibara/indexer\";\nimport { defineIndexerPlugin, useLogger } from \"@apibara/indexer/plugins\";\n\nimport type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\n\nimport { generateIndexerId } from \"@apibara/indexer/internal\";\nimport { useInternalContext } from \"@apibara/indexer/internal/plugins\";\nimport type { Cursor, DataFinality } from \"@apibara/protocol\";\nimport type {\n PgDatabase,\n PgQueryResultHKT,\n PgTransaction,\n} from \"drizzle-orm/pg-core\";\nimport { DRIZZLE_PROPERTY, DRIZZLE_STORAGE_DB_PROPERTY } from \"./constants\";\nimport { type MigrateOptions, migrate } from \"./helper\";\nimport {\n finalizeState,\n getState,\n initializePersistentState,\n invalidateState,\n persistState,\n resetPersistence,\n} from \"./persistence\";\nimport {\n cleanupStorage,\n finalize,\n initializeReorgRollbackTable,\n invalidate,\n registerTriggers,\n removeTriggers,\n} from \"./storage\";\nimport {\n DrizzleStorageError,\n type IdColumnMap,\n getIdColumnForTable,\n sleep,\n withTransaction,\n} from \"./utils\";\n\nexport * from \"./helper\";\n\nexport type { IdColumnMap };\n\nconst MAX_RETRIES = 5;\n\nexport type DrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n> = {\n db: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n};\n\nexport function useDrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n _db?: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n): DrizzleStorage<TQueryResult, TFullSchema, TSchema> {\n const context = useIndexerContext();\n\n if (!context[DRIZZLE_PROPERTY]) {\n throw new DrizzleStorageError(\n \"drizzle storage is not available. Did you register the plugin?\",\n );\n }\n\n return context[DRIZZLE_PROPERTY];\n}\n\nexport function useTestDrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(): PgDatabase<TQueryResult, TFullSchema, TSchema> {\n const context = useIndexerContext();\n\n if (!context[DRIZZLE_STORAGE_DB_PROPERTY]) {\n throw new DrizzleStorageError(\n \"drizzle storage db is not available. Did you register the plugin?\",\n );\n }\n\n return context[DRIZZLE_STORAGE_DB_PROPERTY];\n}\n\nexport interface DrizzleStorageOptions<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n> {\n /**\n * The Drizzle database instance.\n */\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>;\n /**\n * Whether to persist the indexer's state. Defaults to true.\n */\n persistState?: boolean;\n /**\n * The name of the indexer. Default value is 'default'.\n */\n indexerName?: string;\n /**\n * The schema of the database.\n */\n schema?: Record<string, unknown>;\n /**\n * The column to use as the primary identifier for each table.\n *\n * This identifier is used for tracking changes during reorgs and rollbacks.\n *\n * Can be specified in two ways:\n *\n * 1. As a single string that applies to all tables:\n * ```ts\n * idColumn: \"_id\" // Uses \"_id\" column for all tables\n * ```\n *\n * 2. As an object mapping table names to their ID columns:\n * ```ts\n * idColumn: {\n * transfers: \"transaction_hash\", // Use \"transaction_hash\" for transfers table\n * blocks: \"block_number\", // Use \"block_number\" for blocks table\n * \"*\": \"_id\" // Use \"_id\" for all other tables | defaults to \"id\"\n * }\n * ```\n *\n * The special \"*\" key acts as a fallback for any tables not explicitly mapped.\n *\n * @default \"id\"\n * @type {string | Partial<IdColumnMap>}\n */\n idColumn?: string | Partial<IdColumnMap>;\n /**\n * The options for the database migration. When provided, the database will automatically run migrations before the indexer runs.\n */\n migrate?: MigrateOptions;\n}\n\n/**\n * Creates a plugin that uses Drizzle as the storage layer.\n *\n * Supports storing the indexer's state and provides a simple Key-Value store.\n * @param options.db - The Drizzle database instance.\n * @param options.persistState - Whether to persist the indexer's state. Defaults to true.\n * @param options.indexerName - The name of the indexer. Defaults value is 'default'.\n * @param options.schema - The schema of the database.\n * @param options.idColumn - The column to use as the id. Defaults to 'id'.\n * @param options.migrate - The options for the database migration. when provided, the database will automatically run migrations before the indexer runs.\n */\nexport function drizzleStorage<\n TFilter,\n TBlock,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>({\n db,\n persistState: enablePersistence = true,\n indexerName: identifier = \"default\",\n schema: _schema,\n idColumn,\n migrate: migrateOptions,\n}: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>) {\n return defineIndexerPlugin<TFilter, TBlock>((indexer) => {\n let tableNames: string[] = [];\n let indexerId = \"\";\n const alwaysReindex = process.env[\"APIBARA_ALWAYS_REINDEX\"] === \"true\";\n let prevFinality: DataFinality | undefined;\n const schema: TSchema = (_schema as TSchema) ?? db._.schema ?? {};\n const idColumnMap: IdColumnMap = {\n \"*\": typeof idColumn === \"string\" ? idColumn : \"id\",\n ...(typeof idColumn === \"object\" ? idColumn : {}),\n };\n\n try {\n tableNames = Object.values(schema).map((table) => table.dbName);\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to get table names from schema\", {\n cause: error,\n });\n }\n\n // Check if specified idColumn exists in all the tables in schema\n for (const table of Object.values(schema)) {\n const columns = table.columns;\n const tableIdColumn = getIdColumnForTable(table.dbName, idColumnMap);\n\n const columnExists = Object.values(columns).some(\n (column) => column.name === tableIdColumn,\n );\n\n if (!columnExists) {\n throw new DrizzleStorageError(\n `Column \\`\"${tableIdColumn}\"\\` does not exist in table \\`\"${table.dbName}\"\\`. ` +\n \"Make sure the table has the specified column or provide a valid `idColumn` mapping to `drizzleStorage`.\",\n );\n }\n }\n\n indexer.hooks.hook(\"plugins:init\", async () => {\n const internalContext = useInternalContext();\n const context = useIndexerContext();\n const logger = useLogger();\n\n // For testing purposes using vcr.\n context[DRIZZLE_STORAGE_DB_PROPERTY] = db;\n\n const { indexerName: indexerFileName, availableIndexers } =\n internalContext;\n\n indexerId = generateIndexerId(indexerFileName, identifier);\n\n let retries = 0;\n\n // incase the migrations are already applied, we don't want to run them again\n let migrationsApplied = false;\n let cleanupApplied = false;\n\n while (retries <= MAX_RETRIES) {\n try {\n if (migrateOptions && !migrationsApplied) {\n // @ts-ignore type mismatch for db\n await migrate(db, migrateOptions);\n migrationsApplied = true;\n logger.success(\"Migrations applied\");\n }\n await withTransaction(db, async (tx) => {\n await initializeReorgRollbackTable(tx, indexerId);\n if (enablePersistence) {\n await initializePersistentState(tx);\n }\n\n if (alwaysReindex && !cleanupApplied) {\n logger.warn(\n `Reindexing: Deleting all data from tables - ${tableNames.join(\", \")}`,\n );\n\n await cleanupStorage(tx, tableNames, indexerId);\n\n if (enablePersistence) {\n await resetPersistence({ tx, indexerId });\n }\n\n cleanupApplied = true;\n\n logger.success(\"Tables have been cleaned up for reindexing\");\n }\n });\n break;\n } catch (error) {\n if (retries === MAX_RETRIES) {\n if (error instanceof DrizzleStorageError) {\n throw error;\n }\n throw new DrizzleStorageError(\n \"Initialization failed after 5 retries\",\n {\n cause: error,\n },\n );\n }\n await sleep(retries * 1000);\n retries++;\n }\n }\n });\n\n indexer.hooks.hook(\"connect:before\", async ({ request }) => {\n if (!enablePersistence) {\n return;\n }\n\n await withTransaction(db, async (tx) => {\n const { cursor, filter } = await getState<\n TFilter,\n TQueryResult,\n TFullSchema,\n TSchema\n >({\n tx,\n indexerId,\n });\n if (cursor) {\n request.startingCursor = cursor;\n }\n if (filter) {\n request.filter[1] = filter;\n }\n });\n });\n\n indexer.hooks.hook(\"connect:after\", async ({ request }) => {\n // On restart, we need to invalidate data for blocks that were processed but not persisted.\n const cursor = request.startingCursor;\n\n if (!cursor) {\n return;\n }\n\n await withTransaction(db, async (tx) => {\n // Use the appropriate idColumn for each table when calling invalidate\n await invalidate(tx, cursor, idColumnMap, indexerId);\n\n if (enablePersistence) {\n await invalidateState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"connect:factory\", async ({ request, endCursor }) => {\n if (!enablePersistence) {\n return;\n }\n // We can call this hook because this hook is called inside the transaction of handler:middleware\n // so we have access to the transaction from the context\n const { db: tx } = useDrizzleStorage(db);\n\n if (endCursor && request.filter[1]) {\n await persistState({\n tx,\n endCursor,\n filter: request.filter[1],\n indexerId,\n });\n }\n });\n\n indexer.hooks.hook(\"message:finalize\", async ({ message }) => {\n const { cursor } = message;\n\n if (!cursor) {\n throw new DrizzleStorageError(\"Finalized Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n await finalize(tx, cursor, indexerId);\n\n if (enablePersistence) {\n await finalizeState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"message:invalidate\", async ({ message }) => {\n const { cursor } = message;\n\n if (!cursor) {\n throw new DrizzleStorageError(\"Invalidate Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n // Use the appropriate idColumn for each table when calling invalidate\n await invalidate(tx, cursor, idColumnMap, indexerId);\n\n if (enablePersistence) {\n await invalidateState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"handler:middleware\", async ({ use }) => {\n use(async (context, next) => {\n try {\n const { endCursor, finality, cursor } = context as {\n cursor: Cursor;\n endCursor: Cursor;\n finality: DataFinality;\n };\n\n if (!endCursor) {\n throw new DrizzleStorageError(\"End Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n context[DRIZZLE_PROPERTY] = { db: tx } as DrizzleStorage<\n TQueryResult,\n TFullSchema,\n TSchema\n >;\n\n if (prevFinality === \"pending\") {\n // invalidate if previous block's finality was \"pending\"\n await invalidate(tx, cursor, idColumnMap, indexerId);\n }\n\n if (finality !== \"finalized\") {\n await registerTriggers(\n tx,\n tableNames,\n endCursor,\n idColumnMap,\n indexerId,\n );\n }\n\n await next();\n delete context[DRIZZLE_PROPERTY];\n\n if (enablePersistence && finality !== \"pending\") {\n await persistState({\n tx,\n endCursor,\n indexerId,\n });\n }\n\n prevFinality = finality;\n });\n\n if (finality !== \"finalized\") {\n // remove trigger outside of the transaction or it won't be triggered.\n await removeTriggers(db, tableNames, indexerId);\n }\n } catch (error) {\n await removeTriggers(db, tableNames, indexerId);\n\n throw new DrizzleStorageError(\"Failed to run handler:middleware\", {\n cause: error,\n });\n }\n });\n });\n });\n}\n"],"names":["entityKind","schema","pgSchema","SCHEMA_NAME","text","integer","primaryKey","sql","eq","and","isNull","normalizeCursor","gt","lt","serial","char","jsonb","useIndexerContext","DRIZZLE_PROPERTY","DRIZZLE_STORAGE_DB_PROPERTY","defineIndexerPlugin","indexer","useInternalContext","useLogger","generateIndexerId"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/utils.ts","../src/helper.ts","../src/persistence.ts","../src/storage.ts","../src/index.ts"],"sourcesContent":["import type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\nimport type {\n PgDatabase,\n PgQueryResultHKT,\n PgTransaction,\n} from \"drizzle-orm/pg-core\";\n\nexport class DrizzleStorageError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"DrizzleStorageError\";\n }\n}\n\nexport async function withTransaction<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n cb: (db: PgTransaction<TQueryResult, TFullSchema, TSchema>) => Promise<void>,\n) {\n return await db.transaction(async (txnDb) => {\n return await cb(txnDb);\n });\n}\n\nexport function deserialize<T>(str: string): T {\n return JSON.parse(str, (_, value) =>\n typeof value === \"string\" && value.match(/^\\d+n$/)\n ? BigInt(value.slice(0, -1))\n : value,\n ) as T;\n}\n\nexport function serialize<T>(obj: T): string {\n return JSON.stringify(\n obj,\n (_, value) => (typeof value === \"bigint\" ? `${value.toString()}n` : value),\n \"\\t\",\n );\n}\n\nexport function sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport interface IdColumnMap extends Record<string, string> {\n /**\n * Wildcard mapping for all tables.\n */\n \"*\": string;\n}\n\nexport const getIdColumnForTable = (\n tableName: string,\n idColumn: IdColumnMap,\n): string => {\n // If there's a specific mapping for this table, use it\n if (idColumn[tableName]) {\n return idColumn[tableName];\n }\n // Default fallback\n return idColumn[\"*\"];\n};\n","import type { PGlite, PGliteOptions } from \"@electric-sql/pglite\";\nimport type { DrizzleConfig } from \"drizzle-orm\";\nimport { entityKind } from \"drizzle-orm\";\nimport type { MigrationConfig } from \"drizzle-orm/migrator\";\nimport type { NodePgDatabase as OriginalNodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport type { PgliteDatabase as OriginalPgliteDatabase } from \"drizzle-orm/pglite\";\nimport type pg from \"pg\";\nimport { DrizzleStorageError } from \"./utils\";\n\n/**\n * Union type of all possible drizzle database options\n */\nexport type DrizzleOptions = PgliteDrizzleOptions | NodePgDrizzleOptions;\n\n/**\n * Configuration options for Node-Postgres database connection\n */\nexport type NodePgDrizzleOptions = {\n /**\n * Type of database to use -\n * - \"pglite\" - PGLite database\n * - \"node-postgres\" - Node-Postgres database\n * @default \"pglite\"\n */\n type: \"node-postgres\";\n /**\n * Connection string to use for the database\n * @default \"\"\n */\n connectionString?: string;\n /**\n * Pool configuration options for Node-Postgres\n */\n poolConfig?: pg.PoolConfig;\n /**\n * Additional drizzle configuration options\n */\n config?: Omit<DrizzleConfig, \"schema\">;\n};\n\n/**\n * Configuration options for PGLite database connection\n */\nexport type PgliteDrizzleOptions = {\n /**\n * Type of database to use -\n * - \"pglite\" - PGLite database\n * - \"node-postgres\" - Node-Postgres database\n */\n type?: \"pglite\";\n /**\n * Connection string to use for the database\n * @default process.env[\"POSTGRES_CONNECTION_STRING\"] ?? \"memory://pglite\"\n */\n connectionString?: string;\n /**\n * Pool configuration is not supported for PGLite\n */\n poolConfig?: never;\n /**\n * Additional drizzle configuration options with PGLite specific connection options\n */\n config?: Omit<DrizzleConfig, \"schema\"> & {\n connection?:\n | (PGliteOptions & {\n dataDir?: string;\n })\n | string;\n };\n};\n\n/**\n * Extended PGLite database type with client information\n */\nexport type PgliteDatabase<TSchema extends Record<string, unknown>> =\n OriginalPgliteDatabase<TSchema> & {\n $client: PGlite;\n };\n\n/**\n * Extended Node-Postgres database type with client information\n */\nexport type NodePgDatabase<TSchema extends Record<string, unknown>> =\n OriginalNodePgDatabase<TSchema> & {\n $client: pg.Pool;\n };\n\nexport type Database<\n TOptions extends DrizzleOptions,\n TSchema extends Record<string, unknown>,\n> = TOptions extends PgliteDrizzleOptions\n ? PgliteDatabase<TSchema>\n : NodePgDatabase<TSchema>;\n\n/**\n * Creates a new Drizzle database instance based on the provided options\n *\n * @important connectionString defaults to process.env[\"POSTGRES_CONNECTION_STRING\"], if not set, it defaults to \"memory://\" (in-memory pglite)\n *\n * @param options - Configuration options for the database connection\n * @returns A configured Drizzle database instance\n * @throws {Error} If an invalid database type is specified\n */\nexport function drizzle<\n TSchema extends Record<string, unknown>,\n TOptions extends DrizzleOptions,\n>(\n options?: TOptions & {\n /**\n * Schema to use for the database\n * @default {}\n */\n schema?: TSchema;\n },\n): Database<TOptions, TSchema> {\n const {\n connectionString = process.env[\"POSTGRES_CONNECTION_STRING\"] ?? \"memory://\",\n schema,\n type = \"pglite\",\n config,\n poolConfig,\n } = options ?? {};\n\n if (isPgliteConnectionString(connectionString) && type === \"pglite\") {\n const { drizzle: drizzlePGLite } = require(\"drizzle-orm/pglite\");\n\n return drizzlePGLite({\n schema: schema as TSchema,\n connection: {\n dataDir: connectionString || \"memory://pglite\",\n },\n ...(config || {}),\n }) as Database<TOptions, TSchema>;\n }\n\n const { Pool } = require(\"pg\");\n const { drizzle: drizzleNode } = require(\"drizzle-orm/node-postgres\");\n const pool = new Pool({\n connectionString,\n ...(poolConfig || {}),\n });\n return drizzleNode(pool, { schema, ...(config || {}) }) as Database<\n TOptions,\n TSchema\n >;\n}\n\n/**\n * Options for database migration\n */\nexport type MigrateOptions = MigrationConfig;\n\n/**\n * Performs database migration based on the provided configuration\n * @param db - The database instance to migrate\n * @param options - Migration configuration options\n *\n * @important This function runs migrations on the database instance provided to the `drizzleStorage` plugin.\n * It automatically detects the type of database and runs the appropriate migrate function\n * (PGLite or Node-Postgres).\n *\n * @example\n * ```ts\n * await migrate(db, { migrationsFolder: \"./drizzle\" });\n * ```\n */\nexport async function migrate<TSchema extends Record<string, unknown>>(\n db: PgliteDatabase<TSchema> | NodePgDatabase<TSchema>,\n options: MigrateOptions,\n) {\n const isPglite = isDrizzleKind(db, \"PgliteDatabase\");\n\n try {\n if (isPglite) {\n const { migrate: migratePGLite } = require(\"drizzle-orm/pglite/migrator\");\n await migratePGLite(db as PgliteDatabase<TSchema>, options);\n } else {\n const {\n migrate: migrateNode,\n } = require(\"drizzle-orm/node-postgres/migrator\");\n await migrateNode(db as NodePgDatabase<TSchema>, options);\n }\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to apply migrations! Please check if you have generated migrations using drizzle:generate\",\n {\n cause: error,\n },\n );\n }\n}\n\nfunction isPgliteConnectionString(conn: string) {\n return (\n conn.startsWith(\"memory://\") ||\n conn.startsWith(\"file://\") ||\n conn.startsWith(\"idb://\")\n );\n}\n\nfunction isDrizzleKind(value: unknown, entityKindValue: string) {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n // https://github.com/drizzle-team/drizzle-orm/blob/f39f885779800982e90dd3c89aba6df3217a6fd2/drizzle-orm/src/entity.ts#L29-L41\n let cls = Object.getPrototypeOf(value).constructor;\n if (cls) {\n // Traverse the prototype chain to find the entityKind\n while (cls) {\n // https://github.com/drizzle-team/drizzle-orm/blob/f39f885779800982e90dd3c89aba6df3217a6fd2/drizzle-orm/src/pglite/driver.ts#L41\n if (entityKind in cls && cls[entityKind] === entityKindValue) {\n return true;\n }\n cls = Object.getPrototypeOf(cls);\n }\n }\n\n return false;\n}\n","import { type Cursor, normalizeCursor } from \"@apibara/protocol\";\nimport { and, eq, gt, isNull, lt, sql } from \"drizzle-orm\";\nimport type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\nimport type { PgQueryResultHKT, PgTransaction } from \"drizzle-orm/pg-core\";\nimport {\n integer,\n pgSchema,\n primaryKey,\n serial,\n text,\n timestamp,\n} from \"drizzle-orm/pg-core\";\nimport { SCHEMA_NAME } from \"./constants\";\nimport { DrizzleStorageError, deserialize, serialize } from \"./utils\";\n\nconst CHECKPOINTS_TABLE_NAME = \"checkpoints\";\nconst FILTERS_TABLE_NAME = \"filters\";\nconst SCHEMA_VERSION_TABLE_NAME = \"schema_version\";\n\nconst schema = pgSchema(SCHEMA_NAME);\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const checkpoints = schema.table(CHECKPOINTS_TABLE_NAME, {\n id: text(\"id\").notNull().primaryKey(),\n orderKey: integer(\"order_key\").notNull(),\n uniqueKey: text(\"unique_key\"),\n});\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const filters = schema.table(\n FILTERS_TABLE_NAME,\n {\n id: text(\"id\").notNull(),\n filter: text(\"filter\").notNull(),\n fromBlock: integer(\"from_block\").notNull(),\n toBlock: integer(\"to_block\").$type<number | null>().default(null),\n },\n (table) => [\n {\n pk: primaryKey({ columns: [table.id, table.fromBlock] }),\n },\n ],\n);\n\n/** Table for recording chain reorganizations */\nexport const chainReorganizations = schema.table(\"chain_reorganizations\", {\n id: serial(\"id\").primaryKey(),\n indexerId: text(\"indexer_id\").notNull(),\n oldHeadOrderKey: integer(\"old_head_order_key\"),\n oldHeadUniqueKey: text(\"old_head_unique_key\")\n .$type<string | null>()\n .default(null),\n newHeadOrderKey: integer(\"new_head_order_key\").notNull(),\n newHeadUniqueKey: text(\"new_head_unique_key\")\n .$type<string | null>()\n .default(null),\n recordedAt: timestamp(\"recorded_at\").defaultNow().notNull(),\n});\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const schemaVersion = schema.table(SCHEMA_VERSION_TABLE_NAME, {\n k: integer(\"k\").notNull().primaryKey(),\n version: integer(\"version\").notNull(),\n});\n\nexport const CURRENT_SCHEMA_VERSION = 0;\n\n// migrations for future schema updates\nconst MIGRATIONS: string[][] = [\n // migrations[0]: v0 -> v1 (for future use)\n [],\n // Add more migration arrays for future versions\n];\n\nexport async function initializePersistentState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(tx: PgTransaction<TQueryResult, TFullSchema, TSchema>) {\n // Create schema if it doesn't exist\n await tx.execute(\n sql.raw(`\n CREATE SCHEMA IF NOT EXISTS ${SCHEMA_NAME};\n `),\n );\n\n // Create schema version table\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${SCHEMA_VERSION_TABLE_NAME} (\n k INTEGER PRIMARY KEY,\n version INTEGER NOT NULL\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.chain_reorganizations (\n id SERIAL PRIMARY KEY,\n indexer_id TEXT NOT NULL,\n old_head_order_key INTEGER,\n old_head_unique_key TEXT DEFAULT NULL,\n new_head_order_key INTEGER NOT NULL,\n new_head_unique_key TEXT DEFAULT NULL,\n recorded_at TIMESTAMP NOT NULL DEFAULT NOW()\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE INDEX IF NOT EXISTS idx_chain_reorgs_indexer_id \n ON ${SCHEMA_NAME}.chain_reorganizations(indexer_id);\n `),\n );\n\n // Get current schema version\n const versionRows = await tx\n .select()\n .from(schemaVersion)\n .where(eq(schemaVersion.k, 0));\n\n const storedVersion = versionRows[0]?.version ?? -1;\n\n // Check for incompatible version\n if (storedVersion > CURRENT_SCHEMA_VERSION) {\n throw new DrizzleStorageError(\n `Database Persistence schema version v${storedVersion} is newer than supported version v${CURRENT_SCHEMA_VERSION}`,\n );\n }\n\n // Begin schema updates\n try {\n if (storedVersion === -1) {\n // First time initialization\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${CHECKPOINTS_TABLE_NAME} (\n id TEXT PRIMARY KEY,\n order_key INTEGER NOT NULL,\n unique_key TEXT\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${FILTERS_TABLE_NAME} (\n id TEXT NOT NULL,\n filter TEXT NOT NULL,\n from_block INTEGER NOT NULL,\n to_block INTEGER DEFAULT NULL,\n PRIMARY KEY (id, from_block)\n );\n `),\n );\n\n // Set initial schema version\n await tx.insert(schemaVersion).values({\n k: 0,\n version: CURRENT_SCHEMA_VERSION,\n });\n } else {\n // Run any necessary migrations\n let currentVersion = storedVersion;\n while (currentVersion < CURRENT_SCHEMA_VERSION) {\n const migrationStatements = MIGRATIONS[currentVersion];\n for (const statement of migrationStatements) {\n await tx.execute(statement);\n }\n currentVersion++;\n }\n\n // Update schema version\n await tx\n .update(schemaVersion)\n .set({ version: CURRENT_SCHEMA_VERSION })\n .where(eq(schemaVersion.k, 0));\n }\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to initialize or migrate database schema\",\n { cause: error },\n );\n }\n}\n\nexport async function recordChainReorganization<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n indexerId: string;\n oldHead: Cursor | undefined;\n newHead: Cursor;\n}) {\n const { tx, indexerId, oldHead, newHead } = props;\n\n try {\n await tx.insert(chainReorganizations).values({\n indexerId: indexerId,\n oldHeadOrderKey: oldHead ? Number(oldHead.orderKey) : null,\n oldHeadUniqueKey: oldHead?.uniqueKey ? oldHead.uniqueKey : null,\n newHeadOrderKey: Number(newHead.orderKey),\n newHeadUniqueKey: newHead.uniqueKey ? newHead.uniqueKey : null,\n });\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to record chain reorganization\", {\n cause: error,\n });\n }\n}\n\nexport async function persistState<\n TFilter,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n endCursor: Cursor;\n filter?: TFilter;\n indexerId: string;\n}) {\n const { tx, endCursor, filter, indexerId } = props;\n\n try {\n if (endCursor) {\n await tx\n .insert(checkpoints)\n .values({\n id: indexerId,\n orderKey: Number(endCursor.orderKey),\n uniqueKey: endCursor.uniqueKey,\n })\n .onConflictDoUpdate({\n target: checkpoints.id,\n set: {\n orderKey: Number(endCursor.orderKey),\n // Explicitly set the unique key to `null` to indicate that it has been deleted\n // Otherwise drizzle will not update its value.\n uniqueKey: endCursor.uniqueKey ? endCursor.uniqueKey : null,\n },\n });\n\n if (filter) {\n await tx\n .update(filters)\n .set({ toBlock: Number(endCursor.orderKey) })\n .where(and(eq(filters.id, indexerId), isNull(filters.toBlock)));\n\n await tx\n .insert(filters)\n .values({\n id: indexerId,\n filter: serialize(filter),\n fromBlock: Number(endCursor.orderKey),\n toBlock: null,\n })\n .onConflictDoUpdate({\n target: [filters.id, filters.fromBlock],\n set: {\n filter: serialize(filter),\n fromBlock: Number(endCursor.orderKey),\n toBlock: null,\n },\n });\n }\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to persist state\", {\n cause: error,\n });\n }\n}\n\nexport async function getState<\n TFilter,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n indexerId: string;\n}): Promise<{ cursor?: Cursor; filter?: TFilter }> {\n const { tx, indexerId } = props;\n\n try {\n const checkpointRows = await tx\n .select()\n .from(checkpoints)\n .where(eq(checkpoints.id, indexerId));\n\n const cursor = checkpointRows[0]\n ? normalizeCursor({\n orderKey: BigInt(checkpointRows[0].orderKey),\n uniqueKey: checkpointRows[0].uniqueKey,\n })\n : undefined;\n\n const filterRows = await tx\n .select()\n .from(filters)\n .where(and(eq(filters.id, indexerId), isNull(filters.toBlock)));\n\n const filter = filterRows[0]\n ? deserialize<TFilter>(filterRows[0].filter)\n : undefined;\n\n return { cursor, filter };\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to get persistent state\", {\n cause: error,\n });\n }\n}\n\nexport async function invalidateState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n cursor: Cursor;\n indexerId: string;\n}) {\n const { tx, cursor, indexerId } = props;\n\n try {\n await tx\n .update(checkpoints)\n .set({\n orderKey: Number(cursor.orderKey),\n uniqueKey: cursor.uniqueKey ? cursor.uniqueKey : null,\n })\n .where(eq(checkpoints.id, indexerId));\n\n await tx\n .delete(filters)\n .where(\n and(\n eq(filters.id, indexerId),\n gt(filters.fromBlock, Number(cursor.orderKey)),\n ),\n );\n\n await tx\n .update(filters)\n .set({ toBlock: null })\n .where(\n and(\n eq(filters.id, indexerId),\n gt(filters.toBlock, Number(cursor.orderKey)),\n ),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to invalidate state\", {\n cause: error,\n });\n }\n}\n\nexport async function finalizeState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n cursor: Cursor;\n indexerId: string;\n}) {\n const { tx, cursor, indexerId } = props;\n\n try {\n await tx\n .delete(filters)\n .where(\n and(\n eq(filters.id, indexerId),\n lt(filters.toBlock, Number(cursor.orderKey)),\n ),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to finalize state\", {\n cause: error,\n });\n }\n}\n\nexport async function resetPersistence<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n indexerId: string;\n}) {\n const { tx, indexerId } = props;\n\n try {\n await tx.delete(checkpoints).where(eq(checkpoints.id, indexerId));\n await tx.delete(filters).where(eq(filters.id, indexerId));\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to reset persistence state\", {\n cause: error,\n });\n }\n}\n","import type { Cursor } from \"@apibara/protocol\";\nimport {\n type ExtractTablesWithRelations,\n type TablesRelationalConfig,\n sql,\n} from \"drizzle-orm\";\nimport {\n type PgDatabase,\n type PgQueryResultHKT,\n type PgTransaction,\n char,\n integer,\n jsonb,\n pgSchema,\n serial,\n text,\n} from \"drizzle-orm/pg-core\";\nimport { SCHEMA_NAME } from \"./constants\";\nimport {\n DrizzleStorageError,\n type IdColumnMap,\n getIdColumnForTable,\n} from \"./utils\";\n\nconst ROLLBACK_TABLE_NAME = \"reorg_rollback\";\n\nconst schema = pgSchema(SCHEMA_NAME);\n\nfunction getReorgTriggerName(table: string, indexerId: string) {\n return `${table}_reorg_${indexerId}`;\n}\n\nexport type ReorgOperation = \"I\" | \"U\" | \"D\";\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const reorgRollbackTable = schema.table(ROLLBACK_TABLE_NAME, {\n n: serial(\"n\").primaryKey(),\n op: char(\"op\", { length: 1 }).$type<ReorgOperation>().notNull(),\n table_name: text(\"table_name\").notNull(),\n cursor: integer(\"cursor\").notNull(),\n row_id: text(\"row_id\"),\n row_value: jsonb(\"row_value\"),\n indexer_id: text(\"indexer_id\").notNull(),\n});\n\nexport type ReorgRollbackRow = typeof reorgRollbackTable.$inferSelect;\n\nexport async function initializeReorgRollbackTable<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(tx: PgTransaction<TQueryResult, TFullSchema, TSchema>, indexerId: string) {\n try {\n // Create schema if it doesn't exist\n await tx.execute(`\n CREATE SCHEMA IF NOT EXISTS ${SCHEMA_NAME};\n `);\n // Create the audit log table\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(\n n SERIAL PRIMARY KEY,\n op CHAR(1) NOT NULL,\n table_name TEXT NOT NULL,\n cursor INTEGER NOT NULL,\n row_id TEXT,\n row_value JSONB,\n indexer_id TEXT NOT NULL\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE INDEX IF NOT EXISTS idx_reorg_rollback_indexer_id_cursor ON ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(indexer_id, cursor);\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to initialize reorg rollback table\", {\n cause: error,\n });\n }\n\n try {\n // Create the trigger function\n await tx.execute(\n sql.raw(`\n CREATE OR REPLACE FUNCTION ${SCHEMA_NAME}.reorg_checkpoint()\n RETURNS TRIGGER AS $$\n DECLARE\n table_name TEXT := TG_ARGV[0]::TEXT;\n id_col TEXT := TG_ARGV[1]::TEXT;\n order_key INTEGER := TG_ARGV[2]::INTEGER;\n indexer_id TEXT := TG_ARGV[3]::TEXT;\n new_id_value TEXT := row_to_json(NEW.*)->>id_col;\n old_id_value TEXT := row_to_json(OLD.*)->>id_col;\n BEGIN\n IF (TG_OP = 'DELETE') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'D', table_name, order_key, old_id_value, row_to_json(OLD.*), indexer_id;\n ELSIF (TG_OP = 'UPDATE') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'U', table_name, order_key, new_id_value, row_to_json(OLD.*), indexer_id;\n ELSIF (TG_OP = 'INSERT') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'I', table_name, order_key, new_id_value, null, indexer_id;\n END IF;\n RETURN NULL;\n END;\n $$ LANGUAGE plpgsql;\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to create reorg checkpoint function\",\n {\n cause: error,\n },\n );\n }\n}\n\nexport async function registerTriggers<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n endCursor: Cursor,\n idColumnMap: IdColumnMap,\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n // Determine the column ID for this specific table\n const tableIdColumn = getIdColumnForTable(table, idColumnMap);\n\n await tx.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n await tx.execute(\n sql.raw(`\n CREATE CONSTRAINT TRIGGER ${getReorgTriggerName(table, indexerId)}\n AFTER INSERT OR UPDATE OR DELETE ON ${table}\n DEFERRABLE INITIALLY DEFERRED\n FOR EACH ROW EXECUTE FUNCTION ${SCHEMA_NAME}.reorg_checkpoint('${table}', '${tableIdColumn}', ${Number(endCursor.orderKey)}, '${indexerId}');\n `),\n );\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to register triggers\", {\n cause: error,\n });\n }\n}\n\nexport async function removeTriggers<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n await db.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to remove triggers\", {\n cause: error,\n });\n }\n}\n\nexport async function invalidate<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n cursor: Cursor,\n idColumnMap: IdColumnMap,\n indexerId: string,\n) {\n // Get and delete operations after cursor in one query, ordered by newest first\n const { rows: result } = (await tx.execute(\n sql.raw(`\n WITH deleted AS (\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE cursor > ${Number(cursor.orderKey)}\n AND indexer_id = '${indexerId}'\n RETURNING *\n )\n SELECT * FROM deleted ORDER BY n DESC;\n `),\n )) as { rows: ReorgRollbackRow[] };\n\n if (!Array.isArray(result)) {\n throw new DrizzleStorageError(\n \"Invalid result format from reorg_rollback query\",\n );\n }\n\n // Process each operation in reverse order\n for (const op of result) {\n // Determine the column ID for this specific table\n const tableIdColumn = getIdColumnForTable(op.table_name, idColumnMap);\n\n switch (op.op) {\n case \"I\":\n try {\n if (!op.row_id) {\n throw new DrizzleStorageError(\"Insert operation has no row_id\");\n }\n\n await tx.execute(\n sql.raw(`\n DELETE FROM ${op.table_name}\n WHERE ${tableIdColumn} = '${op.row_id}'\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - I\",\n {\n cause: error,\n },\n );\n }\n\n break;\n\n case \"D\":\n try {\n // For deletes, reinsert the row using json_populate_record\n if (!op.row_value) {\n throw new DrizzleStorageError(\"Delete operation has no row_value\");\n }\n\n await tx.execute(\n sql.raw(`\n INSERT INTO ${op.table_name}\n SELECT * FROM json_populate_record(null::${op.table_name}, '${JSON.stringify(op.row_value)}'::json)\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - D\",\n {\n cause: error,\n },\n );\n }\n\n break;\n\n case \"U\":\n try {\n if (!op.row_value || !op.row_id) {\n throw new DrizzleStorageError(\n \"Update operation has no row_value or row_id\",\n );\n }\n\n // For updates, restore previous values\n\n const rowValue =\n typeof op.row_value === \"string\"\n ? JSON.parse(op.row_value)\n : op.row_value;\n\n const nonIdKeys = Object.keys(rowValue).filter(\n (k) => k !== tableIdColumn,\n );\n\n const fields = nonIdKeys.map((c) => `${c} = prev.${c}`).join(\", \");\n\n const query = sql.raw(`\n UPDATE ${op.table_name}\n SET ${fields}\n FROM (\n SELECT * FROM json_populate_record(null::${op.table_name}, '${JSON.stringify(op.row_value)}'::json)\n ) as prev\n WHERE ${op.table_name}.${tableIdColumn} = '${op.row_id}'\n `);\n\n await tx.execute(query);\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - U\",\n {\n cause: error,\n },\n );\n }\n break;\n\n default: {\n throw new DrizzleStorageError(`Unknown operation: ${op.op}`);\n }\n }\n }\n}\n\nexport async function finalize<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n cursor: Cursor,\n indexerId: string,\n) {\n try {\n await tx.execute(\n sql.raw(`\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE cursor <= ${Number(cursor.orderKey)}\n AND indexer_id = '${indexerId}'\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to finalize\", {\n cause: error,\n });\n }\n}\n\nexport async function cleanupStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n await tx.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n }\n\n await tx.execute(\n sql.raw(`\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE indexer_id = '${indexerId}'\n `),\n );\n\n for (const table of tables) {\n try {\n await tx.execute(sql.raw(`TRUNCATE TABLE ${table} CASCADE;`));\n } catch (error) {\n throw new DrizzleStorageError(`Failed to truncate table ${table}`, {\n cause: error,\n });\n }\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to clean up storage\", {\n cause: error,\n });\n }\n}\n","import { useIndexerContext } from \"@apibara/indexer\";\nimport { defineIndexerPlugin, useLogger } from \"@apibara/indexer/plugins\";\n\nimport type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\n\nimport { generateIndexerId } from \"@apibara/indexer/internal\";\nimport { useInternalContext } from \"@apibara/indexer/internal/plugins\";\nimport type { Cursor, DataFinality } from \"@apibara/protocol\";\nimport type {\n PgDatabase,\n PgQueryResultHKT,\n PgTransaction,\n} from \"drizzle-orm/pg-core\";\nimport { DRIZZLE_PROPERTY, DRIZZLE_STORAGE_DB_PROPERTY } from \"./constants\";\nimport { type MigrateOptions, migrate } from \"./helper\";\nimport {\n finalizeState,\n getState,\n initializePersistentState,\n invalidateState,\n persistState,\n recordChainReorganization,\n resetPersistence,\n} from \"./persistence\";\nimport {\n cleanupStorage,\n finalize,\n initializeReorgRollbackTable,\n invalidate,\n registerTriggers,\n removeTriggers,\n} from \"./storage\";\nimport {\n DrizzleStorageError,\n type IdColumnMap,\n getIdColumnForTable,\n sleep,\n withTransaction,\n} from \"./utils\";\n\nexport * from \"./helper\";\n\nexport type { IdColumnMap };\n\nconst MAX_RETRIES = 5;\n\nexport type DrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n> = {\n db: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n};\n\nexport function useDrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n _db?: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n): DrizzleStorage<TQueryResult, TFullSchema, TSchema> {\n const context = useIndexerContext();\n\n if (!context[DRIZZLE_PROPERTY]) {\n throw new DrizzleStorageError(\n \"drizzle storage is not available. Did you register the plugin?\",\n );\n }\n\n return context[DRIZZLE_PROPERTY];\n}\n\nexport function useTestDrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(): PgDatabase<TQueryResult, TFullSchema, TSchema> {\n const context = useIndexerContext();\n\n if (!context[DRIZZLE_STORAGE_DB_PROPERTY]) {\n throw new DrizzleStorageError(\n \"drizzle storage db is not available. Did you register the plugin?\",\n );\n }\n\n return context[DRIZZLE_STORAGE_DB_PROPERTY];\n}\n\nexport interface DrizzleStorageOptions<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n> {\n /**\n * The Drizzle database instance.\n */\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>;\n /**\n * Whether to persist the indexer's state. Defaults to true.\n */\n persistState?: boolean;\n /**\n * The name of the indexer. Default value is 'default'.\n */\n indexerName?: string;\n /**\n * The schema of the database.\n */\n schema?: Record<string, unknown>;\n /**\n * The column to use as the primary identifier for each table.\n *\n * This identifier is used for tracking changes during reorgs and rollbacks.\n *\n * Can be specified in two ways:\n *\n * 1. As a single string that applies to all tables:\n * ```ts\n * idColumn: \"_id\" // Uses \"_id\" column for all tables\n * ```\n *\n * 2. As an object mapping table names to their ID columns:\n * ```ts\n * idColumn: {\n * transfers: \"transaction_hash\", // Use \"transaction_hash\" for transfers table\n * blocks: \"block_number\", // Use \"block_number\" for blocks table\n * \"*\": \"_id\" // Use \"_id\" for all other tables | defaults to \"id\"\n * }\n * ```\n *\n * The special \"*\" key acts as a fallback for any tables not explicitly mapped.\n *\n * @default \"id\"\n * @type {string | Partial<IdColumnMap>}\n */\n idColumn?: string | Partial<IdColumnMap>;\n /**\n * The options for the database migration. When provided, the database will automatically run migrations before the indexer runs.\n */\n migrate?: MigrateOptions;\n\n /**\n * Whether to record chain reorganizations in the database.\n * @default false\n */\n recordChainReorganizations?: boolean;\n}\n\n/**\n * Creates a plugin that uses Drizzle as the storage layer.\n *\n * Supports storing the indexer's state and provides a simple Key-Value store.\n * @param options.db - The Drizzle database instance.\n * @param options.persistState - Whether to persist the indexer's state. Defaults to true.\n * @param options.indexerName - The name of the indexer. Defaults value is 'default'.\n * @param options.schema - The schema of the database.\n * @param options.idColumn - The column to use as the id. Defaults to 'id'.\n * @param options.migrate - The options for the database migration. when provided, the database will automatically run migrations before the indexer runs.\n * @param options.recordChainReorganizations - Whether to record chain reorganizations in the database. Defaults to false.\n */\nexport function drizzleStorage<\n TFilter,\n TBlock,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>({\n db,\n persistState: enablePersistence = true,\n indexerName: identifier = \"default\",\n schema: _schema,\n idColumn,\n migrate: migrateOptions,\n recordChainReorganizations = false,\n}: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>) {\n return defineIndexerPlugin<TFilter, TBlock>((indexer) => {\n let tableNames: string[] = [];\n let indexerId = \"\";\n const alwaysReindex = process.env[\"APIBARA_ALWAYS_REINDEX\"] === \"true\";\n let prevFinality: DataFinality | undefined;\n const schema: TSchema = (_schema as TSchema) ?? db._.schema ?? {};\n const idColumnMap: IdColumnMap = {\n \"*\": typeof idColumn === \"string\" ? idColumn : \"id\",\n ...(typeof idColumn === \"object\" ? idColumn : {}),\n };\n\n try {\n tableNames = Object.values(schema).map((table) => table.dbName);\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to get table names from schema\", {\n cause: error,\n });\n }\n\n // Check if specified idColumn exists in all the tables in schema\n for (const table of Object.values(schema)) {\n const columns = table.columns;\n const tableIdColumn = getIdColumnForTable(table.dbName, idColumnMap);\n\n const columnExists = Object.values(columns).some(\n (column) => column.name === tableIdColumn,\n );\n\n if (!columnExists) {\n throw new DrizzleStorageError(\n `Column \\`\"${tableIdColumn}\"\\` does not exist in table \\`\"${table.dbName}\"\\`. ` +\n \"Make sure the table has the specified column or provide a valid `idColumn` mapping to `drizzleStorage`.\",\n );\n }\n }\n\n indexer.hooks.hook(\"plugins:init\", async () => {\n const internalContext = useInternalContext();\n const context = useIndexerContext();\n const logger = useLogger();\n\n // For testing purposes using vcr.\n context[DRIZZLE_STORAGE_DB_PROPERTY] = db;\n\n const { indexerName: indexerFileName, availableIndexers } =\n internalContext;\n\n indexerId = generateIndexerId(indexerFileName, identifier);\n\n let retries = 0;\n\n // incase the migrations are already applied, we don't want to run them again\n let migrationsApplied = false;\n let cleanupApplied = false;\n\n while (retries <= MAX_RETRIES) {\n try {\n if (migrateOptions && !migrationsApplied) {\n // @ts-ignore type mismatch for db\n await migrate(db, migrateOptions);\n migrationsApplied = true;\n logger.success(\"Migrations applied\");\n }\n await withTransaction(db, async (tx) => {\n await initializeReorgRollbackTable(tx, indexerId);\n if (enablePersistence) {\n await initializePersistentState(tx);\n }\n\n if (alwaysReindex && !cleanupApplied) {\n logger.warn(\n `Reindexing: Deleting all data from tables - ${tableNames.join(\", \")}`,\n );\n\n await cleanupStorage(tx, tableNames, indexerId);\n\n if (enablePersistence) {\n await resetPersistence({ tx, indexerId });\n }\n\n cleanupApplied = true;\n\n logger.success(\"Tables have been cleaned up for reindexing\");\n }\n });\n break;\n } catch (error) {\n if (retries === MAX_RETRIES) {\n if (error instanceof DrizzleStorageError) {\n throw error;\n }\n throw new DrizzleStorageError(\n \"Initialization failed after 5 retries\",\n {\n cause: error,\n },\n );\n }\n await sleep(retries * 1000);\n retries++;\n }\n }\n });\n\n indexer.hooks.hook(\"connect:before\", async ({ request }) => {\n if (!enablePersistence) {\n return;\n }\n\n await withTransaction(db, async (tx) => {\n const { cursor, filter } = await getState<\n TFilter,\n TQueryResult,\n TFullSchema,\n TSchema\n >({\n tx,\n indexerId,\n });\n if (cursor) {\n request.startingCursor = cursor;\n }\n if (filter) {\n request.filter[1] = filter;\n }\n });\n });\n\n indexer.hooks.hook(\"connect:after\", async ({ request }) => {\n // On restart, we need to invalidate data for blocks that were processed but not persisted.\n const cursor = request.startingCursor;\n\n if (!cursor) {\n return;\n }\n\n await withTransaction(db, async (tx) => {\n // Use the appropriate idColumn for each table when calling invalidate\n await invalidate(tx, cursor, idColumnMap, indexerId);\n\n if (enablePersistence) {\n await invalidateState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"connect:factory\", async ({ request, endCursor }) => {\n if (!enablePersistence) {\n return;\n }\n // We can call this hook because this hook is called inside the transaction of handler:middleware\n // so we have access to the transaction from the context\n const { db: tx } = useDrizzleStorage(db);\n\n if (endCursor && request.filter[1]) {\n await persistState({\n tx,\n endCursor,\n filter: request.filter[1],\n indexerId,\n });\n }\n });\n\n indexer.hooks.hook(\"message:finalize\", async ({ message }) => {\n const { cursor } = message;\n\n if (!cursor) {\n throw new DrizzleStorageError(\"Finalized Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n await finalize(tx, cursor, indexerId);\n\n if (enablePersistence) {\n await finalizeState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"message:invalidate\", async ({ message }) => {\n const { cursor } = message;\n\n if (!cursor) {\n throw new DrizzleStorageError(\"Invalidate Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n let oldHead: Cursor | undefined;\n\n if (recordChainReorganizations) {\n const { cursor: currentCursor } = await getState<\n TFilter,\n TQueryResult,\n TFullSchema,\n TSchema\n >({\n tx,\n indexerId,\n });\n oldHead = currentCursor;\n\n await recordChainReorganization({\n tx,\n indexerId,\n oldHead,\n newHead: cursor,\n });\n }\n\n await invalidate(tx, cursor, idColumnMap, indexerId);\n\n if (enablePersistence) {\n await invalidateState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"handler:middleware\", async ({ use }) => {\n use(async (context, next) => {\n try {\n const { endCursor, finality, cursor } = context as {\n cursor: Cursor;\n endCursor: Cursor;\n finality: DataFinality;\n };\n\n if (!endCursor) {\n throw new DrizzleStorageError(\"End Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n context[DRIZZLE_PROPERTY] = { db: tx } as DrizzleStorage<\n TQueryResult,\n TFullSchema,\n TSchema\n >;\n\n if (prevFinality === \"pending\") {\n // invalidate if previous block's finality was \"pending\"\n await invalidate(tx, cursor, idColumnMap, indexerId);\n }\n\n if (finality !== \"finalized\") {\n await registerTriggers(\n tx,\n tableNames,\n endCursor,\n idColumnMap,\n indexerId,\n );\n }\n\n await next();\n delete context[DRIZZLE_PROPERTY];\n\n if (enablePersistence && finality !== \"pending\") {\n await persistState({\n tx,\n endCursor,\n indexerId,\n });\n }\n\n prevFinality = finality;\n });\n\n if (finality !== \"finalized\") {\n // remove trigger outside of the transaction or it won't be triggered.\n await removeTriggers(db, tableNames, indexerId);\n }\n } catch (error) {\n await removeTriggers(db, tableNames, indexerId);\n\n throw error;\n }\n });\n });\n });\n}\n"],"names":["entityKind","schema","pgSchema","SCHEMA_NAME","text","integer","primaryKey","serial","timestamp","sql","eq","and","isNull","normalizeCursor","gt","lt","char","jsonb","useIndexerContext","DRIZZLE_PROPERTY","DRIZZLE_STORAGE_DB_PROPERTY","defineIndexerPlugin","indexer","useInternalContext","useLogger","generateIndexerId"],"mappings":"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"}
package/dist/index.d.cts CHANGED
@@ -173,6 +173,11 @@ interface DrizzleStorageOptions<TQueryResult extends PgQueryResultHKT, TFullSche
173
173
  * The options for the database migration. When provided, the database will automatically run migrations before the indexer runs.
174
174
  */
175
175
  migrate?: MigrateOptions;
176
+ /**
177
+ * Whether to record chain reorganizations in the database.
178
+ * @default false
179
+ */
180
+ recordChainReorganizations?: boolean;
176
181
  }
177
182
  /**
178
183
  * Creates a plugin that uses Drizzle as the storage layer.
@@ -184,7 +189,8 @@ interface DrizzleStorageOptions<TQueryResult extends PgQueryResultHKT, TFullSche
184
189
  * @param options.schema - The schema of the database.
185
190
  * @param options.idColumn - The column to use as the id. Defaults to 'id'.
186
191
  * @param options.migrate - The options for the database migration. when provided, the database will automatically run migrations before the indexer runs.
192
+ * @param options.recordChainReorganizations - Whether to record chain reorganizations in the database. Defaults to false.
187
193
  */
188
- declare function drizzleStorage<TFilter, TBlock, TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>>({ db, persistState: enablePersistence, indexerName: identifier, schema: _schema, idColumn, migrate: migrateOptions, }: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>): _apibara_indexer_plugins.IndexerPlugin<TFilter, TBlock>;
194
+ declare function drizzleStorage<TFilter, TBlock, TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>>({ db, persistState: enablePersistence, indexerName: identifier, schema: _schema, idColumn, migrate: migrateOptions, recordChainReorganizations, }: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>): _apibara_indexer_plugins.IndexerPlugin<TFilter, TBlock>;
189
195
 
190
196
  export { type Database, type DrizzleOptions, type DrizzleStorage, type DrizzleStorageOptions, type IdColumnMap, type MigrateOptions, type NodePgDatabase, type NodePgDrizzleOptions, type PgliteDatabase, type PgliteDrizzleOptions, drizzle, drizzleStorage, migrate, useDrizzleStorage, useTestDrizzleStorage };
package/dist/index.d.mts CHANGED
@@ -173,6 +173,11 @@ interface DrizzleStorageOptions<TQueryResult extends PgQueryResultHKT, TFullSche
173
173
  * The options for the database migration. When provided, the database will automatically run migrations before the indexer runs.
174
174
  */
175
175
  migrate?: MigrateOptions;
176
+ /**
177
+ * Whether to record chain reorganizations in the database.
178
+ * @default false
179
+ */
180
+ recordChainReorganizations?: boolean;
176
181
  }
177
182
  /**
178
183
  * Creates a plugin that uses Drizzle as the storage layer.
@@ -184,7 +189,8 @@ interface DrizzleStorageOptions<TQueryResult extends PgQueryResultHKT, TFullSche
184
189
  * @param options.schema - The schema of the database.
185
190
  * @param options.idColumn - The column to use as the id. Defaults to 'id'.
186
191
  * @param options.migrate - The options for the database migration. when provided, the database will automatically run migrations before the indexer runs.
192
+ * @param options.recordChainReorganizations - Whether to record chain reorganizations in the database. Defaults to false.
187
193
  */
188
- declare function drizzleStorage<TFilter, TBlock, TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>>({ db, persistState: enablePersistence, indexerName: identifier, schema: _schema, idColumn, migrate: migrateOptions, }: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>): _apibara_indexer_plugins.IndexerPlugin<TFilter, TBlock>;
194
+ declare function drizzleStorage<TFilter, TBlock, TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>>({ db, persistState: enablePersistence, indexerName: identifier, schema: _schema, idColumn, migrate: migrateOptions, recordChainReorganizations, }: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>): _apibara_indexer_plugins.IndexerPlugin<TFilter, TBlock>;
189
195
 
190
196
  export { type Database, type DrizzleOptions, type DrizzleStorage, type DrizzleStorageOptions, type IdColumnMap, type MigrateOptions, type NodePgDatabase, type NodePgDrizzleOptions, type PgliteDatabase, type PgliteDrizzleOptions, drizzle, drizzleStorage, migrate, useDrizzleStorage, useTestDrizzleStorage };
package/dist/index.d.ts CHANGED
@@ -173,6 +173,11 @@ interface DrizzleStorageOptions<TQueryResult extends PgQueryResultHKT, TFullSche
173
173
  * The options for the database migration. When provided, the database will automatically run migrations before the indexer runs.
174
174
  */
175
175
  migrate?: MigrateOptions;
176
+ /**
177
+ * Whether to record chain reorganizations in the database.
178
+ * @default false
179
+ */
180
+ recordChainReorganizations?: boolean;
176
181
  }
177
182
  /**
178
183
  * Creates a plugin that uses Drizzle as the storage layer.
@@ -184,7 +189,8 @@ interface DrizzleStorageOptions<TQueryResult extends PgQueryResultHKT, TFullSche
184
189
  * @param options.schema - The schema of the database.
185
190
  * @param options.idColumn - The column to use as the id. Defaults to 'id'.
186
191
  * @param options.migrate - The options for the database migration. when provided, the database will automatically run migrations before the indexer runs.
192
+ * @param options.recordChainReorganizations - Whether to record chain reorganizations in the database. Defaults to false.
187
193
  */
188
- declare function drizzleStorage<TFilter, TBlock, TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>>({ db, persistState: enablePersistence, indexerName: identifier, schema: _schema, idColumn, migrate: migrateOptions, }: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>): _apibara_indexer_plugins.IndexerPlugin<TFilter, TBlock>;
194
+ declare function drizzleStorage<TFilter, TBlock, TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>>({ db, persistState: enablePersistence, indexerName: identifier, schema: _schema, idColumn, migrate: migrateOptions, recordChainReorganizations, }: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>): _apibara_indexer_plugins.IndexerPlugin<TFilter, TBlock>;
189
195
 
190
196
  export { type Database, type DrizzleOptions, type DrizzleStorage, type DrizzleStorageOptions, type IdColumnMap, type MigrateOptions, type NodePgDatabase, type NodePgDrizzleOptions, type PgliteDatabase, type PgliteDrizzleOptions, drizzle, drizzleStorage, migrate, useDrizzleStorage, useTestDrizzleStorage };
package/dist/index.mjs CHANGED
@@ -5,7 +5,7 @@ import { useInternalContext } from '@apibara/indexer/internal/plugins';
5
5
  import { S as SCHEMA_NAME, D as DRIZZLE_PROPERTY, a as DRIZZLE_STORAGE_DB_PROPERTY } from './shared/plugin-drizzle.2d226351.mjs';
6
6
  import { entityKind, sql, eq, and, isNull, gt, lt } from 'drizzle-orm';
7
7
  import { normalizeCursor } from '@apibara/protocol';
8
- import { pgSchema, text, integer, primaryKey, serial, char, jsonb } from 'drizzle-orm/pg-core';
8
+ import { pgSchema, text, integer, primaryKey, serial, timestamp, char, jsonb } from 'drizzle-orm/pg-core';
9
9
 
10
10
  class DrizzleStorageError extends Error {
11
11
  constructor(message, options) {
@@ -130,6 +130,15 @@ const filters = schema$1.table(
130
130
  }
131
131
  ]
132
132
  );
133
+ const chainReorganizations = schema$1.table("chain_reorganizations", {
134
+ id: serial("id").primaryKey(),
135
+ indexerId: text("indexer_id").notNull(),
136
+ oldHeadOrderKey: integer("old_head_order_key"),
137
+ oldHeadUniqueKey: text("old_head_unique_key").$type().default(null),
138
+ newHeadOrderKey: integer("new_head_order_key").notNull(),
139
+ newHeadUniqueKey: text("new_head_unique_key").$type().default(null),
140
+ recordedAt: timestamp("recorded_at").defaultNow().notNull()
141
+ });
133
142
  const schemaVersion = schema$1.table(SCHEMA_VERSION_TABLE_NAME, {
134
143
  k: integer("k").notNull().primaryKey(),
135
144
  version: integer("version").notNull()
@@ -154,6 +163,25 @@ async function initializePersistentState(tx) {
154
163
  );
155
164
  `)
156
165
  );
166
+ await tx.execute(
167
+ sql.raw(`
168
+ CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.chain_reorganizations (
169
+ id SERIAL PRIMARY KEY,
170
+ indexer_id TEXT NOT NULL,
171
+ old_head_order_key INTEGER,
172
+ old_head_unique_key TEXT DEFAULT NULL,
173
+ new_head_order_key INTEGER NOT NULL,
174
+ new_head_unique_key TEXT DEFAULT NULL,
175
+ recorded_at TIMESTAMP NOT NULL DEFAULT NOW()
176
+ );
177
+ `)
178
+ );
179
+ await tx.execute(
180
+ sql.raw(`
181
+ CREATE INDEX IF NOT EXISTS idx_chain_reorgs_indexer_id
182
+ ON ${SCHEMA_NAME}.chain_reorganizations(indexer_id);
183
+ `)
184
+ );
157
185
  const versionRows = await tx.select().from(schemaVersion).where(eq(schemaVersion.k, 0));
158
186
  const storedVersion = versionRows[0]?.version ?? -1;
159
187
  if (storedVersion > CURRENT_SCHEMA_VERSION) {
@@ -205,6 +233,22 @@ async function initializePersistentState(tx) {
205
233
  );
206
234
  }
207
235
  }
236
+ async function recordChainReorganization(props) {
237
+ const { tx, indexerId, oldHead, newHead } = props;
238
+ try {
239
+ await tx.insert(chainReorganizations).values({
240
+ indexerId,
241
+ oldHeadOrderKey: oldHead ? Number(oldHead.orderKey) : null,
242
+ oldHeadUniqueKey: oldHead?.uniqueKey ? oldHead.uniqueKey : null,
243
+ newHeadOrderKey: Number(newHead.orderKey),
244
+ newHeadUniqueKey: newHead.uniqueKey ? newHead.uniqueKey : null
245
+ });
246
+ } catch (error) {
247
+ throw new DrizzleStorageError("Failed to record chain reorganization", {
248
+ cause: error
249
+ });
250
+ }
251
+ }
208
252
  async function persistState(props) {
209
253
  const { tx, endCursor, filter, indexerId } = props;
210
254
  try {
@@ -265,6 +309,10 @@ async function getState(props) {
265
309
  async function invalidateState(props) {
266
310
  const { tx, cursor, indexerId } = props;
267
311
  try {
312
+ await tx.update(checkpoints).set({
313
+ orderKey: Number(cursor.orderKey),
314
+ uniqueKey: cursor.uniqueKey ? cursor.uniqueKey : null
315
+ }).where(eq(checkpoints.id, indexerId));
268
316
  await tx.delete(filters).where(
269
317
  and(
270
318
  eq(filters.id, indexerId),
@@ -595,7 +643,8 @@ function drizzleStorage({
595
643
  indexerName: identifier = "default",
596
644
  schema: _schema,
597
645
  idColumn,
598
- migrate: migrateOptions
646
+ migrate: migrateOptions,
647
+ recordChainReorganizations = false
599
648
  }) {
600
649
  return defineIndexerPlugin((indexer) => {
601
650
  let tableNames = [];
@@ -739,6 +788,20 @@ function drizzleStorage({
739
788
  throw new DrizzleStorageError("Invalidate Cursor is undefined");
740
789
  }
741
790
  await withTransaction(db, async (tx) => {
791
+ let oldHead;
792
+ if (recordChainReorganizations) {
793
+ const { cursor: currentCursor } = await getState({
794
+ tx,
795
+ indexerId
796
+ });
797
+ oldHead = currentCursor;
798
+ await recordChainReorganization({
799
+ tx,
800
+ indexerId,
801
+ oldHead,
802
+ newHead: cursor
803
+ });
804
+ }
742
805
  await invalidate(tx, cursor, idColumnMap, indexerId);
743
806
  if (enablePersistence) {
744
807
  await invalidateState({ tx, cursor, indexerId });
@@ -782,9 +845,7 @@ function drizzleStorage({
782
845
  }
783
846
  } catch (error) {
784
847
  await removeTriggers(db, tableNames, indexerId);
785
- throw new DrizzleStorageError("Failed to run handler:middleware", {
786
- cause: error
787
- });
848
+ throw error;
788
849
  }
789
850
  });
790
851
  });
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/utils.ts","../src/helper.ts","../src/persistence.ts","../src/storage.ts","../src/index.ts"],"sourcesContent":["import type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\nimport type {\n PgDatabase,\n PgQueryResultHKT,\n PgTransaction,\n} from \"drizzle-orm/pg-core\";\n\nexport class DrizzleStorageError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"DrizzleStorageError\";\n }\n}\n\nexport async function withTransaction<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n cb: (db: PgTransaction<TQueryResult, TFullSchema, TSchema>) => Promise<void>,\n) {\n return await db.transaction(async (txnDb) => {\n return await cb(txnDb);\n });\n}\n\nexport function deserialize<T>(str: string): T {\n return JSON.parse(str, (_, value) =>\n typeof value === \"string\" && value.match(/^\\d+n$/)\n ? BigInt(value.slice(0, -1))\n : value,\n ) as T;\n}\n\nexport function serialize<T>(obj: T): string {\n return JSON.stringify(\n obj,\n (_, value) => (typeof value === \"bigint\" ? `${value.toString()}n` : value),\n \"\\t\",\n );\n}\n\nexport function sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport interface IdColumnMap extends Record<string, string> {\n /**\n * Wildcard mapping for all tables.\n */\n \"*\": string;\n}\n\nexport const getIdColumnForTable = (\n tableName: string,\n idColumn: IdColumnMap,\n): string => {\n // If there's a specific mapping for this table, use it\n if (idColumn[tableName]) {\n return idColumn[tableName];\n }\n // Default fallback\n return idColumn[\"*\"];\n};\n","import type { PGlite, PGliteOptions } from \"@electric-sql/pglite\";\nimport type { DrizzleConfig } from \"drizzle-orm\";\nimport { entityKind } from \"drizzle-orm\";\nimport type { MigrationConfig } from \"drizzle-orm/migrator\";\nimport type { NodePgDatabase as OriginalNodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport type { PgliteDatabase as OriginalPgliteDatabase } from \"drizzle-orm/pglite\";\nimport type pg from \"pg\";\nimport { DrizzleStorageError } from \"./utils\";\n\n/**\n * Union type of all possible drizzle database options\n */\nexport type DrizzleOptions = PgliteDrizzleOptions | NodePgDrizzleOptions;\n\n/**\n * Configuration options for Node-Postgres database connection\n */\nexport type NodePgDrizzleOptions = {\n /**\n * Type of database to use -\n * - \"pglite\" - PGLite database\n * - \"node-postgres\" - Node-Postgres database\n * @default \"pglite\"\n */\n type: \"node-postgres\";\n /**\n * Connection string to use for the database\n * @default \"\"\n */\n connectionString?: string;\n /**\n * Pool configuration options for Node-Postgres\n */\n poolConfig?: pg.PoolConfig;\n /**\n * Additional drizzle configuration options\n */\n config?: Omit<DrizzleConfig, \"schema\">;\n};\n\n/**\n * Configuration options for PGLite database connection\n */\nexport type PgliteDrizzleOptions = {\n /**\n * Type of database to use -\n * - \"pglite\" - PGLite database\n * - \"node-postgres\" - Node-Postgres database\n */\n type?: \"pglite\";\n /**\n * Connection string to use for the database\n * @default process.env[\"POSTGRES_CONNECTION_STRING\"] ?? \"memory://pglite\"\n */\n connectionString?: string;\n /**\n * Pool configuration is not supported for PGLite\n */\n poolConfig?: never;\n /**\n * Additional drizzle configuration options with PGLite specific connection options\n */\n config?: Omit<DrizzleConfig, \"schema\"> & {\n connection?:\n | (PGliteOptions & {\n dataDir?: string;\n })\n | string;\n };\n};\n\n/**\n * Extended PGLite database type with client information\n */\nexport type PgliteDatabase<TSchema extends Record<string, unknown>> =\n OriginalPgliteDatabase<TSchema> & {\n $client: PGlite;\n };\n\n/**\n * Extended Node-Postgres database type with client information\n */\nexport type NodePgDatabase<TSchema extends Record<string, unknown>> =\n OriginalNodePgDatabase<TSchema> & {\n $client: pg.Pool;\n };\n\nexport type Database<\n TOptions extends DrizzleOptions,\n TSchema extends Record<string, unknown>,\n> = TOptions extends PgliteDrizzleOptions\n ? PgliteDatabase<TSchema>\n : NodePgDatabase<TSchema>;\n\n/**\n * Creates a new Drizzle database instance based on the provided options\n *\n * @important connectionString defaults to process.env[\"POSTGRES_CONNECTION_STRING\"], if not set, it defaults to \"memory://\" (in-memory pglite)\n *\n * @param options - Configuration options for the database connection\n * @returns A configured Drizzle database instance\n * @throws {Error} If an invalid database type is specified\n */\nexport function drizzle<\n TSchema extends Record<string, unknown>,\n TOptions extends DrizzleOptions,\n>(\n options?: TOptions & {\n /**\n * Schema to use for the database\n * @default {}\n */\n schema?: TSchema;\n },\n): Database<TOptions, TSchema> {\n const {\n connectionString = process.env[\"POSTGRES_CONNECTION_STRING\"] ?? \"memory://\",\n schema,\n type = \"pglite\",\n config,\n poolConfig,\n } = options ?? {};\n\n if (isPgliteConnectionString(connectionString) && type === \"pglite\") {\n const { drizzle: drizzlePGLite } = require(\"drizzle-orm/pglite\");\n\n return drizzlePGLite({\n schema: schema as TSchema,\n connection: {\n dataDir: connectionString || \"memory://pglite\",\n },\n ...(config || {}),\n }) as Database<TOptions, TSchema>;\n }\n\n const { Pool } = require(\"pg\");\n const { drizzle: drizzleNode } = require(\"drizzle-orm/node-postgres\");\n const pool = new Pool({\n connectionString,\n ...(poolConfig || {}),\n });\n return drizzleNode(pool, { schema, ...(config || {}) }) as Database<\n TOptions,\n TSchema\n >;\n}\n\n/**\n * Options for database migration\n */\nexport type MigrateOptions = MigrationConfig;\n\n/**\n * Performs database migration based on the provided configuration\n * @param db - The database instance to migrate\n * @param options - Migration configuration options\n *\n * @important This function runs migrations on the database instance provided to the `drizzleStorage` plugin.\n * It automatically detects the type of database and runs the appropriate migrate function\n * (PGLite or Node-Postgres).\n *\n * @example\n * ```ts\n * await migrate(db, { migrationsFolder: \"./drizzle\" });\n * ```\n */\nexport async function migrate<TSchema extends Record<string, unknown>>(\n db: PgliteDatabase<TSchema> | NodePgDatabase<TSchema>,\n options: MigrateOptions,\n) {\n const isPglite = isDrizzleKind(db, \"PgliteDatabase\");\n\n try {\n if (isPglite) {\n const { migrate: migratePGLite } = require(\"drizzle-orm/pglite/migrator\");\n await migratePGLite(db as PgliteDatabase<TSchema>, options);\n } else {\n const {\n migrate: migrateNode,\n } = require(\"drizzle-orm/node-postgres/migrator\");\n await migrateNode(db as NodePgDatabase<TSchema>, options);\n }\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to apply migrations! Please check if you have generated migrations using drizzle:generate\",\n {\n cause: error,\n },\n );\n }\n}\n\nfunction isPgliteConnectionString(conn: string) {\n return (\n conn.startsWith(\"memory://\") ||\n conn.startsWith(\"file://\") ||\n conn.startsWith(\"idb://\")\n );\n}\n\nfunction isDrizzleKind(value: unknown, entityKindValue: string) {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n // https://github.com/drizzle-team/drizzle-orm/blob/f39f885779800982e90dd3c89aba6df3217a6fd2/drizzle-orm/src/entity.ts#L29-L41\n let cls = Object.getPrototypeOf(value).constructor;\n if (cls) {\n // Traverse the prototype chain to find the entityKind\n while (cls) {\n // https://github.com/drizzle-team/drizzle-orm/blob/f39f885779800982e90dd3c89aba6df3217a6fd2/drizzle-orm/src/pglite/driver.ts#L41\n if (entityKind in cls && cls[entityKind] === entityKindValue) {\n return true;\n }\n cls = Object.getPrototypeOf(cls);\n }\n }\n\n return false;\n}\n","import { type Cursor, normalizeCursor } from \"@apibara/protocol\";\nimport { and, eq, gt, isNull, lt, sql } from \"drizzle-orm\";\nimport type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\nimport type { PgQueryResultHKT, PgTransaction } from \"drizzle-orm/pg-core\";\nimport { integer, pgSchema, primaryKey, text } from \"drizzle-orm/pg-core\";\nimport { SCHEMA_NAME } from \"./constants\";\nimport { DrizzleStorageError, deserialize, serialize } from \"./utils\";\n\nconst CHECKPOINTS_TABLE_NAME = \"checkpoints\";\nconst FILTERS_TABLE_NAME = \"filters\";\nconst SCHEMA_VERSION_TABLE_NAME = \"schema_version\";\n\nconst schema = pgSchema(SCHEMA_NAME);\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const checkpoints = schema.table(CHECKPOINTS_TABLE_NAME, {\n id: text(\"id\").notNull().primaryKey(),\n orderKey: integer(\"order_key\").notNull(),\n uniqueKey: text(\"unique_key\"),\n});\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const filters = schema.table(\n FILTERS_TABLE_NAME,\n {\n id: text(\"id\").notNull(),\n filter: text(\"filter\").notNull(),\n fromBlock: integer(\"from_block\").notNull(),\n toBlock: integer(\"to_block\").$type<number | null>().default(null),\n },\n (table) => [\n {\n pk: primaryKey({ columns: [table.id, table.fromBlock] }),\n },\n ],\n);\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const schemaVersion = schema.table(SCHEMA_VERSION_TABLE_NAME, {\n k: integer(\"k\").notNull().primaryKey(),\n version: integer(\"version\").notNull(),\n});\n\nexport const CURRENT_SCHEMA_VERSION = 0;\n\n// migrations for future schema updates\nconst MIGRATIONS: string[][] = [\n // migrations[0]: v0 -> v1 (for future use)\n [],\n // Add more migration arrays for future versions\n];\n\nexport async function initializePersistentState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(tx: PgTransaction<TQueryResult, TFullSchema, TSchema>) {\n // Create schema if it doesn't exist\n await tx.execute(\n sql.raw(`\n CREATE SCHEMA IF NOT EXISTS ${SCHEMA_NAME};\n `),\n );\n\n // Create schema version table\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${SCHEMA_VERSION_TABLE_NAME} (\n k INTEGER PRIMARY KEY,\n version INTEGER NOT NULL\n );\n `),\n );\n\n // Get current schema version\n const versionRows = await tx\n .select()\n .from(schemaVersion)\n .where(eq(schemaVersion.k, 0));\n\n const storedVersion = versionRows[0]?.version ?? -1;\n\n // Check for incompatible version\n if (storedVersion > CURRENT_SCHEMA_VERSION) {\n throw new DrizzleStorageError(\n `Database Persistence schema version v${storedVersion} is newer than supported version v${CURRENT_SCHEMA_VERSION}`,\n );\n }\n\n // Begin schema updates\n try {\n if (storedVersion === -1) {\n // First time initialization\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${CHECKPOINTS_TABLE_NAME} (\n id TEXT PRIMARY KEY,\n order_key INTEGER NOT NULL,\n unique_key TEXT\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${FILTERS_TABLE_NAME} (\n id TEXT NOT NULL,\n filter TEXT NOT NULL,\n from_block INTEGER NOT NULL,\n to_block INTEGER DEFAULT NULL,\n PRIMARY KEY (id, from_block)\n );\n `),\n );\n\n // Set initial schema version\n await tx.insert(schemaVersion).values({\n k: 0,\n version: CURRENT_SCHEMA_VERSION,\n });\n } else {\n // Run any necessary migrations\n let currentVersion = storedVersion;\n while (currentVersion < CURRENT_SCHEMA_VERSION) {\n const migrationStatements = MIGRATIONS[currentVersion];\n for (const statement of migrationStatements) {\n await tx.execute(statement);\n }\n currentVersion++;\n }\n\n // Update schema version\n await tx\n .update(schemaVersion)\n .set({ version: CURRENT_SCHEMA_VERSION })\n .where(eq(schemaVersion.k, 0));\n }\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to initialize or migrate database schema\",\n { cause: error },\n );\n }\n}\n\nexport async function persistState<\n TFilter,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n endCursor: Cursor;\n filter?: TFilter;\n indexerId: string;\n}) {\n const { tx, endCursor, filter, indexerId } = props;\n\n try {\n if (endCursor) {\n await tx\n .insert(checkpoints)\n .values({\n id: indexerId,\n orderKey: Number(endCursor.orderKey),\n uniqueKey: endCursor.uniqueKey,\n })\n .onConflictDoUpdate({\n target: checkpoints.id,\n set: {\n orderKey: Number(endCursor.orderKey),\n // Explicitly set the unique key to `null` to indicate that it has been deleted\n // Otherwise drizzle will not update its value.\n uniqueKey: endCursor.uniqueKey ? endCursor.uniqueKey : null,\n },\n });\n\n if (filter) {\n await tx\n .update(filters)\n .set({ toBlock: Number(endCursor.orderKey) })\n .where(and(eq(filters.id, indexerId), isNull(filters.toBlock)));\n\n await tx\n .insert(filters)\n .values({\n id: indexerId,\n filter: serialize(filter),\n fromBlock: Number(endCursor.orderKey),\n toBlock: null,\n })\n .onConflictDoUpdate({\n target: [filters.id, filters.fromBlock],\n set: {\n filter: serialize(filter),\n fromBlock: Number(endCursor.orderKey),\n toBlock: null,\n },\n });\n }\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to persist state\", {\n cause: error,\n });\n }\n}\n\nexport async function getState<\n TFilter,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n indexerId: string;\n}): Promise<{ cursor?: Cursor; filter?: TFilter }> {\n const { tx, indexerId } = props;\n\n try {\n const checkpointRows = await tx\n .select()\n .from(checkpoints)\n .where(eq(checkpoints.id, indexerId));\n\n const cursor = checkpointRows[0]\n ? normalizeCursor({\n orderKey: BigInt(checkpointRows[0].orderKey),\n uniqueKey: checkpointRows[0].uniqueKey,\n })\n : undefined;\n\n const filterRows = await tx\n .select()\n .from(filters)\n .where(and(eq(filters.id, indexerId), isNull(filters.toBlock)));\n\n const filter = filterRows[0]\n ? deserialize<TFilter>(filterRows[0].filter)\n : undefined;\n\n return { cursor, filter };\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to get persistent state\", {\n cause: error,\n });\n }\n}\n\nexport async function invalidateState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n cursor: Cursor;\n indexerId: string;\n}) {\n const { tx, cursor, indexerId } = props;\n\n try {\n await tx\n .delete(filters)\n .where(\n and(\n eq(filters.id, indexerId),\n gt(filters.fromBlock, Number(cursor.orderKey)),\n ),\n );\n\n await tx\n .update(filters)\n .set({ toBlock: null })\n .where(\n and(\n eq(filters.id, indexerId),\n gt(filters.toBlock, Number(cursor.orderKey)),\n ),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to invalidate state\", {\n cause: error,\n });\n }\n}\n\nexport async function finalizeState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n cursor: Cursor;\n indexerId: string;\n}) {\n const { tx, cursor, indexerId } = props;\n\n try {\n await tx\n .delete(filters)\n .where(\n and(\n eq(filters.id, indexerId),\n lt(filters.toBlock, Number(cursor.orderKey)),\n ),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to finalize state\", {\n cause: error,\n });\n }\n}\n\nexport async function resetPersistence<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n indexerId: string;\n}) {\n const { tx, indexerId } = props;\n\n try {\n await tx.delete(checkpoints).where(eq(checkpoints.id, indexerId));\n await tx.delete(filters).where(eq(filters.id, indexerId));\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to reset persistence state\", {\n cause: error,\n });\n }\n}\n","import type { Cursor } from \"@apibara/protocol\";\nimport {\n type ExtractTablesWithRelations,\n type TablesRelationalConfig,\n sql,\n} from \"drizzle-orm\";\nimport {\n type PgDatabase,\n type PgQueryResultHKT,\n type PgTransaction,\n char,\n integer,\n jsonb,\n pgSchema,\n serial,\n text,\n} from \"drizzle-orm/pg-core\";\nimport { SCHEMA_NAME } from \"./constants\";\nimport {\n DrizzleStorageError,\n type IdColumnMap,\n getIdColumnForTable,\n} from \"./utils\";\n\nconst ROLLBACK_TABLE_NAME = \"reorg_rollback\";\n\nconst schema = pgSchema(SCHEMA_NAME);\n\nfunction getReorgTriggerName(table: string, indexerId: string) {\n return `${table}_reorg_${indexerId}`;\n}\n\nexport type ReorgOperation = \"I\" | \"U\" | \"D\";\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const reorgRollbackTable = schema.table(ROLLBACK_TABLE_NAME, {\n n: serial(\"n\").primaryKey(),\n op: char(\"op\", { length: 1 }).$type<ReorgOperation>().notNull(),\n table_name: text(\"table_name\").notNull(),\n cursor: integer(\"cursor\").notNull(),\n row_id: text(\"row_id\"),\n row_value: jsonb(\"row_value\"),\n indexer_id: text(\"indexer_id\").notNull(),\n});\n\nexport type ReorgRollbackRow = typeof reorgRollbackTable.$inferSelect;\n\nexport async function initializeReorgRollbackTable<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(tx: PgTransaction<TQueryResult, TFullSchema, TSchema>, indexerId: string) {\n try {\n // Create schema if it doesn't exist\n await tx.execute(`\n CREATE SCHEMA IF NOT EXISTS ${SCHEMA_NAME};\n `);\n // Create the audit log table\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(\n n SERIAL PRIMARY KEY,\n op CHAR(1) NOT NULL,\n table_name TEXT NOT NULL,\n cursor INTEGER NOT NULL,\n row_id TEXT,\n row_value JSONB,\n indexer_id TEXT NOT NULL\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE INDEX IF NOT EXISTS idx_reorg_rollback_indexer_id_cursor ON ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(indexer_id, cursor);\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to initialize reorg rollback table\", {\n cause: error,\n });\n }\n\n try {\n // Create the trigger function\n await tx.execute(\n sql.raw(`\n CREATE OR REPLACE FUNCTION ${SCHEMA_NAME}.reorg_checkpoint()\n RETURNS TRIGGER AS $$\n DECLARE\n table_name TEXT := TG_ARGV[0]::TEXT;\n id_col TEXT := TG_ARGV[1]::TEXT;\n order_key INTEGER := TG_ARGV[2]::INTEGER;\n indexer_id TEXT := TG_ARGV[3]::TEXT;\n new_id_value TEXT := row_to_json(NEW.*)->>id_col;\n old_id_value TEXT := row_to_json(OLD.*)->>id_col;\n BEGIN\n IF (TG_OP = 'DELETE') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'D', table_name, order_key, old_id_value, row_to_json(OLD.*), indexer_id;\n ELSIF (TG_OP = 'UPDATE') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'U', table_name, order_key, new_id_value, row_to_json(OLD.*), indexer_id;\n ELSIF (TG_OP = 'INSERT') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'I', table_name, order_key, new_id_value, null, indexer_id;\n END IF;\n RETURN NULL;\n END;\n $$ LANGUAGE plpgsql;\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to create reorg checkpoint function\",\n {\n cause: error,\n },\n );\n }\n}\n\nexport async function registerTriggers<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n endCursor: Cursor,\n idColumnMap: IdColumnMap,\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n // Determine the column ID for this specific table\n const tableIdColumn = getIdColumnForTable(table, idColumnMap);\n\n await tx.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n await tx.execute(\n sql.raw(`\n CREATE CONSTRAINT TRIGGER ${getReorgTriggerName(table, indexerId)}\n AFTER INSERT OR UPDATE OR DELETE ON ${table}\n DEFERRABLE INITIALLY DEFERRED\n FOR EACH ROW EXECUTE FUNCTION ${SCHEMA_NAME}.reorg_checkpoint('${table}', '${tableIdColumn}', ${Number(endCursor.orderKey)}, '${indexerId}');\n `),\n );\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to register triggers\", {\n cause: error,\n });\n }\n}\n\nexport async function removeTriggers<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n await db.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to remove triggers\", {\n cause: error,\n });\n }\n}\n\nexport async function invalidate<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n cursor: Cursor,\n idColumnMap: IdColumnMap,\n indexerId: string,\n) {\n // Get and delete operations after cursor in one query, ordered by newest first\n const { rows: result } = (await tx.execute(\n sql.raw(`\n WITH deleted AS (\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE cursor > ${Number(cursor.orderKey)}\n AND indexer_id = '${indexerId}'\n RETURNING *\n )\n SELECT * FROM deleted ORDER BY n DESC;\n `),\n )) as { rows: ReorgRollbackRow[] };\n\n if (!Array.isArray(result)) {\n throw new DrizzleStorageError(\n \"Invalid result format from reorg_rollback query\",\n );\n }\n\n // Process each operation in reverse order\n for (const op of result) {\n // Determine the column ID for this specific table\n const tableIdColumn = getIdColumnForTable(op.table_name, idColumnMap);\n\n switch (op.op) {\n case \"I\":\n try {\n if (!op.row_id) {\n throw new DrizzleStorageError(\"Insert operation has no row_id\");\n }\n\n await tx.execute(\n sql.raw(`\n DELETE FROM ${op.table_name}\n WHERE ${tableIdColumn} = '${op.row_id}'\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - I\",\n {\n cause: error,\n },\n );\n }\n\n break;\n\n case \"D\":\n try {\n // For deletes, reinsert the row using json_populate_record\n if (!op.row_value) {\n throw new DrizzleStorageError(\"Delete operation has no row_value\");\n }\n\n await tx.execute(\n sql.raw(`\n INSERT INTO ${op.table_name}\n SELECT * FROM json_populate_record(null::${op.table_name}, '${JSON.stringify(op.row_value)}'::json)\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - D\",\n {\n cause: error,\n },\n );\n }\n\n break;\n\n case \"U\":\n try {\n if (!op.row_value || !op.row_id) {\n throw new DrizzleStorageError(\n \"Update operation has no row_value or row_id\",\n );\n }\n\n // For updates, restore previous values\n\n const rowValue =\n typeof op.row_value === \"string\"\n ? JSON.parse(op.row_value)\n : op.row_value;\n\n const nonIdKeys = Object.keys(rowValue).filter(\n (k) => k !== tableIdColumn,\n );\n\n const fields = nonIdKeys.map((c) => `${c} = prev.${c}`).join(\", \");\n\n const query = sql.raw(`\n UPDATE ${op.table_name}\n SET ${fields}\n FROM (\n SELECT * FROM json_populate_record(null::${op.table_name}, '${JSON.stringify(op.row_value)}'::json)\n ) as prev\n WHERE ${op.table_name}.${tableIdColumn} = '${op.row_id}'\n `);\n\n await tx.execute(query);\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - U\",\n {\n cause: error,\n },\n );\n }\n break;\n\n default: {\n throw new DrizzleStorageError(`Unknown operation: ${op.op}`);\n }\n }\n }\n}\n\nexport async function finalize<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n cursor: Cursor,\n indexerId: string,\n) {\n try {\n await tx.execute(\n sql.raw(`\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE cursor <= ${Number(cursor.orderKey)}\n AND indexer_id = '${indexerId}'\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to finalize\", {\n cause: error,\n });\n }\n}\n\nexport async function cleanupStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n await tx.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n }\n\n await tx.execute(\n sql.raw(`\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE indexer_id = '${indexerId}'\n `),\n );\n\n for (const table of tables) {\n try {\n await tx.execute(sql.raw(`TRUNCATE TABLE ${table} CASCADE;`));\n } catch (error) {\n throw new DrizzleStorageError(`Failed to truncate table ${table}`, {\n cause: error,\n });\n }\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to clean up storage\", {\n cause: error,\n });\n }\n}\n","import { useIndexerContext } from \"@apibara/indexer\";\nimport { defineIndexerPlugin, useLogger } from \"@apibara/indexer/plugins\";\n\nimport type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\n\nimport { generateIndexerId } from \"@apibara/indexer/internal\";\nimport { useInternalContext } from \"@apibara/indexer/internal/plugins\";\nimport type { Cursor, DataFinality } from \"@apibara/protocol\";\nimport type {\n PgDatabase,\n PgQueryResultHKT,\n PgTransaction,\n} from \"drizzle-orm/pg-core\";\nimport { DRIZZLE_PROPERTY, DRIZZLE_STORAGE_DB_PROPERTY } from \"./constants\";\nimport { type MigrateOptions, migrate } from \"./helper\";\nimport {\n finalizeState,\n getState,\n initializePersistentState,\n invalidateState,\n persistState,\n resetPersistence,\n} from \"./persistence\";\nimport {\n cleanupStorage,\n finalize,\n initializeReorgRollbackTable,\n invalidate,\n registerTriggers,\n removeTriggers,\n} from \"./storage\";\nimport {\n DrizzleStorageError,\n type IdColumnMap,\n getIdColumnForTable,\n sleep,\n withTransaction,\n} from \"./utils\";\n\nexport * from \"./helper\";\n\nexport type { IdColumnMap };\n\nconst MAX_RETRIES = 5;\n\nexport type DrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n> = {\n db: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n};\n\nexport function useDrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n _db?: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n): DrizzleStorage<TQueryResult, TFullSchema, TSchema> {\n const context = useIndexerContext();\n\n if (!context[DRIZZLE_PROPERTY]) {\n throw new DrizzleStorageError(\n \"drizzle storage is not available. Did you register the plugin?\",\n );\n }\n\n return context[DRIZZLE_PROPERTY];\n}\n\nexport function useTestDrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(): PgDatabase<TQueryResult, TFullSchema, TSchema> {\n const context = useIndexerContext();\n\n if (!context[DRIZZLE_STORAGE_DB_PROPERTY]) {\n throw new DrizzleStorageError(\n \"drizzle storage db is not available. Did you register the plugin?\",\n );\n }\n\n return context[DRIZZLE_STORAGE_DB_PROPERTY];\n}\n\nexport interface DrizzleStorageOptions<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n> {\n /**\n * The Drizzle database instance.\n */\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>;\n /**\n * Whether to persist the indexer's state. Defaults to true.\n */\n persistState?: boolean;\n /**\n * The name of the indexer. Default value is 'default'.\n */\n indexerName?: string;\n /**\n * The schema of the database.\n */\n schema?: Record<string, unknown>;\n /**\n * The column to use as the primary identifier for each table.\n *\n * This identifier is used for tracking changes during reorgs and rollbacks.\n *\n * Can be specified in two ways:\n *\n * 1. As a single string that applies to all tables:\n * ```ts\n * idColumn: \"_id\" // Uses \"_id\" column for all tables\n * ```\n *\n * 2. As an object mapping table names to their ID columns:\n * ```ts\n * idColumn: {\n * transfers: \"transaction_hash\", // Use \"transaction_hash\" for transfers table\n * blocks: \"block_number\", // Use \"block_number\" for blocks table\n * \"*\": \"_id\" // Use \"_id\" for all other tables | defaults to \"id\"\n * }\n * ```\n *\n * The special \"*\" key acts as a fallback for any tables not explicitly mapped.\n *\n * @default \"id\"\n * @type {string | Partial<IdColumnMap>}\n */\n idColumn?: string | Partial<IdColumnMap>;\n /**\n * The options for the database migration. When provided, the database will automatically run migrations before the indexer runs.\n */\n migrate?: MigrateOptions;\n}\n\n/**\n * Creates a plugin that uses Drizzle as the storage layer.\n *\n * Supports storing the indexer's state and provides a simple Key-Value store.\n * @param options.db - The Drizzle database instance.\n * @param options.persistState - Whether to persist the indexer's state. Defaults to true.\n * @param options.indexerName - The name of the indexer. Defaults value is 'default'.\n * @param options.schema - The schema of the database.\n * @param options.idColumn - The column to use as the id. Defaults to 'id'.\n * @param options.migrate - The options for the database migration. when provided, the database will automatically run migrations before the indexer runs.\n */\nexport function drizzleStorage<\n TFilter,\n TBlock,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>({\n db,\n persistState: enablePersistence = true,\n indexerName: identifier = \"default\",\n schema: _schema,\n idColumn,\n migrate: migrateOptions,\n}: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>) {\n return defineIndexerPlugin<TFilter, TBlock>((indexer) => {\n let tableNames: string[] = [];\n let indexerId = \"\";\n const alwaysReindex = process.env[\"APIBARA_ALWAYS_REINDEX\"] === \"true\";\n let prevFinality: DataFinality | undefined;\n const schema: TSchema = (_schema as TSchema) ?? db._.schema ?? {};\n const idColumnMap: IdColumnMap = {\n \"*\": typeof idColumn === \"string\" ? idColumn : \"id\",\n ...(typeof idColumn === \"object\" ? idColumn : {}),\n };\n\n try {\n tableNames = Object.values(schema).map((table) => table.dbName);\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to get table names from schema\", {\n cause: error,\n });\n }\n\n // Check if specified idColumn exists in all the tables in schema\n for (const table of Object.values(schema)) {\n const columns = table.columns;\n const tableIdColumn = getIdColumnForTable(table.dbName, idColumnMap);\n\n const columnExists = Object.values(columns).some(\n (column) => column.name === tableIdColumn,\n );\n\n if (!columnExists) {\n throw new DrizzleStorageError(\n `Column \\`\"${tableIdColumn}\"\\` does not exist in table \\`\"${table.dbName}\"\\`. ` +\n \"Make sure the table has the specified column or provide a valid `idColumn` mapping to `drizzleStorage`.\",\n );\n }\n }\n\n indexer.hooks.hook(\"plugins:init\", async () => {\n const internalContext = useInternalContext();\n const context = useIndexerContext();\n const logger = useLogger();\n\n // For testing purposes using vcr.\n context[DRIZZLE_STORAGE_DB_PROPERTY] = db;\n\n const { indexerName: indexerFileName, availableIndexers } =\n internalContext;\n\n indexerId = generateIndexerId(indexerFileName, identifier);\n\n let retries = 0;\n\n // incase the migrations are already applied, we don't want to run them again\n let migrationsApplied = false;\n let cleanupApplied = false;\n\n while (retries <= MAX_RETRIES) {\n try {\n if (migrateOptions && !migrationsApplied) {\n // @ts-ignore type mismatch for db\n await migrate(db, migrateOptions);\n migrationsApplied = true;\n logger.success(\"Migrations applied\");\n }\n await withTransaction(db, async (tx) => {\n await initializeReorgRollbackTable(tx, indexerId);\n if (enablePersistence) {\n await initializePersistentState(tx);\n }\n\n if (alwaysReindex && !cleanupApplied) {\n logger.warn(\n `Reindexing: Deleting all data from tables - ${tableNames.join(\", \")}`,\n );\n\n await cleanupStorage(tx, tableNames, indexerId);\n\n if (enablePersistence) {\n await resetPersistence({ tx, indexerId });\n }\n\n cleanupApplied = true;\n\n logger.success(\"Tables have been cleaned up for reindexing\");\n }\n });\n break;\n } catch (error) {\n if (retries === MAX_RETRIES) {\n if (error instanceof DrizzleStorageError) {\n throw error;\n }\n throw new DrizzleStorageError(\n \"Initialization failed after 5 retries\",\n {\n cause: error,\n },\n );\n }\n await sleep(retries * 1000);\n retries++;\n }\n }\n });\n\n indexer.hooks.hook(\"connect:before\", async ({ request }) => {\n if (!enablePersistence) {\n return;\n }\n\n await withTransaction(db, async (tx) => {\n const { cursor, filter } = await getState<\n TFilter,\n TQueryResult,\n TFullSchema,\n TSchema\n >({\n tx,\n indexerId,\n });\n if (cursor) {\n request.startingCursor = cursor;\n }\n if (filter) {\n request.filter[1] = filter;\n }\n });\n });\n\n indexer.hooks.hook(\"connect:after\", async ({ request }) => {\n // On restart, we need to invalidate data for blocks that were processed but not persisted.\n const cursor = request.startingCursor;\n\n if (!cursor) {\n return;\n }\n\n await withTransaction(db, async (tx) => {\n // Use the appropriate idColumn for each table when calling invalidate\n await invalidate(tx, cursor, idColumnMap, indexerId);\n\n if (enablePersistence) {\n await invalidateState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"connect:factory\", async ({ request, endCursor }) => {\n if (!enablePersistence) {\n return;\n }\n // We can call this hook because this hook is called inside the transaction of handler:middleware\n // so we have access to the transaction from the context\n const { db: tx } = useDrizzleStorage(db);\n\n if (endCursor && request.filter[1]) {\n await persistState({\n tx,\n endCursor,\n filter: request.filter[1],\n indexerId,\n });\n }\n });\n\n indexer.hooks.hook(\"message:finalize\", async ({ message }) => {\n const { cursor } = message;\n\n if (!cursor) {\n throw new DrizzleStorageError(\"Finalized Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n await finalize(tx, cursor, indexerId);\n\n if (enablePersistence) {\n await finalizeState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"message:invalidate\", async ({ message }) => {\n const { cursor } = message;\n\n if (!cursor) {\n throw new DrizzleStorageError(\"Invalidate Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n // Use the appropriate idColumn for each table when calling invalidate\n await invalidate(tx, cursor, idColumnMap, indexerId);\n\n if (enablePersistence) {\n await invalidateState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"handler:middleware\", async ({ use }) => {\n use(async (context, next) => {\n try {\n const { endCursor, finality, cursor } = context as {\n cursor: Cursor;\n endCursor: Cursor;\n finality: DataFinality;\n };\n\n if (!endCursor) {\n throw new DrizzleStorageError(\"End Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n context[DRIZZLE_PROPERTY] = { db: tx } as DrizzleStorage<\n TQueryResult,\n TFullSchema,\n TSchema\n >;\n\n if (prevFinality === \"pending\") {\n // invalidate if previous block's finality was \"pending\"\n await invalidate(tx, cursor, idColumnMap, indexerId);\n }\n\n if (finality !== \"finalized\") {\n await registerTriggers(\n tx,\n tableNames,\n endCursor,\n idColumnMap,\n indexerId,\n );\n }\n\n await next();\n delete context[DRIZZLE_PROPERTY];\n\n if (enablePersistence && finality !== \"pending\") {\n await persistState({\n tx,\n endCursor,\n indexerId,\n });\n }\n\n prevFinality = finality;\n });\n\n if (finality !== \"finalized\") {\n // remove trigger outside of the transaction or it won't be triggered.\n await removeTriggers(db, tableNames, indexerId);\n }\n } catch (error) {\n await removeTriggers(db, tableNames, indexerId);\n\n throw new DrizzleStorageError(\"Failed to run handler:middleware\", {\n cause: error,\n });\n }\n });\n });\n });\n}\n"],"names":["schema"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/utils.ts","../src/helper.ts","../src/persistence.ts","../src/storage.ts","../src/index.ts"],"sourcesContent":["import type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\nimport type {\n PgDatabase,\n PgQueryResultHKT,\n PgTransaction,\n} from \"drizzle-orm/pg-core\";\n\nexport class DrizzleStorageError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options);\n this.name = \"DrizzleStorageError\";\n }\n}\n\nexport async function withTransaction<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n cb: (db: PgTransaction<TQueryResult, TFullSchema, TSchema>) => Promise<void>,\n) {\n return await db.transaction(async (txnDb) => {\n return await cb(txnDb);\n });\n}\n\nexport function deserialize<T>(str: string): T {\n return JSON.parse(str, (_, value) =>\n typeof value === \"string\" && value.match(/^\\d+n$/)\n ? BigInt(value.slice(0, -1))\n : value,\n ) as T;\n}\n\nexport function serialize<T>(obj: T): string {\n return JSON.stringify(\n obj,\n (_, value) => (typeof value === \"bigint\" ? `${value.toString()}n` : value),\n \"\\t\",\n );\n}\n\nexport function sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport interface IdColumnMap extends Record<string, string> {\n /**\n * Wildcard mapping for all tables.\n */\n \"*\": string;\n}\n\nexport const getIdColumnForTable = (\n tableName: string,\n idColumn: IdColumnMap,\n): string => {\n // If there's a specific mapping for this table, use it\n if (idColumn[tableName]) {\n return idColumn[tableName];\n }\n // Default fallback\n return idColumn[\"*\"];\n};\n","import type { PGlite, PGliteOptions } from \"@electric-sql/pglite\";\nimport type { DrizzleConfig } from \"drizzle-orm\";\nimport { entityKind } from \"drizzle-orm\";\nimport type { MigrationConfig } from \"drizzle-orm/migrator\";\nimport type { NodePgDatabase as OriginalNodePgDatabase } from \"drizzle-orm/node-postgres\";\nimport type { PgliteDatabase as OriginalPgliteDatabase } from \"drizzle-orm/pglite\";\nimport type pg from \"pg\";\nimport { DrizzleStorageError } from \"./utils\";\n\n/**\n * Union type of all possible drizzle database options\n */\nexport type DrizzleOptions = PgliteDrizzleOptions | NodePgDrizzleOptions;\n\n/**\n * Configuration options for Node-Postgres database connection\n */\nexport type NodePgDrizzleOptions = {\n /**\n * Type of database to use -\n * - \"pglite\" - PGLite database\n * - \"node-postgres\" - Node-Postgres database\n * @default \"pglite\"\n */\n type: \"node-postgres\";\n /**\n * Connection string to use for the database\n * @default \"\"\n */\n connectionString?: string;\n /**\n * Pool configuration options for Node-Postgres\n */\n poolConfig?: pg.PoolConfig;\n /**\n * Additional drizzle configuration options\n */\n config?: Omit<DrizzleConfig, \"schema\">;\n};\n\n/**\n * Configuration options for PGLite database connection\n */\nexport type PgliteDrizzleOptions = {\n /**\n * Type of database to use -\n * - \"pglite\" - PGLite database\n * - \"node-postgres\" - Node-Postgres database\n */\n type?: \"pglite\";\n /**\n * Connection string to use for the database\n * @default process.env[\"POSTGRES_CONNECTION_STRING\"] ?? \"memory://pglite\"\n */\n connectionString?: string;\n /**\n * Pool configuration is not supported for PGLite\n */\n poolConfig?: never;\n /**\n * Additional drizzle configuration options with PGLite specific connection options\n */\n config?: Omit<DrizzleConfig, \"schema\"> & {\n connection?:\n | (PGliteOptions & {\n dataDir?: string;\n })\n | string;\n };\n};\n\n/**\n * Extended PGLite database type with client information\n */\nexport type PgliteDatabase<TSchema extends Record<string, unknown>> =\n OriginalPgliteDatabase<TSchema> & {\n $client: PGlite;\n };\n\n/**\n * Extended Node-Postgres database type with client information\n */\nexport type NodePgDatabase<TSchema extends Record<string, unknown>> =\n OriginalNodePgDatabase<TSchema> & {\n $client: pg.Pool;\n };\n\nexport type Database<\n TOptions extends DrizzleOptions,\n TSchema extends Record<string, unknown>,\n> = TOptions extends PgliteDrizzleOptions\n ? PgliteDatabase<TSchema>\n : NodePgDatabase<TSchema>;\n\n/**\n * Creates a new Drizzle database instance based on the provided options\n *\n * @important connectionString defaults to process.env[\"POSTGRES_CONNECTION_STRING\"], if not set, it defaults to \"memory://\" (in-memory pglite)\n *\n * @param options - Configuration options for the database connection\n * @returns A configured Drizzle database instance\n * @throws {Error} If an invalid database type is specified\n */\nexport function drizzle<\n TSchema extends Record<string, unknown>,\n TOptions extends DrizzleOptions,\n>(\n options?: TOptions & {\n /**\n * Schema to use for the database\n * @default {}\n */\n schema?: TSchema;\n },\n): Database<TOptions, TSchema> {\n const {\n connectionString = process.env[\"POSTGRES_CONNECTION_STRING\"] ?? \"memory://\",\n schema,\n type = \"pglite\",\n config,\n poolConfig,\n } = options ?? {};\n\n if (isPgliteConnectionString(connectionString) && type === \"pglite\") {\n const { drizzle: drizzlePGLite } = require(\"drizzle-orm/pglite\");\n\n return drizzlePGLite({\n schema: schema as TSchema,\n connection: {\n dataDir: connectionString || \"memory://pglite\",\n },\n ...(config || {}),\n }) as Database<TOptions, TSchema>;\n }\n\n const { Pool } = require(\"pg\");\n const { drizzle: drizzleNode } = require(\"drizzle-orm/node-postgres\");\n const pool = new Pool({\n connectionString,\n ...(poolConfig || {}),\n });\n return drizzleNode(pool, { schema, ...(config || {}) }) as Database<\n TOptions,\n TSchema\n >;\n}\n\n/**\n * Options for database migration\n */\nexport type MigrateOptions = MigrationConfig;\n\n/**\n * Performs database migration based on the provided configuration\n * @param db - The database instance to migrate\n * @param options - Migration configuration options\n *\n * @important This function runs migrations on the database instance provided to the `drizzleStorage` plugin.\n * It automatically detects the type of database and runs the appropriate migrate function\n * (PGLite or Node-Postgres).\n *\n * @example\n * ```ts\n * await migrate(db, { migrationsFolder: \"./drizzle\" });\n * ```\n */\nexport async function migrate<TSchema extends Record<string, unknown>>(\n db: PgliteDatabase<TSchema> | NodePgDatabase<TSchema>,\n options: MigrateOptions,\n) {\n const isPglite = isDrizzleKind(db, \"PgliteDatabase\");\n\n try {\n if (isPglite) {\n const { migrate: migratePGLite } = require(\"drizzle-orm/pglite/migrator\");\n await migratePGLite(db as PgliteDatabase<TSchema>, options);\n } else {\n const {\n migrate: migrateNode,\n } = require(\"drizzle-orm/node-postgres/migrator\");\n await migrateNode(db as NodePgDatabase<TSchema>, options);\n }\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to apply migrations! Please check if you have generated migrations using drizzle:generate\",\n {\n cause: error,\n },\n );\n }\n}\n\nfunction isPgliteConnectionString(conn: string) {\n return (\n conn.startsWith(\"memory://\") ||\n conn.startsWith(\"file://\") ||\n conn.startsWith(\"idb://\")\n );\n}\n\nfunction isDrizzleKind(value: unknown, entityKindValue: string) {\n if (!value || typeof value !== \"object\") {\n return false;\n }\n // https://github.com/drizzle-team/drizzle-orm/blob/f39f885779800982e90dd3c89aba6df3217a6fd2/drizzle-orm/src/entity.ts#L29-L41\n let cls = Object.getPrototypeOf(value).constructor;\n if (cls) {\n // Traverse the prototype chain to find the entityKind\n while (cls) {\n // https://github.com/drizzle-team/drizzle-orm/blob/f39f885779800982e90dd3c89aba6df3217a6fd2/drizzle-orm/src/pglite/driver.ts#L41\n if (entityKind in cls && cls[entityKind] === entityKindValue) {\n return true;\n }\n cls = Object.getPrototypeOf(cls);\n }\n }\n\n return false;\n}\n","import { type Cursor, normalizeCursor } from \"@apibara/protocol\";\nimport { and, eq, gt, isNull, lt, sql } from \"drizzle-orm\";\nimport type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\nimport type { PgQueryResultHKT, PgTransaction } from \"drizzle-orm/pg-core\";\nimport {\n integer,\n pgSchema,\n primaryKey,\n serial,\n text,\n timestamp,\n} from \"drizzle-orm/pg-core\";\nimport { SCHEMA_NAME } from \"./constants\";\nimport { DrizzleStorageError, deserialize, serialize } from \"./utils\";\n\nconst CHECKPOINTS_TABLE_NAME = \"checkpoints\";\nconst FILTERS_TABLE_NAME = \"filters\";\nconst SCHEMA_VERSION_TABLE_NAME = \"schema_version\";\n\nconst schema = pgSchema(SCHEMA_NAME);\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const checkpoints = schema.table(CHECKPOINTS_TABLE_NAME, {\n id: text(\"id\").notNull().primaryKey(),\n orderKey: integer(\"order_key\").notNull(),\n uniqueKey: text(\"unique_key\"),\n});\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const filters = schema.table(\n FILTERS_TABLE_NAME,\n {\n id: text(\"id\").notNull(),\n filter: text(\"filter\").notNull(),\n fromBlock: integer(\"from_block\").notNull(),\n toBlock: integer(\"to_block\").$type<number | null>().default(null),\n },\n (table) => [\n {\n pk: primaryKey({ columns: [table.id, table.fromBlock] }),\n },\n ],\n);\n\n/** Table for recording chain reorganizations */\nexport const chainReorganizations = schema.table(\"chain_reorganizations\", {\n id: serial(\"id\").primaryKey(),\n indexerId: text(\"indexer_id\").notNull(),\n oldHeadOrderKey: integer(\"old_head_order_key\"),\n oldHeadUniqueKey: text(\"old_head_unique_key\")\n .$type<string | null>()\n .default(null),\n newHeadOrderKey: integer(\"new_head_order_key\").notNull(),\n newHeadUniqueKey: text(\"new_head_unique_key\")\n .$type<string | null>()\n .default(null),\n recordedAt: timestamp(\"recorded_at\").defaultNow().notNull(),\n});\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const schemaVersion = schema.table(SCHEMA_VERSION_TABLE_NAME, {\n k: integer(\"k\").notNull().primaryKey(),\n version: integer(\"version\").notNull(),\n});\n\nexport const CURRENT_SCHEMA_VERSION = 0;\n\n// migrations for future schema updates\nconst MIGRATIONS: string[][] = [\n // migrations[0]: v0 -> v1 (for future use)\n [],\n // Add more migration arrays for future versions\n];\n\nexport async function initializePersistentState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(tx: PgTransaction<TQueryResult, TFullSchema, TSchema>) {\n // Create schema if it doesn't exist\n await tx.execute(\n sql.raw(`\n CREATE SCHEMA IF NOT EXISTS ${SCHEMA_NAME};\n `),\n );\n\n // Create schema version table\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${SCHEMA_VERSION_TABLE_NAME} (\n k INTEGER PRIMARY KEY,\n version INTEGER NOT NULL\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.chain_reorganizations (\n id SERIAL PRIMARY KEY,\n indexer_id TEXT NOT NULL,\n old_head_order_key INTEGER,\n old_head_unique_key TEXT DEFAULT NULL,\n new_head_order_key INTEGER NOT NULL,\n new_head_unique_key TEXT DEFAULT NULL,\n recorded_at TIMESTAMP NOT NULL DEFAULT NOW()\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE INDEX IF NOT EXISTS idx_chain_reorgs_indexer_id \n ON ${SCHEMA_NAME}.chain_reorganizations(indexer_id);\n `),\n );\n\n // Get current schema version\n const versionRows = await tx\n .select()\n .from(schemaVersion)\n .where(eq(schemaVersion.k, 0));\n\n const storedVersion = versionRows[0]?.version ?? -1;\n\n // Check for incompatible version\n if (storedVersion > CURRENT_SCHEMA_VERSION) {\n throw new DrizzleStorageError(\n `Database Persistence schema version v${storedVersion} is newer than supported version v${CURRENT_SCHEMA_VERSION}`,\n );\n }\n\n // Begin schema updates\n try {\n if (storedVersion === -1) {\n // First time initialization\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${CHECKPOINTS_TABLE_NAME} (\n id TEXT PRIMARY KEY,\n order_key INTEGER NOT NULL,\n unique_key TEXT\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${FILTERS_TABLE_NAME} (\n id TEXT NOT NULL,\n filter TEXT NOT NULL,\n from_block INTEGER NOT NULL,\n to_block INTEGER DEFAULT NULL,\n PRIMARY KEY (id, from_block)\n );\n `),\n );\n\n // Set initial schema version\n await tx.insert(schemaVersion).values({\n k: 0,\n version: CURRENT_SCHEMA_VERSION,\n });\n } else {\n // Run any necessary migrations\n let currentVersion = storedVersion;\n while (currentVersion < CURRENT_SCHEMA_VERSION) {\n const migrationStatements = MIGRATIONS[currentVersion];\n for (const statement of migrationStatements) {\n await tx.execute(statement);\n }\n currentVersion++;\n }\n\n // Update schema version\n await tx\n .update(schemaVersion)\n .set({ version: CURRENT_SCHEMA_VERSION })\n .where(eq(schemaVersion.k, 0));\n }\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to initialize or migrate database schema\",\n { cause: error },\n );\n }\n}\n\nexport async function recordChainReorganization<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n indexerId: string;\n oldHead: Cursor | undefined;\n newHead: Cursor;\n}) {\n const { tx, indexerId, oldHead, newHead } = props;\n\n try {\n await tx.insert(chainReorganizations).values({\n indexerId: indexerId,\n oldHeadOrderKey: oldHead ? Number(oldHead.orderKey) : null,\n oldHeadUniqueKey: oldHead?.uniqueKey ? oldHead.uniqueKey : null,\n newHeadOrderKey: Number(newHead.orderKey),\n newHeadUniqueKey: newHead.uniqueKey ? newHead.uniqueKey : null,\n });\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to record chain reorganization\", {\n cause: error,\n });\n }\n}\n\nexport async function persistState<\n TFilter,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n endCursor: Cursor;\n filter?: TFilter;\n indexerId: string;\n}) {\n const { tx, endCursor, filter, indexerId } = props;\n\n try {\n if (endCursor) {\n await tx\n .insert(checkpoints)\n .values({\n id: indexerId,\n orderKey: Number(endCursor.orderKey),\n uniqueKey: endCursor.uniqueKey,\n })\n .onConflictDoUpdate({\n target: checkpoints.id,\n set: {\n orderKey: Number(endCursor.orderKey),\n // Explicitly set the unique key to `null` to indicate that it has been deleted\n // Otherwise drizzle will not update its value.\n uniqueKey: endCursor.uniqueKey ? endCursor.uniqueKey : null,\n },\n });\n\n if (filter) {\n await tx\n .update(filters)\n .set({ toBlock: Number(endCursor.orderKey) })\n .where(and(eq(filters.id, indexerId), isNull(filters.toBlock)));\n\n await tx\n .insert(filters)\n .values({\n id: indexerId,\n filter: serialize(filter),\n fromBlock: Number(endCursor.orderKey),\n toBlock: null,\n })\n .onConflictDoUpdate({\n target: [filters.id, filters.fromBlock],\n set: {\n filter: serialize(filter),\n fromBlock: Number(endCursor.orderKey),\n toBlock: null,\n },\n });\n }\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to persist state\", {\n cause: error,\n });\n }\n}\n\nexport async function getState<\n TFilter,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n indexerId: string;\n}): Promise<{ cursor?: Cursor; filter?: TFilter }> {\n const { tx, indexerId } = props;\n\n try {\n const checkpointRows = await tx\n .select()\n .from(checkpoints)\n .where(eq(checkpoints.id, indexerId));\n\n const cursor = checkpointRows[0]\n ? normalizeCursor({\n orderKey: BigInt(checkpointRows[0].orderKey),\n uniqueKey: checkpointRows[0].uniqueKey,\n })\n : undefined;\n\n const filterRows = await tx\n .select()\n .from(filters)\n .where(and(eq(filters.id, indexerId), isNull(filters.toBlock)));\n\n const filter = filterRows[0]\n ? deserialize<TFilter>(filterRows[0].filter)\n : undefined;\n\n return { cursor, filter };\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to get persistent state\", {\n cause: error,\n });\n }\n}\n\nexport async function invalidateState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n cursor: Cursor;\n indexerId: string;\n}) {\n const { tx, cursor, indexerId } = props;\n\n try {\n await tx\n .update(checkpoints)\n .set({\n orderKey: Number(cursor.orderKey),\n uniqueKey: cursor.uniqueKey ? cursor.uniqueKey : null,\n })\n .where(eq(checkpoints.id, indexerId));\n\n await tx\n .delete(filters)\n .where(\n and(\n eq(filters.id, indexerId),\n gt(filters.fromBlock, Number(cursor.orderKey)),\n ),\n );\n\n await tx\n .update(filters)\n .set({ toBlock: null })\n .where(\n and(\n eq(filters.id, indexerId),\n gt(filters.toBlock, Number(cursor.orderKey)),\n ),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to invalidate state\", {\n cause: error,\n });\n }\n}\n\nexport async function finalizeState<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n cursor: Cursor;\n indexerId: string;\n}) {\n const { tx, cursor, indexerId } = props;\n\n try {\n await tx\n .delete(filters)\n .where(\n and(\n eq(filters.id, indexerId),\n lt(filters.toBlock, Number(cursor.orderKey)),\n ),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to finalize state\", {\n cause: error,\n });\n }\n}\n\nexport async function resetPersistence<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(props: {\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n indexerId: string;\n}) {\n const { tx, indexerId } = props;\n\n try {\n await tx.delete(checkpoints).where(eq(checkpoints.id, indexerId));\n await tx.delete(filters).where(eq(filters.id, indexerId));\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to reset persistence state\", {\n cause: error,\n });\n }\n}\n","import type { Cursor } from \"@apibara/protocol\";\nimport {\n type ExtractTablesWithRelations,\n type TablesRelationalConfig,\n sql,\n} from \"drizzle-orm\";\nimport {\n type PgDatabase,\n type PgQueryResultHKT,\n type PgTransaction,\n char,\n integer,\n jsonb,\n pgSchema,\n serial,\n text,\n} from \"drizzle-orm/pg-core\";\nimport { SCHEMA_NAME } from \"./constants\";\nimport {\n DrizzleStorageError,\n type IdColumnMap,\n getIdColumnForTable,\n} from \"./utils\";\n\nconst ROLLBACK_TABLE_NAME = \"reorg_rollback\";\n\nconst schema = pgSchema(SCHEMA_NAME);\n\nfunction getReorgTriggerName(table: string, indexerId: string) {\n return `${table}_reorg_${indexerId}`;\n}\n\nexport type ReorgOperation = \"I\" | \"U\" | \"D\";\n\n/** This table is not used for migrations, its only used for ease of internal operations with drizzle. */\nexport const reorgRollbackTable = schema.table(ROLLBACK_TABLE_NAME, {\n n: serial(\"n\").primaryKey(),\n op: char(\"op\", { length: 1 }).$type<ReorgOperation>().notNull(),\n table_name: text(\"table_name\").notNull(),\n cursor: integer(\"cursor\").notNull(),\n row_id: text(\"row_id\"),\n row_value: jsonb(\"row_value\"),\n indexer_id: text(\"indexer_id\").notNull(),\n});\n\nexport type ReorgRollbackRow = typeof reorgRollbackTable.$inferSelect;\n\nexport async function initializeReorgRollbackTable<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(tx: PgTransaction<TQueryResult, TFullSchema, TSchema>, indexerId: string) {\n try {\n // Create schema if it doesn't exist\n await tx.execute(`\n CREATE SCHEMA IF NOT EXISTS ${SCHEMA_NAME};\n `);\n // Create the audit log table\n await tx.execute(\n sql.raw(`\n CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(\n n SERIAL PRIMARY KEY,\n op CHAR(1) NOT NULL,\n table_name TEXT NOT NULL,\n cursor INTEGER NOT NULL,\n row_id TEXT,\n row_value JSONB,\n indexer_id TEXT NOT NULL\n );\n `),\n );\n\n await tx.execute(\n sql.raw(`\n CREATE INDEX IF NOT EXISTS idx_reorg_rollback_indexer_id_cursor ON ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(indexer_id, cursor);\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to initialize reorg rollback table\", {\n cause: error,\n });\n }\n\n try {\n // Create the trigger function\n await tx.execute(\n sql.raw(`\n CREATE OR REPLACE FUNCTION ${SCHEMA_NAME}.reorg_checkpoint()\n RETURNS TRIGGER AS $$\n DECLARE\n table_name TEXT := TG_ARGV[0]::TEXT;\n id_col TEXT := TG_ARGV[1]::TEXT;\n order_key INTEGER := TG_ARGV[2]::INTEGER;\n indexer_id TEXT := TG_ARGV[3]::TEXT;\n new_id_value TEXT := row_to_json(NEW.*)->>id_col;\n old_id_value TEXT := row_to_json(OLD.*)->>id_col;\n BEGIN\n IF (TG_OP = 'DELETE') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'D', table_name, order_key, old_id_value, row_to_json(OLD.*), indexer_id;\n ELSIF (TG_OP = 'UPDATE') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'U', table_name, order_key, new_id_value, row_to_json(OLD.*), indexer_id;\n ELSIF (TG_OP = 'INSERT') THEN\n INSERT INTO ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}(op, table_name, cursor, row_id, row_value, indexer_id)\n SELECT 'I', table_name, order_key, new_id_value, null, indexer_id;\n END IF;\n RETURN NULL;\n END;\n $$ LANGUAGE plpgsql;\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to create reorg checkpoint function\",\n {\n cause: error,\n },\n );\n }\n}\n\nexport async function registerTriggers<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n endCursor: Cursor,\n idColumnMap: IdColumnMap,\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n // Determine the column ID for this specific table\n const tableIdColumn = getIdColumnForTable(table, idColumnMap);\n\n await tx.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n await tx.execute(\n sql.raw(`\n CREATE CONSTRAINT TRIGGER ${getReorgTriggerName(table, indexerId)}\n AFTER INSERT OR UPDATE OR DELETE ON ${table}\n DEFERRABLE INITIALLY DEFERRED\n FOR EACH ROW EXECUTE FUNCTION ${SCHEMA_NAME}.reorg_checkpoint('${table}', '${tableIdColumn}', ${Number(endCursor.orderKey)}, '${indexerId}');\n `),\n );\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to register triggers\", {\n cause: error,\n });\n }\n}\n\nexport async function removeTriggers<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n await db.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to remove triggers\", {\n cause: error,\n });\n }\n}\n\nexport async function invalidate<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n cursor: Cursor,\n idColumnMap: IdColumnMap,\n indexerId: string,\n) {\n // Get and delete operations after cursor in one query, ordered by newest first\n const { rows: result } = (await tx.execute(\n sql.raw(`\n WITH deleted AS (\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE cursor > ${Number(cursor.orderKey)}\n AND indexer_id = '${indexerId}'\n RETURNING *\n )\n SELECT * FROM deleted ORDER BY n DESC;\n `),\n )) as { rows: ReorgRollbackRow[] };\n\n if (!Array.isArray(result)) {\n throw new DrizzleStorageError(\n \"Invalid result format from reorg_rollback query\",\n );\n }\n\n // Process each operation in reverse order\n for (const op of result) {\n // Determine the column ID for this specific table\n const tableIdColumn = getIdColumnForTable(op.table_name, idColumnMap);\n\n switch (op.op) {\n case \"I\":\n try {\n if (!op.row_id) {\n throw new DrizzleStorageError(\"Insert operation has no row_id\");\n }\n\n await tx.execute(\n sql.raw(`\n DELETE FROM ${op.table_name}\n WHERE ${tableIdColumn} = '${op.row_id}'\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - I\",\n {\n cause: error,\n },\n );\n }\n\n break;\n\n case \"D\":\n try {\n // For deletes, reinsert the row using json_populate_record\n if (!op.row_value) {\n throw new DrizzleStorageError(\"Delete operation has no row_value\");\n }\n\n await tx.execute(\n sql.raw(`\n INSERT INTO ${op.table_name}\n SELECT * FROM json_populate_record(null::${op.table_name}, '${JSON.stringify(op.row_value)}'::json)\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - D\",\n {\n cause: error,\n },\n );\n }\n\n break;\n\n case \"U\":\n try {\n if (!op.row_value || !op.row_id) {\n throw new DrizzleStorageError(\n \"Update operation has no row_value or row_id\",\n );\n }\n\n // For updates, restore previous values\n\n const rowValue =\n typeof op.row_value === \"string\"\n ? JSON.parse(op.row_value)\n : op.row_value;\n\n const nonIdKeys = Object.keys(rowValue).filter(\n (k) => k !== tableIdColumn,\n );\n\n const fields = nonIdKeys.map((c) => `${c} = prev.${c}`).join(\", \");\n\n const query = sql.raw(`\n UPDATE ${op.table_name}\n SET ${fields}\n FROM (\n SELECT * FROM json_populate_record(null::${op.table_name}, '${JSON.stringify(op.row_value)}'::json)\n ) as prev\n WHERE ${op.table_name}.${tableIdColumn} = '${op.row_id}'\n `);\n\n await tx.execute(query);\n } catch (error) {\n throw new DrizzleStorageError(\n \"Failed to invalidate | Operation - U\",\n {\n cause: error,\n },\n );\n }\n break;\n\n default: {\n throw new DrizzleStorageError(`Unknown operation: ${op.op}`);\n }\n }\n }\n}\n\nexport async function finalize<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n cursor: Cursor,\n indexerId: string,\n) {\n try {\n await tx.execute(\n sql.raw(`\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE cursor <= ${Number(cursor.orderKey)}\n AND indexer_id = '${indexerId}'\n `),\n );\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to finalize\", {\n cause: error,\n });\n }\n}\n\nexport async function cleanupStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n tx: PgTransaction<TQueryResult, TFullSchema, TSchema>,\n tables: string[],\n indexerId: string,\n) {\n try {\n for (const table of tables) {\n await tx.execute(\n sql.raw(\n `DROP TRIGGER IF EXISTS ${getReorgTriggerName(table, indexerId)} ON ${table};`,\n ),\n );\n }\n\n await tx.execute(\n sql.raw(`\n DELETE FROM ${SCHEMA_NAME}.${ROLLBACK_TABLE_NAME}\n WHERE indexer_id = '${indexerId}'\n `),\n );\n\n for (const table of tables) {\n try {\n await tx.execute(sql.raw(`TRUNCATE TABLE ${table} CASCADE;`));\n } catch (error) {\n throw new DrizzleStorageError(`Failed to truncate table ${table}`, {\n cause: error,\n });\n }\n }\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to clean up storage\", {\n cause: error,\n });\n }\n}\n","import { useIndexerContext } from \"@apibara/indexer\";\nimport { defineIndexerPlugin, useLogger } from \"@apibara/indexer/plugins\";\n\nimport type {\n ExtractTablesWithRelations,\n TablesRelationalConfig,\n} from \"drizzle-orm\";\n\nimport { generateIndexerId } from \"@apibara/indexer/internal\";\nimport { useInternalContext } from \"@apibara/indexer/internal/plugins\";\nimport type { Cursor, DataFinality } from \"@apibara/protocol\";\nimport type {\n PgDatabase,\n PgQueryResultHKT,\n PgTransaction,\n} from \"drizzle-orm/pg-core\";\nimport { DRIZZLE_PROPERTY, DRIZZLE_STORAGE_DB_PROPERTY } from \"./constants\";\nimport { type MigrateOptions, migrate } from \"./helper\";\nimport {\n finalizeState,\n getState,\n initializePersistentState,\n invalidateState,\n persistState,\n recordChainReorganization,\n resetPersistence,\n} from \"./persistence\";\nimport {\n cleanupStorage,\n finalize,\n initializeReorgRollbackTable,\n invalidate,\n registerTriggers,\n removeTriggers,\n} from \"./storage\";\nimport {\n DrizzleStorageError,\n type IdColumnMap,\n getIdColumnForTable,\n sleep,\n withTransaction,\n} from \"./utils\";\n\nexport * from \"./helper\";\n\nexport type { IdColumnMap };\n\nconst MAX_RETRIES = 5;\n\nexport type DrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n> = {\n db: PgTransaction<TQueryResult, TFullSchema, TSchema>;\n};\n\nexport function useDrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(\n _db?: PgDatabase<TQueryResult, TFullSchema, TSchema>,\n): DrizzleStorage<TQueryResult, TFullSchema, TSchema> {\n const context = useIndexerContext();\n\n if (!context[DRIZZLE_PROPERTY]) {\n throw new DrizzleStorageError(\n \"drizzle storage is not available. Did you register the plugin?\",\n );\n }\n\n return context[DRIZZLE_PROPERTY];\n}\n\nexport function useTestDrizzleStorage<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>(): PgDatabase<TQueryResult, TFullSchema, TSchema> {\n const context = useIndexerContext();\n\n if (!context[DRIZZLE_STORAGE_DB_PROPERTY]) {\n throw new DrizzleStorageError(\n \"drizzle storage db is not available. Did you register the plugin?\",\n );\n }\n\n return context[DRIZZLE_STORAGE_DB_PROPERTY];\n}\n\nexport interface DrizzleStorageOptions<\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n> {\n /**\n * The Drizzle database instance.\n */\n db: PgDatabase<TQueryResult, TFullSchema, TSchema>;\n /**\n * Whether to persist the indexer's state. Defaults to true.\n */\n persistState?: boolean;\n /**\n * The name of the indexer. Default value is 'default'.\n */\n indexerName?: string;\n /**\n * The schema of the database.\n */\n schema?: Record<string, unknown>;\n /**\n * The column to use as the primary identifier for each table.\n *\n * This identifier is used for tracking changes during reorgs and rollbacks.\n *\n * Can be specified in two ways:\n *\n * 1. As a single string that applies to all tables:\n * ```ts\n * idColumn: \"_id\" // Uses \"_id\" column for all tables\n * ```\n *\n * 2. As an object mapping table names to their ID columns:\n * ```ts\n * idColumn: {\n * transfers: \"transaction_hash\", // Use \"transaction_hash\" for transfers table\n * blocks: \"block_number\", // Use \"block_number\" for blocks table\n * \"*\": \"_id\" // Use \"_id\" for all other tables | defaults to \"id\"\n * }\n * ```\n *\n * The special \"*\" key acts as a fallback for any tables not explicitly mapped.\n *\n * @default \"id\"\n * @type {string | Partial<IdColumnMap>}\n */\n idColumn?: string | Partial<IdColumnMap>;\n /**\n * The options for the database migration. When provided, the database will automatically run migrations before the indexer runs.\n */\n migrate?: MigrateOptions;\n\n /**\n * Whether to record chain reorganizations in the database.\n * @default false\n */\n recordChainReorganizations?: boolean;\n}\n\n/**\n * Creates a plugin that uses Drizzle as the storage layer.\n *\n * Supports storing the indexer's state and provides a simple Key-Value store.\n * @param options.db - The Drizzle database instance.\n * @param options.persistState - Whether to persist the indexer's state. Defaults to true.\n * @param options.indexerName - The name of the indexer. Defaults value is 'default'.\n * @param options.schema - The schema of the database.\n * @param options.idColumn - The column to use as the id. Defaults to 'id'.\n * @param options.migrate - The options for the database migration. when provided, the database will automatically run migrations before the indexer runs.\n * @param options.recordChainReorganizations - Whether to record chain reorganizations in the database. Defaults to false.\n */\nexport function drizzleStorage<\n TFilter,\n TBlock,\n TQueryResult extends PgQueryResultHKT,\n TFullSchema extends Record<string, unknown> = Record<string, never>,\n TSchema extends\n TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,\n>({\n db,\n persistState: enablePersistence = true,\n indexerName: identifier = \"default\",\n schema: _schema,\n idColumn,\n migrate: migrateOptions,\n recordChainReorganizations = false,\n}: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>) {\n return defineIndexerPlugin<TFilter, TBlock>((indexer) => {\n let tableNames: string[] = [];\n let indexerId = \"\";\n const alwaysReindex = process.env[\"APIBARA_ALWAYS_REINDEX\"] === \"true\";\n let prevFinality: DataFinality | undefined;\n const schema: TSchema = (_schema as TSchema) ?? db._.schema ?? {};\n const idColumnMap: IdColumnMap = {\n \"*\": typeof idColumn === \"string\" ? idColumn : \"id\",\n ...(typeof idColumn === \"object\" ? idColumn : {}),\n };\n\n try {\n tableNames = Object.values(schema).map((table) => table.dbName);\n } catch (error) {\n throw new DrizzleStorageError(\"Failed to get table names from schema\", {\n cause: error,\n });\n }\n\n // Check if specified idColumn exists in all the tables in schema\n for (const table of Object.values(schema)) {\n const columns = table.columns;\n const tableIdColumn = getIdColumnForTable(table.dbName, idColumnMap);\n\n const columnExists = Object.values(columns).some(\n (column) => column.name === tableIdColumn,\n );\n\n if (!columnExists) {\n throw new DrizzleStorageError(\n `Column \\`\"${tableIdColumn}\"\\` does not exist in table \\`\"${table.dbName}\"\\`. ` +\n \"Make sure the table has the specified column or provide a valid `idColumn` mapping to `drizzleStorage`.\",\n );\n }\n }\n\n indexer.hooks.hook(\"plugins:init\", async () => {\n const internalContext = useInternalContext();\n const context = useIndexerContext();\n const logger = useLogger();\n\n // For testing purposes using vcr.\n context[DRIZZLE_STORAGE_DB_PROPERTY] = db;\n\n const { indexerName: indexerFileName, availableIndexers } =\n internalContext;\n\n indexerId = generateIndexerId(indexerFileName, identifier);\n\n let retries = 0;\n\n // incase the migrations are already applied, we don't want to run them again\n let migrationsApplied = false;\n let cleanupApplied = false;\n\n while (retries <= MAX_RETRIES) {\n try {\n if (migrateOptions && !migrationsApplied) {\n // @ts-ignore type mismatch for db\n await migrate(db, migrateOptions);\n migrationsApplied = true;\n logger.success(\"Migrations applied\");\n }\n await withTransaction(db, async (tx) => {\n await initializeReorgRollbackTable(tx, indexerId);\n if (enablePersistence) {\n await initializePersistentState(tx);\n }\n\n if (alwaysReindex && !cleanupApplied) {\n logger.warn(\n `Reindexing: Deleting all data from tables - ${tableNames.join(\", \")}`,\n );\n\n await cleanupStorage(tx, tableNames, indexerId);\n\n if (enablePersistence) {\n await resetPersistence({ tx, indexerId });\n }\n\n cleanupApplied = true;\n\n logger.success(\"Tables have been cleaned up for reindexing\");\n }\n });\n break;\n } catch (error) {\n if (retries === MAX_RETRIES) {\n if (error instanceof DrizzleStorageError) {\n throw error;\n }\n throw new DrizzleStorageError(\n \"Initialization failed after 5 retries\",\n {\n cause: error,\n },\n );\n }\n await sleep(retries * 1000);\n retries++;\n }\n }\n });\n\n indexer.hooks.hook(\"connect:before\", async ({ request }) => {\n if (!enablePersistence) {\n return;\n }\n\n await withTransaction(db, async (tx) => {\n const { cursor, filter } = await getState<\n TFilter,\n TQueryResult,\n TFullSchema,\n TSchema\n >({\n tx,\n indexerId,\n });\n if (cursor) {\n request.startingCursor = cursor;\n }\n if (filter) {\n request.filter[1] = filter;\n }\n });\n });\n\n indexer.hooks.hook(\"connect:after\", async ({ request }) => {\n // On restart, we need to invalidate data for blocks that were processed but not persisted.\n const cursor = request.startingCursor;\n\n if (!cursor) {\n return;\n }\n\n await withTransaction(db, async (tx) => {\n // Use the appropriate idColumn for each table when calling invalidate\n await invalidate(tx, cursor, idColumnMap, indexerId);\n\n if (enablePersistence) {\n await invalidateState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"connect:factory\", async ({ request, endCursor }) => {\n if (!enablePersistence) {\n return;\n }\n // We can call this hook because this hook is called inside the transaction of handler:middleware\n // so we have access to the transaction from the context\n const { db: tx } = useDrizzleStorage(db);\n\n if (endCursor && request.filter[1]) {\n await persistState({\n tx,\n endCursor,\n filter: request.filter[1],\n indexerId,\n });\n }\n });\n\n indexer.hooks.hook(\"message:finalize\", async ({ message }) => {\n const { cursor } = message;\n\n if (!cursor) {\n throw new DrizzleStorageError(\"Finalized Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n await finalize(tx, cursor, indexerId);\n\n if (enablePersistence) {\n await finalizeState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"message:invalidate\", async ({ message }) => {\n const { cursor } = message;\n\n if (!cursor) {\n throw new DrizzleStorageError(\"Invalidate Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n let oldHead: Cursor | undefined;\n\n if (recordChainReorganizations) {\n const { cursor: currentCursor } = await getState<\n TFilter,\n TQueryResult,\n TFullSchema,\n TSchema\n >({\n tx,\n indexerId,\n });\n oldHead = currentCursor;\n\n await recordChainReorganization({\n tx,\n indexerId,\n oldHead,\n newHead: cursor,\n });\n }\n\n await invalidate(tx, cursor, idColumnMap, indexerId);\n\n if (enablePersistence) {\n await invalidateState({ tx, cursor, indexerId });\n }\n });\n });\n\n indexer.hooks.hook(\"handler:middleware\", async ({ use }) => {\n use(async (context, next) => {\n try {\n const { endCursor, finality, cursor } = context as {\n cursor: Cursor;\n endCursor: Cursor;\n finality: DataFinality;\n };\n\n if (!endCursor) {\n throw new DrizzleStorageError(\"End Cursor is undefined\");\n }\n\n await withTransaction(db, async (tx) => {\n context[DRIZZLE_PROPERTY] = { db: tx } as DrizzleStorage<\n TQueryResult,\n TFullSchema,\n TSchema\n >;\n\n if (prevFinality === \"pending\") {\n // invalidate if previous block's finality was \"pending\"\n await invalidate(tx, cursor, idColumnMap, indexerId);\n }\n\n if (finality !== \"finalized\") {\n await registerTriggers(\n tx,\n tableNames,\n endCursor,\n idColumnMap,\n indexerId,\n );\n }\n\n await next();\n delete context[DRIZZLE_PROPERTY];\n\n if (enablePersistence && finality !== \"pending\") {\n await persistState({\n tx,\n endCursor,\n indexerId,\n });\n }\n\n prevFinality = finality;\n });\n\n if (finality !== \"finalized\") {\n // remove trigger outside of the transaction or it won't be triggered.\n await removeTriggers(db, tableNames, indexerId);\n }\n } catch (error) {\n await removeTriggers(db, tableNames, indexerId);\n\n throw error;\n }\n });\n });\n });\n}\n"],"names":["schema"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apibara/plugin-drizzle",
3
- "version": "2.1.0-beta.40",
3
+ "version": "2.1.0-beta.41",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -54,8 +54,8 @@
54
54
  "vitest": "^1.6.0"
55
55
  },
56
56
  "dependencies": {
57
- "@apibara/indexer": "2.1.0-beta.40",
58
- "@apibara/protocol": "2.1.0-beta.40",
57
+ "@apibara/indexer": "2.1.0-beta.41",
58
+ "@apibara/protocol": "2.1.0-beta.41",
59
59
  "postgres-range": "^1.1.4"
60
60
  }
61
61
  }
package/src/index.ts CHANGED
@@ -22,6 +22,7 @@ import {
22
22
  initializePersistentState,
23
23
  invalidateState,
24
24
  persistState,
25
+ recordChainReorganization,
25
26
  resetPersistence,
26
27
  } from "./persistence";
27
28
  import {
@@ -144,6 +145,12 @@ export interface DrizzleStorageOptions<
144
145
  * The options for the database migration. When provided, the database will automatically run migrations before the indexer runs.
145
146
  */
146
147
  migrate?: MigrateOptions;
148
+
149
+ /**
150
+ * Whether to record chain reorganizations in the database.
151
+ * @default false
152
+ */
153
+ recordChainReorganizations?: boolean;
147
154
  }
148
155
 
149
156
  /**
@@ -156,6 +163,7 @@ export interface DrizzleStorageOptions<
156
163
  * @param options.schema - The schema of the database.
157
164
  * @param options.idColumn - The column to use as the id. Defaults to 'id'.
158
165
  * @param options.migrate - The options for the database migration. when provided, the database will automatically run migrations before the indexer runs.
166
+ * @param options.recordChainReorganizations - Whether to record chain reorganizations in the database. Defaults to false.
159
167
  */
160
168
  export function drizzleStorage<
161
169
  TFilter,
@@ -171,6 +179,7 @@ export function drizzleStorage<
171
179
  schema: _schema,
172
180
  idColumn,
173
181
  migrate: migrateOptions,
182
+ recordChainReorganizations = false,
174
183
  }: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>) {
175
184
  return defineIndexerPlugin<TFilter, TBlock>((indexer) => {
176
185
  let tableNames: string[] = [];
@@ -360,7 +369,28 @@ export function drizzleStorage<
360
369
  }
361
370
 
362
371
  await withTransaction(db, async (tx) => {
363
- // Use the appropriate idColumn for each table when calling invalidate
372
+ let oldHead: Cursor | undefined;
373
+
374
+ if (recordChainReorganizations) {
375
+ const { cursor: currentCursor } = await getState<
376
+ TFilter,
377
+ TQueryResult,
378
+ TFullSchema,
379
+ TSchema
380
+ >({
381
+ tx,
382
+ indexerId,
383
+ });
384
+ oldHead = currentCursor;
385
+
386
+ await recordChainReorganization({
387
+ tx,
388
+ indexerId,
389
+ oldHead,
390
+ newHead: cursor,
391
+ });
392
+ }
393
+
364
394
  await invalidate(tx, cursor, idColumnMap, indexerId);
365
395
 
366
396
  if (enablePersistence) {
@@ -425,9 +455,7 @@ export function drizzleStorage<
425
455
  } catch (error) {
426
456
  await removeTriggers(db, tableNames, indexerId);
427
457
 
428
- throw new DrizzleStorageError("Failed to run handler:middleware", {
429
- cause: error,
430
- });
458
+ throw error;
431
459
  }
432
460
  });
433
461
  });
@@ -5,7 +5,14 @@ import type {
5
5
  TablesRelationalConfig,
6
6
  } from "drizzle-orm";
7
7
  import type { PgQueryResultHKT, PgTransaction } from "drizzle-orm/pg-core";
8
- import { integer, pgSchema, primaryKey, text } from "drizzle-orm/pg-core";
8
+ import {
9
+ integer,
10
+ pgSchema,
11
+ primaryKey,
12
+ serial,
13
+ text,
14
+ timestamp,
15
+ } from "drizzle-orm/pg-core";
9
16
  import { SCHEMA_NAME } from "./constants";
10
17
  import { DrizzleStorageError, deserialize, serialize } from "./utils";
11
18
 
@@ -38,6 +45,21 @@ export const filters = schema.table(
38
45
  ],
39
46
  );
40
47
 
48
+ /** Table for recording chain reorganizations */
49
+ export const chainReorganizations = schema.table("chain_reorganizations", {
50
+ id: serial("id").primaryKey(),
51
+ indexerId: text("indexer_id").notNull(),
52
+ oldHeadOrderKey: integer("old_head_order_key"),
53
+ oldHeadUniqueKey: text("old_head_unique_key")
54
+ .$type<string | null>()
55
+ .default(null),
56
+ newHeadOrderKey: integer("new_head_order_key").notNull(),
57
+ newHeadUniqueKey: text("new_head_unique_key")
58
+ .$type<string | null>()
59
+ .default(null),
60
+ recordedAt: timestamp("recorded_at").defaultNow().notNull(),
61
+ });
62
+
41
63
  /** This table is not used for migrations, its only used for ease of internal operations with drizzle. */
42
64
  export const schemaVersion = schema.table(SCHEMA_VERSION_TABLE_NAME, {
43
65
  k: integer("k").notNull().primaryKey(),
@@ -76,6 +98,27 @@ export async function initializePersistentState<
76
98
  `),
77
99
  );
78
100
 
101
+ await tx.execute(
102
+ sql.raw(`
103
+ CREATE TABLE IF NOT EXISTS ${SCHEMA_NAME}.chain_reorganizations (
104
+ id SERIAL PRIMARY KEY,
105
+ indexer_id TEXT NOT NULL,
106
+ old_head_order_key INTEGER,
107
+ old_head_unique_key TEXT DEFAULT NULL,
108
+ new_head_order_key INTEGER NOT NULL,
109
+ new_head_unique_key TEXT DEFAULT NULL,
110
+ recorded_at TIMESTAMP NOT NULL DEFAULT NOW()
111
+ );
112
+ `),
113
+ );
114
+
115
+ await tx.execute(
116
+ sql.raw(`
117
+ CREATE INDEX IF NOT EXISTS idx_chain_reorgs_indexer_id
118
+ ON ${SCHEMA_NAME}.chain_reorganizations(indexer_id);
119
+ `),
120
+ );
121
+
79
122
  // Get current schema version
80
123
  const versionRows = await tx
81
124
  .select()
@@ -147,6 +190,34 @@ export async function initializePersistentState<
147
190
  }
148
191
  }
149
192
 
193
+ export async function recordChainReorganization<
194
+ TQueryResult extends PgQueryResultHKT,
195
+ TFullSchema extends Record<string, unknown> = Record<string, never>,
196
+ TSchema extends
197
+ TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,
198
+ >(props: {
199
+ tx: PgTransaction<TQueryResult, TFullSchema, TSchema>;
200
+ indexerId: string;
201
+ oldHead: Cursor | undefined;
202
+ newHead: Cursor;
203
+ }) {
204
+ const { tx, indexerId, oldHead, newHead } = props;
205
+
206
+ try {
207
+ await tx.insert(chainReorganizations).values({
208
+ indexerId: indexerId,
209
+ oldHeadOrderKey: oldHead ? Number(oldHead.orderKey) : null,
210
+ oldHeadUniqueKey: oldHead?.uniqueKey ? oldHead.uniqueKey : null,
211
+ newHeadOrderKey: Number(newHead.orderKey),
212
+ newHeadUniqueKey: newHead.uniqueKey ? newHead.uniqueKey : null,
213
+ });
214
+ } catch (error) {
215
+ throw new DrizzleStorageError("Failed to record chain reorganization", {
216
+ cause: error,
217
+ });
218
+ }
219
+ }
220
+
150
221
  export async function persistState<
151
222
  TFilter,
152
223
  TQueryResult extends PgQueryResultHKT,
@@ -266,6 +337,14 @@ export async function invalidateState<
266
337
  const { tx, cursor, indexerId } = props;
267
338
 
268
339
  try {
340
+ await tx
341
+ .update(checkpoints)
342
+ .set({
343
+ orderKey: Number(cursor.orderKey),
344
+ uniqueKey: cursor.uniqueKey ? cursor.uniqueKey : null,
345
+ })
346
+ .where(eq(checkpoints.id, indexerId));
347
+
269
348
  await tx
270
349
  .delete(filters)
271
350
  .where(