@apibara/indexer 2.0.0-beta.9 → 2.1.0-beta.2

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.
Files changed (127) hide show
  1. package/dist/index.cjs +271 -39
  2. package/dist/index.d.cts +1 -16
  3. package/dist/index.d.mts +1 -16
  4. package/dist/index.d.ts +1 -16
  5. package/dist/index.mjs +262 -25
  6. package/dist/internal/index.cjs +10 -0
  7. package/dist/internal/index.d.cts +3 -0
  8. package/dist/internal/index.d.mts +3 -0
  9. package/dist/internal/index.d.ts +3 -0
  10. package/dist/internal/index.mjs +8 -0
  11. package/dist/internal/plugins.cjs +38 -0
  12. package/dist/internal/plugins.d.cts +13 -0
  13. package/dist/internal/plugins.d.mts +13 -0
  14. package/dist/internal/plugins.d.ts +13 -0
  15. package/dist/internal/plugins.mjs +34 -0
  16. package/dist/internal/testing.cjs +118 -0
  17. package/dist/internal/testing.d.cts +42 -0
  18. package/dist/internal/testing.d.mts +42 -0
  19. package/dist/internal/testing.d.ts +42 -0
  20. package/dist/internal/testing.mjs +113 -0
  21. package/dist/plugins/index.cjs +39 -3
  22. package/dist/plugins/index.d.cts +16 -2
  23. package/dist/plugins/index.d.mts +16 -2
  24. package/dist/plugins/index.d.ts +16 -2
  25. package/dist/plugins/index.mjs +36 -3
  26. package/dist/shared/indexer.077335f3.cjs +15 -0
  27. package/dist/shared/indexer.2416906c.cjs +29 -0
  28. package/dist/shared/indexer.601ceab0.cjs +7 -0
  29. package/dist/shared/indexer.9b21ddd2.mjs +5 -0
  30. package/dist/shared/indexer.a55ad619.mjs +12 -0
  31. package/dist/shared/indexer.fedcd831.d.cts +100 -0
  32. package/dist/shared/indexer.fedcd831.d.mts +100 -0
  33. package/dist/shared/indexer.fedcd831.d.ts +100 -0
  34. package/dist/shared/indexer.ff25c953.mjs +26 -0
  35. package/dist/testing/index.cjs +52 -50
  36. package/dist/testing/index.d.cts +8 -36
  37. package/dist/testing/index.d.mts +8 -36
  38. package/dist/testing/index.d.ts +8 -36
  39. package/dist/testing/index.mjs +47 -47
  40. package/dist/vcr/index.cjs +84 -17
  41. package/dist/vcr/index.d.cts +16 -7
  42. package/dist/vcr/index.d.mts +16 -7
  43. package/dist/vcr/index.d.ts +16 -7
  44. package/dist/vcr/index.mjs +75 -11
  45. package/package.json +22 -42
  46. package/src/compose.test.ts +76 -0
  47. package/src/compose.ts +71 -0
  48. package/src/context.ts +14 -8
  49. package/src/index.ts +0 -5
  50. package/src/indexer.test.ts +125 -186
  51. package/src/indexer.ts +278 -151
  52. package/src/internal/index.ts +6 -0
  53. package/src/internal/plugins.ts +1 -0
  54. package/src/internal/testing.ts +148 -0
  55. package/src/plugins/config.ts +4 -4
  56. package/src/plugins/context.ts +40 -0
  57. package/src/plugins/index.ts +8 -1
  58. package/src/plugins/logger.ts +30 -0
  59. package/src/plugins/persistence.ts +24 -187
  60. package/src/testing/index.ts +58 -3
  61. package/src/vcr/record.ts +5 -3
  62. package/src/vcr/replay.ts +8 -18
  63. package/dist/plugins/kv.cjs +0 -131
  64. package/dist/plugins/kv.d.cts +0 -32
  65. package/dist/plugins/kv.d.mts +0 -32
  66. package/dist/plugins/kv.d.ts +0 -32
  67. package/dist/plugins/kv.mjs +0 -124
  68. package/dist/plugins/persistence.cjs +0 -182
  69. package/dist/plugins/persistence.d.cts +0 -50
  70. package/dist/plugins/persistence.d.mts +0 -50
  71. package/dist/plugins/persistence.d.ts +0 -50
  72. package/dist/plugins/persistence.mjs +0 -179
  73. package/dist/shared/indexer.2c23c9cd.mjs +0 -35
  74. package/dist/shared/indexer.318d3617.cjs +0 -47
  75. package/dist/shared/indexer.36530330.mjs +0 -249
  76. package/dist/shared/indexer.500fd281.d.cts +0 -23
  77. package/dist/shared/indexer.541d43eb.cjs +0 -266
  78. package/dist/shared/indexer.93d6b2eb.mjs +0 -17
  79. package/dist/shared/indexer.a8b7ab1f.cjs +0 -25
  80. package/dist/shared/indexer.b9c8f0d8.d.cts +0 -19
  81. package/dist/shared/indexer.b9c8f0d8.d.mts +0 -19
  82. package/dist/shared/indexer.b9c8f0d8.d.ts +0 -19
  83. package/dist/shared/indexer.c7ed6b83.d.cts +0 -82
  84. package/dist/shared/indexer.e1856641.d.mts +0 -23
  85. package/dist/shared/indexer.e4f2430f.d.ts +0 -23
  86. package/dist/shared/indexer.e8bd138d.d.mts +0 -82
  87. package/dist/shared/indexer.f761abcd.d.ts +0 -82
  88. package/dist/sinks/csv.cjs +0 -85
  89. package/dist/sinks/csv.d.cts +0 -66
  90. package/dist/sinks/csv.d.mts +0 -66
  91. package/dist/sinks/csv.d.ts +0 -66
  92. package/dist/sinks/csv.mjs +0 -78
  93. package/dist/sinks/drizzle/index.cjs +0 -212
  94. package/dist/sinks/drizzle/index.d.cts +0 -153
  95. package/dist/sinks/drizzle/index.d.mts +0 -153
  96. package/dist/sinks/drizzle/index.d.ts +0 -153
  97. package/dist/sinks/drizzle/index.mjs +0 -198
  98. package/dist/sinks/sqlite.cjs +0 -90
  99. package/dist/sinks/sqlite.d.cts +0 -71
  100. package/dist/sinks/sqlite.d.mts +0 -71
  101. package/dist/sinks/sqlite.d.ts +0 -71
  102. package/dist/sinks/sqlite.mjs +0 -87
  103. package/src/hooks/index.ts +0 -2
  104. package/src/hooks/useKVStore.ts +0 -12
  105. package/src/hooks/useSink.ts +0 -13
  106. package/src/plugins/kv.test.ts +0 -120
  107. package/src/plugins/kv.ts +0 -132
  108. package/src/plugins/persistence.test.ts +0 -151
  109. package/src/sink.ts +0 -36
  110. package/src/sinks/csv.test.ts +0 -65
  111. package/src/sinks/csv.ts +0 -159
  112. package/src/sinks/drizzle/Int8Range.ts +0 -52
  113. package/src/sinks/drizzle/delete.ts +0 -42
  114. package/src/sinks/drizzle/drizzle.test.ts +0 -239
  115. package/src/sinks/drizzle/drizzle.ts +0 -115
  116. package/src/sinks/drizzle/index.ts +0 -6
  117. package/src/sinks/drizzle/insert.ts +0 -42
  118. package/src/sinks/drizzle/select.ts +0 -44
  119. package/src/sinks/drizzle/transaction.ts +0 -49
  120. package/src/sinks/drizzle/update.ts +0 -47
  121. package/src/sinks/drizzle/utils.ts +0 -99
  122. package/src/sinks/sqlite.test.ts +0 -99
  123. package/src/sinks/sqlite.ts +0 -170
  124. package/src/testing/helper.ts +0 -13
  125. package/src/testing/indexer.ts +0 -35
  126. package/src/testing/setup.ts +0 -59
  127. package/src/testing/vcr.ts +0 -54
@@ -1,239 +0,0 @@
1
- import type { Cursor } from "@apibara/protocol";
2
- import {
3
- type MockBlock,
4
- MockClient,
5
- type MockFilter,
6
- } from "@apibara/protocol/testing";
7
- import { asc, eq, sql } from "drizzle-orm";
8
- import { drizzle } from "drizzle-orm/node-postgres";
9
- import { serial, text } from "drizzle-orm/pg-core";
10
- import { Client } from "pg";
11
- import { beforeAll, beforeEach, describe, expect, it } from "vitest";
12
- import {
13
- type Int8Range,
14
- drizzle as drizzleSink,
15
- getDrizzleCursor,
16
- pgTable,
17
- } from ".";
18
- import { useSink } from "../../hooks";
19
- import { run } from "../../indexer";
20
- import { generateMockMessages } from "../../testing";
21
- import { getMockIndexer } from "../../testing/indexer";
22
-
23
- const testTable = pgTable("test_table", {
24
- id: serial("id").primaryKey(),
25
- data: text("data"),
26
- });
27
-
28
- const client = new Client({
29
- connectionString: "postgres://postgres:postgres@localhost:5432/postgres",
30
- });
31
-
32
- await client.connect();
33
-
34
- const db = drizzle(client);
35
-
36
- describe("Drizzle Test", () => {
37
- beforeAll(async () => {
38
- // drop test_table if exists
39
- await db.execute(sql`DROP TABLE IF EXISTS test_table`);
40
- // create test_table with db
41
- await db.execute(
42
- sql`CREATE TABLE test_table (id SERIAL PRIMARY KEY, data TEXT, _cursor INT8RANGE)`,
43
- );
44
- });
45
-
46
- beforeEach(async () => {
47
- await db.delete(testTable).execute();
48
- });
49
-
50
- it("should insert data", async () => {
51
- const client = new MockClient<MockFilter, MockBlock>((request, options) => {
52
- return generateMockMessages(5);
53
- });
54
-
55
- const sink = drizzleSink({ database: db, tables: [testTable] });
56
-
57
- const indexer = getMockIndexer({
58
- sink,
59
- override: {
60
- transform: async ({ context, endCursor, block: { data } }) => {
61
- const { db } = useSink({ context });
62
- // Insert a new row into the test_table
63
- // The id is set to the current cursor's orderKey
64
- // The data is set to the block data
65
- await db
66
- .insert(testTable)
67
- .values([{ id: Number(endCursor?.orderKey), data }]);
68
- },
69
- },
70
- });
71
-
72
- await run(client, indexer);
73
-
74
- const result = await db.select().from(testTable).orderBy(asc(testTable.id));
75
-
76
- expect(result).toHaveLength(5);
77
- expect(result[0].data).toBe("5000000");
78
- expect(result[2].data).toBe("5000002");
79
- });
80
-
81
- it("should update data", async () => {
82
- const client = new MockClient<MockFilter, MockBlock>((request, options) => {
83
- return generateMockMessages(5);
84
- });
85
-
86
- const sink = drizzleSink({ database: db, tables: [testTable] });
87
-
88
- const indexer = getMockIndexer({
89
- sink,
90
- override: {
91
- transform: async ({ context, endCursor, block: { data } }) => {
92
- const { db } = useSink({ context });
93
-
94
- // insert data for each message in db
95
- await db
96
- .insert(testTable)
97
- .values([{ id: Number(endCursor?.orderKey), data }]);
98
-
99
- // update data for id 5000002 when orderKey is 5000004
100
- // this is to test if the update query is working
101
- if (endCursor?.orderKey === 5000004n) {
102
- await db
103
- .update(testTable)
104
- .set({ data: "0000000" })
105
- .where(eq(testTable.id, 5000002));
106
- }
107
- },
108
- },
109
- });
110
-
111
- await run(client, indexer);
112
-
113
- const result = await db.select().from(testTable).orderBy(asc(testTable.id));
114
-
115
- expect(result).toHaveLength(5);
116
- expect(result[2].data).toBe("0000000");
117
- });
118
-
119
- it("should delete data", async () => {
120
- const client = new MockClient<MockFilter, MockBlock>((request, options) => {
121
- return generateMockMessages(5);
122
- });
123
-
124
- const sink = drizzleSink({ database: db, tables: [testTable] });
125
-
126
- const indexer = getMockIndexer({
127
- sink,
128
- override: {
129
- transform: async ({ context, endCursor, block: { data } }) => {
130
- const { db } = useSink({ context });
131
-
132
- // insert data for each message in db
133
- await db
134
- .insert(testTable)
135
- .values([{ id: Number(endCursor?.orderKey), data }]);
136
-
137
- // delete data for id 5000002 when orderKey is 5000004
138
- // this is to test if the delete query is working
139
- if (endCursor?.orderKey === 5000004n) {
140
- await db.delete(testTable).where(eq(testTable.id, 5000002));
141
- }
142
- },
143
- },
144
- });
145
-
146
- await run(client, indexer);
147
-
148
- const result = await db.select().from(testTable).orderBy(asc(testTable.id));
149
-
150
- expect(result).toHaveLength(5);
151
-
152
- // as when you run delete query on a data, it isnt literally deleted from the db,
153
- // instead, we just update the upper bound of that row to the current cursor
154
- // check if the cursor upper bound has been set correctly
155
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
156
- expect(((result[2] as any)._cursor as Int8Range).range.upper).toBe(5000004);
157
- });
158
-
159
- it("should select data", async () => {
160
- const client = new MockClient<MockFilter, MockBlock>((request, options) => {
161
- return generateMockMessages(5);
162
- });
163
-
164
- const sink = drizzleSink({ database: db, tables: [testTable] });
165
-
166
- let result: (typeof testTable.$inferSelect)[] = [];
167
-
168
- const indexer = getMockIndexer({
169
- sink,
170
- override: {
171
- transform: async ({ context, endCursor, block: { data } }) => {
172
- const { db } = useSink({ context });
173
-
174
- // insert data for each message in db
175
- await db
176
- .insert(testTable)
177
- .values([{ id: Number(endCursor?.orderKey), data }]);
178
-
179
- // delete data for id 5000002 when orderKey is 5000004
180
- // this will update the upper bound of the row with id 5000002 from infinity to 5000004
181
- // so when we select all rows, row with id 5000002 will not be included
182
- // as when we run select query it should only return rows with upper bound infinity
183
- if (endCursor?.orderKey === 5000003n) {
184
- await db.delete(testTable).where(eq(testTable.id, 5000002));
185
- }
186
-
187
- // when on last message of mock stream, select all rows from db
188
- if (endCursor?.orderKey === 5000004n) {
189
- result = await db
190
- .select()
191
- .from(testTable)
192
- .orderBy(asc(testTable.id));
193
- }
194
- },
195
- },
196
- });
197
-
198
- await run(client, indexer);
199
-
200
- expect(result).toHaveLength(4);
201
- expect(result.find((r) => r.id === 5000002)).toBeUndefined();
202
- // check if all rows are still in db
203
- const allRows = await db.select().from(testTable);
204
- expect(allRows).toHaveLength(5);
205
- });
206
-
207
- it("should invalidate data correctly", async () => {
208
- const sink = drizzleSink({ database: db, tables: [testTable] });
209
-
210
- // Insert some test data
211
- await db.insert(testTable).values(
212
- // @ts-ignore
213
- [
214
- { id: 1, data: "data1", _cursor: getDrizzleCursor([1n, 5n]) },
215
- { id: 2, data: "data2", _cursor: getDrizzleCursor([2n, 5n]) },
216
- { id: 3, data: "data3", _cursor: getDrizzleCursor(3n) },
217
- { id: 4, data: "data4", _cursor: getDrizzleCursor(4n) },
218
- { id: 5, data: "data5", _cursor: getDrizzleCursor(5n) },
219
- ],
220
- );
221
-
222
- // Create a cursor at position 3
223
- const cursor: Cursor = { orderKey: 3n };
224
-
225
- // Invalidate data
226
- await sink.invalidate(cursor);
227
-
228
- // Check the results
229
- const result = await db.select().from(testTable).orderBy(asc(testTable.id));
230
-
231
- expect(result).toHaveLength(3);
232
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
233
- expect(((result[0] as any)._cursor as Int8Range).range.upper).toBe(null);
234
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
235
- expect(((result[1] as any)._cursor as Int8Range).range.upper).toBe(null);
236
- // biome-ignore lint/suspicious/noExplicitAny: <explanation>
237
- expect(((result[2] as any)._cursor as Int8Range).range.upper).toBe(null);
238
- });
239
- });
@@ -1,115 +0,0 @@
1
- import type { Cursor } from "@apibara/protocol";
2
- import {
3
- type ExtractTablesWithRelations,
4
- type TablesRelationalConfig,
5
- gt,
6
- sql,
7
- } from "drizzle-orm";
8
- import type {
9
- AnyPgTable,
10
- PgDatabase,
11
- PgQueryResultHKT,
12
- PgTableWithColumns,
13
- TableConfig,
14
- } from "drizzle-orm/pg-core";
15
- import { Sink, type SinkCursorParams } from "../../sink";
16
- import { DrizzleSinkTransaction } from "./transaction";
17
-
18
- export type DrizzleSinkTables<
19
- TTableConfig extends Record<string, TableConfig>,
20
- > = {
21
- [K in keyof TTableConfig]: PgTableWithColumns<TTableConfig[K]>;
22
- };
23
-
24
- export type DrizzleSinkOptions<
25
- TQueryResult extends PgQueryResultHKT,
26
- TFullSchema extends Record<string, unknown> = Record<string, never>,
27
- TSchema extends
28
- TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,
29
- > = {
30
- /**
31
- * Database instance of drizzle-orm
32
- */
33
- database: PgDatabase<TQueryResult, TFullSchema, TSchema>;
34
- tables: AnyPgTable[];
35
- };
36
-
37
- /**
38
- * A sink that writes data to a PostgreSQL database using Drizzle ORM.
39
- *
40
- * @example
41
- *
42
- * ```ts
43
- * const sink = drizzle({
44
- * database: db,
45
- * });
46
- *
47
- * ...
48
- * async transform({context, endCursor}){
49
- * const { transaction } = useSink(context);
50
- * const db = transaction(endCursor);
51
- *
52
- * db.insert(users).values([
53
- * { id: 1, name: "John" },
54
- * { id: 2, name: "Jane" },
55
- * ]);
56
- * }
57
- *
58
- * ```
59
- */
60
- export class DrizzleSink<
61
- TQueryResult extends PgQueryResultHKT,
62
- TFullSchema extends Record<string, unknown> = Record<string, never>,
63
- TSchema extends
64
- TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,
65
- > extends Sink {
66
- private _db: PgDatabase<TQueryResult, TFullSchema, TSchema>;
67
- private _tables: AnyPgTable[];
68
- constructor(options: DrizzleSinkOptions<TQueryResult, TFullSchema, TSchema>) {
69
- super();
70
- const { database, tables } = options;
71
- this._db = database;
72
- this._tables = tables;
73
- }
74
-
75
- async transaction(
76
- { cursor, endCursor, finality }: SinkCursorParams,
77
- cb: (params: {
78
- db: DrizzleSinkTransaction<TQueryResult, TFullSchema, TSchema>;
79
- }) => Promise<void>,
80
- ): Promise<void> {
81
- await this._db.transaction(async (db) => {
82
- await cb({ db: new DrizzleSinkTransaction(db, endCursor) });
83
- });
84
- }
85
-
86
- async invalidate(cursor?: Cursor) {
87
- await this._db.transaction(async (db) => {
88
- for (const table of this._tables) {
89
- // delete all rows whose lowerbound of "_cursor" (int8range) column is greater than the invalidate cursor
90
- await db
91
- .delete(table)
92
- .where(gt(sql`lower(_cursor)`, sql`${Number(cursor?.orderKey)}`))
93
- .returning();
94
- // and for rows whose upperbound of "_cursor" (int8range) column is greater than the invalidate cursor, set the upperbound to infinity
95
- await db
96
- .update(table)
97
- .set({
98
- _cursor: sql`int8range(lower(_cursor), NULL, '[)')`,
99
- })
100
- .where(gt(sql`upper(_cursor)`, sql`${Number(cursor?.orderKey)}`));
101
- }
102
- });
103
- }
104
- }
105
-
106
- export const drizzle = <
107
- TQueryResult extends PgQueryResultHKT,
108
- TFullSchema extends Record<string, unknown> = Record<string, never>,
109
- TSchema extends
110
- TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,
111
- >(
112
- args: DrizzleSinkOptions<TQueryResult, TFullSchema, TSchema>,
113
- ) => {
114
- return new DrizzleSink(args);
115
- };
@@ -1,6 +0,0 @@
1
- export * from "./drizzle";
2
- export * from "./Int8Range";
3
- export * from "./utils";
4
- export * from "./transaction";
5
- export * from "./update";
6
- export * from "./delete";
@@ -1,42 +0,0 @@
1
- import type { Cursor } from "@apibara/protocol";
2
- import type {
3
- ExtractTablesWithRelations,
4
- TablesRelationalConfig,
5
- } from "drizzle-orm";
6
- import type {
7
- PgInsertValue as DrizzleInsertValue,
8
- PgQueryResultHKT,
9
- PgTable,
10
- PgTransaction,
11
- } from "drizzle-orm/pg-core";
12
- import { type PgInsertValue, getDrizzleCursor } from "./utils";
13
-
14
- export class DrizzleSinkInsert<
15
- TTable extends PgTable,
16
- TQueryResult extends PgQueryResultHKT,
17
- TFullSchema extends Record<string, unknown> = Record<string, never>,
18
- TSchema extends
19
- TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,
20
- > {
21
- constructor(
22
- private db: PgTransaction<TQueryResult, TFullSchema, TSchema>,
23
- private table: TTable,
24
- private endCursor?: Cursor,
25
- ) {}
26
-
27
- values(values: PgInsertValue<TTable> | PgInsertValue<TTable>[]) {
28
- const originalInsert = this.db.insert(this.table);
29
- const cursoredValues = (Array.isArray(values) ? values : [values]).map(
30
- (v) => {
31
- return {
32
- ...v,
33
- _cursor: getDrizzleCursor(this.endCursor?.orderKey),
34
- };
35
- },
36
- );
37
-
38
- return originalInsert.values(
39
- cursoredValues as DrizzleInsertValue<TTable>[],
40
- );
41
- }
42
- }
@@ -1,44 +0,0 @@
1
- import type { Cursor } from "@apibara/protocol";
2
- import {
3
- type ExtractTablesWithRelations,
4
- type SQL,
5
- type Subquery,
6
- type TablesRelationalConfig,
7
- sql,
8
- } from "drizzle-orm";
9
- import type {
10
- PgQueryResultHKT,
11
- PgTable,
12
- PgTransaction,
13
- SelectedFields,
14
- } from "drizzle-orm/pg-core";
15
- import type { PgViewBase } from "drizzle-orm/pg-core/view-base";
16
-
17
- export class DrizzleSinkSelect<
18
- TSelection extends SelectedFields,
19
- TQueryResult extends PgQueryResultHKT,
20
- TFullSchema extends Record<string, unknown> = Record<string, never>,
21
- TSchema extends
22
- TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,
23
- > {
24
- constructor(
25
- private db: PgTransaction<TQueryResult, TFullSchema, TSchema>,
26
- private fields?: TSelection,
27
- private endCursor?: Cursor,
28
- ) {}
29
-
30
- from<TFrom extends PgTable | Subquery | PgViewBase | SQL>(source: TFrom) {
31
- if (this.fields) {
32
- const originalFrom = this.db.select(this.fields).from(source);
33
- return {
34
- ...originalFrom,
35
- where: (where?: SQL) => {
36
- const combinedWhere = sql`${where ? sql`${where} AND ` : sql``}upper_inf(_cursor)`;
37
- return originalFrom.where(combinedWhere);
38
- },
39
- };
40
- }
41
-
42
- return this.db.select().from(source).where(sql`upper_inf(_cursor)`);
43
- }
44
- }
@@ -1,49 +0,0 @@
1
- import type { Cursor } from "@apibara/protocol";
2
- import type {
3
- ExtractTablesWithRelations,
4
- TablesRelationalConfig,
5
- } from "drizzle-orm";
6
- import type {
7
- PgQueryResultHKT,
8
- PgSelectBuilder,
9
- PgTable,
10
- PgTransaction,
11
- SelectedFields,
12
- } from "drizzle-orm/pg-core";
13
- import { DrizzleSinkDelete } from "./delete";
14
- import { DrizzleSinkInsert } from "./insert";
15
- import { DrizzleSinkSelect } from "./select";
16
- import { DrizzleSinkUpdate } from "./update";
17
-
18
- export class DrizzleSinkTransaction<
19
- TQueryResult extends PgQueryResultHKT,
20
- TFullSchema extends Record<string, unknown> = Record<string, never>,
21
- TSchema extends
22
- TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,
23
- > {
24
- constructor(
25
- private db: PgTransaction<TQueryResult, TFullSchema, TSchema>,
26
- private endCursor?: Cursor,
27
- ) {}
28
-
29
- insert<TTable extends PgTable>(table: TTable) {
30
- return new DrizzleSinkInsert(this.db, table, this.endCursor);
31
- }
32
-
33
- update<TTable extends PgTable>(table: TTable) {
34
- return new DrizzleSinkUpdate(this.db, table, this.endCursor);
35
- }
36
-
37
- delete<TTable extends PgTable>(table: TTable) {
38
- return new DrizzleSinkDelete(this.db, table, this.endCursor);
39
- }
40
-
41
- // @ts-ignore
42
- select(): PgSelectBuilder<undefined>;
43
- select<TSelection extends SelectedFields>(
44
- fields: TSelection,
45
- ): PgSelectBuilder<TSelection>;
46
- select(fields?: SelectedFields) {
47
- return new DrizzleSinkSelect(this.db, fields, this.endCursor);
48
- }
49
- }
@@ -1,47 +0,0 @@
1
- import type { Cursor } from "@apibara/protocol";
2
- import {
3
- type ExtractTablesWithRelations,
4
- type SQL,
5
- type TablesRelationalConfig,
6
- sql,
7
- } from "drizzle-orm";
8
- import type {
9
- PgQueryResultHKT,
10
- PgTable,
11
- PgTransaction,
12
- PgUpdateBase,
13
- PgUpdateSetSource,
14
- } from "drizzle-orm/pg-core";
15
-
16
- export class DrizzleSinkUpdate<
17
- TTable extends PgTable,
18
- TQueryResult extends PgQueryResultHKT,
19
- TFullSchema extends Record<string, unknown> = Record<string, never>,
20
- TSchema extends
21
- TablesRelationalConfig = ExtractTablesWithRelations<TFullSchema>,
22
- > {
23
- constructor(
24
- private db: PgTransaction<TQueryResult, TFullSchema, TSchema>,
25
- private table: TTable,
26
- private endCursor?: Cursor,
27
- ) {}
28
-
29
- set(values: PgUpdateSetSource<TTable>): PgUpdateBase<TTable, TQueryResult> {
30
- const originalUpdate = this.db.update(this.table);
31
- const originalSet = originalUpdate.set(values);
32
- return {
33
- ...originalSet,
34
- where: async (where: SQL | undefined) => {
35
- await this.db
36
- .update(this.table)
37
- .set({
38
- _cursor: sql`int8range(lower(_cursor), ${Number(this.endCursor?.orderKey!)}, '[)')`,
39
- } as PgUpdateSetSource<TTable>)
40
- .where(sql`${where ? sql`${where} AND ` : sql``}upper_inf(_cursor)`)
41
- .execute();
42
-
43
- return originalSet.where(where);
44
- },
45
- } as PgUpdateBase<TTable, TQueryResult>;
46
- }
47
- }
@@ -1,99 +0,0 @@
1
- import type {
2
- BuildColumns,
3
- BuildExtraConfigColumns,
4
- NotNull,
5
- Placeholder,
6
- SQL,
7
- } from "drizzle-orm";
8
- import type {
9
- PgColumnBuilderBase,
10
- PgCustomColumnBuilder,
11
- PgTable,
12
- PgTableExtraConfig,
13
- PgTableWithColumns,
14
- } from "drizzle-orm/pg-core";
15
- import { pgTable as drizzlePgTable } from "drizzle-orm/pg-core";
16
- import range from "postgres-range";
17
- import { Int8Range, int8range } from "./Int8Range";
18
-
19
- export type CursorColumnBuilder = NotNull<
20
- PgCustomColumnBuilder<{
21
- name: "_cursor";
22
- dataType: "custom";
23
- columnType: "PgCustomColumn";
24
- data: Int8Range;
25
- driverParam: undefined;
26
- enumValues: undefined;
27
- generated: undefined;
28
- }>
29
- >;
30
-
31
- // Redefining the type of `pgTable` to include the `_cursor` column.
32
- export type PgTableWithCursorFn<
33
- TSchema extends string | undefined = undefined,
34
- > = <
35
- TTableName extends string,
36
- TColumnsMap extends Record<string, PgColumnBuilderBase>,
37
- >(
38
- name: TTableName,
39
- columns: TColumnsMap,
40
- extraConfig?: (
41
- self: BuildExtraConfigColumns<
42
- TTableName,
43
- TColumnsMap & { _cursor: CursorColumnBuilder },
44
- "pg"
45
- >,
46
- ) => PgTableExtraConfig,
47
- ) => PgTableWithColumns<{
48
- name: TTableName;
49
- schema: TSchema;
50
- columns: BuildColumns<
51
- TTableName,
52
- TColumnsMap & { _cursor: CursorColumnBuilder },
53
- "pg"
54
- >;
55
- dialect: "pg";
56
- }>;
57
-
58
- // Same as the drizzle's `PgInsertValue` type, but without the `_cursor` column.
59
- export type PgInsertValue<TTable extends PgTable> = Omit<
60
- {
61
- [Key in keyof TTable["$inferInsert"]]:
62
- | TTable["$inferInsert"][Key]
63
- | SQL
64
- | Placeholder;
65
- } & {},
66
- "_cursor"
67
- >;
68
-
69
- export const pgTable: PgTableWithCursorFn = (name, columns, extraConfig?) => {
70
- return drizzlePgTable(
71
- name,
72
- {
73
- ...columns,
74
- _cursor: int8range("_cursor").notNull(),
75
- },
76
- extraConfig,
77
- );
78
- };
79
-
80
- export const getDrizzleCursor = (
81
- cursor_range: [bigint | undefined, bigint | undefined] | bigint | undefined,
82
- ) => {
83
- const isArray = Array.isArray(cursor_range);
84
- const [lower, upper] = isArray ? cursor_range : [cursor_range, undefined];
85
- let isNoUpperBound = false;
86
- if (!lower) {
87
- throw new Error("Lower bound cursor is required");
88
- }
89
- if (!upper) {
90
- isNoUpperBound = true;
91
- }
92
- return new Int8Range(
93
- new range.Range(
94
- Number(lower),
95
- Number(upper),
96
- range.RANGE_LB_INC | (isNoUpperBound ? range.RANGE_UB_INF : 0),
97
- ),
98
- );
99
- };