@apibara/plugin-drizzle 2.0.0-beta.28 → 2.0.0-beta.29

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
@@ -1,14 +1,545 @@
1
1
  'use strict';
2
2
 
3
+ const indexer = require('@apibara/indexer');
4
+ const plugins = require('@apibara/indexer/plugins');
5
+ const drizzleOrm = require('drizzle-orm');
6
+ const pgCore = require('drizzle-orm/pg-core');
7
+
3
8
  class DrizzleStorageError extends Error {
4
- constructor(message) {
5
- super(message);
9
+ constructor(message, options) {
10
+ super(message, options);
6
11
  this.name = "DrizzleStorageError";
7
12
  }
8
13
  }
14
+ async function withTransaction(db, cb) {
15
+ return await db.transaction(async (txnDb) => {
16
+ return await cb(txnDb);
17
+ });
18
+ }
19
+ function deserialize(str) {
20
+ return JSON.parse(
21
+ str,
22
+ (_, value) => typeof value === "string" && value.match(/^\d+n$/) ? BigInt(value.slice(0, -1)) : value
23
+ );
24
+ }
25
+ function serialize(obj) {
26
+ return JSON.stringify(
27
+ obj,
28
+ (_, value) => typeof value === "bigint" ? `${value.toString()}n` : value,
29
+ " "
30
+ );
31
+ }
32
+
33
+ const CHECKPOINTS_TABLE_NAME = "__indexer_checkpoints";
34
+ const FILTERS_TABLE_NAME = "__indexer_filters";
35
+ const SCHEMA_VERSION_TABLE_NAME = "__indexer_schema_version";
36
+ const checkpoints = pgCore.pgTable(CHECKPOINTS_TABLE_NAME, {
37
+ id: pgCore.text("id").notNull().primaryKey(),
38
+ orderKey: pgCore.integer("order_key").notNull(),
39
+ uniqueKey: pgCore.text("unique_key").$type().notNull().default(void 0)
40
+ });
41
+ const filters = pgCore.pgTable(
42
+ FILTERS_TABLE_NAME,
43
+ {
44
+ id: pgCore.text("id").notNull(),
45
+ filter: pgCore.text("filter").notNull(),
46
+ fromBlock: pgCore.integer("from_block").notNull(),
47
+ toBlock: pgCore.integer("to_block").$type().default(null)
48
+ },
49
+ (table) => [
50
+ {
51
+ pk: pgCore.primaryKey({ columns: [table.id, table.fromBlock] })
52
+ }
53
+ ]
54
+ );
55
+ const schemaVersion = pgCore.pgTable(SCHEMA_VERSION_TABLE_NAME, {
56
+ k: pgCore.integer("k").notNull().primaryKey(),
57
+ version: pgCore.integer("version").notNull()
58
+ });
59
+ const CURRENT_SCHEMA_VERSION = 0;
60
+ const MIGRATIONS = [
61
+ // migrations[0]: v0 -> v1 (for future use)
62
+ []
63
+ // Add more migration arrays for future versions
64
+ ];
65
+ async function initializePersistentState(tx) {
66
+ await tx.execute(`
67
+ CREATE TABLE IF NOT EXISTS ${SCHEMA_VERSION_TABLE_NAME} (
68
+ k INTEGER PRIMARY KEY,
69
+ version INTEGER NOT NULL
70
+ );
71
+ `);
72
+ const versionRows = await tx.select().from(schemaVersion).where(drizzleOrm.eq(schemaVersion.k, 0));
73
+ const storedVersion = versionRows[0]?.version ?? -1;
74
+ if (storedVersion > CURRENT_SCHEMA_VERSION) {
75
+ throw new DrizzleStorageError(
76
+ `Database Persistence schema version v${storedVersion} is newer than supported version v${CURRENT_SCHEMA_VERSION}`
77
+ );
78
+ }
79
+ try {
80
+ if (storedVersion === -1) {
81
+ await tx.execute(`
82
+ CREATE TABLE IF NOT EXISTS ${CHECKPOINTS_TABLE_NAME} (
83
+ id TEXT PRIMARY KEY,
84
+ order_key INTEGER NOT NULL,
85
+ unique_key TEXT NOT NULL DEFAULT ''
86
+ );
87
+ `);
88
+ await tx.execute(`
89
+ CREATE TABLE IF NOT EXISTS ${FILTERS_TABLE_NAME} (
90
+ id TEXT NOT NULL,
91
+ filter TEXT NOT NULL,
92
+ from_block INTEGER NOT NULL,
93
+ to_block INTEGER DEFAULT NULL,
94
+ PRIMARY KEY (id, from_block)
95
+ );
96
+ `);
97
+ await tx.insert(schemaVersion).values({
98
+ k: 0,
99
+ version: CURRENT_SCHEMA_VERSION
100
+ });
101
+ } else {
102
+ let currentVersion = storedVersion;
103
+ while (currentVersion < CURRENT_SCHEMA_VERSION) {
104
+ const migrationStatements = MIGRATIONS[currentVersion];
105
+ for (const statement of migrationStatements) {
106
+ await tx.execute(statement);
107
+ }
108
+ currentVersion++;
109
+ }
110
+ await tx.update(schemaVersion).set({ version: CURRENT_SCHEMA_VERSION }).where(drizzleOrm.eq(schemaVersion.k, 0));
111
+ }
112
+ } catch (error) {
113
+ throw new DrizzleStorageError(
114
+ "Failed to initialize or migrate database schema",
115
+ { cause: error }
116
+ );
117
+ }
118
+ }
119
+ async function persistState(props) {
120
+ const { tx, endCursor, filter, indexerName } = props;
121
+ try {
122
+ if (endCursor) {
123
+ await tx.insert(checkpoints).values({
124
+ id: indexerName,
125
+ orderKey: Number(endCursor.orderKey),
126
+ uniqueKey: endCursor.uniqueKey
127
+ }).onConflictDoUpdate({
128
+ target: checkpoints.id,
129
+ set: {
130
+ orderKey: Number(endCursor.orderKey),
131
+ uniqueKey: endCursor.uniqueKey
132
+ }
133
+ });
134
+ if (filter) {
135
+ await tx.update(filters).set({ toBlock: Number(endCursor.orderKey) }).where(drizzleOrm.and(drizzleOrm.eq(filters.id, indexerName), drizzleOrm.isNull(filters.toBlock)));
136
+ await tx.insert(filters).values({
137
+ id: indexerName,
138
+ filter: serialize(filter),
139
+ fromBlock: Number(endCursor.orderKey),
140
+ toBlock: null
141
+ }).onConflictDoUpdate({
142
+ target: [filters.id, filters.fromBlock],
143
+ set: {
144
+ filter: serialize(filter),
145
+ fromBlock: Number(endCursor.orderKey),
146
+ toBlock: null
147
+ }
148
+ });
149
+ }
150
+ }
151
+ } catch (error) {
152
+ throw new DrizzleStorageError("Failed to persist state", {
153
+ cause: error
154
+ });
155
+ }
156
+ }
157
+ async function getState(props) {
158
+ const { tx, indexerName } = props;
159
+ try {
160
+ const checkpointRows = await tx.select().from(checkpoints).where(drizzleOrm.eq(checkpoints.id, indexerName));
161
+ const cursor = checkpointRows[0] ? {
162
+ orderKey: BigInt(checkpointRows[0].orderKey),
163
+ uniqueKey: checkpointRows[0].uniqueKey
164
+ } : void 0;
165
+ const filterRows = await tx.select().from(filters).where(drizzleOrm.and(drizzleOrm.eq(filters.id, indexerName), drizzleOrm.isNull(filters.toBlock)));
166
+ const filter = filterRows[0] ? deserialize(filterRows[0].filter) : void 0;
167
+ return { cursor, filter };
168
+ } catch (error) {
169
+ throw new DrizzleStorageError("Failed to get persistent state", {
170
+ cause: error
171
+ });
172
+ }
173
+ }
174
+ async function invalidateState(props) {
175
+ const { tx, cursor, indexerName } = props;
176
+ try {
177
+ await tx.delete(filters).where(
178
+ drizzleOrm.and(
179
+ drizzleOrm.eq(filters.id, indexerName),
180
+ drizzleOrm.gt(filters.fromBlock, Number(cursor.orderKey))
181
+ )
182
+ );
183
+ await tx.update(filters).set({ toBlock: null }).where(
184
+ drizzleOrm.and(
185
+ drizzleOrm.eq(filters.id, indexerName),
186
+ drizzleOrm.gt(filters.toBlock, Number(cursor.orderKey))
187
+ )
188
+ );
189
+ } catch (error) {
190
+ throw new DrizzleStorageError("Failed to invalidate state", {
191
+ cause: error
192
+ });
193
+ }
194
+ }
195
+ async function finalizeState(props) {
196
+ const { tx, cursor, indexerName } = props;
197
+ try {
198
+ await tx.delete(filters).where(
199
+ drizzleOrm.and(
200
+ drizzleOrm.eq(filters.id, indexerName),
201
+ drizzleOrm.lt(filters.toBlock, Number(cursor.orderKey))
202
+ )
203
+ );
204
+ } catch (error) {
205
+ throw new DrizzleStorageError("Failed to finalize state", {
206
+ cause: error
207
+ });
208
+ }
209
+ }
9
210
 
10
- function drizzleStorage() {
11
- throw new DrizzleStorageError("Not implemented");
211
+ pgCore.pgTable("__reorg_rollback", {
212
+ n: pgCore.serial("n").primaryKey(),
213
+ op: pgCore.char("op", { length: 1 }).$type().notNull(),
214
+ table_name: pgCore.text("table_name").notNull(),
215
+ cursor: pgCore.integer("cursor").notNull(),
216
+ row_id: pgCore.text("row_id"),
217
+ row_value: pgCore.jsonb("row_value")
218
+ });
219
+ async function initializeReorgRollbackTable(tx) {
220
+ try {
221
+ await tx.execute(
222
+ drizzleOrm.sql.raw(`
223
+ CREATE TABLE IF NOT EXISTS __reorg_rollback(
224
+ n SERIAL PRIMARY KEY,
225
+ op CHAR(1) NOT NULL,
226
+ table_name TEXT NOT NULL,
227
+ cursor INTEGER NOT NULL,
228
+ row_id TEXT,
229
+ row_value JSONB
230
+ );
231
+ `)
232
+ );
233
+ await tx.execute(
234
+ drizzleOrm.sql.raw(`
235
+ CREATE OR REPLACE FUNCTION reorg_checkpoint()
236
+ RETURNS TRIGGER AS $$
237
+ DECLARE
238
+ id_col TEXT := TG_ARGV[0]::TEXT;
239
+ order_key INTEGER := TG_ARGV[1]::INTEGER;
240
+ new_id_value TEXT := row_to_json(NEW.*)->>id_col;
241
+ old_id_value TEXT := row_to_json(OLD.*)->>id_col;
242
+ BEGIN
243
+ IF (TG_OP = 'DELETE') THEN
244
+ INSERT INTO __reorg_rollback(op, table_name, cursor, row_id, row_value)
245
+ SELECT 'D', TG_TABLE_NAME, order_key, old_id_value, row_to_json(OLD.*);
246
+ ELSIF (TG_OP = 'UPDATE') THEN
247
+ INSERT INTO __reorg_rollback(op, table_name, cursor, row_id, row_value)
248
+ SELECT 'U', TG_TABLE_NAME, order_key, new_id_value, row_to_json(OLD.*);
249
+ ELSIF (TG_OP = 'INSERT') THEN
250
+ INSERT INTO __reorg_rollback(op, table_name, cursor, row_id, row_value)
251
+ SELECT 'I', TG_TABLE_NAME, order_key, new_id_value, null;
252
+ END IF;
253
+ RETURN NULL;
254
+ END;
255
+ $$ LANGUAGE plpgsql;
256
+ `)
257
+ );
258
+ } catch (error) {
259
+ throw new DrizzleStorageError("Failed to initialize reorg rollback table", {
260
+ cause: error
261
+ });
262
+ }
263
+ }
264
+ async function registerTriggers(tx, tables, endCursor, idColumn) {
265
+ try {
266
+ for (const table of tables) {
267
+ await tx.execute(
268
+ drizzleOrm.sql.raw(`DROP TRIGGER IF EXISTS ${table}_reorg ON ${table};`)
269
+ );
270
+ await tx.execute(
271
+ drizzleOrm.sql.raw(`
272
+ CREATE CONSTRAINT TRIGGER ${table}_reorg
273
+ AFTER INSERT OR UPDATE OR DELETE ON ${table}
274
+ DEFERRABLE INITIALLY DEFERRED
275
+ FOR EACH ROW EXECUTE FUNCTION reorg_checkpoint('${idColumn}', ${`${Number(endCursor.orderKey)}`});
276
+ `)
277
+ );
278
+ }
279
+ } catch (error) {
280
+ throw new DrizzleStorageError("Failed to register triggers", {
281
+ cause: error
282
+ });
283
+ }
284
+ }
285
+ async function removeTriggers(db, tables) {
286
+ try {
287
+ for (const table of tables) {
288
+ await db.execute(
289
+ drizzleOrm.sql.raw(`DROP TRIGGER IF EXISTS ${table}_reorg ON ${table};`)
290
+ );
291
+ }
292
+ } catch (error) {
293
+ throw new DrizzleStorageError("Failed to remove triggers", {
294
+ cause: error
295
+ });
296
+ }
297
+ }
298
+ async function invalidate(tx, cursor, idColumn) {
299
+ const { rows: result } = await tx.execute(
300
+ drizzleOrm.sql.raw(`
301
+ WITH deleted AS (
302
+ DELETE FROM __reorg_rollback
303
+ WHERE cursor > ${Number(cursor.orderKey)}
304
+ RETURNING *
305
+ )
306
+ SELECT * FROM deleted ORDER BY n DESC;
307
+ `)
308
+ );
309
+ if (!Array.isArray(result)) {
310
+ throw new DrizzleStorageError(
311
+ "Invalid result format from reorg_rollback query"
312
+ );
313
+ }
314
+ for (const op of result) {
315
+ switch (op.op) {
316
+ case "I":
317
+ try {
318
+ if (!op.row_id) {
319
+ throw new DrizzleStorageError("Insert operation has no row_id");
320
+ }
321
+ await tx.execute(
322
+ drizzleOrm.sql.raw(`
323
+ DELETE FROM ${op.table_name}
324
+ WHERE ${idColumn} = '${op.row_id}'
325
+ `)
326
+ );
327
+ } catch (error) {
328
+ throw new DrizzleStorageError(
329
+ "Failed to invalidate | Operation - I",
330
+ {
331
+ cause: error
332
+ }
333
+ );
334
+ }
335
+ break;
336
+ case "D":
337
+ try {
338
+ if (!op.row_value) {
339
+ throw new DrizzleStorageError("Delete operation has no row_value");
340
+ }
341
+ await tx.execute(
342
+ drizzleOrm.sql.raw(`
343
+ INSERT INTO ${op.table_name}
344
+ SELECT * FROM json_populate_record(null::${op.table_name}, '${JSON.stringify(op.row_value)}'::json)
345
+ `)
346
+ );
347
+ } catch (error) {
348
+ throw new DrizzleStorageError(
349
+ "Failed to invalidate | Operation - D",
350
+ {
351
+ cause: error
352
+ }
353
+ );
354
+ }
355
+ break;
356
+ case "U":
357
+ try {
358
+ if (!op.row_value || !op.row_id) {
359
+ throw new DrizzleStorageError(
360
+ "Update operation has no row_value or row_id"
361
+ );
362
+ }
363
+ const rowValue = typeof op.row_value === "string" ? JSON.parse(op.row_value) : op.row_value;
364
+ const nonIdKeys = Object.keys(rowValue).filter((k) => k !== idColumn);
365
+ const fields = nonIdKeys.map((c) => `${c} = prev.${c}`).join(", ");
366
+ const query = drizzleOrm.sql.raw(`
367
+ UPDATE ${op.table_name}
368
+ SET ${fields}
369
+ FROM (
370
+ SELECT * FROM json_populate_record(null::${op.table_name}, '${JSON.stringify(op.row_value)}'::json)
371
+ ) as prev
372
+ WHERE ${op.table_name}.${idColumn} = '${op.row_id}'
373
+ `);
374
+ await tx.execute(query);
375
+ } catch (error) {
376
+ throw new DrizzleStorageError(
377
+ "Failed to invalidate | Operation - U",
378
+ {
379
+ cause: error
380
+ }
381
+ );
382
+ }
383
+ break;
384
+ default: {
385
+ throw new DrizzleStorageError(`Unknown operation: ${op.op}`);
386
+ }
387
+ }
388
+ }
389
+ }
390
+ async function finalize(tx, cursor) {
391
+ try {
392
+ await tx.execute(
393
+ drizzleOrm.sql.raw(`
394
+ DELETE FROM __reorg_rollback
395
+ WHERE cursor <= ${Number(cursor.orderKey)}
396
+ `)
397
+ );
398
+ } catch (error) {
399
+ throw new DrizzleStorageError("Failed to finalize", {
400
+ cause: error
401
+ });
402
+ }
403
+ }
404
+
405
+ const DRIZZLE_PROPERTY = "_drizzle";
406
+ function useDrizzleStorage(_db) {
407
+ const context = indexer.useIndexerContext();
408
+ if (!context[DRIZZLE_PROPERTY]) {
409
+ throw new DrizzleStorageError(
410
+ "drizzle storage is not available. Did you register the plugin?"
411
+ );
412
+ }
413
+ return context[DRIZZLE_PROPERTY];
414
+ }
415
+ function drizzleStorage({
416
+ db,
417
+ persistState: enablePersistence = true,
418
+ indexerName = "default",
419
+ schema,
420
+ idColumn = "id"
421
+ }) {
422
+ return plugins.defineIndexerPlugin((indexer) => {
423
+ let tableNames = [];
424
+ try {
425
+ tableNames = Object.values(schema ?? db._.schema ?? {}).map(
426
+ (table) => table.dbName
427
+ );
428
+ } catch (error) {
429
+ throw new DrizzleStorageError("Failed to get table names from schema", {
430
+ cause: error
431
+ });
432
+ }
433
+ indexer.hooks.hook("run:before", async () => {
434
+ await withTransaction(db, async (tx) => {
435
+ await initializeReorgRollbackTable(tx);
436
+ if (enablePersistence) {
437
+ await initializePersistentState(tx);
438
+ }
439
+ });
440
+ });
441
+ indexer.hooks.hook("connect:before", async ({ request }) => {
442
+ if (!enablePersistence) {
443
+ return;
444
+ }
445
+ await withTransaction(db, async (tx) => {
446
+ const { cursor, filter } = await getState({
447
+ tx,
448
+ indexerName
449
+ });
450
+ if (cursor) {
451
+ request.startingCursor = cursor;
452
+ }
453
+ if (filter) {
454
+ request.filter[1] = filter;
455
+ }
456
+ });
457
+ });
458
+ indexer.hooks.hook("connect:after", async ({ request }) => {
459
+ const cursor = request.startingCursor;
460
+ if (!cursor) {
461
+ return;
462
+ }
463
+ await withTransaction(db, async (tx) => {
464
+ await invalidate(tx, cursor, idColumn);
465
+ if (enablePersistence) {
466
+ await invalidateState({ tx, cursor, indexerName });
467
+ }
468
+ });
469
+ });
470
+ indexer.hooks.hook("connect:factory", async ({ request, endCursor }) => {
471
+ if (!enablePersistence) {
472
+ return;
473
+ }
474
+ const { db: tx } = useDrizzleStorage();
475
+ if (endCursor && request.filter[1]) {
476
+ await persistState({
477
+ tx,
478
+ endCursor,
479
+ filter: request.filter[1],
480
+ indexerName
481
+ });
482
+ }
483
+ });
484
+ indexer.hooks.hook("message:finalize", async ({ message }) => {
485
+ const { cursor } = message.finalize;
486
+ if (!cursor) {
487
+ throw new DrizzleStorageError("Finalized Cursor is undefined");
488
+ }
489
+ await withTransaction(db, async (tx) => {
490
+ await finalize(tx, cursor);
491
+ if (enablePersistence) {
492
+ await finalizeState({ tx, cursor, indexerName });
493
+ }
494
+ });
495
+ });
496
+ indexer.hooks.hook("message:invalidate", async ({ message }) => {
497
+ const { cursor } = message.invalidate;
498
+ if (!cursor) {
499
+ throw new DrizzleStorageError("Invalidate Cursor is undefined");
500
+ }
501
+ await withTransaction(db, async (tx) => {
502
+ await invalidate(tx, cursor, idColumn);
503
+ if (enablePersistence) {
504
+ await invalidateState({ tx, cursor, indexerName });
505
+ }
506
+ });
507
+ });
508
+ indexer.hooks.hook("handler:middleware", async ({ use }) => {
509
+ use(async (context, next) => {
510
+ try {
511
+ const { endCursor, finality } = context;
512
+ if (!endCursor) {
513
+ throw new DrizzleStorageError("End Cursor is undefined");
514
+ }
515
+ await withTransaction(db, async (tx) => {
516
+ context[DRIZZLE_PROPERTY] = { db: tx };
517
+ if (finality !== "finalized") {
518
+ await registerTriggers(tx, tableNames, endCursor, idColumn);
519
+ }
520
+ await next();
521
+ delete context[DRIZZLE_PROPERTY];
522
+ if (enablePersistence) {
523
+ await persistState({
524
+ tx,
525
+ endCursor,
526
+ indexerName
527
+ });
528
+ }
529
+ });
530
+ if (finality !== "finalized") {
531
+ await removeTriggers(db, tableNames);
532
+ }
533
+ } catch (error) {
534
+ await removeTriggers(db, tableNames);
535
+ throw new DrizzleStorageError("Failed to run handler:middleware", {
536
+ cause: error
537
+ });
538
+ }
539
+ });
540
+ });
541
+ });
12
542
  }
13
543
 
14
544
  exports.drizzleStorage = drizzleStorage;
545
+ exports.useDrizzleStorage = useDrizzleStorage;
package/dist/index.d.cts CHANGED
@@ -1,3 +1,28 @@
1
- declare function drizzleStorage<TFilter, TBlock>(): void;
1
+ import * as _apibara_indexer_plugins from '@apibara/indexer/plugins';
2
+ import { TablesRelationalConfig, ExtractTablesWithRelations } from 'drizzle-orm';
3
+ import { PgQueryResultHKT, PgTransaction, PgDatabase } from 'drizzle-orm/pg-core';
2
4
 
3
- export { drizzleStorage };
5
+ type DrizzleStorage<TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>> = {
6
+ db: PgTransaction<TQueryResult, TFullSchema, TSchema>;
7
+ };
8
+ declare function useDrizzleStorage<TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>>(_db?: PgDatabase<TQueryResult, TFullSchema, TSchema>): DrizzleStorage<TQueryResult, TFullSchema, TSchema>;
9
+ interface DrizzleStorageOptions<TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>> {
10
+ db: PgDatabase<TQueryResult, TFullSchema, TSchema>;
11
+ persistState?: boolean;
12
+ indexerName?: string;
13
+ schema?: Record<string, unknown>;
14
+ idColumn?: string;
15
+ }
16
+ /**
17
+ * Creates a plugin that uses Drizzle as the storage layer.
18
+ *
19
+ * Supports storing the indexer's state and provides a simple Key-Value store.
20
+ * @param options.db - The Drizzle database instance.
21
+ * @param options.persistState - Whether to persist the indexer's state. Defaults to true.
22
+ * @param options.indexerName - The name of the indexer. Defaults value is 'default'.
23
+ * @param options.schema - The schema of the database.
24
+ * @param options.idColumn - The column to use as the id. Defaults to 'id'.
25
+ */
26
+ 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, schema, idColumn, }: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>): _apibara_indexer_plugins.IndexerPlugin<TFilter, TBlock>;
27
+
28
+ export { type DrizzleStorage, type DrizzleStorageOptions, drizzleStorage, useDrizzleStorage };
package/dist/index.d.mts CHANGED
@@ -1,3 +1,28 @@
1
- declare function drizzleStorage<TFilter, TBlock>(): void;
1
+ import * as _apibara_indexer_plugins from '@apibara/indexer/plugins';
2
+ import { TablesRelationalConfig, ExtractTablesWithRelations } from 'drizzle-orm';
3
+ import { PgQueryResultHKT, PgTransaction, PgDatabase } from 'drizzle-orm/pg-core';
2
4
 
3
- export { drizzleStorage };
5
+ type DrizzleStorage<TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>> = {
6
+ db: PgTransaction<TQueryResult, TFullSchema, TSchema>;
7
+ };
8
+ declare function useDrizzleStorage<TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>>(_db?: PgDatabase<TQueryResult, TFullSchema, TSchema>): DrizzleStorage<TQueryResult, TFullSchema, TSchema>;
9
+ interface DrizzleStorageOptions<TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>> {
10
+ db: PgDatabase<TQueryResult, TFullSchema, TSchema>;
11
+ persistState?: boolean;
12
+ indexerName?: string;
13
+ schema?: Record<string, unknown>;
14
+ idColumn?: string;
15
+ }
16
+ /**
17
+ * Creates a plugin that uses Drizzle as the storage layer.
18
+ *
19
+ * Supports storing the indexer's state and provides a simple Key-Value store.
20
+ * @param options.db - The Drizzle database instance.
21
+ * @param options.persistState - Whether to persist the indexer's state. Defaults to true.
22
+ * @param options.indexerName - The name of the indexer. Defaults value is 'default'.
23
+ * @param options.schema - The schema of the database.
24
+ * @param options.idColumn - The column to use as the id. Defaults to 'id'.
25
+ */
26
+ 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, schema, idColumn, }: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>): _apibara_indexer_plugins.IndexerPlugin<TFilter, TBlock>;
27
+
28
+ export { type DrizzleStorage, type DrizzleStorageOptions, drizzleStorage, useDrizzleStorage };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,28 @@
1
- declare function drizzleStorage<TFilter, TBlock>(): void;
1
+ import * as _apibara_indexer_plugins from '@apibara/indexer/plugins';
2
+ import { TablesRelationalConfig, ExtractTablesWithRelations } from 'drizzle-orm';
3
+ import { PgQueryResultHKT, PgTransaction, PgDatabase } from 'drizzle-orm/pg-core';
2
4
 
3
- export { drizzleStorage };
5
+ type DrizzleStorage<TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>> = {
6
+ db: PgTransaction<TQueryResult, TFullSchema, TSchema>;
7
+ };
8
+ declare function useDrizzleStorage<TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>>(_db?: PgDatabase<TQueryResult, TFullSchema, TSchema>): DrizzleStorage<TQueryResult, TFullSchema, TSchema>;
9
+ interface DrizzleStorageOptions<TQueryResult extends PgQueryResultHKT, TFullSchema extends Record<string, unknown> = Record<string, never>, TSchema extends TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>> {
10
+ db: PgDatabase<TQueryResult, TFullSchema, TSchema>;
11
+ persistState?: boolean;
12
+ indexerName?: string;
13
+ schema?: Record<string, unknown>;
14
+ idColumn?: string;
15
+ }
16
+ /**
17
+ * Creates a plugin that uses Drizzle as the storage layer.
18
+ *
19
+ * Supports storing the indexer's state and provides a simple Key-Value store.
20
+ * @param options.db - The Drizzle database instance.
21
+ * @param options.persistState - Whether to persist the indexer's state. Defaults to true.
22
+ * @param options.indexerName - The name of the indexer. Defaults value is 'default'.
23
+ * @param options.schema - The schema of the database.
24
+ * @param options.idColumn - The column to use as the id. Defaults to 'id'.
25
+ */
26
+ 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, schema, idColumn, }: DrizzleStorageOptions<TQueryResult, TFullSchema, TSchema>): _apibara_indexer_plugins.IndexerPlugin<TFilter, TBlock>;
27
+
28
+ export { type DrizzleStorage, type DrizzleStorageOptions, drizzleStorage, useDrizzleStorage };