@secondlayer/subgraphs 3.26.1 → 3.26.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/dist/src/index.js +339 -68
- package/dist/src/index.js.map +6 -4
- package/dist/src/runtime/catchup.d.ts +34 -1
- package/dist/src/runtime/catchup.js +14 -3
- package/dist/src/runtime/catchup.js.map +3 -3
- package/dist/src/runtime/processor.js +316 -305
- package/dist/src/runtime/processor.js.map +6 -6
- package/dist/src/runtime/reindex.js +314 -43
- package/dist/src/runtime/reindex.js.map +6 -4
- package/dist/src/runtime/reorg.js +14 -5
- package/dist/src/runtime/reorg.js.map +3 -3
- package/dist/src/service.js +318 -307
- package/dist/src/service.js.map +6 -6
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -3259,9 +3259,278 @@ class StatsAccumulator {
|
|
|
3259
3259
|
}
|
|
3260
3260
|
}
|
|
3261
3261
|
|
|
3262
|
+
// src/runtime/catchup.ts
|
|
3263
|
+
import { getTargetDb as getTargetDb2, sql as sql4 } from "@secondlayer/shared/db";
|
|
3264
|
+
import { getSubgraph } from "@secondlayer/shared/db/queries/subgraphs";
|
|
3265
|
+
import { logger as logger8 } from "@secondlayer/shared/logger";
|
|
3266
|
+
|
|
3267
|
+
// src/runtime/catchup-leader.ts
|
|
3268
|
+
import {
|
|
3269
|
+
SUBGRAPH_CATCHUP_LOCK_KEY,
|
|
3270
|
+
createPostgresLeaderBackend,
|
|
3271
|
+
withLeaderLock
|
|
3272
|
+
} from "@secondlayer/shared/leader";
|
|
3273
|
+
import { targetListenerUrl } from "@secondlayer/shared/queue/listener";
|
|
3274
|
+
var catchUpLeader = false;
|
|
3275
|
+
function isCatchUpLeader() {
|
|
3276
|
+
return catchUpLeader;
|
|
3277
|
+
}
|
|
3278
|
+
function startCatchUpLeader(opts = {}) {
|
|
3279
|
+
return withLeaderLock(SUBGRAPH_CATCHUP_LOCK_KEY, async () => {
|
|
3280
|
+
catchUpLeader = true;
|
|
3281
|
+
await opts.onAcquire?.();
|
|
3282
|
+
return () => {
|
|
3283
|
+
catchUpLeader = false;
|
|
3284
|
+
};
|
|
3285
|
+
}, {
|
|
3286
|
+
pollMs: opts.pollMs,
|
|
3287
|
+
heartbeatMs: opts.heartbeatMs,
|
|
3288
|
+
createBackend: opts.createBackend ?? (() => createPostgresLeaderBackend(targetListenerUrl()))
|
|
3289
|
+
});
|
|
3290
|
+
}
|
|
3291
|
+
|
|
3292
|
+
// src/runtime/catchup.ts
|
|
3293
|
+
var LOG_INTERVAL = 1000;
|
|
3294
|
+
var STANDARD_CATCHUP_BATCH_CONFIG = {
|
|
3295
|
+
defaultBatchSize: 500,
|
|
3296
|
+
minBatchSize: 100,
|
|
3297
|
+
maxBatchSize: 1000,
|
|
3298
|
+
prefetch: true
|
|
3299
|
+
};
|
|
3300
|
+
var catchingUp = new Set;
|
|
3301
|
+
var subgraphBlockLockHeld = new Set;
|
|
3302
|
+
var subgraphBlockLockWaiters = new Map;
|
|
3303
|
+
var reorgEpoch = new Map;
|
|
3304
|
+
async function acquireSubgraphBlockLock(name) {
|
|
3305
|
+
if (!subgraphBlockLockHeld.has(name)) {
|
|
3306
|
+
subgraphBlockLockHeld.add(name);
|
|
3307
|
+
return () => releaseSubgraphBlockLock(name);
|
|
3308
|
+
}
|
|
3309
|
+
return new Promise((resolve) => {
|
|
3310
|
+
const waiters = subgraphBlockLockWaiters.get(name) ?? [];
|
|
3311
|
+
waiters.push(() => resolve(() => releaseSubgraphBlockLock(name)));
|
|
3312
|
+
subgraphBlockLockWaiters.set(name, waiters);
|
|
3313
|
+
});
|
|
3314
|
+
}
|
|
3315
|
+
function releaseSubgraphBlockLock(name) {
|
|
3316
|
+
const waiters = subgraphBlockLockWaiters.get(name);
|
|
3317
|
+
if (waiters && waiters.length > 0) {
|
|
3318
|
+
const next = waiters.shift();
|
|
3319
|
+
if (waiters.length === 0)
|
|
3320
|
+
subgraphBlockLockWaiters.delete(name);
|
|
3321
|
+
next();
|
|
3322
|
+
return;
|
|
3323
|
+
}
|
|
3324
|
+
subgraphBlockLockHeld.delete(name);
|
|
3325
|
+
}
|
|
3326
|
+
async function withSubgraphBlockLock(name, fn) {
|
|
3327
|
+
const release = await acquireSubgraphBlockLock(name);
|
|
3328
|
+
try {
|
|
3329
|
+
return await fn();
|
|
3330
|
+
} finally {
|
|
3331
|
+
release();
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
async function withSubgraphBlockAdvisoryLock(name, fn) {
|
|
3335
|
+
return getTargetDb2().transaction().execute(async (lockTx) => {
|
|
3336
|
+
await sql4`SELECT pg_advisory_xact_lock(hashtext(${`subgraph-block:${name}`}))`.execute(lockTx);
|
|
3337
|
+
return fn();
|
|
3338
|
+
});
|
|
3339
|
+
}
|
|
3340
|
+
async function withSubgraphBlockWriteLock(name, fn) {
|
|
3341
|
+
return withSubgraphBlockLock(name, () => withSubgraphBlockAdvisoryLock(name, fn));
|
|
3342
|
+
}
|
|
3343
|
+
function bumpReorgEpoch(name) {
|
|
3344
|
+
reorgEpoch.set(name, (reorgEpoch.get(name) ?? 0) + 1);
|
|
3345
|
+
}
|
|
3346
|
+
function getReorgEpoch(name) {
|
|
3347
|
+
return reorgEpoch.get(name) ?? 0;
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3350
|
+
class ReorgEpochChangedError extends Error {
|
|
3351
|
+
constructor(name) {
|
|
3352
|
+
super(`reorg epoch changed for ${name} mid catch-up`);
|
|
3353
|
+
this.name = "ReorgEpochChangedError";
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
function parsePositiveInt(value) {
|
|
3357
|
+
if (value == null || value.trim() === "")
|
|
3358
|
+
return;
|
|
3359
|
+
const parsed = Number.parseInt(value, 10);
|
|
3360
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : undefined;
|
|
3361
|
+
}
|
|
3362
|
+
function parseBoolean(value) {
|
|
3363
|
+
if (value == null || value.trim() === "")
|
|
3364
|
+
return;
|
|
3365
|
+
const normalized = value.trim().toLowerCase();
|
|
3366
|
+
if (normalized === "true")
|
|
3367
|
+
return true;
|
|
3368
|
+
if (normalized === "false")
|
|
3369
|
+
return false;
|
|
3370
|
+
return;
|
|
3371
|
+
}
|
|
3372
|
+
function resolveCatchupBatchConfig(env = process.env) {
|
|
3373
|
+
const base = STANDARD_CATCHUP_BATCH_CONFIG;
|
|
3374
|
+
const minBatchSize = parsePositiveInt(env.SUBGRAPH_CATCHUP_MIN_BATCH_SIZE) ?? base.minBatchSize;
|
|
3375
|
+
const maxBatchSize = parsePositiveInt(env.SUBGRAPH_CATCHUP_MAX_BATCH_SIZE) ?? base.maxBatchSize;
|
|
3376
|
+
const defaultBatchSize = parsePositiveInt(env.SUBGRAPH_CATCHUP_BATCH_SIZE) ?? base.defaultBatchSize;
|
|
3377
|
+
return {
|
|
3378
|
+
minBatchSize,
|
|
3379
|
+
maxBatchSize,
|
|
3380
|
+
defaultBatchSize: Math.min(Math.max(defaultBatchSize, minBatchSize), maxBatchSize),
|
|
3381
|
+
prefetch: parseBoolean(env.SUBGRAPH_CATCHUP_PREFETCH) ?? base.prefetch
|
|
3382
|
+
};
|
|
3383
|
+
}
|
|
3384
|
+
function adjustBatchSize(current, avgEvents, config) {
|
|
3385
|
+
if (avgEvents > 50)
|
|
3386
|
+
return Math.max(Math.round(current * 0.5), config.minBatchSize);
|
|
3387
|
+
if (avgEvents < 10)
|
|
3388
|
+
return Math.min(Math.round(current * 1.5), config.maxBatchSize);
|
|
3389
|
+
return current;
|
|
3390
|
+
}
|
|
3391
|
+
async function catchUpSubgraph(subgraph, subgraphName) {
|
|
3392
|
+
if (catchingUp.has(subgraphName))
|
|
3393
|
+
return 0;
|
|
3394
|
+
catchingUp.add(subgraphName);
|
|
3395
|
+
try {
|
|
3396
|
+
const source = resolveBlockSource(subgraph);
|
|
3397
|
+
const targetDb = getTargetDb2();
|
|
3398
|
+
const subgraphRow = await getSubgraph(targetDb, subgraphName);
|
|
3399
|
+
if (!subgraphRow)
|
|
3400
|
+
return 0;
|
|
3401
|
+
const lastProcessedBlock = Number(subgraphRow.last_processed_block);
|
|
3402
|
+
const chainTip = await source.getTip();
|
|
3403
|
+
if (chainTip <= 0 || lastProcessedBlock >= chainTip)
|
|
3404
|
+
return 0;
|
|
3405
|
+
const subgraphStart = Number(subgraphRow.start_block) || 1;
|
|
3406
|
+
const startBlock = Math.max(lastProcessedBlock + 1, subgraphStart);
|
|
3407
|
+
const totalBlocks = chainTip - lastProcessedBlock;
|
|
3408
|
+
logger8.info("Subgraph catch-up starting", {
|
|
3409
|
+
subgraph: subgraphName,
|
|
3410
|
+
from: startBlock,
|
|
3411
|
+
to: chainTip,
|
|
3412
|
+
blocks: totalBlocks
|
|
3413
|
+
});
|
|
3414
|
+
const stats = new StatsAccumulator(subgraphName, true);
|
|
3415
|
+
let processed = 0;
|
|
3416
|
+
const batchConfig = resolveCatchupBatchConfig();
|
|
3417
|
+
let batchSize = batchConfig.defaultBatchSize;
|
|
3418
|
+
let currentHeight = startBlock;
|
|
3419
|
+
const walkEpoch = getReorgEpoch(subgraphName);
|
|
3420
|
+
let prefetchedBatchEnd = Math.min(currentHeight + batchSize - 1, chainTip);
|
|
3421
|
+
let nextBatchPromise = batchConfig.prefetch ? source.loadBlockRange(currentHeight, prefetchedBatchEnd) : undefined;
|
|
3422
|
+
while (currentHeight <= chainTip) {
|
|
3423
|
+
if (!isCatchUpLeader()) {
|
|
3424
|
+
logger8.info("Lost catch-up leadership, stopping catch-up", {
|
|
3425
|
+
subgraph: subgraphName,
|
|
3426
|
+
processed
|
|
3427
|
+
});
|
|
3428
|
+
break;
|
|
3429
|
+
}
|
|
3430
|
+
const currentRow = await getSubgraph(targetDb, subgraphName);
|
|
3431
|
+
if (!currentRow || currentRow.status !== "active") {
|
|
3432
|
+
logger8.info("Subgraph status changed, stopping catch-up", {
|
|
3433
|
+
subgraph: subgraphName,
|
|
3434
|
+
status: currentRow?.status ?? "deleted"
|
|
3435
|
+
});
|
|
3436
|
+
break;
|
|
3437
|
+
}
|
|
3438
|
+
let batchEnd;
|
|
3439
|
+
let batch;
|
|
3440
|
+
if (nextBatchPromise) {
|
|
3441
|
+
batch = await nextBatchPromise;
|
|
3442
|
+
batchEnd = prefetchedBatchEnd;
|
|
3443
|
+
const nextStart = batchEnd + 1;
|
|
3444
|
+
if (nextStart <= chainTip) {
|
|
3445
|
+
prefetchedBatchEnd = Math.min(nextStart + batchSize - 1, chainTip);
|
|
3446
|
+
nextBatchPromise = source.loadBlockRange(nextStart, prefetchedBatchEnd);
|
|
3447
|
+
} else {
|
|
3448
|
+
nextBatchPromise = undefined;
|
|
3449
|
+
}
|
|
3450
|
+
} else {
|
|
3451
|
+
batchEnd = Math.min(currentHeight + batchSize - 1, chainTip);
|
|
3452
|
+
batch = await source.loadBlockRange(currentHeight, batchEnd);
|
|
3453
|
+
}
|
|
3454
|
+
let stopCatchup = false;
|
|
3455
|
+
for (let height = currentHeight;height <= batchEnd; height++) {
|
|
3456
|
+
let blockData = batch.get(height);
|
|
3457
|
+
if (!blockData) {
|
|
3458
|
+
blockData = (await source.loadBlockRange(height, height)).get(height);
|
|
3459
|
+
}
|
|
3460
|
+
if (!blockData) {
|
|
3461
|
+
logger8.warn("Block missing during catch-up, deferring to next tick", {
|
|
3462
|
+
subgraph: subgraphName,
|
|
3463
|
+
blockHeight: height
|
|
3464
|
+
});
|
|
3465
|
+
stopCatchup = true;
|
|
3466
|
+
break;
|
|
3467
|
+
}
|
|
3468
|
+
const preloaded = blockData;
|
|
3469
|
+
let result;
|
|
3470
|
+
try {
|
|
3471
|
+
result = await withSubgraphBlockWriteLock(subgraphName, async () => {
|
|
3472
|
+
if (getReorgEpoch(subgraphName) !== walkEpoch) {
|
|
3473
|
+
throw new ReorgEpochChangedError(subgraphName);
|
|
3474
|
+
}
|
|
3475
|
+
return processBlockWithRetry(subgraph, subgraphName, height, {
|
|
3476
|
+
preloaded
|
|
3477
|
+
});
|
|
3478
|
+
});
|
|
3479
|
+
} catch (err) {
|
|
3480
|
+
if (err instanceof ReorgEpochChangedError) {
|
|
3481
|
+
logger8.info("Reorg detected mid catch-up, aborting walk without writing further progress", { subgraph: subgraphName, blockHeight: height });
|
|
3482
|
+
stopCatchup = true;
|
|
3483
|
+
break;
|
|
3484
|
+
}
|
|
3485
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
3486
|
+
logger8.error("Block processing failed persistently during catch-up", {
|
|
3487
|
+
subgraph: subgraphName,
|
|
3488
|
+
blockHeight: height,
|
|
3489
|
+
error: errorMsg
|
|
3490
|
+
});
|
|
3491
|
+
const { updateSubgraphStatus: updateSubgraphStatus2, recordSubgraphProcessed: recordSubgraphProcessed2 } = await import("@secondlayer/shared/db/queries/subgraphs");
|
|
3492
|
+
await recordSubgraphProcessed2(targetDb, subgraphName, 0, 1, `catch-up halted at block ${height}: ${errorMsg}`).catch(() => {});
|
|
3493
|
+
await updateSubgraphStatus2(targetDb, subgraphName, "error").catch(() => {});
|
|
3494
|
+
stopCatchup = true;
|
|
3495
|
+
break;
|
|
3496
|
+
}
|
|
3497
|
+
processed++;
|
|
3498
|
+
if (result.timing) {
|
|
3499
|
+
stats.record(result.timing, result.processed);
|
|
3500
|
+
if (stats.shouldFlush()) {
|
|
3501
|
+
await stats.flush(targetDb);
|
|
3502
|
+
}
|
|
3503
|
+
}
|
|
3504
|
+
if (processed % LOG_INTERVAL === 0) {
|
|
3505
|
+
logger8.info("Subgraph catch-up progress", {
|
|
3506
|
+
subgraph: subgraphName,
|
|
3507
|
+
processed,
|
|
3508
|
+
total: totalBlocks,
|
|
3509
|
+
currentBlock: height,
|
|
3510
|
+
pct: Math.round(processed / totalBlocks * 100)
|
|
3511
|
+
});
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
if (stopCatchup)
|
|
3515
|
+
break;
|
|
3516
|
+
const avg = avgEventsPerBlock(batch);
|
|
3517
|
+
batchSize = adjustBatchSize(batchSize, avg, batchConfig);
|
|
3518
|
+
currentHeight = batchEnd + 1;
|
|
3519
|
+
}
|
|
3520
|
+
await stats.flush(targetDb);
|
|
3521
|
+
logger8.info("Subgraph catch-up complete", {
|
|
3522
|
+
subgraph: subgraphName,
|
|
3523
|
+
processed
|
|
3524
|
+
});
|
|
3525
|
+
return processed;
|
|
3526
|
+
} finally {
|
|
3527
|
+
catchingUp.delete(subgraphName);
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3262
3531
|
// src/runtime/reindex.ts
|
|
3263
3532
|
import { getErrorMessage as getErrorMessage3 } from "@secondlayer/shared";
|
|
3264
|
-
import { getRawClient, getTargetDb as
|
|
3533
|
+
import { getRawClient, getTargetDb as getTargetDb3 } from "@secondlayer/shared/db";
|
|
3265
3534
|
import {
|
|
3266
3535
|
recordGapBatch,
|
|
3267
3536
|
resolveGaps
|
|
@@ -3274,11 +3543,11 @@ import {
|
|
|
3274
3543
|
recordSubgraphProcessed as recordSubgraphProcessed2,
|
|
3275
3544
|
updateSubgraphStatus as updateSubgraphStatus2
|
|
3276
3545
|
} from "@secondlayer/shared/db/queries/subgraphs";
|
|
3277
|
-
import { logger as
|
|
3546
|
+
import { logger as logger10 } from "@secondlayer/shared/logger";
|
|
3278
3547
|
|
|
3279
3548
|
// src/runtime/reindex-notify.ts
|
|
3280
3549
|
import { getErrorMessage as getErrorMessage2 } from "@secondlayer/shared";
|
|
3281
|
-
import { logger as
|
|
3550
|
+
import { logger as logger9 } from "@secondlayer/shared/logger";
|
|
3282
3551
|
async function notifyReindexComplete(db, subgraphName, stats) {
|
|
3283
3552
|
try {
|
|
3284
3553
|
const subgraph = await db.selectFrom("subgraphs").select(["account_id"]).where("name", "=", subgraphName).executeTakeFirst();
|
|
@@ -3289,7 +3558,7 @@ async function notifyReindexComplete(db, subgraphName, stats) {
|
|
|
3289
3558
|
return;
|
|
3290
3559
|
const resendKey = process.env.RESEND_API_KEY;
|
|
3291
3560
|
if (!resendKey) {
|
|
3292
|
-
|
|
3561
|
+
logger9.warn("RESEND_API_KEY unset — skipping reindex-complete email", {
|
|
3293
3562
|
subgraph: subgraphName
|
|
3294
3563
|
});
|
|
3295
3564
|
return;
|
|
@@ -3311,14 +3580,14 @@ async function notifyReindexComplete(db, subgraphName, stats) {
|
|
|
3311
3580
|
});
|
|
3312
3581
|
if (!res.ok) {
|
|
3313
3582
|
const text = await res.text().catch(() => "");
|
|
3314
|
-
|
|
3583
|
+
logger9.warn("reindex-complete email failed", {
|
|
3315
3584
|
subgraph: subgraphName,
|
|
3316
3585
|
status: res.status,
|
|
3317
3586
|
body: text.slice(0, 200)
|
|
3318
3587
|
});
|
|
3319
3588
|
}
|
|
3320
3589
|
} catch (err) {
|
|
3321
|
-
|
|
3590
|
+
logger9.warn("reindex-complete email threw", {
|
|
3322
3591
|
subgraph: subgraphName,
|
|
3323
3592
|
error: getErrorMessage2(err)
|
|
3324
3593
|
});
|
|
@@ -3326,7 +3595,7 @@ async function notifyReindexComplete(db, subgraphName, stats) {
|
|
|
3326
3595
|
}
|
|
3327
3596
|
|
|
3328
3597
|
// src/runtime/reindex.ts
|
|
3329
|
-
var
|
|
3598
|
+
var LOG_INTERVAL2 = 1000;
|
|
3330
3599
|
var HEALTH_FLUSH_INTERVAL = 1000;
|
|
3331
3600
|
var PROGRESS_FLUSH_INTERVAL_MS = 5000;
|
|
3332
3601
|
var EMPTY_BATCH_HALT_THRESHOLD = 3;
|
|
@@ -3346,7 +3615,7 @@ function resolveReindexResumeBlock(row) {
|
|
|
3346
3615
|
const reindexFromBlock = Number(row.reindex_from_block);
|
|
3347
3616
|
return Math.max(lastProcessedBlock + 1, reindexFromBlock);
|
|
3348
3617
|
}
|
|
3349
|
-
function
|
|
3618
|
+
function parsePositiveInt2(value) {
|
|
3350
3619
|
if (value == null || value.trim() === "")
|
|
3351
3620
|
return;
|
|
3352
3621
|
const parsed = Number.parseInt(value, 10);
|
|
@@ -3354,9 +3623,9 @@ function parsePositiveInt(value) {
|
|
|
3354
3623
|
}
|
|
3355
3624
|
function resolveReindexBatchConfig(env = process.env) {
|
|
3356
3625
|
const base = STANDARD_REINDEX_BATCH_CONFIG;
|
|
3357
|
-
const minBatchSize =
|
|
3358
|
-
const maxBatchSize =
|
|
3359
|
-
const defaultBatchSize =
|
|
3626
|
+
const minBatchSize = parsePositiveInt2(env.SUBGRAPH_REINDEX_MIN_BATCH_SIZE) ?? base.minBatchSize;
|
|
3627
|
+
const maxBatchSize = parsePositiveInt2(env.SUBGRAPH_REINDEX_MAX_BATCH_SIZE) ?? base.maxBatchSize;
|
|
3628
|
+
const defaultBatchSize = parsePositiveInt2(env.SUBGRAPH_REINDEX_BATCH_SIZE) ?? base.defaultBatchSize;
|
|
3360
3629
|
return {
|
|
3361
3630
|
minBatchSize,
|
|
3362
3631
|
maxBatchSize,
|
|
@@ -3387,7 +3656,7 @@ function coalesceFailedBlocks(blocks) {
|
|
|
3387
3656
|
}
|
|
3388
3657
|
async function processBlockRange(def, opts) {
|
|
3389
3658
|
const source = resolveBlockSource(def);
|
|
3390
|
-
const targetDb =
|
|
3659
|
+
const targetDb = getTargetDb3();
|
|
3391
3660
|
const subgraphName = def.name;
|
|
3392
3661
|
const { fromBlock, toBlock, status } = opts;
|
|
3393
3662
|
const totalBlocks = toBlock - fromBlock + 1;
|
|
@@ -3430,7 +3699,7 @@ async function processBlockRange(def, opts) {
|
|
|
3430
3699
|
while (currentHeight <= toBlock) {
|
|
3431
3700
|
if (opts.signal?.aborted) {
|
|
3432
3701
|
aborted = true;
|
|
3433
|
-
|
|
3702
|
+
logger10.info("Block processing aborted", {
|
|
3434
3703
|
subgraph: subgraphName,
|
|
3435
3704
|
currentBlock: currentHeight,
|
|
3436
3705
|
reason: String(opts.signal.reason ?? "unknown")
|
|
@@ -3472,14 +3741,16 @@ async function processBlockRange(def, opts) {
|
|
|
3472
3741
|
}
|
|
3473
3742
|
let result;
|
|
3474
3743
|
try {
|
|
3475
|
-
|
|
3744
|
+
const mayWrite = blockData.txs.length > 0 || blockData.events.length > 0;
|
|
3745
|
+
const runBlock = () => processBlockWithRetry(def, subgraphName, height, {
|
|
3476
3746
|
skipProgressUpdate: true,
|
|
3477
3747
|
atomicProgress,
|
|
3478
3748
|
preloaded: blockData
|
|
3479
3749
|
});
|
|
3750
|
+
result = mayWrite ? await withSubgraphBlockWriteLock(subgraphName, runBlock) : await runBlock();
|
|
3480
3751
|
} catch (err) {
|
|
3481
3752
|
const errorMsg = getErrorMessage3(err);
|
|
3482
|
-
|
|
3753
|
+
logger10.error("Block processing failed persistently", {
|
|
3483
3754
|
subgraph: subgraphName,
|
|
3484
3755
|
blockHeight: height,
|
|
3485
3756
|
error: errorMsg
|
|
@@ -3524,8 +3795,8 @@ async function processBlockRange(def, opts) {
|
|
|
3524
3795
|
}
|
|
3525
3796
|
lastProgressFlushAt = now;
|
|
3526
3797
|
}
|
|
3527
|
-
if (blocksProcessed %
|
|
3528
|
-
|
|
3798
|
+
if (blocksProcessed % LOG_INTERVAL2 === 0) {
|
|
3799
|
+
logger10.info(`${status === "reindexing" ? "Reindex" : "Backfill"} progress`, {
|
|
3529
3800
|
subgraph: subgraphName,
|
|
3530
3801
|
processed: blocksProcessed,
|
|
3531
3802
|
total: totalBlocks,
|
|
@@ -3545,7 +3816,7 @@ async function processBlockRange(def, opts) {
|
|
|
3545
3816
|
if (batchFailedBlocks.length > 0 && opts.subgraphId) {
|
|
3546
3817
|
const gaps = coalesceFailedBlocks(batchFailedBlocks);
|
|
3547
3818
|
await recordGapBatch(targetDb, opts.subgraphId, subgraphName, gaps).catch((err) => {
|
|
3548
|
-
|
|
3819
|
+
logger10.warn("Failed to record subgraph gaps", {
|
|
3549
3820
|
subgraph: subgraphName,
|
|
3550
3821
|
error: err instanceof Error ? err.message : String(err)
|
|
3551
3822
|
});
|
|
@@ -3562,7 +3833,7 @@ async function processBlockRange(def, opts) {
|
|
|
3562
3833
|
} else {
|
|
3563
3834
|
await updateSubgraphStatus2(targetDb, subgraphName, status, jumpTo - 1);
|
|
3564
3835
|
}
|
|
3565
|
-
|
|
3836
|
+
logger10.info("Sparse skip", {
|
|
3566
3837
|
subgraph: subgraphName,
|
|
3567
3838
|
from: batchEnd + 1,
|
|
3568
3839
|
to: jumpTo - 1,
|
|
@@ -3597,16 +3868,16 @@ async function clearReindexMetadata(db, subgraphName) {
|
|
|
3597
3868
|
}
|
|
3598
3869
|
async function reindexSubgraph(def, opts) {
|
|
3599
3870
|
const source = resolveBlockSource(def);
|
|
3600
|
-
const targetDb =
|
|
3871
|
+
const targetDb = getTargetDb3();
|
|
3601
3872
|
const client = getRawClient("target");
|
|
3602
3873
|
const subgraphName = def.name;
|
|
3603
3874
|
const schemaName = opts?.schemaName ?? pgSchemaName(subgraphName);
|
|
3604
3875
|
await updateSubgraphStatus2(targetDb, subgraphName, "reindexing");
|
|
3605
|
-
|
|
3876
|
+
logger10.info("Reindex starting", { subgraph: subgraphName });
|
|
3606
3877
|
try {
|
|
3607
3878
|
const { fromBlock, toBlock } = await resolveBlockRange(source, def, opts);
|
|
3608
3879
|
if (fromBlock > toBlock) {
|
|
3609
|
-
|
|
3880
|
+
logger10.info("No blocks to reindex", {
|
|
3610
3881
|
subgraph: subgraphName,
|
|
3611
3882
|
fromBlock,
|
|
3612
3883
|
toBlock
|
|
@@ -3620,7 +3891,7 @@ async function reindexSubgraph(def, opts) {
|
|
|
3620
3891
|
await client.unsafe(stmt);
|
|
3621
3892
|
}
|
|
3622
3893
|
await updateSubgraphStatus2(targetDb, subgraphName, "reindexing", Math.max(0, fromBlock - 1));
|
|
3623
|
-
|
|
3894
|
+
logger10.info("Schema recreated for reindex", {
|
|
3624
3895
|
subgraph: subgraphName,
|
|
3625
3896
|
cursorResetTo: Math.max(0, fromBlock - 1)
|
|
3626
3897
|
});
|
|
@@ -3634,7 +3905,7 @@ async function reindexSubgraph(def, opts) {
|
|
|
3634
3905
|
last_error_at: null,
|
|
3635
3906
|
updated_at: new Date
|
|
3636
3907
|
}).where("name", "=", subgraphName).execute();
|
|
3637
|
-
|
|
3908
|
+
logger10.info("Reindexing blocks", {
|
|
3638
3909
|
subgraph: subgraphName,
|
|
3639
3910
|
fromBlock,
|
|
3640
3911
|
toBlock,
|
|
@@ -3656,9 +3927,9 @@ async function reindexSubgraph(def, opts) {
|
|
|
3656
3927
|
if (reason === "user-cancelled") {
|
|
3657
3928
|
await updateSubgraphStatus2(targetDb, subgraphName, "active");
|
|
3658
3929
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
3659
|
-
|
|
3930
|
+
logger10.info("Reindex cancelled by user", { subgraph: subgraphName });
|
|
3660
3931
|
} else {
|
|
3661
|
-
|
|
3932
|
+
logger10.info("Reindex interrupted by shutdown, will resume", {
|
|
3662
3933
|
subgraph: subgraphName
|
|
3663
3934
|
});
|
|
3664
3935
|
}
|
|
@@ -3666,7 +3937,7 @@ async function reindexSubgraph(def, opts) {
|
|
|
3666
3937
|
}
|
|
3667
3938
|
await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
|
|
3668
3939
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
3669
|
-
|
|
3940
|
+
logger10.info("Reindex complete", {
|
|
3670
3941
|
subgraph: subgraphName,
|
|
3671
3942
|
blocks: result.blocksProcessed,
|
|
3672
3943
|
events: result.totalEventsProcessed,
|
|
@@ -3679,7 +3950,7 @@ async function reindexSubgraph(def, opts) {
|
|
|
3679
3950
|
});
|
|
3680
3951
|
return { processed: result.blocksProcessed };
|
|
3681
3952
|
} catch (err) {
|
|
3682
|
-
|
|
3953
|
+
logger10.error("Reindex failed", {
|
|
3683
3954
|
subgraph: subgraphName,
|
|
3684
3955
|
error: getErrorMessage3(err)
|
|
3685
3956
|
});
|
|
@@ -3688,7 +3959,7 @@ async function reindexSubgraph(def, opts) {
|
|
|
3688
3959
|
}
|
|
3689
3960
|
}
|
|
3690
3961
|
async function resumeReindex(def, opts) {
|
|
3691
|
-
const targetDb =
|
|
3962
|
+
const targetDb = getTargetDb3();
|
|
3692
3963
|
const subgraphName = def.name;
|
|
3693
3964
|
const row = await targetDb.selectFrom("subgraphs").select([
|
|
3694
3965
|
"id",
|
|
@@ -3701,7 +3972,7 @@ async function resumeReindex(def, opts) {
|
|
|
3701
3972
|
const fromBlock = resolveReindexResumeBlock(row);
|
|
3702
3973
|
const toBlock = Number(row.reindex_to_block);
|
|
3703
3974
|
if (fromBlock == null) {
|
|
3704
|
-
|
|
3975
|
+
logger10.info("No reindex metadata, starting fresh reindex", {
|
|
3705
3976
|
subgraph: subgraphName
|
|
3706
3977
|
});
|
|
3707
3978
|
return reindexSubgraph(def, {
|
|
@@ -3710,12 +3981,12 @@ async function resumeReindex(def, opts) {
|
|
|
3710
3981
|
});
|
|
3711
3982
|
}
|
|
3712
3983
|
if (fromBlock > toBlock) {
|
|
3713
|
-
|
|
3984
|
+
logger10.info("Resume: no remaining blocks", { subgraph: subgraphName });
|
|
3714
3985
|
await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
|
|
3715
3986
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
3716
3987
|
return { processed: 0 };
|
|
3717
3988
|
}
|
|
3718
|
-
|
|
3989
|
+
logger10.info("Resuming reindex", {
|
|
3719
3990
|
subgraph: subgraphName,
|
|
3720
3991
|
fromBlock,
|
|
3721
3992
|
toBlock,
|
|
@@ -3737,9 +4008,9 @@ async function resumeReindex(def, opts) {
|
|
|
3737
4008
|
if (reason === "user-cancelled") {
|
|
3738
4009
|
await updateSubgraphStatus2(targetDb, subgraphName, "active");
|
|
3739
4010
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
3740
|
-
|
|
4011
|
+
logger10.info("Resume cancelled by user", { subgraph: subgraphName });
|
|
3741
4012
|
} else {
|
|
3742
|
-
|
|
4013
|
+
logger10.info("Resume interrupted by shutdown, will resume again", {
|
|
3743
4014
|
subgraph: subgraphName
|
|
3744
4015
|
});
|
|
3745
4016
|
}
|
|
@@ -3747,13 +4018,13 @@ async function resumeReindex(def, opts) {
|
|
|
3747
4018
|
}
|
|
3748
4019
|
await updateSubgraphStatus2(targetDb, subgraphName, "active", toBlock);
|
|
3749
4020
|
await clearReindexMetadata(targetDb, subgraphName);
|
|
3750
|
-
|
|
4021
|
+
logger10.info("Resumed reindex complete", {
|
|
3751
4022
|
subgraph: subgraphName,
|
|
3752
4023
|
blocks: result.blocksProcessed
|
|
3753
4024
|
});
|
|
3754
4025
|
return { processed: result.blocksProcessed };
|
|
3755
4026
|
} catch (err) {
|
|
3756
|
-
|
|
4027
|
+
logger10.error("Resumed reindex failed", {
|
|
3757
4028
|
subgraph: subgraphName,
|
|
3758
4029
|
error: getErrorMessage3(err)
|
|
3759
4030
|
});
|
|
@@ -3762,9 +4033,9 @@ async function resumeReindex(def, opts) {
|
|
|
3762
4033
|
}
|
|
3763
4034
|
}
|
|
3764
4035
|
async function backfillSubgraph(def, opts) {
|
|
3765
|
-
const targetDb =
|
|
4036
|
+
const targetDb = getTargetDb3();
|
|
3766
4037
|
const subgraphName = def.name;
|
|
3767
|
-
|
|
4038
|
+
logger10.info("Backfill starting", {
|
|
3768
4039
|
subgraph: subgraphName,
|
|
3769
4040
|
from: opts.fromBlock,
|
|
3770
4041
|
to: opts.toBlock
|
|
@@ -3782,17 +4053,17 @@ async function backfillSubgraph(def, opts) {
|
|
|
3782
4053
|
signal: opts.signal
|
|
3783
4054
|
});
|
|
3784
4055
|
if (result.aborted) {
|
|
3785
|
-
|
|
4056
|
+
logger10.info("Backfill aborted", { subgraph: subgraphName });
|
|
3786
4057
|
return { processed: result.blocksProcessed };
|
|
3787
4058
|
}
|
|
3788
4059
|
const resolved = await resolveGaps(targetDb, subgraphName, opts.fromBlock, opts.toBlock).catch(() => 0);
|
|
3789
4060
|
if (resolved > 0) {
|
|
3790
|
-
|
|
4061
|
+
logger10.info("Resolved subgraph gaps via backfill", {
|
|
3791
4062
|
subgraph: subgraphName,
|
|
3792
4063
|
resolved
|
|
3793
4064
|
});
|
|
3794
4065
|
}
|
|
3795
|
-
|
|
4066
|
+
logger10.info("Backfill complete", {
|
|
3796
4067
|
subgraph: subgraphName,
|
|
3797
4068
|
blocks: result.blocksProcessed,
|
|
3798
4069
|
events: result.totalEventsProcessed,
|
|
@@ -3800,7 +4071,7 @@ async function backfillSubgraph(def, opts) {
|
|
|
3800
4071
|
});
|
|
3801
4072
|
return { processed: result.blocksProcessed };
|
|
3802
4073
|
} catch (err) {
|
|
3803
|
-
|
|
4074
|
+
logger10.error("Backfill failed", {
|
|
3804
4075
|
subgraph: subgraphName,
|
|
3805
4076
|
error: getErrorMessage3(err)
|
|
3806
4077
|
});
|
|
@@ -4721,7 +4992,7 @@ function generateIndexSchema(target, opts = {}) {
|
|
|
4721
4992
|
}
|
|
4722
4993
|
var INDEX_CODEGEN_TABLES = Object.keys(SOURCE_READ_TYPES);
|
|
4723
4994
|
// src/schema/deployer.ts
|
|
4724
|
-
import { sql as
|
|
4995
|
+
import { sql as sql5 } from "kysely";
|
|
4725
4996
|
function toJsonSafe(obj) {
|
|
4726
4997
|
return JSON.parse(JSON.stringify(obj, (_key, value) => typeof value === "bigint" ? value.toString() : value));
|
|
4727
4998
|
}
|
|
@@ -4836,7 +5107,7 @@ function renderDeployPlan(def, schemaName) {
|
|
|
4836
5107
|
async function deploySchema(db, def, handlerPath, opts) {
|
|
4837
5108
|
validateSubgraphDefinition(def);
|
|
4838
5109
|
const { statements, hash } = generateSubgraphSQL(def, opts?.schemaName);
|
|
4839
|
-
const { getSubgraph, registerSubgraph } = await import("@secondlayer/shared/db/queries/subgraphs");
|
|
5110
|
+
const { getSubgraph: getSubgraph2, registerSubgraph } = await import("@secondlayer/shared/db/queries/subgraphs");
|
|
4840
5111
|
const ddlDb = opts?.dataDb ?? db;
|
|
4841
5112
|
const byo = opts?.dataDb != null;
|
|
4842
5113
|
const refuseDestructiveOnByo = (reasons, diff) => {
|
|
@@ -4848,7 +5119,7 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
4848
5119
|
grantScript: plan.grantScript
|
|
4849
5120
|
});
|
|
4850
5121
|
};
|
|
4851
|
-
const existing = await
|
|
5122
|
+
const existing = await getSubgraph2(db, def.name, opts?.accountId);
|
|
4852
5123
|
const schemaName = opts?.schemaName ?? pgSchemaName(def.name);
|
|
4853
5124
|
const newVersion = opts?.version ?? (existing ? bumpPatch(existing.version) : "1.0.0");
|
|
4854
5125
|
const regData = {
|
|
@@ -4873,7 +5144,7 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
4873
5144
|
databaseUrlEnc: opts?.databaseUrlEnc ?? null
|
|
4874
5145
|
};
|
|
4875
5146
|
if (existing) {
|
|
4876
|
-
const schemaExists = await
|
|
5147
|
+
const schemaExists = await sql5`
|
|
4877
5148
|
SELECT EXISTS (
|
|
4878
5149
|
SELECT 1 FROM information_schema.schemata
|
|
4879
5150
|
WHERE schema_name = ${schemaName}
|
|
@@ -4881,7 +5152,7 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
4881
5152
|
`.execute(ddlDb).then((r) => r.rows[0]?.exists ?? false);
|
|
4882
5153
|
if (!schemaExists) {
|
|
4883
5154
|
for (const stmt of statements) {
|
|
4884
|
-
await
|
|
5155
|
+
await sql5.raw(stmt).execute(ddlDb);
|
|
4885
5156
|
}
|
|
4886
5157
|
const sg2 = await registerSubgraph(db, regData);
|
|
4887
5158
|
return { action: "reindexed", subgraphId: sg2.id, version: newVersion };
|
|
@@ -4907,9 +5178,9 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
4907
5178
|
if (existing.schema_hash === hash && opts?.forceReindex) {
|
|
4908
5179
|
if (byo)
|
|
4909
5180
|
refuseDestructiveOnByo(["force reindex"], null);
|
|
4910
|
-
await
|
|
5181
|
+
await sql5.raw(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`).execute(ddlDb);
|
|
4911
5182
|
for (const stmt of statements) {
|
|
4912
|
-
await
|
|
5183
|
+
await sql5.raw(stmt).execute(ddlDb);
|
|
4913
5184
|
}
|
|
4914
5185
|
const sg2 = await registerSubgraph(db, regData);
|
|
4915
5186
|
return { action: "reindexed", subgraphId: sg2.id, version: newVersion };
|
|
@@ -4921,9 +5192,9 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
4921
5192
|
if (byo) {
|
|
4922
5193
|
refuseDestructiveOnByo(reasons.length > 0 ? reasons : ["force reindex"], diff);
|
|
4923
5194
|
}
|
|
4924
|
-
await
|
|
5195
|
+
await sql5.raw(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`).execute(ddlDb);
|
|
4925
5196
|
for (const stmt of statements) {
|
|
4926
|
-
await
|
|
5197
|
+
await sql5.raw(stmt).execute(ddlDb);
|
|
4927
5198
|
}
|
|
4928
5199
|
const sg3 = await registerSubgraph(db, regData);
|
|
4929
5200
|
const deployDiff2 = toDeployDiff(diff, reasons);
|
|
@@ -4936,16 +5207,16 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
4936
5207
|
}
|
|
4937
5208
|
const addedDefs = diff.addedTables.map((tableName) => ({ tableName, tableDef: def.schema[tableName] })).filter((t) => t.tableDef !== undefined);
|
|
4938
5209
|
if (addedDefs.some(({ tableDef }) => tableNeedsTrgm(tableDef))) {
|
|
4939
|
-
await
|
|
5210
|
+
await sql5.raw("CREATE EXTENSION IF NOT EXISTS pg_trgm").execute(ddlDb);
|
|
4940
5211
|
}
|
|
4941
5212
|
for (const { tableName, tableDef } of addedDefs) {
|
|
4942
5213
|
for (const stmt of emitTableDDL(schemaName, tableName, tableDef)) {
|
|
4943
|
-
await
|
|
5214
|
+
await sql5.raw(stmt).execute(ddlDb);
|
|
4944
5215
|
}
|
|
4945
5216
|
}
|
|
4946
5217
|
for (const { tableName, tableDef } of addedDefs) {
|
|
4947
5218
|
for (const stmt of emitForeignKeyDDL(schemaName, tableName, tableDef)) {
|
|
4948
|
-
await
|
|
5219
|
+
await sql5.raw(stmt).execute(ddlDb);
|
|
4949
5220
|
}
|
|
4950
5221
|
}
|
|
4951
5222
|
for (const [tableName, colDiff] of Object.entries(diff.tables)) {
|
|
@@ -4963,12 +5234,12 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
4963
5234
|
if (!sqlType)
|
|
4964
5235
|
continue;
|
|
4965
5236
|
const nullable = col.nullable ? "" : ` NOT NULL DEFAULT ${getDefault(col.type)}`;
|
|
4966
|
-
await
|
|
5237
|
+
await sql5.raw(`ALTER TABLE ${qualifiedName} ADD COLUMN ${colName} ${sqlType}${nullable}`).execute(ddlDb);
|
|
4967
5238
|
if (col.indexed) {
|
|
4968
|
-
await
|
|
5239
|
+
await sql5.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName} ON ${qualifiedName} (${colName})`).execute(ddlDb);
|
|
4969
5240
|
}
|
|
4970
5241
|
if (col.search) {
|
|
4971
|
-
await
|
|
5242
|
+
await sql5.raw(`CREATE INDEX IF NOT EXISTS idx_${schemaName}_${tableName}_${colName}_trgm ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`).execute(ddlDb);
|
|
4972
5243
|
}
|
|
4973
5244
|
}
|
|
4974
5245
|
}
|
|
@@ -4976,7 +5247,7 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
4976
5247
|
const flagFlips = {};
|
|
4977
5248
|
const needsTrgmForFlips = Object.entries(diff.tables).some(([tableName, colDiff]) => colDiff.indexChanged.some((colName) => def.schema[tableName]?.columns[colName]?.search && !existingSchema[tableName]?.columns[colName]?.search));
|
|
4978
5249
|
if (needsTrgmForFlips) {
|
|
4979
|
-
await
|
|
5250
|
+
await sql5.raw("CREATE EXTENSION IF NOT EXISTS pg_trgm").execute(ddlDb);
|
|
4980
5251
|
}
|
|
4981
5252
|
for (const [tableName, colDiff] of Object.entries(diff.tables)) {
|
|
4982
5253
|
if (colDiff.indexChanged.length === 0)
|
|
@@ -4991,14 +5262,14 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
4991
5262
|
const plainIdx = `idx_${schemaName}_${tableName}_${colName}`;
|
|
4992
5263
|
const trgmIdx = `idx_${schemaName}_${tableName}_${colName}_trgm`;
|
|
4993
5264
|
if (now.indexed && !was?.indexed) {
|
|
4994
|
-
await
|
|
5265
|
+
await sql5.raw(`CREATE INDEX CONCURRENTLY IF NOT EXISTS ${plainIdx} ON ${qualifiedName} (${colName})`).execute(ddlDb);
|
|
4995
5266
|
} else if (!now.indexed && was?.indexed) {
|
|
4996
|
-
await
|
|
5267
|
+
await sql5.raw(`DROP INDEX CONCURRENTLY IF EXISTS ${schemaName}.${plainIdx}`).execute(ddlDb);
|
|
4997
5268
|
}
|
|
4998
5269
|
if (now.search && !was?.search) {
|
|
4999
|
-
await
|
|
5270
|
+
await sql5.raw(`CREATE INDEX CONCURRENTLY IF NOT EXISTS ${trgmIdx} ON ${qualifiedName} USING gin (${colName} gin_trgm_ops)`).execute(ddlDb);
|
|
5000
5271
|
} else if (!now.search && was?.search) {
|
|
5001
|
-
await
|
|
5272
|
+
await sql5.raw(`DROP INDEX CONCURRENTLY IF EXISTS ${schemaName}.${trgmIdx}`).execute(ddlDb);
|
|
5002
5273
|
}
|
|
5003
5274
|
}
|
|
5004
5275
|
}
|
|
@@ -5007,28 +5278,28 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
5007
5278
|
const qualifiedName = `${schemaName}.${tableName}`;
|
|
5008
5279
|
for (const cols of conDiff.addedUniqueKeys) {
|
|
5009
5280
|
const constraintName = `uq_${schemaName}_${tableName}_${cols.join("_")}`;
|
|
5010
|
-
const exists = await
|
|
5281
|
+
const exists = await sql5`
|
|
5011
5282
|
SELECT EXISTS (
|
|
5012
5283
|
SELECT 1 FROM pg_constraint
|
|
5013
5284
|
WHERE conname = ${constraintName}
|
|
5014
5285
|
) AS "exists"
|
|
5015
5286
|
`.execute(ddlDb).then((r) => r.rows[0]?.exists ?? false);
|
|
5016
5287
|
if (!exists) {
|
|
5017
|
-
await
|
|
5288
|
+
await sql5.raw(`ALTER TABLE ${qualifiedName} ADD CONSTRAINT ${constraintName} UNIQUE (${cols.join(", ")})`).execute(ddlDb);
|
|
5018
5289
|
}
|
|
5019
5290
|
addedUq[tableName] = [...addedUq[tableName] ?? [], cols];
|
|
5020
5291
|
}
|
|
5021
5292
|
for (const cols of conDiff.addedIndexes) {
|
|
5022
5293
|
const i = (def.schema[tableName]?.indexes ?? []).findIndex((entry) => JSON.stringify(entry) === JSON.stringify(cols));
|
|
5023
5294
|
const idxName = `idx_${schemaName}_${tableName}_composite_${i}`;
|
|
5024
|
-
await
|
|
5295
|
+
await sql5.raw(`CREATE INDEX CONCURRENTLY IF NOT EXISTS ${idxName} ON ${qualifiedName} (${cols.join(", ")})`).execute(ddlDb);
|
|
5025
5296
|
}
|
|
5026
5297
|
for (const cols of conDiff.removedIndexes) {
|
|
5027
5298
|
const i = (existingSchema[tableName]?.indexes ?? []).findIndex((entry) => JSON.stringify(entry) === JSON.stringify(cols));
|
|
5028
5299
|
if (i < 0)
|
|
5029
5300
|
continue;
|
|
5030
5301
|
const idxName = `idx_${schemaName}_${tableName}_composite_${i}`;
|
|
5031
|
-
await
|
|
5302
|
+
await sql5.raw(`DROP INDEX CONCURRENTLY IF EXISTS ${schemaName}.${idxName}`).execute(ddlDb);
|
|
5032
5303
|
}
|
|
5033
5304
|
}
|
|
5034
5305
|
const sg2 = await registerSubgraph(db, regData);
|
|
@@ -5054,7 +5325,7 @@ async function deploySchema(db, def, handlerPath, opts) {
|
|
|
5054
5325
|
}
|
|
5055
5326
|
}
|
|
5056
5327
|
for (const stmt of statements) {
|
|
5057
|
-
await
|
|
5328
|
+
await sql5.raw(stmt).execute(ddlDb);
|
|
5058
5329
|
}
|
|
5059
5330
|
const sg = await registerSubgraph(db, regData);
|
|
5060
5331
|
return { action: "created", subgraphId: sg.id, version: newVersion };
|
|
@@ -5106,5 +5377,5 @@ export {
|
|
|
5106
5377
|
ByoBreakingChangeError
|
|
5107
5378
|
};
|
|
5108
5379
|
|
|
5109
|
-
//# debugId=
|
|
5380
|
+
//# debugId=99416B000428839064756E2164756E21
|
|
5110
5381
|
//# sourceMappingURL=index.js.map
|