@secondlayer/subgraphs 0.5.6 → 0.6.0
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/src/index.d.ts +16 -4
- package/dist/src/index.js +261 -98
- package/dist/src/index.js.map +9 -8
- package/dist/src/runtime/block-processor.d.ts +9 -1
- package/dist/src/runtime/block-processor.js +89 -47
- package/dist/src/runtime/block-processor.js.map +4 -4
- package/dist/src/runtime/catchup.d.ts +2 -2
- package/dist/src/runtime/catchup.js +194 -63
- package/dist/src/runtime/catchup.js.map +7 -6
- package/dist/src/runtime/context.d.ts +3 -1
- package/dist/src/runtime/context.js +63 -33
- package/dist/src/runtime/context.js.map +3 -3
- package/dist/src/runtime/processor.js +195 -64
- package/dist/src/runtime/processor.js.map +8 -7
- package/dist/src/runtime/reindex.d.ts +13 -1
- package/dist/src/runtime/reindex.js +258 -94
- package/dist/src/runtime/reindex.js.map +8 -7
- package/dist/src/runtime/reorg.js +90 -48
- package/dist/src/runtime/reorg.js.map +5 -5
- package/dist/src/runtime/runner.d.ts +3 -1
- package/dist/src/schema/index.js +4 -5
- package/dist/src/schema/index.js.map +4 -4
- package/dist/src/service.js +195 -64
- package/dist/src/service.js.map +8 -7
- package/dist/src/validate.js +2 -2
- package/dist/src/validate.js.map +3 -3
- package/package.json +2 -2
|
@@ -108,53 +108,83 @@ class SubgraphContext {
|
|
|
108
108
|
}
|
|
109
109
|
return opsToFlush.length;
|
|
110
110
|
}
|
|
111
|
+
prepareInsert(op) {
|
|
112
|
+
const upsertKeys = op.data._upsert_keys;
|
|
113
|
+
const data = { ...op.data };
|
|
114
|
+
delete data._upsert_keys;
|
|
115
|
+
delete data._upsert_fallback_keys;
|
|
116
|
+
delete data._upsert_fallback_set;
|
|
117
|
+
data._block_height = this.block.height;
|
|
118
|
+
data._tx_id = this._tx.txId;
|
|
119
|
+
data._created_at = "NOW()";
|
|
120
|
+
const cols = Object.keys(data);
|
|
121
|
+
cols.forEach(validateColumnName);
|
|
122
|
+
const vals = cols.map((c) => data[c] === "NOW()" ? "NOW()" : escapeLiteral(data[c]));
|
|
123
|
+
const batchKey = `${op.table}:${[...cols].sort().join(",")}:${upsertKeys ? [...upsertKeys].sort().join(",") : ""}`;
|
|
124
|
+
return { data, cols, vals, upsertKeys, batchKey };
|
|
125
|
+
}
|
|
111
126
|
buildStatements(ops) {
|
|
112
127
|
const statements = [];
|
|
128
|
+
let currentBatch = null;
|
|
129
|
+
let currentBatchKey = "";
|
|
130
|
+
const flushInsertBatch = () => {
|
|
131
|
+
if (!currentBatch)
|
|
132
|
+
return;
|
|
133
|
+
const qualifiedTable = `"${this.pgSchemaName}"."${currentBatch.table}"`;
|
|
134
|
+
const colList = currentBatch.cols.map((c) => `"${c}"`).join(", ");
|
|
135
|
+
let rows = currentBatch.rows;
|
|
136
|
+
if (currentBatch.upsertKeys && currentBatch.upsertKeys.length > 0) {
|
|
137
|
+
const keyIndices = currentBatch.upsertKeys.map((k) => currentBatch.cols.indexOf(k));
|
|
138
|
+
const seen = new Map;
|
|
139
|
+
for (let i = 0;i < rows.length; i++) {
|
|
140
|
+
const key = keyIndices.map((ki) => rows[i][ki]).join("\x00");
|
|
141
|
+
seen.set(key, i);
|
|
142
|
+
}
|
|
143
|
+
if (seen.size < rows.length) {
|
|
144
|
+
rows = Array.from(seen.values()).map((i) => rows[i]);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const valuesList = rows.map((r) => `(${r.join(", ")})`).join(", ");
|
|
148
|
+
let stmt = `INSERT INTO ${qualifiedTable} (${colList}) VALUES ${valuesList}`;
|
|
149
|
+
if (currentBatch.upsertKeys && currentBatch.upsertKeys.length > 0) {
|
|
150
|
+
const updateCols = currentBatch.cols.filter((c) => !currentBatch.upsertKeys.includes(c) && !c.startsWith("_"));
|
|
151
|
+
if (updateCols.length > 0) {
|
|
152
|
+
const setClauses = updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`);
|
|
153
|
+
stmt += ` ON CONFLICT (${currentBatch.upsertKeys.map((k) => `"${k}"`).join(", ")}) DO UPDATE SET ${setClauses.join(", ")}`;
|
|
154
|
+
} else {
|
|
155
|
+
stmt += ` ON CONFLICT (${currentBatch.upsertKeys.map((k) => `"${k}"`).join(", ")}) DO NOTHING`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
statements.push(stmt);
|
|
159
|
+
currentBatch = null;
|
|
160
|
+
currentBatchKey = "";
|
|
161
|
+
};
|
|
113
162
|
for (const op of ops) {
|
|
114
163
|
const qualifiedTable = `"${this.pgSchemaName}"."${op.table}"`;
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
delete data._upsert_fallback_set;
|
|
124
|
-
data._block_height = this.block.height;
|
|
125
|
-
data._tx_id = this._tx.txId;
|
|
126
|
-
data._created_at = "NOW()";
|
|
127
|
-
const cols = Object.keys(data);
|
|
128
|
-
cols.forEach(validateColumnName);
|
|
129
|
-
const vals = cols.map((c) => data[c] === "NOW()" ? "NOW()" : escapeLiteral(data[c]));
|
|
130
|
-
let stmt = `INSERT INTO ${qualifiedTable} (${cols.map((c) => `"${c}"`).join(", ")}) VALUES (${vals.join(", ")})`;
|
|
131
|
-
if (upsertKeys && upsertKeys.length > 0) {
|
|
132
|
-
const updateCols = cols.filter((c) => !upsertKeys.includes(c) && !c.startsWith("_"));
|
|
133
|
-
if (updateCols.length > 0) {
|
|
134
|
-
const setClauses = updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`);
|
|
135
|
-
stmt += ` ON CONFLICT (${upsertKeys.map((k) => `"${k}"`).join(", ")}) DO UPDATE SET ${setClauses.join(", ")}`;
|
|
136
|
-
} else {
|
|
137
|
-
stmt += ` ON CONFLICT (${upsertKeys.map((k) => `"${k}"`).join(", ")}) DO NOTHING`;
|
|
138
|
-
}
|
|
139
|
-
} else if (fallbackKeys && fallbackSet) {}
|
|
140
|
-
statements.push(stmt);
|
|
141
|
-
break;
|
|
164
|
+
if (op.kind === "insert") {
|
|
165
|
+
const { cols, vals, upsertKeys, batchKey } = this.prepareInsert(op);
|
|
166
|
+
if (batchKey === currentBatchKey && currentBatch) {
|
|
167
|
+
currentBatch.rows.push(vals);
|
|
168
|
+
} else {
|
|
169
|
+
flushInsertBatch();
|
|
170
|
+
currentBatch = { table: op.table, cols, rows: [vals], upsertKeys };
|
|
171
|
+
currentBatchKey = batchKey;
|
|
142
172
|
}
|
|
143
|
-
|
|
173
|
+
} else {
|
|
174
|
+
flushInsertBatch();
|
|
175
|
+
if (op.kind === "update") {
|
|
144
176
|
const setEntries = Object.entries(op.set);
|
|
145
177
|
setEntries.forEach(([k]) => validateColumnName(k));
|
|
146
178
|
const setClauses = setEntries.map(([k, v]) => `"${k}" = ${escapeLiteral(v)}`);
|
|
147
179
|
const { clause } = buildWhereClause(op.data);
|
|
148
180
|
statements.push(`UPDATE ${qualifiedTable} SET ${setClauses.join(", ")} WHERE ${clause}`);
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
case "delete": {
|
|
181
|
+
} else if (op.kind === "delete") {
|
|
152
182
|
const { clause } = buildWhereClause(op.data);
|
|
153
183
|
statements.push(`DELETE FROM ${qualifiedTable} WHERE ${clause}`);
|
|
154
|
-
break;
|
|
155
184
|
}
|
|
156
185
|
}
|
|
157
186
|
}
|
|
187
|
+
flushInsertBatch();
|
|
158
188
|
return statements;
|
|
159
189
|
}
|
|
160
190
|
validateTable(table) {
|
|
@@ -186,5 +216,5 @@ export {
|
|
|
186
216
|
SubgraphContext
|
|
187
217
|
};
|
|
188
218
|
|
|
189
|
-
//# debugId=
|
|
219
|
+
//# debugId=CE4757E3FCD15A2D64756E2164756E21
|
|
190
220
|
//# sourceMappingURL=context.js.map
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/runtime/context.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"import { sql, type Kysely, type Transaction } from \"kysely\";\nimport type { Database } from \"@secondlayer/shared/db\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport type { SubgraphSchema } from \"../types.ts\";\n\ntype AnyDb = Kysely<Database> | Transaction<Database>;\n\ninterface WriteOp {\n kind: \"insert\" | \"update\" | \"delete\";\n table: string;\n data: Record<string, unknown>;\n /** For update: SET clause */\n set?: Record<string, unknown>;\n}\n\nexport interface BlockMeta {\n height: number;\n hash: string;\n timestamp: number;\n burnBlockHeight: number;\n}\n\nexport interface TxMeta {\n txId: string;\n sender: string;\n type: string;\n status: string;\n}\n\n/** Validate that a column name is safe for SQL identifiers */\nfunction validateColumnName(name: string): void {\n if (!/^[a-z_][a-z0-9_]*$/i.test(name)) {\n throw new Error(`Invalid column name: ${name}`);\n }\n}\n\n/**\n * Runtime context passed to subgraph handlers.\n * Batches writes and flushes them atomically at the end of a block.\n * Reads execute immediately against the DB (pre-flush state).\n */\nexport class SubgraphContext {\n readonly block: BlockMeta;\n private _tx: TxMeta;\n private readonly db: AnyDb;\n private readonly pgSchemaName: string;\n private readonly subgraphSchema: SubgraphSchema;\n private readonly ops: WriteOp[] = [];\n\n constructor(\n db: AnyDb,\n pgSchemaName: string,\n subgraphSchema: SubgraphSchema,\n block: BlockMeta,\n tx: TxMeta,\n ) {\n this.db = db;\n this.pgSchemaName = pgSchemaName;\n this.subgraphSchema = subgraphSchema;\n this.block = block;\n this._tx = tx;\n }\n\n get tx(): TxMeta {\n return this._tx;\n }\n\n /** Update the current transaction context (used by runner between events) */\n setTx(tx: TxMeta): void {\n this._tx = tx;\n }\n\n // --- Write operations (batched) ---\n\n insert(table: string, row: Record<string, unknown>): void {\n this.validateTable(table);\n this.ops.push({ kind: \"insert\", table, data: row });\n }\n\n update(\n table: string,\n where: Record<string, unknown>,\n set: Record<string, unknown>,\n ): void {\n this.validateTable(table);\n this.ops.push({ kind: \"update\", table, data: where, set });\n }\n\n upsert(\n table: string,\n key: Record<string, unknown>,\n row: Record<string, unknown>,\n ): void {\n this.validateTable(table);\n const tableDef = this.subgraphSchema[table]!;\n const keyColumns = Object.keys(key);\n\n // Check if there's a matching uniqueKeys constraint\n const hasUniqueConstraint = tableDef.uniqueKeys?.some(\n (uk) => uk.length === keyColumns.length && uk.every((c) => keyColumns.includes(c)),\n );\n\n if (hasUniqueConstraint) {\n // Use ON CONFLICT for proper upsert\n this.ops.push({ kind: \"insert\", table, data: { ...key, ...row, _upsert_keys: keyColumns } });\n } else {\n // Fallback: log warning, use findOne + conditional insert/update\n logger.warn(\"upsert called without matching uniqueKeys constraint, using fallback\", {\n table,\n keys: keyColumns,\n });\n this.ops.push({ kind: \"insert\", table, data: { ...key, ...row, _upsert_fallback_keys: keyColumns, _upsert_fallback_set: row } });\n }\n }\n\n delete(table: string, where: Record<string, unknown>): void {\n this.validateTable(table);\n this.ops.push({ kind: \"delete\", table, data: where });\n }\n\n // --- Read operations (immediate) ---\n\n async findOne(\n table: string,\n where: Record<string, unknown>,\n ): Promise<Record<string, unknown> | null> {\n this.validateTable(table);\n const qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n const { clause } = buildWhereClause(where);\n const query = `SELECT * FROM ${qualifiedTable} WHERE ${clause} LIMIT 1`;\n const { rows } = await sql.raw(query).execute(this.db);\n const row = (rows as Record<string, unknown>[])[0] ?? null;\n return row ? this.coerceRow(table, row) : null;\n }\n\n async findMany(\n table: string,\n where: Record<string, unknown>,\n ): Promise<Record<string, unknown>[]> {\n this.validateTable(table);\n const qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n const { clause } = buildWhereClause(where);\n const query = `SELECT * FROM ${qualifiedTable} WHERE ${clause}`;\n const { rows } = await sql.raw(query).execute(this.db);\n return (rows as Record<string, unknown>[]).map((r) => this.coerceRow(table, r));\n }\n\n /** Coerce string values from Postgres back to BigInt for uint/int columns */\n private coerceRow(table: string, row: Record<string, unknown>): Record<string, unknown> {\n const tableDef = this.subgraphSchema[table];\n if (!tableDef) return row;\n const result = { ...row };\n for (const [col, def] of Object.entries(tableDef.columns)) {\n if ((def.type === \"uint\" || def.type === \"int\") && typeof result[col] === \"string\") {\n result[col] = BigInt(result[col] as string);\n }\n }\n return result;\n }\n\n // --- Flush ---\n\n /** Number of pending write operations */\n get pendingOps(): number {\n return this.ops.length;\n }\n\n /**\n * Execute all batched writes in a single transaction.\n * Auto-populates _block_height, _tx_id, _created_at on inserts.\n */\n async flush(): Promise<number> {\n if (this.ops.length === 0) return 0;\n\n const opsToFlush = [...this.ops];\n this.ops.length = 0;\n\n const statements = this.buildStatements(opsToFlush);\n\n // If db is already a transaction, execute directly\n if (\"isTransaction\" in this.db) {\n for (const stmt of statements) {\n await sql.raw(stmt).execute(this.db);\n }\n } else {\n await (this.db as Kysely<Database>).transaction().execute(async (tx) => {\n for (const stmt of statements) {\n await sql.raw(stmt).execute(tx);\n }\n });\n }\n\n return opsToFlush.length;\n }\n\n /** Build SQL statements from write ops */\n private buildStatements(ops: WriteOp[]): string[] {\n const statements: string[] = [];\n\n for (const op of ops) {\n const qualifiedTable = `\"${this.pgSchemaName}\".\"${op.table}\"`;\n\n switch (op.kind) {\n case \"insert\": {\n const upsertKeys = op.data._upsert_keys as string[] | undefined;\n const fallbackKeys = op.data._upsert_fallback_keys as string[] | undefined;\n const fallbackSet = op.data._upsert_fallback_set as Record<string, unknown> | undefined;\n const data = { ...op.data };\n delete data._upsert_keys;\n delete data._upsert_fallback_keys;\n delete data._upsert_fallback_set;\n\n // Auto-populate meta columns\n data._block_height = this.block.height;\n data._tx_id = this._tx.txId;\n data._created_at = \"NOW()\";\n\n const cols = Object.keys(data);\n cols.forEach(validateColumnName);\n const vals = cols.map((c) =>\n data[c] === \"NOW()\" ? \"NOW()\" : escapeLiteral(data[c]),\n );\n let stmt = `INSERT INTO ${qualifiedTable} (${cols.map((c) => `\"${c}\"`).join(\", \")}) VALUES (${vals.join(\", \")})`;\n\n if (upsertKeys && upsertKeys.length > 0) {\n const updateCols = cols.filter((c) => !upsertKeys.includes(c) && !c.startsWith(\"_\"));\n if (updateCols.length > 0) {\n const setClauses = updateCols.map((c) => `\"${c}\" = EXCLUDED.\"${c}\"`);\n stmt += ` ON CONFLICT (${upsertKeys.map((k) => `\"${k}\"`).join(\", \")}) DO UPDATE SET ${setClauses.join(\", \")}`;\n } else {\n stmt += ` ON CONFLICT (${upsertKeys.map((k) => `\"${k}\"`).join(\", \")}) DO NOTHING`;\n }\n } else if (fallbackKeys && fallbackSet) {\n // Fallback upsert: use ON CONFLICT DO UPDATE but without a declared constraint\n // This will just be a plain INSERT — if it conflicts, PG will raise an error.\n // The caller was already warned. This is the best we can do without a unique constraint.\n }\n\n statements.push(stmt);\n break;\n }\n case \"update\": {\n const setEntries = Object.entries(op.set!);\n setEntries.forEach(([k]) => validateColumnName(k));\n const setClauses = setEntries.map(\n ([k, v]) => `\"${k}\" = ${escapeLiteral(v)}`,\n );\n const { clause } = buildWhereClause(op.data);\n statements.push(\n `UPDATE ${qualifiedTable} SET ${setClauses.join(\", \")} WHERE ${clause}`,\n );\n break;\n }\n case \"delete\": {\n const { clause } = buildWhereClause(op.data);\n statements.push(`DELETE FROM ${qualifiedTable} WHERE ${clause}`);\n break;\n }\n }\n }\n\n return statements;\n }\n\n private validateTable(table: string): void {\n if (!this.subgraphSchema[table]) {\n throw new Error(\n `Table \"${table}\" not found in subgraph schema. Available: [${Object.keys(this.subgraphSchema).join(\", \")}]`,\n );\n }\n }\n}\n\n// --- Helpers ---\n\nfunction escapeLiteral(value: unknown): string {\n if (value === null || value === undefined) return \"NULL\";\n if (typeof value === \"number\" || typeof value === \"bigint\") return String(value);\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n if (typeof value === \"object\") return `'${JSON.stringify(value).replace(/'/g, \"''\")}'::jsonb`;\n // String — escape single quotes\n return `'${String(value).replace(/'/g, \"''\")}'`;\n}\n\nfunction buildWhereClause(where: Record<string, unknown>): {\n clause: string;\n values: unknown[];\n} {\n const entries = Object.entries(where);\n if (entries.length === 0) return { clause: \"TRUE\", values: [] };\n\n entries.forEach(([k]) => validateColumnName(k));\n const parts = entries.map(([k, v]) => `\"${k}\" = ${escapeLiteral(v)}`);\n return { clause: parts.join(\" AND \"), values: [] };\n}\n"
|
|
5
|
+
"import { sql, type Kysely, type Transaction } from \"kysely\";\nimport type { Database } from \"@secondlayer/shared/db\";\nimport { logger } from \"@secondlayer/shared/logger\";\nimport type { SubgraphSchema } from \"../types.ts\";\n\ntype AnyDb = Kysely<Database> | Transaction<Database>;\n\ninterface WriteOp {\n kind: \"insert\" | \"update\" | \"delete\";\n table: string;\n data: Record<string, unknown>;\n /** For update: SET clause */\n set?: Record<string, unknown>;\n}\n\nexport interface BlockMeta {\n height: number;\n hash: string;\n timestamp: number;\n burnBlockHeight: number;\n}\n\nexport interface TxMeta {\n txId: string;\n sender: string;\n type: string;\n status: string;\n}\n\n/** Validate that a column name is safe for SQL identifiers */\nfunction validateColumnName(name: string): void {\n if (!/^[a-z_][a-z0-9_]*$/i.test(name)) {\n throw new Error(`Invalid column name: ${name}`);\n }\n}\n\n/**\n * Runtime context passed to subgraph handlers.\n * Batches writes and flushes them atomically at the end of a block.\n * Reads execute immediately against the DB (pre-flush state).\n */\nexport class SubgraphContext {\n readonly block: BlockMeta;\n private _tx: TxMeta;\n private readonly db: AnyDb;\n private readonly pgSchemaName: string;\n private readonly subgraphSchema: SubgraphSchema;\n private readonly ops: WriteOp[] = [];\n\n constructor(\n db: AnyDb,\n pgSchemaName: string,\n subgraphSchema: SubgraphSchema,\n block: BlockMeta,\n tx: TxMeta,\n ) {\n this.db = db;\n this.pgSchemaName = pgSchemaName;\n this.subgraphSchema = subgraphSchema;\n this.block = block;\n this._tx = tx;\n }\n\n get tx(): TxMeta {\n return this._tx;\n }\n\n /** Update the current transaction context (used by runner between events) */\n setTx(tx: TxMeta): void {\n this._tx = tx;\n }\n\n // --- Write operations (batched) ---\n\n insert(table: string, row: Record<string, unknown>): void {\n this.validateTable(table);\n this.ops.push({ kind: \"insert\", table, data: row });\n }\n\n update(\n table: string,\n where: Record<string, unknown>,\n set: Record<string, unknown>,\n ): void {\n this.validateTable(table);\n this.ops.push({ kind: \"update\", table, data: where, set });\n }\n\n upsert(\n table: string,\n key: Record<string, unknown>,\n row: Record<string, unknown>,\n ): void {\n this.validateTable(table);\n const tableDef = this.subgraphSchema[table]!;\n const keyColumns = Object.keys(key);\n\n // Check if there's a matching uniqueKeys constraint\n const hasUniqueConstraint = tableDef.uniqueKeys?.some(\n (uk) => uk.length === keyColumns.length && uk.every((c) => keyColumns.includes(c)),\n );\n\n if (hasUniqueConstraint) {\n // Use ON CONFLICT for proper upsert\n this.ops.push({ kind: \"insert\", table, data: { ...key, ...row, _upsert_keys: keyColumns } });\n } else {\n // Fallback: log warning, use findOne + conditional insert/update\n logger.warn(\"upsert called without matching uniqueKeys constraint, using fallback\", {\n table,\n keys: keyColumns,\n });\n this.ops.push({ kind: \"insert\", table, data: { ...key, ...row, _upsert_fallback_keys: keyColumns, _upsert_fallback_set: row } });\n }\n }\n\n delete(table: string, where: Record<string, unknown>): void {\n this.validateTable(table);\n this.ops.push({ kind: \"delete\", table, data: where });\n }\n\n // --- Read operations (immediate) ---\n\n async findOne(\n table: string,\n where: Record<string, unknown>,\n ): Promise<Record<string, unknown> | null> {\n this.validateTable(table);\n const qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n const { clause } = buildWhereClause(where);\n const query = `SELECT * FROM ${qualifiedTable} WHERE ${clause} LIMIT 1`;\n const { rows } = await sql.raw(query).execute(this.db);\n const row = (rows as Record<string, unknown>[])[0] ?? null;\n return row ? this.coerceRow(table, row) : null;\n }\n\n async findMany(\n table: string,\n where: Record<string, unknown>,\n ): Promise<Record<string, unknown>[]> {\n this.validateTable(table);\n const qualifiedTable = `\"${this.pgSchemaName}\".\"${table}\"`;\n const { clause } = buildWhereClause(where);\n const query = `SELECT * FROM ${qualifiedTable} WHERE ${clause}`;\n const { rows } = await sql.raw(query).execute(this.db);\n return (rows as Record<string, unknown>[]).map((r) => this.coerceRow(table, r));\n }\n\n /** Coerce string values from Postgres back to BigInt for uint/int columns */\n private coerceRow(table: string, row: Record<string, unknown>): Record<string, unknown> {\n const tableDef = this.subgraphSchema[table];\n if (!tableDef) return row;\n const result = { ...row };\n for (const [col, def] of Object.entries(tableDef.columns)) {\n if ((def.type === \"uint\" || def.type === \"int\") && typeof result[col] === \"string\") {\n result[col] = BigInt(result[col] as string);\n }\n }\n return result;\n }\n\n // --- Flush ---\n\n /** Number of pending write operations */\n get pendingOps(): number {\n return this.ops.length;\n }\n\n /**\n * Execute all batched writes in a single transaction.\n * Auto-populates _block_height, _tx_id, _created_at on inserts.\n */\n async flush(): Promise<number> {\n if (this.ops.length === 0) return 0;\n\n const opsToFlush = [...this.ops];\n this.ops.length = 0;\n\n const statements = this.buildStatements(opsToFlush);\n\n // If db is already a transaction, execute directly\n if (\"isTransaction\" in this.db) {\n for (const stmt of statements) {\n await sql.raw(stmt).execute(this.db);\n }\n } else {\n await (this.db as Kysely<Database>).transaction().execute(async (tx) => {\n for (const stmt of statements) {\n await sql.raw(stmt).execute(tx);\n }\n });\n }\n\n return opsToFlush.length;\n }\n\n /** Prepare a single insert row, returning its data, columns, upsert key for batching. */\n private prepareInsert(op: WriteOp): {\n data: Record<string, unknown>;\n cols: string[];\n vals: string[];\n upsertKeys: string[] | undefined;\n batchKey: string;\n } {\n const upsertKeys = op.data._upsert_keys as string[] | undefined;\n const data = { ...op.data };\n delete data._upsert_keys;\n delete data._upsert_fallback_keys;\n delete data._upsert_fallback_set;\n\n data._block_height = this.block.height;\n data._tx_id = this._tx.txId;\n data._created_at = \"NOW()\";\n\n const cols = Object.keys(data);\n cols.forEach(validateColumnName);\n const vals = cols.map((c) =>\n data[c] === \"NOW()\" ? \"NOW()\" : escapeLiteral(data[c]),\n );\n\n // Batch key: table + sorted columns + upsert key signature (spread to avoid mutating cols)\n const batchKey = `${op.table}:${[...cols].sort().join(\",\")}:${upsertKeys ? [...upsertKeys].sort().join(\",\") : \"\"}`;\n\n return { data, cols, vals, upsertKeys, batchKey };\n }\n\n /** Build SQL statements from write ops, batching compatible INSERTs. */\n private buildStatements(ops: WriteOp[]): string[] {\n const statements: string[] = [];\n\n // Group consecutive inserts by batch key\n type InsertBatch = {\n table: string;\n cols: string[];\n rows: string[][];\n upsertKeys: string[] | undefined;\n };\n\n let currentBatch: InsertBatch | null = null;\n let currentBatchKey = \"\";\n\n const flushInsertBatch = () => {\n if (!currentBatch) return;\n const qualifiedTable = `\"${this.pgSchemaName}\".\"${currentBatch.table}\"`;\n const colList = currentBatch.cols.map((c) => `\"${c}\"`).join(\", \");\n\n // Deduplicate by upsert key — last row wins (Postgres rejects duplicate keys in one INSERT)\n let rows = currentBatch.rows;\n if (currentBatch.upsertKeys && currentBatch.upsertKeys.length > 0) {\n const keyIndices = currentBatch.upsertKeys.map((k) => currentBatch!.cols.indexOf(k));\n const seen = new Map<string, number>();\n for (let i = 0; i < rows.length; i++) {\n const key = keyIndices.map((ki) => rows[i][ki]).join(\"\\0\");\n seen.set(key, i);\n }\n if (seen.size < rows.length) {\n rows = Array.from(seen.values()).map((i) => rows[i]);\n }\n }\n\n const valuesList = rows.map((r) => `(${r.join(\", \")})`).join(\", \");\n let stmt = `INSERT INTO ${qualifiedTable} (${colList}) VALUES ${valuesList}`;\n\n if (currentBatch.upsertKeys && currentBatch.upsertKeys.length > 0) {\n const updateCols = currentBatch.cols.filter(\n (c) => !currentBatch!.upsertKeys!.includes(c) && !c.startsWith(\"_\"),\n );\n if (updateCols.length > 0) {\n const setClauses = updateCols.map((c) => `\"${c}\" = EXCLUDED.\"${c}\"`);\n stmt += ` ON CONFLICT (${currentBatch.upsertKeys.map((k) => `\"${k}\"`).join(\", \")}) DO UPDATE SET ${setClauses.join(\", \")}`;\n } else {\n stmt += ` ON CONFLICT (${currentBatch.upsertKeys.map((k) => `\"${k}\"`).join(\", \")}) DO NOTHING`;\n }\n }\n\n statements.push(stmt);\n currentBatch = null;\n currentBatchKey = \"\";\n };\n\n for (const op of ops) {\n const qualifiedTable = `\"${this.pgSchemaName}\".\"${op.table}\"`;\n\n if (op.kind === \"insert\") {\n const { cols, vals, upsertKeys, batchKey } = this.prepareInsert(op);\n\n if (batchKey === currentBatchKey && currentBatch) {\n // Same table + columns + upsert key — append to batch\n currentBatch.rows.push(vals);\n } else {\n // Different batch — flush previous and start new\n flushInsertBatch();\n currentBatch = { table: op.table, cols, rows: [vals], upsertKeys };\n currentBatchKey = batchKey;\n }\n } else {\n // Non-insert — flush any pending insert batch first\n flushInsertBatch();\n\n if (op.kind === \"update\") {\n const setEntries = Object.entries(op.set!);\n setEntries.forEach(([k]) => validateColumnName(k));\n const setClauses = setEntries.map(\n ([k, v]) => `\"${k}\" = ${escapeLiteral(v)}`,\n );\n const { clause } = buildWhereClause(op.data);\n statements.push(\n `UPDATE ${qualifiedTable} SET ${setClauses.join(\", \")} WHERE ${clause}`,\n );\n } else if (op.kind === \"delete\") {\n const { clause } = buildWhereClause(op.data);\n statements.push(`DELETE FROM ${qualifiedTable} WHERE ${clause}`);\n }\n }\n }\n\n // Flush any remaining insert batch\n flushInsertBatch();\n\n return statements;\n }\n\n private validateTable(table: string): void {\n if (!this.subgraphSchema[table]) {\n throw new Error(\n `Table \"${table}\" not found in subgraph schema. Available: [${Object.keys(this.subgraphSchema).join(\", \")}]`,\n );\n }\n }\n}\n\n// --- Helpers ---\n\nfunction escapeLiteral(value: unknown): string {\n if (value === null || value === undefined) return \"NULL\";\n if (typeof value === \"number\" || typeof value === \"bigint\") return String(value);\n if (typeof value === \"boolean\") return value ? \"TRUE\" : \"FALSE\";\n if (typeof value === \"object\") return `'${JSON.stringify(value).replace(/'/g, \"''\")}'::jsonb`;\n // String — escape single quotes\n return `'${String(value).replace(/'/g, \"''\")}'`;\n}\n\nfunction buildWhereClause(where: Record<string, unknown>): {\n clause: string;\n values: unknown[];\n} {\n const entries = Object.entries(where);\n if (entries.length === 0) return { clause: \"TRUE\", values: [] };\n\n entries.forEach(([k]) => validateColumnName(k));\n const parts = entries.map(([k, v]) => `\"${k}\" = ${escapeLiteral(v)}`);\n return { clause: parts.join(\" AND \"), values: [] };\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": ";;;;AAAA;AAEA;AA4BA,SAAS,kBAAkB,CAAC,MAAoB;AAAA,EAC9C,IAAI,CAAC,sBAAsB,KAAK,IAAI,GAAG;AAAA,IACrC,MAAM,IAAI,MAAM,wBAAwB,MAAM;AAAA,EAChD;AAAA;AAAA;AAQK,MAAM,gBAAgB;AAAA,EAClB;AAAA,EACD;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAiB,CAAC;AAAA,EAEnC,WAAW,CACT,IACA,cACA,gBACA,OACA,IACA;AAAA,IACA,KAAK,KAAK;AAAA,IACV,KAAK,eAAe;AAAA,IACpB,KAAK,iBAAiB;AAAA,IACtB,KAAK,QAAQ;AAAA,IACb,KAAK,MAAM;AAAA;AAAA,MAGT,EAAE,GAAW;AAAA,IACf,OAAO,KAAK;AAAA;AAAA,EAId,KAAK,CAAC,IAAkB;AAAA,IACtB,KAAK,MAAM;AAAA;AAAA,EAKb,MAAM,CAAC,OAAe,KAAoC;AAAA,IACxD,KAAK,cAAc,KAAK;AAAA,IACxB,KAAK,IAAI,KAAK,EAAE,MAAM,UAAU,OAAO,MAAM,IAAI,CAAC;AAAA;AAAA,EAGpD,MAAM,CACJ,OACA,OACA,KACM;AAAA,IACN,KAAK,cAAc,KAAK;AAAA,IACxB,KAAK,IAAI,KAAK,EAAE,MAAM,UAAU,OAAO,MAAM,OAAO,IAAI,CAAC;AAAA;AAAA,EAG3D,MAAM,CACJ,OACA,KACA,KACM;AAAA,IACN,KAAK,cAAc,KAAK;AAAA,IACxB,MAAM,WAAW,KAAK,eAAe;AAAA,IACrC,MAAM,aAAa,OAAO,KAAK,GAAG;AAAA,IAGlC,MAAM,sBAAsB,SAAS,YAAY,KAC/C,CAAC,OAAO,GAAG,WAAW,WAAW,UAAU,GAAG,MAAM,CAAC,MAAM,WAAW,SAAS,CAAC,CAAC,CACnF;AAAA,IAEA,IAAI,qBAAqB;AAAA,MAEvB,KAAK,IAAI,KAAK,EAAE,MAAM,UAAU,OAAO,MAAM,KAAK,QAAQ,KAAK,cAAc,WAAW,EAAE,CAAC;AAAA,IAC7F,EAAO;AAAA,MAEL,OAAO,KAAK,wEAAwE;AAAA,QAClF;AAAA,QACA,MAAM;AAAA,MACR,CAAC;AAAA,MACD,KAAK,IAAI,KAAK,EAAE,MAAM,UAAU,OAAO,MAAM,KAAK,QAAQ,KAAK,uBAAuB,YAAY,sBAAsB,IAAI,EAAE,CAAC;AAAA;AAAA;AAAA,EAInI,MAAM,CAAC,OAAe,OAAsC;AAAA,IAC1D,KAAK,cAAc,KAAK;AAAA,IACxB,KAAK,IAAI,KAAK,EAAE,MAAM,UAAU,OAAO,MAAM,MAAM,CAAC;AAAA;AAAA,OAKhD,QAAO,CACX,OACA,OACyC;AAAA,IACzC,KAAK,cAAc,KAAK;AAAA,IACxB,MAAM,iBAAiB,IAAI,KAAK,kBAAkB;AAAA,IAClD,QAAQ,WAAW,iBAAiB,KAAK;AAAA,IACzC,MAAM,QAAQ,iBAAiB,wBAAwB;AAAA,IACvD,QAAQ,SAAS,MAAM,IAAI,IAAI,KAAK,EAAE,QAAQ,KAAK,EAAE;AAAA,IACrD,MAAM,MAAO,KAAmC,MAAM;AAAA,IACtD,OAAO,MAAM,KAAK,UAAU,OAAO,GAAG,IAAI;AAAA;AAAA,OAGtC,SAAQ,CACZ,OACA,OACoC;AAAA,IACpC,KAAK,cAAc,KAAK;AAAA,IACxB,MAAM,iBAAiB,IAAI,KAAK,kBAAkB;AAAA,IAClD,QAAQ,WAAW,iBAAiB,KAAK;AAAA,IACzC,MAAM,QAAQ,iBAAiB,wBAAwB;AAAA,IACvD,QAAQ,SAAS,MAAM,IAAI,IAAI,KAAK,EAAE,QAAQ,KAAK,EAAE;AAAA,IACrD,OAAQ,KAAmC,IAAI,CAAC,MAAM,KAAK,UAAU,OAAO,CAAC,CAAC;AAAA;AAAA,EAIxE,SAAS,CAAC,OAAe,KAAuD;AAAA,IACtF,MAAM,WAAW,KAAK,eAAe;AAAA,IACrC,IAAI,CAAC;AAAA,MAAU,OAAO;AAAA,IACtB,MAAM,SAAS,KAAK,IAAI;AAAA,IACxB,YAAY,KAAK,QAAQ,OAAO,QAAQ,SAAS,OAAO,GAAG;AAAA,MACzD,KAAK,IAAI,SAAS,UAAU,IAAI,SAAS,UAAU,OAAO,OAAO,SAAS,UAAU;AAAA,QAClF,OAAO,OAAO,OAAO,OAAO,IAAc;AAAA,MAC5C;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,MAML,UAAU,GAAW;AAAA,IACvB,OAAO,KAAK,IAAI;AAAA;AAAA,OAOZ,MAAK,GAAoB;AAAA,IAC7B,IAAI,KAAK,IAAI,WAAW;AAAA,MAAG,OAAO;AAAA,IAElC,MAAM,aAAa,CAAC,GAAG,KAAK,GAAG;AAAA,IAC/B,KAAK,IAAI,SAAS;AAAA,IAElB,MAAM,aAAa,KAAK,gBAAgB,UAAU;AAAA,IAGlD,IAAI,mBAAmB,KAAK,IAAI;AAAA,MAC9B,WAAW,QAAQ,YAAY;AAAA,QAC7B,MAAM,IAAI,IAAI,IAAI,EAAE,QAAQ,KAAK,EAAE;AAAA,MACrC;AAAA,IACF,EAAO;AAAA,MACL,MAAO,KAAK,GAAwB,YAAY,EAAE,QAAQ,OAAO,OAAO;AAAA,QACtE,WAAW,QAAQ,YAAY;AAAA,UAC7B,MAAM,IAAI,IAAI,IAAI,EAAE,QAAQ,EAAE;AAAA,QAChC;AAAA,OACD;AAAA;AAAA,IAGH,OAAO,WAAW;AAAA;AAAA,EAIZ,
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "CE4757E3FCD15A2D64756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -122,53 +122,83 @@ class SubgraphContext {
|
|
|
122
122
|
}
|
|
123
123
|
return opsToFlush.length;
|
|
124
124
|
}
|
|
125
|
+
prepareInsert(op) {
|
|
126
|
+
const upsertKeys = op.data._upsert_keys;
|
|
127
|
+
const data = { ...op.data };
|
|
128
|
+
delete data._upsert_keys;
|
|
129
|
+
delete data._upsert_fallback_keys;
|
|
130
|
+
delete data._upsert_fallback_set;
|
|
131
|
+
data._block_height = this.block.height;
|
|
132
|
+
data._tx_id = this._tx.txId;
|
|
133
|
+
data._created_at = "NOW()";
|
|
134
|
+
const cols = Object.keys(data);
|
|
135
|
+
cols.forEach(validateColumnName);
|
|
136
|
+
const vals = cols.map((c) => data[c] === "NOW()" ? "NOW()" : escapeLiteral(data[c]));
|
|
137
|
+
const batchKey = `${op.table}:${[...cols].sort().join(",")}:${upsertKeys ? [...upsertKeys].sort().join(",") : ""}`;
|
|
138
|
+
return { data, cols, vals, upsertKeys, batchKey };
|
|
139
|
+
}
|
|
125
140
|
buildStatements(ops) {
|
|
126
141
|
const statements = [];
|
|
142
|
+
let currentBatch = null;
|
|
143
|
+
let currentBatchKey = "";
|
|
144
|
+
const flushInsertBatch = () => {
|
|
145
|
+
if (!currentBatch)
|
|
146
|
+
return;
|
|
147
|
+
const qualifiedTable = `"${this.pgSchemaName}"."${currentBatch.table}"`;
|
|
148
|
+
const colList = currentBatch.cols.map((c) => `"${c}"`).join(", ");
|
|
149
|
+
let rows = currentBatch.rows;
|
|
150
|
+
if (currentBatch.upsertKeys && currentBatch.upsertKeys.length > 0) {
|
|
151
|
+
const keyIndices = currentBatch.upsertKeys.map((k) => currentBatch.cols.indexOf(k));
|
|
152
|
+
const seen = new Map;
|
|
153
|
+
for (let i = 0;i < rows.length; i++) {
|
|
154
|
+
const key = keyIndices.map((ki) => rows[i][ki]).join("\x00");
|
|
155
|
+
seen.set(key, i);
|
|
156
|
+
}
|
|
157
|
+
if (seen.size < rows.length) {
|
|
158
|
+
rows = Array.from(seen.values()).map((i) => rows[i]);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const valuesList = rows.map((r) => `(${r.join(", ")})`).join(", ");
|
|
162
|
+
let stmt = `INSERT INTO ${qualifiedTable} (${colList}) VALUES ${valuesList}`;
|
|
163
|
+
if (currentBatch.upsertKeys && currentBatch.upsertKeys.length > 0) {
|
|
164
|
+
const updateCols = currentBatch.cols.filter((c) => !currentBatch.upsertKeys.includes(c) && !c.startsWith("_"));
|
|
165
|
+
if (updateCols.length > 0) {
|
|
166
|
+
const setClauses = updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`);
|
|
167
|
+
stmt += ` ON CONFLICT (${currentBatch.upsertKeys.map((k) => `"${k}"`).join(", ")}) DO UPDATE SET ${setClauses.join(", ")}`;
|
|
168
|
+
} else {
|
|
169
|
+
stmt += ` ON CONFLICT (${currentBatch.upsertKeys.map((k) => `"${k}"`).join(", ")}) DO NOTHING`;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
statements.push(stmt);
|
|
173
|
+
currentBatch = null;
|
|
174
|
+
currentBatchKey = "";
|
|
175
|
+
};
|
|
127
176
|
for (const op of ops) {
|
|
128
177
|
const qualifiedTable = `"${this.pgSchemaName}"."${op.table}"`;
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
delete data._upsert_fallback_set;
|
|
138
|
-
data._block_height = this.block.height;
|
|
139
|
-
data._tx_id = this._tx.txId;
|
|
140
|
-
data._created_at = "NOW()";
|
|
141
|
-
const cols = Object.keys(data);
|
|
142
|
-
cols.forEach(validateColumnName);
|
|
143
|
-
const vals = cols.map((c) => data[c] === "NOW()" ? "NOW()" : escapeLiteral(data[c]));
|
|
144
|
-
let stmt = `INSERT INTO ${qualifiedTable} (${cols.map((c) => `"${c}"`).join(", ")}) VALUES (${vals.join(", ")})`;
|
|
145
|
-
if (upsertKeys && upsertKeys.length > 0) {
|
|
146
|
-
const updateCols = cols.filter((c) => !upsertKeys.includes(c) && !c.startsWith("_"));
|
|
147
|
-
if (updateCols.length > 0) {
|
|
148
|
-
const setClauses = updateCols.map((c) => `"${c}" = EXCLUDED."${c}"`);
|
|
149
|
-
stmt += ` ON CONFLICT (${upsertKeys.map((k) => `"${k}"`).join(", ")}) DO UPDATE SET ${setClauses.join(", ")}`;
|
|
150
|
-
} else {
|
|
151
|
-
stmt += ` ON CONFLICT (${upsertKeys.map((k) => `"${k}"`).join(", ")}) DO NOTHING`;
|
|
152
|
-
}
|
|
153
|
-
} else if (fallbackKeys && fallbackSet) {}
|
|
154
|
-
statements.push(stmt);
|
|
155
|
-
break;
|
|
178
|
+
if (op.kind === "insert") {
|
|
179
|
+
const { cols, vals, upsertKeys, batchKey } = this.prepareInsert(op);
|
|
180
|
+
if (batchKey === currentBatchKey && currentBatch) {
|
|
181
|
+
currentBatch.rows.push(vals);
|
|
182
|
+
} else {
|
|
183
|
+
flushInsertBatch();
|
|
184
|
+
currentBatch = { table: op.table, cols, rows: [vals], upsertKeys };
|
|
185
|
+
currentBatchKey = batchKey;
|
|
156
186
|
}
|
|
157
|
-
|
|
187
|
+
} else {
|
|
188
|
+
flushInsertBatch();
|
|
189
|
+
if (op.kind === "update") {
|
|
158
190
|
const setEntries = Object.entries(op.set);
|
|
159
191
|
setEntries.forEach(([k]) => validateColumnName(k));
|
|
160
192
|
const setClauses = setEntries.map(([k, v]) => `"${k}" = ${escapeLiteral(v)}`);
|
|
161
193
|
const { clause } = buildWhereClause(op.data);
|
|
162
194
|
statements.push(`UPDATE ${qualifiedTable} SET ${setClauses.join(", ")} WHERE ${clause}`);
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
case "delete": {
|
|
195
|
+
} else if (op.kind === "delete") {
|
|
166
196
|
const { clause } = buildWhereClause(op.data);
|
|
167
197
|
statements.push(`DELETE FROM ${qualifiedTable} WHERE ${clause}`);
|
|
168
|
-
break;
|
|
169
198
|
}
|
|
170
199
|
}
|
|
171
200
|
}
|
|
201
|
+
flushInsertBatch();
|
|
172
202
|
return statements;
|
|
173
203
|
}
|
|
174
204
|
validateTable(table) {
|
|
@@ -418,6 +448,7 @@ import { updateSubgraphStatus, recordSubgraphProcessed } from "@secondlayer/shar
|
|
|
418
448
|
import { pgSchemaName } from "@secondlayer/shared/db/queries/subgraphs";
|
|
419
449
|
|
|
420
450
|
// src/runtime/block-processor.ts
|
|
451
|
+
var schemaNameCache = new Map;
|
|
421
452
|
async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
422
453
|
const db = getDb();
|
|
423
454
|
const blockStart = performance.now();
|
|
@@ -428,19 +459,26 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
428
459
|
errors: 0,
|
|
429
460
|
skipped: false
|
|
430
461
|
};
|
|
431
|
-
|
|
432
|
-
if (
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
462
|
+
let block, txs, evts;
|
|
463
|
+
if (opts?.preloaded) {
|
|
464
|
+
block = opts.preloaded.block;
|
|
465
|
+
txs = opts.preloaded.txs;
|
|
466
|
+
evts = opts.preloaded.events;
|
|
467
|
+
} else {
|
|
468
|
+
block = await db.selectFrom("blocks").selectAll().where("height", "=", blockHeight).executeTakeFirst();
|
|
469
|
+
if (!block) {
|
|
470
|
+
logger3.warn("Block not found for subgraph processing", { subgraph: subgraphName, blockHeight });
|
|
471
|
+
result.skipped = true;
|
|
472
|
+
return result;
|
|
473
|
+
}
|
|
474
|
+
if (!block.canonical) {
|
|
475
|
+
logger3.debug("Skipping non-canonical block", { subgraph: subgraphName, blockHeight });
|
|
476
|
+
result.skipped = true;
|
|
477
|
+
return result;
|
|
478
|
+
}
|
|
479
|
+
txs = await db.selectFrom("transactions").selectAll().where("block_height", "=", blockHeight).execute();
|
|
480
|
+
evts = await db.selectFrom("events").selectAll().where("block_height", "=", blockHeight).execute();
|
|
441
481
|
}
|
|
442
|
-
const txs = await db.selectFrom("transactions").selectAll().where("block_height", "=", blockHeight).execute();
|
|
443
|
-
const evts = await db.selectFrom("events").selectAll().where("block_height", "=", blockHeight).execute();
|
|
444
482
|
const matched = matchSources(subgraph.sources, txs, evts);
|
|
445
483
|
result.matched = matched.length;
|
|
446
484
|
if (matched.length === 0) {
|
|
@@ -449,8 +487,12 @@ async function processBlock(subgraph, subgraphName, blockHeight, opts) {
|
|
|
449
487
|
}
|
|
450
488
|
return result;
|
|
451
489
|
}
|
|
452
|
-
|
|
453
|
-
|
|
490
|
+
let schemaName = schemaNameCache.get(subgraphName);
|
|
491
|
+
if (!schemaName) {
|
|
492
|
+
const subgraphRecord = await db.selectFrom("subgraphs").select("schema_name").where("name", "=", subgraphName).executeTakeFirst();
|
|
493
|
+
schemaName = subgraphRecord?.schema_name ?? pgSchemaName(subgraphName);
|
|
494
|
+
schemaNameCache.set(subgraphName, schemaName);
|
|
495
|
+
}
|
|
454
496
|
const blockMeta = {
|
|
455
497
|
height: block.height,
|
|
456
498
|
hash: block.hash,
|
|
@@ -578,8 +620,62 @@ class StatsAccumulator {
|
|
|
578
620
|
import { getDb as getDb2 } from "@secondlayer/shared/db";
|
|
579
621
|
import { logger as logger4 } from "@secondlayer/shared/logger";
|
|
580
622
|
import { getSubgraph } from "@secondlayer/shared/db/queries/subgraphs";
|
|
623
|
+
|
|
624
|
+
// src/runtime/batch-loader.ts
|
|
625
|
+
async function loadBlockRange(db, fromHeight, toHeight) {
|
|
626
|
+
const [blocks, txs, events] = await Promise.all([
|
|
627
|
+
db.selectFrom("blocks").selectAll().where("height", ">=", fromHeight).where("height", "<=", toHeight).where("canonical", "=", true).execute(),
|
|
628
|
+
db.selectFrom("transactions").selectAll().where("block_height", ">=", fromHeight).where("block_height", "<=", toHeight).execute(),
|
|
629
|
+
db.selectFrom("events").selectAll().where("block_height", ">=", fromHeight).where("block_height", "<=", toHeight).execute()
|
|
630
|
+
]);
|
|
631
|
+
const txsByHeight = new Map;
|
|
632
|
+
for (const tx of txs) {
|
|
633
|
+
const h = Number(tx.block_height);
|
|
634
|
+
const list = txsByHeight.get(h) ?? [];
|
|
635
|
+
list.push(tx);
|
|
636
|
+
txsByHeight.set(h, list);
|
|
637
|
+
}
|
|
638
|
+
const eventsByHeight = new Map;
|
|
639
|
+
for (const evt of events) {
|
|
640
|
+
const h = Number(evt.block_height);
|
|
641
|
+
const list = eventsByHeight.get(h) ?? [];
|
|
642
|
+
list.push(evt);
|
|
643
|
+
eventsByHeight.set(h, list);
|
|
644
|
+
}
|
|
645
|
+
const result = new Map;
|
|
646
|
+
for (const block of blocks) {
|
|
647
|
+
const h = Number(block.height);
|
|
648
|
+
result.set(h, {
|
|
649
|
+
block,
|
|
650
|
+
txs: txsByHeight.get(h) ?? [],
|
|
651
|
+
events: eventsByHeight.get(h) ?? []
|
|
652
|
+
});
|
|
653
|
+
}
|
|
654
|
+
return result;
|
|
655
|
+
}
|
|
656
|
+
function avgEventsPerBlock(batch) {
|
|
657
|
+
if (batch.size === 0)
|
|
658
|
+
return 0;
|
|
659
|
+
let totalEvents = 0;
|
|
660
|
+
for (const data of batch.values()) {
|
|
661
|
+
totalEvents += data.events.length;
|
|
662
|
+
}
|
|
663
|
+
return totalEvents / batch.size;
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
// src/runtime/catchup.ts
|
|
581
667
|
var LOG_INTERVAL = 1000;
|
|
668
|
+
var DEFAULT_BATCH_SIZE = 500;
|
|
669
|
+
var MIN_BATCH_SIZE = 100;
|
|
670
|
+
var MAX_BATCH_SIZE = 1000;
|
|
582
671
|
var catchingUp = new Set;
|
|
672
|
+
function adjustBatchSize(current, avgEvents) {
|
|
673
|
+
if (avgEvents > 50)
|
|
674
|
+
return Math.max(Math.round(current * 0.5), MIN_BATCH_SIZE);
|
|
675
|
+
if (avgEvents < 10)
|
|
676
|
+
return Math.min(Math.round(current * 1.5), MAX_BATCH_SIZE);
|
|
677
|
+
return current;
|
|
678
|
+
}
|
|
583
679
|
async function catchUpSubgraph(subgraph, subgraphName) {
|
|
584
680
|
if (catchingUp.has(subgraphName))
|
|
585
681
|
return 0;
|
|
@@ -606,24 +702,59 @@ async function catchUpSubgraph(subgraph, subgraphName) {
|
|
|
606
702
|
});
|
|
607
703
|
const stats = new StatsAccumulator(subgraphName, subgraphRow.api_key_id, true);
|
|
608
704
|
let processed = 0;
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
705
|
+
let batchSize = DEFAULT_BATCH_SIZE;
|
|
706
|
+
let currentHeight = startBlock;
|
|
707
|
+
let nextBatchPromise = loadBlockRange(db, currentHeight, Math.min(currentHeight + batchSize - 1, chainTip));
|
|
708
|
+
while (currentHeight <= chainTip) {
|
|
709
|
+
const batch = await nextBatchPromise;
|
|
710
|
+
const batchEnd = Math.min(currentHeight + batchSize - 1, chainTip);
|
|
711
|
+
const nextStart = batchEnd + 1;
|
|
712
|
+
if (nextStart <= chainTip) {
|
|
713
|
+
const nextEnd = Math.min(nextStart + batchSize - 1, chainTip);
|
|
714
|
+
nextBatchPromise = loadBlockRange(db, nextStart, nextEnd);
|
|
617
715
|
}
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
processed
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
716
|
+
for (let height = currentHeight;height <= batchEnd; height++) {
|
|
717
|
+
const blockData = batch.get(height);
|
|
718
|
+
if (!blockData) {
|
|
719
|
+
processed++;
|
|
720
|
+
continue;
|
|
721
|
+
}
|
|
722
|
+
let result;
|
|
723
|
+
try {
|
|
724
|
+
result = await processBlock(subgraph, subgraphName, height, {
|
|
725
|
+
preloaded: blockData
|
|
726
|
+
});
|
|
727
|
+
} catch (err) {
|
|
728
|
+
logger4.error("Block processing error during catch-up", {
|
|
729
|
+
subgraph: subgraphName,
|
|
730
|
+
blockHeight: height,
|
|
731
|
+
error: err instanceof Error ? err.message : String(err)
|
|
732
|
+
});
|
|
733
|
+
const { updateSubgraphStatus: updateSubgraphStatus2 } = await import("@secondlayer/shared/db/queries/subgraphs");
|
|
734
|
+
await updateSubgraphStatus2(db, subgraphName, "active", height).catch(() => {});
|
|
735
|
+
processed++;
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
processed++;
|
|
739
|
+
if (result.timing) {
|
|
740
|
+
stats.record(result.timing, result.processed);
|
|
741
|
+
if (stats.shouldFlush()) {
|
|
742
|
+
await stats.flush(db);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
if (processed % LOG_INTERVAL === 0) {
|
|
746
|
+
logger4.info("Subgraph catch-up progress", {
|
|
747
|
+
subgraph: subgraphName,
|
|
748
|
+
processed,
|
|
749
|
+
total: totalBlocks,
|
|
750
|
+
currentBlock: height,
|
|
751
|
+
pct: Math.round(processed / totalBlocks * 100)
|
|
752
|
+
});
|
|
753
|
+
}
|
|
626
754
|
}
|
|
755
|
+
const avg = avgEventsPerBlock(batch);
|
|
756
|
+
batchSize = adjustBatchSize(batchSize, avg);
|
|
757
|
+
currentHeight = batchEnd + 1;
|
|
627
758
|
}
|
|
628
759
|
await stats.flush(db);
|
|
629
760
|
logger4.info("Subgraph catch-up complete", {
|
|
@@ -650,7 +781,7 @@ async function handleSubgraphReorg(blockHeight, loadSubgraphDef) {
|
|
|
650
781
|
logger5.info("Propagating reorg to subgraphs", { blockHeight, subgraphCount: activeSubgraphs.length });
|
|
651
782
|
for (const sg of activeSubgraphs) {
|
|
652
783
|
try {
|
|
653
|
-
const schema = sg.definition
|
|
784
|
+
const schema = sg.definition.schema;
|
|
654
785
|
if (!schema)
|
|
655
786
|
continue;
|
|
656
787
|
const schemaName = sg.schema_name ?? pgSchemaName(sg.name);
|
|
@@ -779,5 +910,5 @@ export {
|
|
|
779
910
|
startSubgraphProcessor
|
|
780
911
|
};
|
|
781
912
|
|
|
782
|
-
//# debugId=
|
|
913
|
+
//# debugId=584F9781CF28817C64756E2164756E21
|
|
783
914
|
//# sourceMappingURL=processor.js.map
|