envio 3.3.1 → 3.3.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "envio",
3
- "version": "3.3.1",
3
+ "version": "3.3.2",
4
4
  "type": "module",
5
5
  "description": "A latency and sync speed optimized, developer friendly blockchain data indexer.",
6
6
  "bin": "./bin.mjs",
@@ -69,10 +69,10 @@
69
69
  "tsx": "4.21.0"
70
70
  },
71
71
  "optionalDependencies": {
72
- "envio-linux-x64": "3.3.1",
73
- "envio-linux-x64-musl": "3.3.1",
74
- "envio-linux-arm64": "3.3.1",
75
- "envio-darwin-x64": "3.3.1",
76
- "envio-darwin-arm64": "3.3.1"
72
+ "envio-linux-x64": "3.3.2",
73
+ "envio-linux-x64-musl": "3.3.2",
74
+ "envio-linux-arm64": "3.3.2",
75
+ "envio-darwin-x64": "3.3.2",
76
+ "envio-darwin-arm64": "3.3.2"
77
77
  }
78
78
  }
package/src/PgStorage.res CHANGED
@@ -1,5 +1,3 @@
1
- let getCacheRowCountFnName = "get_cache_row_count"
2
-
3
1
  let makeClient = () => {
4
2
  Postgres.makeSql(
5
3
  ~config={
@@ -267,18 +265,7 @@ GRANT ALL ON SCHEMA "${pgSchema}" TO public;`,
267
265
  | None => ()
268
266
  }
269
267
 
270
- [
271
- query.contents,
272
- `CREATE OR REPLACE FUNCTION ${getCacheRowCountFnName}(table_name text)
273
- RETURNS integer AS $$
274
- DECLARE
275
- result integer;
276
- BEGIN
277
- EXECUTE format('SELECT COUNT(*) FROM "${pgSchema}".%I', table_name) INTO result;
278
- RETURN result;
279
- END;
280
- $$ LANGUAGE plpgsql;`,
281
- ]
268
+ [query.contents]
282
269
  }
283
270
 
284
271
  let makeLoadQuery = (~pgSchema, ~tableName, ~condition) => {
@@ -661,16 +648,19 @@ type schemaCacheTableInfo = {
661
648
  count: int,
662
649
  }
663
650
 
651
+ type cacheRowCount = {
652
+ @as("count")
653
+ count: int,
654
+ }
655
+
664
656
  // Matches both the cross-chain (`envio_effect_<name>`) and chain-scoped
665
657
  // (`envio_<chainId>_effect_<name>`) cache-table formats. Kept in sync with
666
658
  // Internal.EffectCache.
667
- let makeSchemaCacheTableInfoQuery = (~pgSchema) => {
659
+ let makeEffectCacheTableNamesQuery = (~pgSchema) => {
668
660
  // The column guard requires the effect-cache shape (exactly an `id` + `output`
669
661
  // pair) so a user entity table that happens to match the name pattern is never
670
662
  // mistaken for an effect cache.
671
- `SELECT
672
- t.table_name,
673
- ${getCacheRowCountFnName}(t.table_name) as count
663
+ `SELECT t.table_name
674
664
  FROM information_schema.tables t
675
665
  WHERE t.table_schema = '${pgSchema}'
676
666
  AND t.table_name ~ '^envio_([0-9]+_)?effect_.+'
@@ -681,6 +671,15 @@ let makeSchemaCacheTableInfoQuery = (~pgSchema) => {
681
671
  ) = ARRAY['id', 'output'];`
682
672
  }
683
673
 
674
+ let makeCacheRowCountQuery = (~pgSchema, ~tableName) => {
675
+ // The table name comes from information_schema, so anything cache-shaped that
676
+ // was created out-of-band in the schema reaches here. Splice both identifiers
677
+ // as quoted identifiers, doubling embedded quotes, so a crafted name can't
678
+ // break out into raw SQL.
679
+ let quoteIdent = ident => `"${ident->String.replaceAll("\"", "\"\"")}"`
680
+ `SELECT COUNT(*)::int AS count FROM ${quoteIdent(pgSchema)}.${quoteIdent(tableName)};`
681
+ }
682
+
684
683
  type psqlExecState =
685
684
  Unknown | Pending(promise<result<string, string>>) | Resolved(result<string, string>)
686
685
 
@@ -1301,6 +1300,23 @@ let make = (
1301
1300
  result
1302
1301
  }
1303
1302
 
1303
+ // Each indexer counts the effect-cache tables in its own schema. The counts
1304
+ // are computed here per table rather than through a shared SQL helper so
1305
+ // indexers isolated by schema in one database never touch each other's state.
1306
+ let queryCacheTableInfo = async (): array<schemaCacheTableInfo> => {
1307
+ let tableNames: array<schemaTableName> = await sql->Postgres.unsafe(
1308
+ makeEffectCacheTableNamesQuery(~pgSchema),
1309
+ )
1310
+ await tableNames
1311
+ ->Array.map(async ({tableName}) => {
1312
+ let rows: array<cacheRowCount> = await sql->Postgres.unsafe(
1313
+ makeCacheRowCountQuery(~pgSchema, ~tableName),
1314
+ )
1315
+ ({tableName, count: (rows->Array.getUnsafe(0)).count}: schemaCacheTableInfo)
1316
+ })
1317
+ ->Promise.all
1318
+ }
1319
+
1304
1320
  let restoreEffectCache = async (~withUpload) => {
1305
1321
  if withUpload {
1306
1322
  // Try to restore cache tables from the .envio/cache TSV files
@@ -1340,9 +1356,7 @@ let make = (
1340
1356
  }
1341
1357
  }
1342
1358
 
1343
- let cacheTableInfo: array<schemaCacheTableInfo> = await sql->Postgres.unsafe(
1344
- makeSchemaCacheTableInfoQuery(~pgSchema),
1345
- )
1359
+ let cacheTableInfo = await queryCacheTableInfo()
1346
1360
 
1347
1361
  if withUpload && cacheTableInfo->Utils.Array.notEmpty {
1348
1362
  // Integration with other tools like Hasura
@@ -1551,10 +1565,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
1551
1565
 
1552
1566
  let dumpEffectCache = async () => {
1553
1567
  try {
1554
- let cacheTableInfo: array<schemaCacheTableInfo> =
1555
- (await sql->Postgres.unsafe(makeSchemaCacheTableInfoQuery(~pgSchema)))->Array.filter(i =>
1556
- i.count > 0
1557
- )
1568
+ let cacheTableInfo = (await queryCacheTableInfo())->Array.filter(i => i.count > 0)
1558
1569
 
1559
1570
  if cacheTableInfo->Utils.Array.notEmpty {
1560
1571
  // Create .envio/cache directory if it doesn't exist
@@ -27,8 +27,6 @@ import * as Primitive_option from "@rescript/runtime/lib/es6/Primitive_option.js
27
27
  import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
28
28
  import * as Primitive_exceptions from "@rescript/runtime/lib/es6/Primitive_exceptions.js";
29
29
 
30
- let getCacheRowCountFnName = "get_cache_row_count";
31
-
32
30
  function makeClient() {
33
31
  return Postgres({
34
32
  host: Env.Db.host,
@@ -222,18 +220,7 @@ GRANT ALL ON SCHEMA "` + pgSchema + `" TO public;`)
222
220
  if (initialChainsValuesQuery !== undefined) {
223
221
  query.contents = query.contents + "\n" + initialChainsValuesQuery;
224
222
  }
225
- return [
226
- query.contents,
227
- `CREATE OR REPLACE FUNCTION ` + getCacheRowCountFnName + `(table_name text)
228
- RETURNS integer AS $$
229
- DECLARE
230
- result integer;
231
- BEGIN
232
- EXECUTE format('SELECT COUNT(*) FROM "` + pgSchema + `".%I', table_name) INTO result;
233
- RETURN result;
234
- END;
235
- $$ LANGUAGE plpgsql;`
236
- ];
223
+ return [query.contents];
237
224
  }
238
225
 
239
226
  function makeLoadQuery(pgSchema, tableName, condition) {
@@ -492,10 +479,8 @@ function makeSchemaTableNamesQuery(pgSchema) {
492
479
  return `SELECT table_name FROM information_schema.tables WHERE table_schema = '` + pgSchema + `';`;
493
480
  }
494
481
 
495
- function makeSchemaCacheTableInfoQuery(pgSchema) {
496
- return `SELECT
497
- t.table_name,
498
- ` + getCacheRowCountFnName + `(t.table_name) as count
482
+ function makeEffectCacheTableNamesQuery(pgSchema) {
483
+ return `SELECT t.table_name
499
484
  FROM information_schema.tables t
500
485
  WHERE t.table_schema = '` + pgSchema + `'
501
486
  AND t.table_name ~ '^envio_([0-9]+_)?effect_.+'
@@ -506,6 +491,11 @@ function makeSchemaCacheTableInfoQuery(pgSchema) {
506
491
  ) = ARRAY['id', 'output'];`;
507
492
  }
508
493
 
494
+ function makeCacheRowCountQuery(pgSchema, tableName) {
495
+ let quoteIdent = ident => `"` + ident.replaceAll("\"", "\"\"") + `"`;
496
+ return `SELECT COUNT(*)::int AS count FROM ` + quoteIdent(pgSchema) + `.` + quoteIdent(tableName) + `;`;
497
+ }
498
+
509
499
  let psqlExecState = {
510
500
  contents: "Unknown"
511
501
  };
@@ -889,6 +879,17 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
889
879
  }));
890
880
  return result;
891
881
  };
882
+ let queryCacheTableInfo = async () => {
883
+ let tableNames = await sql.unsafe(makeEffectCacheTableNamesQuery(pgSchema));
884
+ return await Promise.all(tableNames.map(async param => {
885
+ let tableName = param.table_name;
886
+ let rows = await sql.unsafe(makeCacheRowCountQuery(pgSchema, tableName));
887
+ return {
888
+ table_name: tableName,
889
+ count: rows[0].count
890
+ };
891
+ }));
892
+ };
892
893
  let restoreEffectCache = async withUpload => {
893
894
  if (withUpload) {
894
895
  let entries = await scanCacheDir();
@@ -920,7 +921,7 @@ function make(sql, pgHost, pgSchema, pgPort, pgUser, pgDatabase, pgPassword, isH
920
921
  Logging.info("No cache found to upload.");
921
922
  }
922
923
  }
923
- let cacheTableInfo = await sql.unsafe(makeSchemaCacheTableInfoQuery(pgSchema));
924
+ let cacheTableInfo = await queryCacheTableInfo();
924
925
  if (withUpload && Utils.$$Array.notEmpty(cacheTableInfo) && onNewTables !== undefined) {
925
926
  await onNewTables(cacheTableInfo.map(info => info.table_name));
926
927
  }
@@ -1041,7 +1042,7 @@ SELECT id, chain_id, -1, -1, contract_name FROM unnest($1::text[],$2::int[],$3::
1041
1042
  };
1042
1043
  let dumpEffectCache = async () => {
1043
1044
  try {
1044
- let cacheTableInfo = (await sql.unsafe(makeSchemaCacheTableInfoQuery(pgSchema))).filter(i => i.count > 0);
1045
+ let cacheTableInfo = (await queryCacheTableInfo()).filter(i => i.count > 0);
1045
1046
  if (!Utils.$$Array.notEmpty(cacheTableInfo)) {
1046
1047
  return;
1047
1048
  }
@@ -1250,7 +1251,6 @@ function makePersistenceFromConfig(config, storageOpt) {
1250
1251
  let maxItemsPerQuery = 500;
1251
1252
 
1252
1253
  export {
1253
- getCacheRowCountFnName,
1254
1254
  makeClient,
1255
1255
  makeCreateIndexQuery,
1256
1256
  directionToSql,
@@ -1279,7 +1279,8 @@ export {
1279
1279
  setQueryCache,
1280
1280
  setOrThrow,
1281
1281
  makeSchemaTableNamesQuery,
1282
- makeSchemaCacheTableInfoQuery,
1282
+ makeEffectCacheTableNamesQuery,
1283
+ makeCacheRowCountQuery,
1283
1284
  getConnectedPsqlExec,
1284
1285
  deleteByIdsOrThrow,
1285
1286
  makeInsertDeleteUpdatesQuery,