ponder 0.16.5 → 0.16.7
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/CHANGELOG.md +16 -0
- package/dist/esm/bin/commands/createViews.js +5 -27
- package/dist/esm/bin/commands/createViews.js.map +1 -1
- package/dist/esm/build/schema.js +0 -7
- package/dist/esm/build/schema.js.map +1 -1
- package/dist/esm/database/actions.js +7 -55
- package/dist/esm/database/actions.js.map +1 -1
- package/dist/esm/drizzle/onchain.js +44 -0
- package/dist/esm/drizzle/onchain.js.map +1 -1
- package/dist/esm/graphql/index.js +33 -3
- package/dist/esm/graphql/index.js.map +1 -1
- package/dist/esm/indexing-store/cache.js +2 -2
- package/dist/esm/indexing-store/cache.js.map +1 -1
- package/dist/esm/indexing-store/index.js +1 -1
- package/dist/esm/indexing-store/index.js.map +1 -1
- package/dist/esm/indexing-store/utils.js +1 -1
- package/dist/esm/indexing-store/utils.js.map +1 -1
- package/dist/esm/utils/print.js +3 -2
- package/dist/esm/utils/print.js.map +1 -1
- package/dist/types/bin/commands/createViews.d.ts.map +1 -1
- package/dist/types/build/schema.d.ts.map +1 -1
- package/dist/types/database/actions.d.ts.map +1 -1
- package/dist/types/drizzle/onchain.d.ts +4 -0
- package/dist/types/drizzle/onchain.d.ts.map +1 -1
- package/dist/types/graphql/index.d.ts.map +1 -1
- package/dist/types/indexing-store/index.d.ts.map +1 -1
- package/dist/types/indexing-store/utils.d.ts.map +1 -1
- package/dist/types/utils/print.d.ts +3 -1
- package/dist/types/utils/print.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/bin/commands/createViews.ts +7 -27
- package/src/build/schema.ts +0 -11
- package/src/database/actions.ts +9 -55
- package/src/drizzle/onchain.ts +48 -0
- package/src/graphql/index.ts +42 -2
- package/src/indexing-store/cache.ts +2 -2
- package/src/indexing-store/index.ts +3 -1
- package/src/indexing-store/utils.ts +3 -1
- package/src/utils/print.ts +4 -1
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
import {
|
|
17
17
|
getLiveQueryChannelName,
|
|
18
18
|
getLiveQueryNotifyProcedureName,
|
|
19
|
-
|
|
19
|
+
getLiveQueryNotifyProcedureSql,
|
|
20
20
|
getViewsLiveQueryNotifyTriggerName,
|
|
21
21
|
} from "@/drizzle/onchain.js";
|
|
22
22
|
import { sql } from "@/index.js";
|
|
@@ -273,32 +273,12 @@ export async function createViews({
|
|
|
273
273
|
const channel = getLiveQueryChannelName(cliOptions.viewsSchema);
|
|
274
274
|
|
|
275
275
|
await database.adminQB.wrap((db) =>
|
|
276
|
-
db.execute(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
table_exists boolean := false;
|
|
283
|
-
BEGIN
|
|
284
|
-
SELECT EXISTS (
|
|
285
|
-
SELECT 1
|
|
286
|
-
FROM information_schema.tables
|
|
287
|
-
WHERE table_name = '${getLiveQueryTempTableName()}'
|
|
288
|
-
AND table_type = 'LOCAL TEMPORARY'
|
|
289
|
-
) INTO table_exists;
|
|
290
|
-
|
|
291
|
-
IF table_exists THEN
|
|
292
|
-
SELECT json_agg(table_name) INTO table_names
|
|
293
|
-
FROM ${getLiveQueryTempTableName()};
|
|
294
|
-
|
|
295
|
-
table_names := COALESCE(table_names, '[]'::json);
|
|
296
|
-
PERFORM pg_notify('${channel}', table_names::text);
|
|
297
|
-
END IF;
|
|
298
|
-
|
|
299
|
-
RETURN NULL;
|
|
300
|
-
END;
|
|
301
|
-
$$;`),
|
|
276
|
+
db.execute(
|
|
277
|
+
getLiveQueryNotifyProcedureSql({
|
|
278
|
+
schema: cliOptions.viewsSchema!,
|
|
279
|
+
channel,
|
|
280
|
+
}),
|
|
281
|
+
),
|
|
302
282
|
);
|
|
303
283
|
|
|
304
284
|
const trigger = getViewsLiveQueryNotifyTriggerName(cliOptions.viewsSchema);
|
package/src/build/schema.ts
CHANGED
|
@@ -27,11 +27,6 @@ import {
|
|
|
27
27
|
getViewConfig,
|
|
28
28
|
} from "drizzle-orm/pg-core";
|
|
29
29
|
|
|
30
|
-
/**
|
|
31
|
-
* @dev The maximum notify message size is 8KB (8000 / 63 > 100).
|
|
32
|
-
*/
|
|
33
|
-
const TABLE_LIMIT = 100;
|
|
34
|
-
|
|
35
30
|
export const buildSchema = ({
|
|
36
31
|
schema,
|
|
37
32
|
preBuild,
|
|
@@ -330,12 +325,6 @@ export const buildSchema = ({
|
|
|
330
325
|
}
|
|
331
326
|
}
|
|
332
327
|
|
|
333
|
-
if (tableNames.size > TABLE_LIMIT) {
|
|
334
|
-
throw new Error(
|
|
335
|
-
`Schema validation failed: the maximum number of tables is ${TABLE_LIMIT}.`,
|
|
336
|
-
);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
328
|
return { statements };
|
|
340
329
|
};
|
|
341
330
|
|
package/src/database/actions.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { getColumnCasing, getReorgTable } from "@/drizzle/kit/index.js";
|
|
|
3
3
|
import {
|
|
4
4
|
getLiveQueryChannelName,
|
|
5
5
|
getLiveQueryNotifyProcedureName,
|
|
6
|
+
getLiveQueryNotifyProcedureSql,
|
|
6
7
|
getLiveQueryNotifyTriggerName,
|
|
7
8
|
getLiveQueryProcedureName,
|
|
8
9
|
getLiveQueryTempTableName,
|
|
@@ -246,37 +247,10 @@ $$;`,
|
|
|
246
247
|
context,
|
|
247
248
|
);
|
|
248
249
|
|
|
249
|
-
const notifyProcedure = getLiveQueryNotifyProcedureName();
|
|
250
250
|
const channel = getLiveQueryChannelName(namespaceBuild.schema);
|
|
251
251
|
|
|
252
252
|
await tx.wrap(
|
|
253
|
-
(tx) =>
|
|
254
|
-
tx.execute(`
|
|
255
|
-
CREATE OR REPLACE FUNCTION "${schema}".${notifyProcedure}
|
|
256
|
-
RETURNS TRIGGER LANGUAGE plpgsql
|
|
257
|
-
AS $$
|
|
258
|
-
DECLARE
|
|
259
|
-
table_names json;
|
|
260
|
-
table_exists boolean := false;
|
|
261
|
-
BEGIN
|
|
262
|
-
SELECT EXISTS (
|
|
263
|
-
SELECT 1
|
|
264
|
-
FROM information_schema.tables
|
|
265
|
-
WHERE table_name = '${getLiveQueryTempTableName()}'
|
|
266
|
-
AND table_type = 'LOCAL TEMPORARY'
|
|
267
|
-
) INTO table_exists;
|
|
268
|
-
|
|
269
|
-
IF table_exists THEN
|
|
270
|
-
SELECT json_agg(table_name) INTO table_names
|
|
271
|
-
FROM ${getLiveQueryTempTableName()};
|
|
272
|
-
|
|
273
|
-
table_names := COALESCE(table_names, '[]'::json);
|
|
274
|
-
PERFORM pg_notify('${channel}', table_names::text);
|
|
275
|
-
END IF;
|
|
276
|
-
|
|
277
|
-
RETURN NULL;
|
|
278
|
-
END;
|
|
279
|
-
$$;`),
|
|
253
|
+
(tx) => tx.execute(getLiveQueryNotifyProcedureSql({ schema, channel })),
|
|
280
254
|
context,
|
|
281
255
|
);
|
|
282
256
|
},
|
|
@@ -358,41 +332,21 @@ export const createViews = async (
|
|
|
358
332
|
),
|
|
359
333
|
);
|
|
360
334
|
|
|
361
|
-
const notifyProcedure = getLiveQueryNotifyProcedureName();
|
|
362
335
|
const channel = getLiveQueryChannelName(namespaceBuild.viewsSchema!);
|
|
363
336
|
|
|
364
337
|
await tx.wrap((tx) =>
|
|
365
|
-
tx.execute(
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
table_exists boolean := false;
|
|
372
|
-
BEGIN
|
|
373
|
-
SELECT EXISTS (
|
|
374
|
-
SELECT 1
|
|
375
|
-
FROM information_schema.tables
|
|
376
|
-
WHERE table_name = '${getLiveQueryTempTableName()}'
|
|
377
|
-
AND table_type = 'LOCAL TEMPORARY'
|
|
378
|
-
) INTO table_exists;
|
|
379
|
-
|
|
380
|
-
IF table_exists THEN
|
|
381
|
-
SELECT json_agg(table_name) INTO table_names
|
|
382
|
-
FROM ${getLiveQueryTempTableName()};
|
|
383
|
-
|
|
384
|
-
table_names := COALESCE(table_names, '[]'::json);
|
|
385
|
-
PERFORM pg_notify('${channel}', table_names::text);
|
|
386
|
-
END IF;
|
|
387
|
-
|
|
388
|
-
RETURN NULL;
|
|
389
|
-
END;
|
|
390
|
-
$$;`),
|
|
338
|
+
tx.execute(
|
|
339
|
+
getLiveQueryNotifyProcedureSql({
|
|
340
|
+
schema: namespaceBuild.viewsSchema!,
|
|
341
|
+
channel,
|
|
342
|
+
}),
|
|
343
|
+
),
|
|
391
344
|
);
|
|
392
345
|
|
|
393
346
|
const trigger = getViewsLiveQueryNotifyTriggerName(
|
|
394
347
|
namespaceBuild.viewsSchema!,
|
|
395
348
|
);
|
|
349
|
+
const notifyProcedure = getLiveQueryNotifyProcedureName();
|
|
396
350
|
|
|
397
351
|
await tx.wrap((tx) =>
|
|
398
352
|
tx.execute(
|
package/src/drizzle/onchain.ts
CHANGED
|
@@ -70,6 +70,54 @@ export const getLiveQueryNotifyProcedureName = () => {
|
|
|
70
70
|
export const getLiveQueryTempTableName = () => {
|
|
71
71
|
return "live_query_tables";
|
|
72
72
|
};
|
|
73
|
+
export const getLiveQueryNotifyProcedureSql = ({
|
|
74
|
+
schema,
|
|
75
|
+
channel,
|
|
76
|
+
}: { schema: string; channel: string }) => {
|
|
77
|
+
const tempTableName = getLiveQueryTempTableName();
|
|
78
|
+
|
|
79
|
+
return `
|
|
80
|
+
CREATE OR REPLACE FUNCTION "${schema}".${getLiveQueryNotifyProcedureName()}
|
|
81
|
+
RETURNS TRIGGER LANGUAGE plpgsql
|
|
82
|
+
AS $$
|
|
83
|
+
DECLARE
|
|
84
|
+
current_payload text := '[';
|
|
85
|
+
separator text := '';
|
|
86
|
+
entry text;
|
|
87
|
+
entry_json text;
|
|
88
|
+
BEGIN
|
|
89
|
+
IF NOT EXISTS (
|
|
90
|
+
SELECT 1
|
|
91
|
+
FROM information_schema.tables
|
|
92
|
+
WHERE table_name = '${tempTableName}'
|
|
93
|
+
AND table_type = 'LOCAL TEMPORARY'
|
|
94
|
+
) THEN
|
|
95
|
+
RETURN NULL;
|
|
96
|
+
END IF;
|
|
97
|
+
|
|
98
|
+
FOR entry IN SELECT table_name FROM ${tempTableName} ORDER BY table_name LOOP
|
|
99
|
+
entry_json := to_json(entry)::text;
|
|
100
|
+
|
|
101
|
+
IF current_payload <> '[' AND octet_length(current_payload) + octet_length(separator) + octet_length(entry_json) + 1 >= 7900 THEN
|
|
102
|
+
PERFORM pg_notify('${channel}', current_payload || ']');
|
|
103
|
+
current_payload := '[' || entry_json;
|
|
104
|
+
separator := ',';
|
|
105
|
+
ELSE
|
|
106
|
+
current_payload := current_payload || separator || entry_json;
|
|
107
|
+
separator := ',';
|
|
108
|
+
END IF;
|
|
109
|
+
END LOOP;
|
|
110
|
+
|
|
111
|
+
IF current_payload = '[' THEN
|
|
112
|
+
PERFORM pg_notify('${channel}', '[]');
|
|
113
|
+
ELSE
|
|
114
|
+
PERFORM pg_notify('${channel}', current_payload || ']');
|
|
115
|
+
END IF;
|
|
116
|
+
|
|
117
|
+
RETURN NULL;
|
|
118
|
+
END;
|
|
119
|
+
$$;`;
|
|
120
|
+
};
|
|
73
121
|
export const getPartitionName = (table: string | PgTable, chainId: number) => {
|
|
74
122
|
return `${typeof table === "string" ? table : getTableName(table)}_${chainId}`;
|
|
75
123
|
};
|
package/src/graphql/index.ts
CHANGED
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
getTableColumns,
|
|
24
24
|
gt,
|
|
25
25
|
gte,
|
|
26
|
+
ilike,
|
|
26
27
|
inArray,
|
|
27
28
|
is,
|
|
28
29
|
isNotNull,
|
|
@@ -32,6 +33,7 @@ import {
|
|
|
32
33
|
lte,
|
|
33
34
|
ne,
|
|
34
35
|
not,
|
|
36
|
+
notIlike,
|
|
35
37
|
notInArray,
|
|
36
38
|
notLike,
|
|
37
39
|
or,
|
|
@@ -171,7 +173,14 @@ export function buildGraphQLSchema({
|
|
|
171
173
|
});
|
|
172
174
|
|
|
173
175
|
if (["String", "ID"].includes(type.name)) {
|
|
174
|
-
|
|
176
|
+
const stringConditionSuffixes =
|
|
177
|
+
column.columnType === "PgHex"
|
|
178
|
+
? conditionSuffixes.string.filter(
|
|
179
|
+
(suffix) => suffix.endsWith("_nocase") === false,
|
|
180
|
+
)
|
|
181
|
+
: conditionSuffixes.string;
|
|
182
|
+
|
|
183
|
+
stringConditionSuffixes.forEach((suffix) => {
|
|
175
184
|
filterFields[`${columnName}${suffix}`] = {
|
|
176
185
|
type: type,
|
|
177
186
|
};
|
|
@@ -251,7 +260,14 @@ export function buildGraphQLSchema({
|
|
|
251
260
|
});
|
|
252
261
|
|
|
253
262
|
if (["String", "ID"].includes(type.name)) {
|
|
254
|
-
|
|
263
|
+
const stringConditionSuffixes =
|
|
264
|
+
(column as PgColumn).columnType === "PgHex"
|
|
265
|
+
? conditionSuffixes.string.filter(
|
|
266
|
+
(suffix) => suffix.endsWith("_nocase") === false,
|
|
267
|
+
)
|
|
268
|
+
: conditionSuffixes.string;
|
|
269
|
+
|
|
270
|
+
stringConditionSuffixes.forEach((suffix) => {
|
|
255
271
|
filterFields[`${columnName}${suffix}`] = {
|
|
256
272
|
type: type,
|
|
257
273
|
};
|
|
@@ -1012,6 +1028,12 @@ const conditionSuffixes = {
|
|
|
1012
1028
|
"_ends_with",
|
|
1013
1029
|
"_not_starts_with",
|
|
1014
1030
|
"_not_ends_with",
|
|
1031
|
+
"_contains_nocase",
|
|
1032
|
+
"_not_contains_nocase",
|
|
1033
|
+
"_starts_with_nocase",
|
|
1034
|
+
"_ends_with_nocase",
|
|
1035
|
+
"_not_starts_with_nocase",
|
|
1036
|
+
"_not_ends_with_nocase",
|
|
1015
1037
|
],
|
|
1016
1038
|
} as const;
|
|
1017
1039
|
|
|
@@ -1152,6 +1174,24 @@ function buildWhereConditions(
|
|
|
1152
1174
|
case "_not_ends_with":
|
|
1153
1175
|
conditions.push(notLike(column, `%${rawValue}`));
|
|
1154
1176
|
break;
|
|
1177
|
+
case "_contains_nocase":
|
|
1178
|
+
conditions.push(ilike(column, `%${rawValue}%`));
|
|
1179
|
+
break;
|
|
1180
|
+
case "_not_contains_nocase":
|
|
1181
|
+
conditions.push(notIlike(column, `%${rawValue}%`));
|
|
1182
|
+
break;
|
|
1183
|
+
case "_starts_with_nocase":
|
|
1184
|
+
conditions.push(ilike(column, `${rawValue}%`));
|
|
1185
|
+
break;
|
|
1186
|
+
case "_ends_with_nocase":
|
|
1187
|
+
conditions.push(ilike(column, `%${rawValue}`));
|
|
1188
|
+
break;
|
|
1189
|
+
case "_not_starts_with_nocase":
|
|
1190
|
+
conditions.push(notIlike(column, `${rawValue}%`));
|
|
1191
|
+
break;
|
|
1192
|
+
case "_not_ends_with_nocase":
|
|
1193
|
+
conditions.push(notIlike(column, `%${rawValue}`));
|
|
1194
|
+
break;
|
|
1155
1195
|
default:
|
|
1156
1196
|
never(conditionSuffix);
|
|
1157
1197
|
}
|
|
@@ -762,7 +762,7 @@ export const createIndexingCache = ({
|
|
|
762
762
|
|
|
763
763
|
addErrorMeta(
|
|
764
764
|
error,
|
|
765
|
-
`db.insert arguments:\n${prettyPrint(result.value.row)}`,
|
|
765
|
+
`db.insert arguments:\n${prettyPrint(result.value.row, { truncate: false })}`,
|
|
766
766
|
);
|
|
767
767
|
|
|
768
768
|
if (result.value.metadata.event) {
|
|
@@ -834,7 +834,7 @@ export const createIndexingCache = ({
|
|
|
834
834
|
|
|
835
835
|
addErrorMeta(
|
|
836
836
|
error,
|
|
837
|
-
`db.update arguments:\n${prettyPrint(result.value.row)}`,
|
|
837
|
+
`db.update arguments:\n${prettyPrint(result.value.row, { truncate: false })}`,
|
|
838
838
|
);
|
|
839
839
|
|
|
840
840
|
if (result.value.metadata.event) {
|
|
@@ -497,7 +497,9 @@ export const createIndexingStore = ({
|
|
|
497
497
|
const error = new RecordNotFoundError(
|
|
498
498
|
`No existing record found in table '${getTableName(table)}'`,
|
|
499
499
|
);
|
|
500
|
-
error.meta.push(
|
|
500
|
+
error.meta.push(
|
|
501
|
+
`db.update arguments:\n${prettyPrint(key, { truncate: false })}`,
|
|
502
|
+
);
|
|
501
503
|
throw error;
|
|
502
504
|
}
|
|
503
505
|
|
|
@@ -115,7 +115,9 @@ export const normalizeRow = (
|
|
|
115
115
|
table,
|
|
116
116
|
)}.${columnName}' violates not-null constraint.`,
|
|
117
117
|
);
|
|
118
|
-
error.meta.push(
|
|
118
|
+
error.meta.push(
|
|
119
|
+
`db.insert arguments:\n${prettyPrint(row, { truncate: false })}`,
|
|
120
|
+
);
|
|
119
121
|
throw error;
|
|
120
122
|
}
|
|
121
123
|
|
package/src/utils/print.ts
CHANGED
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
// https://github.com/wagmi-dev/viem/blob/021ce8e5a3fb02db6139564345a91fc77cba08a6/src/errors/transaction.ts#L6-L19
|
|
3
3
|
export function prettyPrint(
|
|
4
4
|
args?: Record<string, bigint | number | string | undefined | false | unknown>,
|
|
5
|
+
options?: { truncate?: boolean },
|
|
5
6
|
) {
|
|
6
7
|
if (args === undefined) return "(undefined)";
|
|
7
8
|
|
|
9
|
+
const shouldTruncate = options?.truncate !== false;
|
|
10
|
+
|
|
8
11
|
const entries = Object.entries(args)
|
|
9
12
|
.map(([key, value]) => {
|
|
10
13
|
if (value === undefined) return null;
|
|
11
14
|
|
|
12
15
|
const trimmedValue =
|
|
13
|
-
typeof value === "string" && value.length > 80
|
|
16
|
+
typeof value === "string" && value.length > 80 && shouldTruncate
|
|
14
17
|
? value.slice(0, 80).concat("...")
|
|
15
18
|
: value;
|
|
16
19
|
|