@apibara/plugin-sqlite 2.1.0-beta.20 → 2.1.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -49,45 +49,56 @@ function initializeKeyValueStore(db) {
49
49
  db.exec(statements$1.createTable);
50
50
  }
51
51
  class KeyValueStore {
52
- constructor(db, endCursor, finality, serialize, deserialize) {
52
+ constructor(db, endCursor, finality, serialize, deserialize, indexerId) {
53
53
  this.db = db;
54
54
  this.endCursor = endCursor;
55
55
  this.finality = finality;
56
56
  this.serialize = serialize;
57
57
  this.deserialize = deserialize;
58
+ this.indexerId = indexerId;
58
59
  assertInTransaction(db);
59
60
  }
60
61
  get(key) {
61
- const row = this.db.prepare(statements$1.get).get(key);
62
+ const row = this.db.prepare(statements$1.get).get(key, this.indexerId);
62
63
  return row ? this.deserialize(row.v) : void 0;
63
64
  }
64
65
  put(key, value) {
65
- this.db.prepare(statements$1.updateToBlock).run(Number(this.endCursor.orderKey), key);
66
- this.db.prepare(statements$1.insertIntoKvs).run(
66
+ this.db.prepare(statements$1.updateToBlock).run(Number(this.endCursor.orderKey), key, this.indexerId);
67
+ this.db.prepare(
68
+ statements$1.insertIntoKvs
69
+ ).run(
67
70
  Number(this.endCursor.orderKey),
68
71
  key,
69
- this.serialize(value)
72
+ this.serialize(value),
73
+ this.indexerId
70
74
  );
71
75
  }
72
76
  del(key) {
73
- this.db.prepare(statements$1.del).run(Number(this.endCursor.orderKey), key);
77
+ this.db.prepare(statements$1.del).run(Number(this.endCursor.orderKey), key, this.indexerId);
74
78
  }
75
79
  }
76
- function finalizeKV(db, cursor) {
80
+ function finalizeKV(db, cursor, indexerId) {
77
81
  assertInTransaction(db);
78
82
  db.prepare(statements$1.finalize).run(
79
- Number(cursor.orderKey)
83
+ Number(cursor.orderKey),
84
+ indexerId
80
85
  );
81
86
  }
82
- function invalidateKV(db, cursor) {
87
+ function invalidateKV(db, cursor, indexerId) {
83
88
  assertInTransaction(db);
84
89
  db.prepare(statements$1.invalidateDelete).run(
85
- Number(cursor.orderKey)
90
+ Number(cursor.orderKey),
91
+ indexerId
86
92
  );
87
93
  db.prepare(statements$1.invalidateUpdate).run(
88
- Number(cursor.orderKey)
94
+ Number(cursor.orderKey),
95
+ indexerId
89
96
  );
90
97
  }
98
+ function cleanupKV(db, indexerId) {
99
+ assertInTransaction(db);
100
+ db.prepare(statements$1.cleanup).run(indexerId);
101
+ }
91
102
  const statements$1 = {
92
103
  createTable: `
93
104
  CREATE TABLE IF NOT EXISTS kvs (
@@ -95,33 +106,37 @@ const statements$1 = {
95
106
  to_block INTEGER,
96
107
  k TEXT NOT NULL,
97
108
  v BLOB NOT NULL,
98
- PRIMARY KEY (from_block, k)
109
+ id TEXT NOT NULL,
110
+ PRIMARY KEY (from_block, k, id)
99
111
  );`,
100
112
  get: `
101
113
  SELECT v
102
114
  FROM kvs
103
- WHERE k = ? AND to_block IS NULL`,
115
+ WHERE k = ? AND id = ? AND to_block IS NULL`,
104
116
  updateToBlock: `
105
117
  UPDATE kvs
106
118
  SET to_block = ?
107
- WHERE k = ? AND to_block IS NULL`,
119
+ WHERE k = ? AND id = ? AND to_block IS NULL`,
108
120
  insertIntoKvs: `
109
- INSERT INTO kvs (from_block, to_block, k, v)
110
- VALUES (?, NULL, ?, ?)`,
121
+ INSERT INTO kvs (from_block, to_block, k, v, id)
122
+ VALUES (?, NULL, ?, ?, ?)`,
111
123
  del: `
112
124
  UPDATE kvs
113
125
  SET to_block = ?
114
- WHERE k = ? AND to_block IS NULL`,
126
+ WHERE k = ? AND id = ? AND to_block IS NULL`,
115
127
  finalize: `
116
128
  DELETE FROM kvs
117
- WHERE to_block <= ?`,
129
+ WHERE to_block <= ? AND id = ?`,
118
130
  invalidateDelete: `
119
131
  DELETE FROM kvs
120
- WHERE from_block > ?`,
132
+ WHERE from_block > ? AND id = ?`,
121
133
  invalidateUpdate: `
122
134
  UPDATE kvs
123
135
  SET to_block = NULL
124
- WHERE to_block > ?`
136
+ WHERE to_block > ? AND id = ?`,
137
+ cleanup: `
138
+ DELETE FROM kvs
139
+ WHERE id = ?`
125
140
  };
126
141
 
127
142
  function initializePersistentState(db) {
@@ -189,6 +204,12 @@ function invalidateState(props) {
189
204
  Number(cursor.orderKey)
190
205
  );
191
206
  }
207
+ function resetPersistence(props) {
208
+ const { db, indexerId } = props;
209
+ assertInTransaction(db);
210
+ db.prepare(statements.resetCheckpoint).run(indexerId);
211
+ db.prepare(statements.resetFilter).run(indexerId);
212
+ }
192
213
  const statements = {
193
214
  createCheckpointsTable: `
194
215
  CREATE TABLE IF NOT EXISTS checkpoints (
@@ -243,7 +264,13 @@ const statements = {
243
264
  invalidateFilterUpdate: `
244
265
  UPDATE filters
245
266
  SET to_block = NULL
246
- WHERE id = ? AND to_block > ?`
267
+ WHERE id = ? AND to_block > ?`,
268
+ resetCheckpoint: `
269
+ DELETE FROM checkpoints
270
+ WHERE id = ?`,
271
+ resetFilter: `
272
+ DELETE FROM filters
273
+ WHERE id = ?`
247
274
  };
248
275
 
249
276
  const KV_PROPERTY = "_kv_sqlite";
@@ -268,10 +295,13 @@ function sqliteStorage({
268
295
  return plugins.defineIndexerPlugin((indexer) => {
269
296
  let indexerId = "";
270
297
  let prevFinality;
298
+ const alwaysReindex = process.env["APIBARA_ALWAYS_REINDEX"] === "true";
271
299
  indexer.hooks.hook("run:before", async () => {
272
300
  const { indexerName: indexerFileName, availableIndexers } = plugins$1.useInternalContext();
301
+ const logger = plugins.useLogger();
273
302
  indexerId = internal.generateIndexerId(indexerFileName, identifier);
274
303
  let retries = 0;
304
+ let cleanupApplied = false;
275
305
  while (retries <= MAX_RETRIES) {
276
306
  try {
277
307
  await withTransaction(database, async (db) => {
@@ -281,6 +311,18 @@ function sqliteStorage({
281
311
  if (enableKeyValueStore) {
282
312
  initializeKeyValueStore(db);
283
313
  }
314
+ if (alwaysReindex && !cleanupApplied) {
315
+ if (enableKeyValueStore) {
316
+ logger.warn("Reindexing: Cleaning up key-value store");
317
+ cleanupKV(db, indexerId);
318
+ }
319
+ if (enablePersistState) {
320
+ logger.warn("Reindexing: Resetting persistence state");
321
+ resetPersistence({ db, indexerId });
322
+ }
323
+ cleanupApplied = true;
324
+ logger.success("All data has been cleaned up for reindexing");
325
+ }
284
326
  });
285
327
  break;
286
328
  } catch (error) {
@@ -321,7 +363,7 @@ function sqliteStorage({
321
363
  invalidateState({ db, cursor, indexerId });
322
364
  }
323
365
  if (enableKeyValueStore) {
324
- invalidateKV(db, cursor);
366
+ invalidateKV(db, cursor, indexerId);
325
367
  }
326
368
  });
327
369
  });
@@ -349,7 +391,7 @@ function sqliteStorage({
349
391
  finalizeState({ db, cursor, indexerId });
350
392
  }
351
393
  if (enableKeyValueStore) {
352
- finalizeKV(db, cursor);
394
+ finalizeKV(db, cursor, indexerId);
353
395
  }
354
396
  });
355
397
  });
@@ -363,7 +405,7 @@ function sqliteStorage({
363
405
  invalidateState({ db, cursor, indexerId });
364
406
  }
365
407
  if (enableKeyValueStore) {
366
- invalidateKV(db, cursor);
408
+ invalidateKV(db, cursor, indexerId);
367
409
  }
368
410
  });
369
411
  });
@@ -381,7 +423,7 @@ function sqliteStorage({
381
423
  await withTransaction(database, async (db) => {
382
424
  if (prevFinality === "pending") {
383
425
  if (enableKeyValueStore) {
384
- invalidateKV(db, cursor);
426
+ invalidateKV(db, cursor, indexerId);
385
427
  }
386
428
  }
387
429
  if (enableKeyValueStore) {
@@ -390,7 +432,8 @@ function sqliteStorage({
390
432
  endCursor,
391
433
  finality,
392
434
  serializeFn,
393
- deserializeFn
435
+ deserializeFn,
436
+ indexerId
394
437
  );
395
438
  }
396
439
  await next();
package/dist/index.d.cts CHANGED
@@ -11,7 +11,8 @@ declare class KeyValueStore {
11
11
  private readonly finality;
12
12
  private readonly serialize;
13
13
  private readonly deserialize;
14
- constructor(db: Database, endCursor: Cursor, finality: DataFinality, serialize: SerializeFn, deserialize: DeserializeFn);
14
+ private readonly indexerId;
15
+ constructor(db: Database, endCursor: Cursor, finality: DataFinality, serialize: SerializeFn, deserialize: DeserializeFn, indexerId: string);
15
16
  get<T>(key: string): T | undefined;
16
17
  put<T>(key: string, value: T): void;
17
18
  del(key: string): void;
package/dist/index.d.mts CHANGED
@@ -11,7 +11,8 @@ declare class KeyValueStore {
11
11
  private readonly finality;
12
12
  private readonly serialize;
13
13
  private readonly deserialize;
14
- constructor(db: Database, endCursor: Cursor, finality: DataFinality, serialize: SerializeFn, deserialize: DeserializeFn);
14
+ private readonly indexerId;
15
+ constructor(db: Database, endCursor: Cursor, finality: DataFinality, serialize: SerializeFn, deserialize: DeserializeFn, indexerId: string);
15
16
  get<T>(key: string): T | undefined;
16
17
  put<T>(key: string, value: T): void;
17
18
  del(key: string): void;
package/dist/index.d.ts CHANGED
@@ -11,7 +11,8 @@ declare class KeyValueStore {
11
11
  private readonly finality;
12
12
  private readonly serialize;
13
13
  private readonly deserialize;
14
- constructor(db: Database, endCursor: Cursor, finality: DataFinality, serialize: SerializeFn, deserialize: DeserializeFn);
14
+ private readonly indexerId;
15
+ constructor(db: Database, endCursor: Cursor, finality: DataFinality, serialize: SerializeFn, deserialize: DeserializeFn, indexerId: string);
15
16
  get<T>(key: string): T | undefined;
16
17
  put<T>(key: string, value: T): void;
17
18
  del(key: string): void;
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { useIndexerContext } from '@apibara/indexer';
2
- import { defineIndexerPlugin } from '@apibara/indexer/plugins';
2
+ import { defineIndexerPlugin, useLogger } from '@apibara/indexer/plugins';
3
3
  import { generateIndexerId } from '@apibara/indexer/internal';
4
4
  import { useInternalContext } from '@apibara/indexer/internal/plugins';
5
5
  import { normalizeCursor } from '@apibara/protocol';
@@ -47,45 +47,56 @@ function initializeKeyValueStore(db) {
47
47
  db.exec(statements$1.createTable);
48
48
  }
49
49
  class KeyValueStore {
50
- constructor(db, endCursor, finality, serialize, deserialize) {
50
+ constructor(db, endCursor, finality, serialize, deserialize, indexerId) {
51
51
  this.db = db;
52
52
  this.endCursor = endCursor;
53
53
  this.finality = finality;
54
54
  this.serialize = serialize;
55
55
  this.deserialize = deserialize;
56
+ this.indexerId = indexerId;
56
57
  assertInTransaction(db);
57
58
  }
58
59
  get(key) {
59
- const row = this.db.prepare(statements$1.get).get(key);
60
+ const row = this.db.prepare(statements$1.get).get(key, this.indexerId);
60
61
  return row ? this.deserialize(row.v) : void 0;
61
62
  }
62
63
  put(key, value) {
63
- this.db.prepare(statements$1.updateToBlock).run(Number(this.endCursor.orderKey), key);
64
- this.db.prepare(statements$1.insertIntoKvs).run(
64
+ this.db.prepare(statements$1.updateToBlock).run(Number(this.endCursor.orderKey), key, this.indexerId);
65
+ this.db.prepare(
66
+ statements$1.insertIntoKvs
67
+ ).run(
65
68
  Number(this.endCursor.orderKey),
66
69
  key,
67
- this.serialize(value)
70
+ this.serialize(value),
71
+ this.indexerId
68
72
  );
69
73
  }
70
74
  del(key) {
71
- this.db.prepare(statements$1.del).run(Number(this.endCursor.orderKey), key);
75
+ this.db.prepare(statements$1.del).run(Number(this.endCursor.orderKey), key, this.indexerId);
72
76
  }
73
77
  }
74
- function finalizeKV(db, cursor) {
78
+ function finalizeKV(db, cursor, indexerId) {
75
79
  assertInTransaction(db);
76
80
  db.prepare(statements$1.finalize).run(
77
- Number(cursor.orderKey)
81
+ Number(cursor.orderKey),
82
+ indexerId
78
83
  );
79
84
  }
80
- function invalidateKV(db, cursor) {
85
+ function invalidateKV(db, cursor, indexerId) {
81
86
  assertInTransaction(db);
82
87
  db.prepare(statements$1.invalidateDelete).run(
83
- Number(cursor.orderKey)
88
+ Number(cursor.orderKey),
89
+ indexerId
84
90
  );
85
91
  db.prepare(statements$1.invalidateUpdate).run(
86
- Number(cursor.orderKey)
92
+ Number(cursor.orderKey),
93
+ indexerId
87
94
  );
88
95
  }
96
+ function cleanupKV(db, indexerId) {
97
+ assertInTransaction(db);
98
+ db.prepare(statements$1.cleanup).run(indexerId);
99
+ }
89
100
  const statements$1 = {
90
101
  createTable: `
91
102
  CREATE TABLE IF NOT EXISTS kvs (
@@ -93,33 +104,37 @@ const statements$1 = {
93
104
  to_block INTEGER,
94
105
  k TEXT NOT NULL,
95
106
  v BLOB NOT NULL,
96
- PRIMARY KEY (from_block, k)
107
+ id TEXT NOT NULL,
108
+ PRIMARY KEY (from_block, k, id)
97
109
  );`,
98
110
  get: `
99
111
  SELECT v
100
112
  FROM kvs
101
- WHERE k = ? AND to_block IS NULL`,
113
+ WHERE k = ? AND id = ? AND to_block IS NULL`,
102
114
  updateToBlock: `
103
115
  UPDATE kvs
104
116
  SET to_block = ?
105
- WHERE k = ? AND to_block IS NULL`,
117
+ WHERE k = ? AND id = ? AND to_block IS NULL`,
106
118
  insertIntoKvs: `
107
- INSERT INTO kvs (from_block, to_block, k, v)
108
- VALUES (?, NULL, ?, ?)`,
119
+ INSERT INTO kvs (from_block, to_block, k, v, id)
120
+ VALUES (?, NULL, ?, ?, ?)`,
109
121
  del: `
110
122
  UPDATE kvs
111
123
  SET to_block = ?
112
- WHERE k = ? AND to_block IS NULL`,
124
+ WHERE k = ? AND id = ? AND to_block IS NULL`,
113
125
  finalize: `
114
126
  DELETE FROM kvs
115
- WHERE to_block <= ?`,
127
+ WHERE to_block <= ? AND id = ?`,
116
128
  invalidateDelete: `
117
129
  DELETE FROM kvs
118
- WHERE from_block > ?`,
130
+ WHERE from_block > ? AND id = ?`,
119
131
  invalidateUpdate: `
120
132
  UPDATE kvs
121
133
  SET to_block = NULL
122
- WHERE to_block > ?`
134
+ WHERE to_block > ? AND id = ?`,
135
+ cleanup: `
136
+ DELETE FROM kvs
137
+ WHERE id = ?`
123
138
  };
124
139
 
125
140
  function initializePersistentState(db) {
@@ -187,6 +202,12 @@ function invalidateState(props) {
187
202
  Number(cursor.orderKey)
188
203
  );
189
204
  }
205
+ function resetPersistence(props) {
206
+ const { db, indexerId } = props;
207
+ assertInTransaction(db);
208
+ db.prepare(statements.resetCheckpoint).run(indexerId);
209
+ db.prepare(statements.resetFilter).run(indexerId);
210
+ }
190
211
  const statements = {
191
212
  createCheckpointsTable: `
192
213
  CREATE TABLE IF NOT EXISTS checkpoints (
@@ -241,7 +262,13 @@ const statements = {
241
262
  invalidateFilterUpdate: `
242
263
  UPDATE filters
243
264
  SET to_block = NULL
244
- WHERE id = ? AND to_block > ?`
265
+ WHERE id = ? AND to_block > ?`,
266
+ resetCheckpoint: `
267
+ DELETE FROM checkpoints
268
+ WHERE id = ?`,
269
+ resetFilter: `
270
+ DELETE FROM filters
271
+ WHERE id = ?`
245
272
  };
246
273
 
247
274
  const KV_PROPERTY = "_kv_sqlite";
@@ -266,10 +293,13 @@ function sqliteStorage({
266
293
  return defineIndexerPlugin((indexer) => {
267
294
  let indexerId = "";
268
295
  let prevFinality;
296
+ const alwaysReindex = process.env["APIBARA_ALWAYS_REINDEX"] === "true";
269
297
  indexer.hooks.hook("run:before", async () => {
270
298
  const { indexerName: indexerFileName, availableIndexers } = useInternalContext();
299
+ const logger = useLogger();
271
300
  indexerId = generateIndexerId(indexerFileName, identifier);
272
301
  let retries = 0;
302
+ let cleanupApplied = false;
273
303
  while (retries <= MAX_RETRIES) {
274
304
  try {
275
305
  await withTransaction(database, async (db) => {
@@ -279,6 +309,18 @@ function sqliteStorage({
279
309
  if (enableKeyValueStore) {
280
310
  initializeKeyValueStore(db);
281
311
  }
312
+ if (alwaysReindex && !cleanupApplied) {
313
+ if (enableKeyValueStore) {
314
+ logger.warn("Reindexing: Cleaning up key-value store");
315
+ cleanupKV(db, indexerId);
316
+ }
317
+ if (enablePersistState) {
318
+ logger.warn("Reindexing: Resetting persistence state");
319
+ resetPersistence({ db, indexerId });
320
+ }
321
+ cleanupApplied = true;
322
+ logger.success("All data has been cleaned up for reindexing");
323
+ }
282
324
  });
283
325
  break;
284
326
  } catch (error) {
@@ -319,7 +361,7 @@ function sqliteStorage({
319
361
  invalidateState({ db, cursor, indexerId });
320
362
  }
321
363
  if (enableKeyValueStore) {
322
- invalidateKV(db, cursor);
364
+ invalidateKV(db, cursor, indexerId);
323
365
  }
324
366
  });
325
367
  });
@@ -347,7 +389,7 @@ function sqliteStorage({
347
389
  finalizeState({ db, cursor, indexerId });
348
390
  }
349
391
  if (enableKeyValueStore) {
350
- finalizeKV(db, cursor);
392
+ finalizeKV(db, cursor, indexerId);
351
393
  }
352
394
  });
353
395
  });
@@ -361,7 +403,7 @@ function sqliteStorage({
361
403
  invalidateState({ db, cursor, indexerId });
362
404
  }
363
405
  if (enableKeyValueStore) {
364
- invalidateKV(db, cursor);
406
+ invalidateKV(db, cursor, indexerId);
365
407
  }
366
408
  });
367
409
  });
@@ -379,7 +421,7 @@ function sqliteStorage({
379
421
  await withTransaction(database, async (db) => {
380
422
  if (prevFinality === "pending") {
381
423
  if (enableKeyValueStore) {
382
- invalidateKV(db, cursor);
424
+ invalidateKV(db, cursor, indexerId);
383
425
  }
384
426
  }
385
427
  if (enableKeyValueStore) {
@@ -388,7 +430,8 @@ function sqliteStorage({
388
430
  endCursor,
389
431
  finality,
390
432
  serializeFn,
391
- deserializeFn
433
+ deserializeFn,
434
+ indexerId
392
435
  );
393
436
  }
394
437
  await next();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apibara/plugin-sqlite",
3
- "version": "2.1.0-beta.20",
3
+ "version": "2.1.0-beta.21",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist",
@@ -36,7 +36,7 @@
36
36
  "better-sqlite3": "^9.0.0"
37
37
  },
38
38
  "dependencies": {
39
- "@apibara/indexer": "2.1.0-beta.20",
40
- "@apibara/protocol": "2.1.0-beta.20"
39
+ "@apibara/indexer": "2.1.0-beta.21",
40
+ "@apibara/protocol": "2.1.0-beta.21"
41
41
  }
42
42
  }
package/src/index.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { useIndexerContext } from "@apibara/indexer";
2
- import { defineIndexerPlugin } from "@apibara/indexer/plugins";
2
+ import { defineIndexerPlugin, useLogger } from "@apibara/indexer/plugins";
3
3
  import type { Cursor, DataFinality } from "@apibara/protocol";
4
4
  import type { Database as SqliteDatabase } from "better-sqlite3";
5
5
 
@@ -7,6 +7,7 @@ import { generateIndexerId } from "@apibara/indexer/internal";
7
7
  import { useInternalContext } from "@apibara/indexer/internal/plugins";
8
8
  import {
9
9
  KeyValueStore,
10
+ cleanupKV,
10
11
  finalizeKV,
11
12
  initializeKeyValueStore,
12
13
  invalidateKV,
@@ -17,6 +18,7 @@ import {
17
18
  initializePersistentState,
18
19
  invalidateState,
19
20
  persistState,
21
+ resetPersistence,
20
22
  } from "./persistence";
21
23
  import {
22
24
  type DeserializeFn,
@@ -77,15 +79,20 @@ export function sqliteStorage<TFilter, TBlock>({
77
79
  return defineIndexerPlugin<TFilter, TBlock>((indexer) => {
78
80
  let indexerId = "";
79
81
  let prevFinality: DataFinality | undefined;
82
+ const alwaysReindex = process.env["APIBARA_ALWAYS_REINDEX"] === "true";
80
83
 
81
84
  indexer.hooks.hook("run:before", async () => {
82
85
  const { indexerName: indexerFileName, availableIndexers } =
83
86
  useInternalContext();
84
87
 
88
+ const logger = useLogger();
89
+
85
90
  indexerId = generateIndexerId(indexerFileName, identifier);
86
91
 
87
92
  let retries = 0;
88
93
 
94
+ let cleanupApplied = false;
95
+
89
96
  while (retries <= MAX_RETRIES) {
90
97
  try {
91
98
  await withTransaction(database, async (db) => {
@@ -96,6 +103,22 @@ export function sqliteStorage<TFilter, TBlock>({
96
103
  if (enableKeyValueStore) {
97
104
  initializeKeyValueStore(db);
98
105
  }
106
+
107
+ if (alwaysReindex && !cleanupApplied) {
108
+ if (enableKeyValueStore) {
109
+ logger.warn("Reindexing: Cleaning up key-value store");
110
+ cleanupKV(db, indexerId);
111
+ }
112
+
113
+ if (enablePersistState) {
114
+ logger.warn("Reindexing: Resetting persistence state");
115
+ resetPersistence({ db, indexerId });
116
+ }
117
+
118
+ cleanupApplied = true;
119
+
120
+ logger.success("All data has been cleaned up for reindexing");
121
+ }
99
122
  });
100
123
  break;
101
124
  } catch (error) {
@@ -145,7 +168,7 @@ export function sqliteStorage<TFilter, TBlock>({
145
168
  }
146
169
 
147
170
  if (enableKeyValueStore) {
148
- invalidateKV(db, cursor);
171
+ invalidateKV(db, cursor, indexerId);
149
172
  }
150
173
  });
151
174
  });
@@ -182,7 +205,7 @@ export function sqliteStorage<TFilter, TBlock>({
182
205
  }
183
206
 
184
207
  if (enableKeyValueStore) {
185
- finalizeKV(db, cursor);
208
+ finalizeKV(db, cursor, indexerId);
186
209
  }
187
210
  });
188
211
  });
@@ -200,7 +223,7 @@ export function sqliteStorage<TFilter, TBlock>({
200
223
  }
201
224
 
202
225
  if (enableKeyValueStore) {
203
- invalidateKV(db, cursor);
226
+ invalidateKV(db, cursor, indexerId);
204
227
  }
205
228
  });
206
229
  });
@@ -227,7 +250,7 @@ export function sqliteStorage<TFilter, TBlock>({
227
250
  if (prevFinality === "pending") {
228
251
  // invalidate if previous block's finality was "pending"
229
252
  if (enableKeyValueStore) {
230
- invalidateKV(db, cursor);
253
+ invalidateKV(db, cursor, indexerId);
231
254
  }
232
255
  }
233
256
 
@@ -238,6 +261,7 @@ export function sqliteStorage<TFilter, TBlock>({
238
261
  finality,
239
262
  serializeFn,
240
263
  deserializeFn,
264
+ indexerId,
241
265
  );
242
266
  }
243
267
 
package/src/kv.ts CHANGED
@@ -19,64 +19,80 @@ export class KeyValueStore {
19
19
  private readonly finality: DataFinality,
20
20
  private readonly serialize: SerializeFn,
21
21
  private readonly deserialize: DeserializeFn,
22
+ private readonly indexerId: string,
22
23
  ) {
23
24
  assertInTransaction(db);
24
25
  }
25
26
 
26
27
  get<T>(key: string): T | undefined {
27
- const row = this.db.prepare<string, KeyValueRow>(statements.get).get(key);
28
+ const row = this.db
29
+ .prepare<[string, string], KeyValueRow>(statements.get)
30
+ .get(key, this.indexerId);
28
31
 
29
32
  return row ? this.deserialize(row.v) : undefined;
30
33
  }
31
34
 
32
35
  put<T>(key: string, value: T) {
33
36
  this.db
34
- .prepare<[number, string], KeyValueRow>(statements.updateToBlock)
35
- .run(Number(this.endCursor.orderKey), key);
37
+ .prepare<[number, string, string], KeyValueRow>(statements.updateToBlock)
38
+ .run(Number(this.endCursor.orderKey), key, this.indexerId);
36
39
 
37
40
  this.db
38
- .prepare<[number, string, string], KeyValueRow>(statements.insertIntoKvs)
41
+ .prepare<[number, string, string, string], KeyValueRow>(
42
+ statements.insertIntoKvs,
43
+ )
39
44
  .run(
40
45
  Number(this.endCursor.orderKey),
41
46
  key,
42
47
  this.serialize(value as Record<string, unknown>),
48
+ this.indexerId,
43
49
  );
44
50
  }
45
51
 
46
52
  del(key: string) {
47
53
  this.db
48
- .prepare<[number, string], KeyValueRow>(statements.del)
49
- .run(Number(this.endCursor.orderKey), key);
54
+ .prepare<[number, string, string], KeyValueRow>(statements.del)
55
+ .run(Number(this.endCursor.orderKey), key, this.indexerId);
50
56
  }
51
57
  }
52
58
 
53
- export function finalizeKV(db: Database, cursor: Cursor) {
59
+ export function finalizeKV(db: Database, cursor: Cursor, indexerId: string) {
54
60
  assertInTransaction(db);
55
61
 
56
- db.prepare<[number], KeyValueRow>(statements.finalize).run(
62
+ db.prepare<[number, string], KeyValueRow>(statements.finalize).run(
57
63
  Number(cursor.orderKey),
64
+ indexerId,
58
65
  );
59
66
  }
60
67
 
61
- export function invalidateKV(db: Database, cursor: Cursor) {
68
+ export function invalidateKV(db: Database, cursor: Cursor, indexerId: string) {
62
69
  assertInTransaction(db);
63
70
 
64
71
  // Delete entries that started after the invalidation cursor
65
- db.prepare<[number], KeyValueRow>(statements.invalidateDelete).run(
72
+ db.prepare<[number, string], KeyValueRow>(statements.invalidateDelete).run(
66
73
  Number(cursor.orderKey),
74
+ indexerId,
67
75
  );
68
76
 
69
77
  // Update entries that were supposed to end after the invalidation cursor
70
- db.prepare<[number], KeyValueRow>(statements.invalidateUpdate).run(
78
+ db.prepare<[number, string], KeyValueRow>(statements.invalidateUpdate).run(
71
79
  Number(cursor.orderKey),
80
+ indexerId,
72
81
  );
73
82
  }
74
83
 
84
+ export function cleanupKV(db: Database, indexerId: string) {
85
+ assertInTransaction(db);
86
+
87
+ db.prepare<[string], KeyValueRow>(statements.cleanup).run(indexerId);
88
+ }
89
+
75
90
  export type KeyValueRow = {
76
91
  from_block: number;
77
92
  to_block: number;
78
93
  k: string;
79
94
  v: string;
95
+ id: string;
80
96
  };
81
97
 
82
98
  const statements = {
@@ -86,31 +102,35 @@ const statements = {
86
102
  to_block INTEGER,
87
103
  k TEXT NOT NULL,
88
104
  v BLOB NOT NULL,
89
- PRIMARY KEY (from_block, k)
105
+ id TEXT NOT NULL,
106
+ PRIMARY KEY (from_block, k, id)
90
107
  );`,
91
108
  get: `
92
109
  SELECT v
93
110
  FROM kvs
94
- WHERE k = ? AND to_block IS NULL`,
111
+ WHERE k = ? AND id = ? AND to_block IS NULL`,
95
112
  updateToBlock: `
96
113
  UPDATE kvs
97
114
  SET to_block = ?
98
- WHERE k = ? AND to_block IS NULL`,
115
+ WHERE k = ? AND id = ? AND to_block IS NULL`,
99
116
  insertIntoKvs: `
100
- INSERT INTO kvs (from_block, to_block, k, v)
101
- VALUES (?, NULL, ?, ?)`,
117
+ INSERT INTO kvs (from_block, to_block, k, v, id)
118
+ VALUES (?, NULL, ?, ?, ?)`,
102
119
  del: `
103
120
  UPDATE kvs
104
121
  SET to_block = ?
105
- WHERE k = ? AND to_block IS NULL`,
122
+ WHERE k = ? AND id = ? AND to_block IS NULL`,
106
123
  finalize: `
107
124
  DELETE FROM kvs
108
- WHERE to_block <= ?`,
125
+ WHERE to_block <= ? AND id = ?`,
109
126
  invalidateDelete: `
110
127
  DELETE FROM kvs
111
- WHERE from_block > ?`,
128
+ WHERE from_block > ? AND id = ?`,
112
129
  invalidateUpdate: `
113
130
  UPDATE kvs
114
131
  SET to_block = NULL
115
- WHERE to_block > ?`,
116
- };
132
+ WHERE to_block > ? AND id = ?`,
133
+ cleanup: `
134
+ DELETE FROM kvs
135
+ WHERE id = ?`,
136
+ } as const;
@@ -100,6 +100,16 @@ export function invalidateState(props: {
100
100
  );
101
101
  }
102
102
 
103
+ export function resetPersistence(props: {
104
+ db: Database;
105
+ indexerId: string;
106
+ }) {
107
+ const { db, indexerId } = props;
108
+ assertInTransaction(db);
109
+ db.prepare<[string]>(statements.resetCheckpoint).run(indexerId);
110
+ db.prepare<[string]>(statements.resetFilter).run(indexerId);
111
+ }
112
+
103
113
  export type CheckpointRow = {
104
114
  id: string;
105
115
  order_key: number;
@@ -168,4 +178,10 @@ const statements = {
168
178
  UPDATE filters
169
179
  SET to_block = NULL
170
180
  WHERE id = ? AND to_block > ?`,
181
+ resetCheckpoint: `
182
+ DELETE FROM checkpoints
183
+ WHERE id = ?`,
184
+ resetFilter: `
185
+ DELETE FROM filters
186
+ WHERE id = ?`,
171
187
  };