@secondlayer/subgraphs 3.25.1 → 3.26.1

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.
@@ -574,6 +574,26 @@ declare class SubgraphContext2 {
574
574
  * with the flush itself.
575
575
  */
576
576
  flush(): Promise<FlushManifest>;
577
+ /**
578
+ * Run a built statement list on an open transaction.
579
+ *
580
+ * Plain statements run in order. An increment runs UPDATE-first and then,
581
+ * ONLY if that matched nothing, the guarded INSERT — and if the INSERT also
582
+ * wrote nothing, the UPDATE again.
583
+ *
584
+ * That last step is the whole point. Under READ COMMITTED, two block
585
+ * transactions flushing the same key while the row is absent both see
586
+ * `UPDATE → 0 rows`; the first commits its INSERT, and the second's
587
+ * `WHERE NOT EXISTS` then sees that committed row and inserts nothing. No
588
+ * error, no constraint violation — the second delta was simply dropped.
589
+ * Re-running the UPDATE takes a fresh snapshot that DOES see the winner's
590
+ * row and applies the delta onto it.
591
+ *
592
+ * It cannot double-apply: the retry is reached only when the first UPDATE
593
+ * matched no row AND the INSERT wrote no row, so the delta has not been
594
+ * applied by either.
595
+ */
596
+ private execStatements;
577
597
  /** Prepare a single insert row, returning its data, columns, upsert key for batching. */
578
598
  private prepareInsert;
579
599
  /**
@@ -605,14 +605,10 @@ class SubgraphContext {
605
605
  this.ops.length = 0;
606
606
  const statements = this.buildStatements(opsToFlush);
607
607
  if ("isTransaction" in this.db) {
608
- for (const stmt of statements) {
609
- await sql.raw(stmt).execute(this.db);
610
- }
608
+ await this.execStatements(this.db, statements);
611
609
  } else {
612
610
  await this.db.transaction().execute(async (tx) => {
613
- for (const stmt of statements) {
614
- await sql.raw(stmt).execute(tx);
615
- }
611
+ await this.execStatements(tx, statements);
616
612
  });
617
613
  }
618
614
  const writes = opsToFlush.map((op, rowIndex) => {
@@ -631,6 +627,25 @@ class SubgraphContext {
631
627
  });
632
628
  return { count: opsToFlush.length, writes };
633
629
  }
630
+ async execStatements(executor, statements) {
631
+ const affected = (r) => r.numAffectedRows ?? 0n;
632
+ for (const stmt of statements) {
633
+ if (typeof stmt === "string") {
634
+ await sql.raw(stmt).execute(executor);
635
+ continue;
636
+ }
637
+ const updated = await sql.raw(stmt.update).execute(executor);
638
+ if (affected(updated) > 0n)
639
+ continue;
640
+ const inserted = await sql.raw(stmt.insert).execute(executor);
641
+ if (affected(inserted) > 0n)
642
+ continue;
643
+ const retried = await sql.raw(stmt.update).execute(executor);
644
+ if (affected(retried) === 0n) {
645
+ throw new Error(`increment could not be applied to ${this.pgSchemaName}.${stmt.table} where ${stmt.keyPred}: row neither updated nor inserted`);
646
+ }
647
+ }
648
+ }
634
649
  prepareInsert(op) {
635
650
  const upsertKeys = op.data._upsert_keys;
636
651
  const data = { ...op.data };
@@ -710,7 +725,6 @@ class SubgraphContext {
710
725
  for (const r of batch.rows.values()) {
711
726
  const keyPred = batch.keyCols.map((k) => `"${k}" = ${escapeLiteral(r.keys[k])}`).join(" AND ");
712
727
  const updSet = batch.deltaCols.map((c) => `"${c}" = COALESCE("${c}", 0) + (${String(r.deltas[c] ?? 0n)})`).join(", ");
713
- statements.push(`UPDATE ${qualifiedTable} SET ${updSet} WHERE ${keyPred}`);
714
728
  const insertVals = [
715
729
  ...batch.keyCols.map((k) => escapeLiteral(r.keys[k])),
716
730
  ...batch.deltaCols.map((c) => String(r.deltas[c] ?? 0n)),
@@ -718,7 +732,13 @@ class SubgraphContext {
718
732
  escapeLiteral(r.meta.txId),
719
733
  "NOW()"
720
734
  ];
721
- statements.push(`INSERT INTO ${qualifiedTable} (${cols.map((c) => `"${c}"`).join(", ")}) ` + `SELECT ${insertVals.join(", ")} ` + `WHERE NOT EXISTS (SELECT 1 FROM ${qualifiedTable} WHERE ${keyPred})`);
735
+ statements.push({
736
+ kind: "increment",
737
+ table: batch.table,
738
+ keyPred,
739
+ update: `UPDATE ${qualifiedTable} SET ${updSet} WHERE ${keyPred}`,
740
+ insert: `INSERT INTO ${qualifiedTable} (${cols.map((c) => `"${c}"`).join(", ")}) ` + `SELECT ${insertVals.join(", ")} ` + `WHERE NOT EXISTS (SELECT 1 FROM ${qualifiedTable} WHERE ${keyPred})`
741
+ });
722
742
  }
723
743
  incBatch = null;
724
744
  incBatchKey = "";
@@ -3353,9 +3373,9 @@ async function processBlockRange(def, opts) {
3353
3373
  return { blocksProcessed, totalEventsProcessed, totalErrors, aborted };
3354
3374
  }
3355
3375
  async function resolveBlockRange(source, def, opts) {
3356
- const fromBlock = opts?.fromBlock ?? def.startBlock ?? 1;
3357
- const toBlock = opts?.toBlock != null ? opts.toBlock : await source.getTip();
3358
- return { fromBlock, toBlock };
3376
+ const definitionStart = def.startBlock ?? 1;
3377
+ const fromBlock = opts?.startBlockFloor != null ? Math.max(definitionStart, opts.startBlockFloor) : definitionStart;
3378
+ return { fromBlock, toBlock: await source.getTip() };
3359
3379
  }
3360
3380
  async function clearReindexMetadata(db, subgraphName) {
3361
3381
  await db.updateTable("subgraphs").set({ reindex_from_block: null, reindex_to_block: null }).where("name", "=", subgraphName).execute();
@@ -4203,8 +4223,7 @@ async function runSubgraphOperation(operation, signal) {
4203
4223
  return result2.processed;
4204
4224
  }
4205
4225
  const result = await reindexSubgraph(def, {
4206
- fromBlock: operation.from_block == null ? undefined : Number(operation.from_block),
4207
- toBlock: operation.to_block == null ? undefined : Number(operation.to_block),
4226
+ startBlockFloor: operation.from_block == null ? undefined : Number(operation.from_block),
4208
4227
  schemaName,
4209
4228
  operationId: operation.id,
4210
4229
  signal
@@ -4442,5 +4461,5 @@ var shutdown = async () => {
4442
4461
  process.on("SIGINT", shutdown);
4443
4462
  process.on("SIGTERM", shutdown);
4444
4463
 
4445
- //# debugId=957751E5CE73209364756E2164756E21
4464
+ //# debugId=80FE8B3630A7D83D64756E2164756E21
4446
4465
  //# sourceMappingURL=service.js.map