deepline 0.3.228 → 0.3.229
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/bundling-sources/sdk/src/release.ts +1 -1
- package/dist/bundling-sources/shared_libs/play-data-plane/contracts.ts +12 -0
- package/dist/bundling-sources/shared_libs/play-data-plane/index.ts +1 -0
- package/dist/bundling-sources/shared_libs/play-data-plane/sheet-column-storage.ts +252 -0
- package/dist/bundling-sources/shared_libs/play-data-plane/sheet-contract.ts +29 -8
- package/dist/bundling-sources/shared_libs/play-runtime/context.ts +250 -37
- package/dist/bundling-sources/shared_libs/play-runtime/ctx-types.ts +2 -0
- package/dist/bundling-sources/shared_libs/play-runtime/runner-app/index.ts +6 -1
- package/dist/bundling-sources/shared_libs/play-runtime/runtime-api.ts +380 -183
- package/dist/bundling-sources/shared_libs/play-runtime/tool-result.ts +1 -0
- package/dist/bundling-sources/shared_libs/plays/dataset.ts +16 -2
- package/dist/bundling-sources/shared_libs/plays/execution-pipeline.ts +72 -0
- package/dist/bundling-sources/shared_libs/plays/launch/prepare.ts +1 -3
- package/dist/bundling-sources/shared_libs/plays/sheet-filter.ts +9 -13
- package/dist/bundling-sources/shared_libs/plays/static-pipeline.ts +28 -31
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/{compiler-manifest-Dpd2hEet.d.mts → compiler-manifest-n8ZtPv2h.d.mts} +31 -21
- package/dist/{compiler-manifest-Dpd2hEet.d.ts → compiler-manifest-n8ZtPv2h.d.ts} +31 -21
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +6 -1
- package/dist/index.mjs +6 -1
- package/dist/install-integrity.json +4 -2
- package/dist/plays/bundle-play-file.d.mts +2 -2
- package/dist/plays/bundle-play-file.d.ts +2 -2
- package/dist/release.d.mts +1 -1
- package/dist/release.d.ts +1 -1
- package/dist/release.js +1 -1
- package/dist/release.mjs +1 -1
- package/package.json +1 -1
|
@@ -24,6 +24,10 @@ import {
|
|
|
24
24
|
physicalSheetColumnProjections,
|
|
25
25
|
type PhysicalSheetColumnProjection,
|
|
26
26
|
} from '../play-data-plane/sheet-contract';
|
|
27
|
+
import {
|
|
28
|
+
RuntimeSheetColumns,
|
|
29
|
+
type RuntimeSheetColumnTypes,
|
|
30
|
+
} from '../play-data-plane/sheet-column-storage';
|
|
27
31
|
import { RUNTIME_SHEET_CELL_META_COLUMN } from '../play-data-plane/runtime-sheet-storage-contract';
|
|
28
32
|
import {
|
|
29
33
|
createRuntimeSheetOrm,
|
|
@@ -2925,7 +2929,7 @@ function missingOutputCellSql(
|
|
|
2925
2929
|
const quoted = `${tableAlias}.${quoteIdentifier(column.sqlName)}`;
|
|
2926
2930
|
const staleAt = `${tableAlias}._cell_meta -> ${quoteLiteral(column.fieldName)} -> 'staleAt'`;
|
|
2927
2931
|
const staleAtMs = `(CASE WHEN jsonb_typeof(${staleAt}) = 'number' THEN (${staleAt})::text::double precision ELSE NULL END)`;
|
|
2928
|
-
return `(${quoted} IS NULL OR ${quoted} = 'null'::jsonb OR ${quoted} = '""'::jsonb OR (${staleAtMs} IS NOT NULL AND ${staleAtMs} <= extract(epoch from now()) * 1000))`;
|
|
2932
|
+
return `(${quoted} IS NULL OR to_jsonb(${quoted}) = 'null'::jsonb OR to_jsonb(${quoted}) = '""'::jsonb OR (${staleAtMs} IS NOT NULL AND ${staleAtMs} <= extract(epoch from now()) * 1000))`;
|
|
2929
2933
|
})
|
|
2930
2934
|
.join(' OR ');
|
|
2931
2935
|
}
|
|
@@ -2941,7 +2945,7 @@ function changedPatchedCellSql(
|
|
|
2941
2945
|
return projections
|
|
2942
2946
|
.map((column) => {
|
|
2943
2947
|
const quoted = `${tableAlias}.${quoteIdentifier(column.sqlName)}`;
|
|
2944
|
-
return `(${patchAlias} ? ${quoteLiteral(column.fieldName)} AND ${quoted} IS DISTINCT FROM ${patchAlias} -> ${quoteLiteral(column.fieldName)})`;
|
|
2948
|
+
return `(${patchAlias} ? ${quoteLiteral(column.fieldName)} AND coalesce(to_jsonb(${quoted}), 'null'::jsonb) IS DISTINCT FROM ${patchAlias} -> ${quoteLiteral(column.fieldName)})`;
|
|
2945
2949
|
})
|
|
2946
2950
|
.join(' OR ');
|
|
2947
2951
|
}
|
|
@@ -3331,12 +3335,6 @@ async function writeRuntimeRows(
|
|
|
3331
3335
|
physicalColumns.length > 0
|
|
3332
3336
|
? `, ${physicalColumns.map(quoteIdentifier).join(', ')}`
|
|
3333
3337
|
: '';
|
|
3334
|
-
const physicalInsertValuesSql =
|
|
3335
|
-
physicalColumns.length > 0
|
|
3336
|
-
? `, ${physicalColumnProjections
|
|
3337
|
-
.map((column) => `payload -> ${quoteLiteral(column.fieldName)}`)
|
|
3338
|
-
.join(', ')}`
|
|
3339
|
-
: '';
|
|
3340
3338
|
|
|
3341
3339
|
const rowsToWrite = input.rows.filter(
|
|
3342
3340
|
(row) => row && typeof row === 'object' && !Array.isArray(row),
|
|
@@ -3349,10 +3347,8 @@ async function writeRuntimeRows(
|
|
|
3349
3347
|
input.tableNamespace,
|
|
3350
3348
|
);
|
|
3351
3349
|
|
|
3352
|
-
//
|
|
3353
|
-
//
|
|
3354
|
-
// statement level), and the per-chunk mega-CTE folds: starting-index lookup,
|
|
3355
|
-
// sheet insert, and summary upsert into one round-trip.
|
|
3350
|
+
// Keep every chunk's row insert and summary update in the same transaction
|
|
3351
|
+
// as column inference, so a concurrent writer cannot invalidate its schema.
|
|
3356
3352
|
const rowEntries =
|
|
3357
3353
|
input.mode === 'upsert'
|
|
3358
3354
|
? Array.from(
|
|
@@ -3365,7 +3361,11 @@ async function writeRuntimeRows(
|
|
|
3365
3361
|
return uniqueRows;
|
|
3366
3362
|
}, new Map<string, Record<string, unknown>>())
|
|
3367
3363
|
.entries(),
|
|
3368
|
-
).map(([key, row], inputIndex) => ({
|
|
3364
|
+
).map(([key, row], inputIndex) => ({
|
|
3365
|
+
key,
|
|
3366
|
+
row: sanitizePostgresJsonValue(row),
|
|
3367
|
+
inputIndex,
|
|
3368
|
+
}))
|
|
3369
3369
|
: rowsToWrite.map((row, index) => ({
|
|
3370
3370
|
key: buildAppendedRowKey({
|
|
3371
3371
|
row,
|
|
@@ -3373,7 +3373,7 @@ async function writeRuntimeRows(
|
|
|
3373
3373
|
idempotencyKey: input.idempotencyKey,
|
|
3374
3374
|
ordinal: index,
|
|
3375
3375
|
}),
|
|
3376
|
-
row,
|
|
3376
|
+
row: sanitizePostgresJsonValue(row),
|
|
3377
3377
|
// For append/replace modes the starting offset is computed in SQL
|
|
3378
3378
|
// as `coalesce(max(_input_index), -1) + 1 + (ord - 1)`; we only
|
|
3379
3379
|
// pass the per-chunk ordinal here so the SQL can add it to the
|
|
@@ -3382,12 +3382,47 @@ async function writeRuntimeRows(
|
|
|
3382
3382
|
}));
|
|
3383
3383
|
|
|
3384
3384
|
const chunks = chunkValues(rowEntries, DIRECT_POSTGRES_BATCH_SIZE);
|
|
3385
|
-
|
|
3385
|
+
// Type evolution and the row mutation share one transaction and schema lock.
|
|
3386
|
+
const needsTransaction = true;
|
|
3386
3387
|
|
|
3387
3388
|
return await withRuntimePostgres(session, async (client, transaction) => {
|
|
3388
3389
|
const managesTransaction = needsTransaction && !transaction.active;
|
|
3389
3390
|
if (managesTransaction) await client.query('BEGIN');
|
|
3390
3391
|
try {
|
|
3392
|
+
const columnTypes = await RuntimeSheetColumns.prepareWrite(client, {
|
|
3393
|
+
schema: session.postgres.schema,
|
|
3394
|
+
table: session.postgres.sheetTable,
|
|
3395
|
+
columns: physicalColumnProjections,
|
|
3396
|
+
rows: async () => {
|
|
3397
|
+
if (input.mode !== 'upsert')
|
|
3398
|
+
return rowEntries.map((entry) => entry.row);
|
|
3399
|
+
const existing = await client.query<{ _key: string }>(
|
|
3400
|
+
`SELECT _key FROM ${sheetTable(session)} WHERE _key = ANY($1::text[])`,
|
|
3401
|
+
[rowEntries.map((entry) => entry.key)],
|
|
3402
|
+
);
|
|
3403
|
+
const existingKeys = new Set(existing.rows.map((row) => row._key));
|
|
3404
|
+
return rowEntries
|
|
3405
|
+
.filter((entry) => !existingKeys.has(entry.key))
|
|
3406
|
+
.map((entry) => entry.row);
|
|
3407
|
+
},
|
|
3408
|
+
});
|
|
3409
|
+
const physicalInsertValuesSql =
|
|
3410
|
+
physicalColumns.length > 0
|
|
3411
|
+
? `, ${physicalColumnProjections
|
|
3412
|
+
.map((column) => {
|
|
3413
|
+
const incoming = RuntimeSheetColumns.jsonValueSql(
|
|
3414
|
+
`input_rows.payload -> ${quoteLiteral(column.fieldName)}`,
|
|
3415
|
+
sheetTable(session),
|
|
3416
|
+
column.sqlName,
|
|
3417
|
+
columnTypes,
|
|
3418
|
+
);
|
|
3419
|
+
return input.mode === 'upsert'
|
|
3420
|
+
? `CASE WHEN existing_input._key IS NOT NULL THEN existing_input.${quoteIdentifier(column.sqlName)} ELSE ${incoming} END`
|
|
3421
|
+
: incoming;
|
|
3422
|
+
})
|
|
3423
|
+
.join(', ')}`
|
|
3424
|
+
: '';
|
|
3425
|
+
|
|
3391
3426
|
if (input.mode === 'replace') {
|
|
3392
3427
|
// Collapse 4 cleanup statements into one CTE-shaped query. Postgres
|
|
3393
3428
|
// executes data-modifying CTEs against the same snapshot, but each
|
|
@@ -3438,8 +3473,9 @@ async function writeRuntimeRows(
|
|
|
3438
3473
|
input.mode === 'upsert'
|
|
3439
3474
|
? `inserted_rows AS (
|
|
3440
3475
|
INSERT INTO ${sheetTable(session)} (_key, _status, _run_id, _input_index, _created_at${physicalInsertColumnsSql})
|
|
3441
|
-
SELECT _key, 'pending', $4::text, _input_index, now()${physicalInsertValuesSql}
|
|
3476
|
+
SELECT input_rows._key, 'pending', $4::text, input_rows._input_index, now()${physicalInsertValuesSql}
|
|
3442
3477
|
FROM input_rows
|
|
3478
|
+
LEFT JOIN ${sheetTable(session)} AS existing_input ON existing_input._key = input_rows._key
|
|
3443
3479
|
ON CONFLICT (_key) DO UPDATE SET
|
|
3444
3480
|
_status = 'pending',
|
|
3445
3481
|
_run_id = EXCLUDED._run_id,
|
|
@@ -3764,8 +3800,9 @@ async function prepareRuntimeSheetDatasetRows(
|
|
|
3764
3800
|
),
|
|
3765
3801
|
inserted_rows AS (
|
|
3766
3802
|
INSERT INTO ${sheetTable(session)} (_key, _status, _run_id, _input_index, _attempt_id, _attempt_owner_run_id, _attempt_expires_at, _attempt_seq, _write_version, _writer_run_id, _created_at${input.physicalInsertColumnsSql})
|
|
3767
|
-
SELECT _key, 'pending', $4::text, _input_index, $7::text, $8::text, $9::timestamptz, $10::integer, $12::bigint, $4::text, now()${input.physicalInsertValuesSql}
|
|
3803
|
+
SELECT input_rows._key, 'pending', $4::text, input_rows._input_index, $7::text, $8::text, $9::timestamptz, $10::integer, $12::bigint, $4::text, now()${input.physicalInsertValuesSql}
|
|
3768
3804
|
FROM input_rows
|
|
3805
|
+
LEFT JOIN ${sheetTable(session)} AS existing_input ON existing_input._key = input_rows._key
|
|
3769
3806
|
ON CONFLICT (_key) DO UPDATE SET
|
|
3770
3807
|
_status = 'pending',
|
|
3771
3808
|
_run_id = EXCLUDED._run_id,
|
|
@@ -4111,9 +4148,10 @@ async function prepareNetNewRuntimeSheetDatasetRows(
|
|
|
4111
4148
|
INSERT INTO ${sheetTable(session)}
|
|
4112
4149
|
(_key, _status, _run_id, _input_index, _attempt_id, _attempt_owner_run_id,
|
|
4113
4150
|
_attempt_expires_at, _attempt_seq, _write_version, _writer_run_id, _created_at${input.physicalInsertColumnsSql})
|
|
4114
|
-
SELECT _key, 'pending', $4::text, _input_index, $5::text, $6::text,
|
|
4151
|
+
SELECT input_rows._key, 'pending', $4::text, input_rows._input_index, $5::text, $6::text,
|
|
4115
4152
|
$7::timestamptz, $8::integer, $9::bigint, $4::text, now()${input.physicalInsertValuesSql}
|
|
4116
4153
|
FROM input_rows
|
|
4154
|
+
LEFT JOIN ${sheetTable(session)} AS existing_input ON existing_input._key = input_rows._key
|
|
4117
4155
|
ON CONFLICT (_key) DO NOTHING
|
|
4118
4156
|
RETURNING _key
|
|
4119
4157
|
),
|
|
@@ -6591,7 +6629,7 @@ export async function startRuntimeSheetDataset(
|
|
|
6591
6629
|
derivePlayRowIdentity(cleanedRow, input.tableNamespace);
|
|
6592
6630
|
if (key && !uniqueRows.has(key)) {
|
|
6593
6631
|
uniqueRows.set(key, {
|
|
6594
|
-
row: cleanedRow,
|
|
6632
|
+
row: sanitizePostgresJsonValue(cleanedRow),
|
|
6595
6633
|
inputIndex: normalizeRuntimeMapInputIndex(
|
|
6596
6634
|
row[MAP_ROW_OUTCOME_RUNTIME_FIELDS.inputIndex],
|
|
6597
6635
|
),
|
|
@@ -6635,12 +6673,6 @@ export async function startRuntimeSheetDataset(
|
|
|
6635
6673
|
physicalColumns.length > 0
|
|
6636
6674
|
? `, ${physicalColumns.map(quoteIdentifier).join(', ')}`
|
|
6637
6675
|
: '';
|
|
6638
|
-
const physicalInsertValuesSql =
|
|
6639
|
-
physicalColumns.length > 0
|
|
6640
|
-
? `, ${physicalColumns
|
|
6641
|
-
.map((column) => `payload -> ${quoteLiteral(column)}`)
|
|
6642
|
-
.join(', ')}`
|
|
6643
|
-
: '';
|
|
6644
6676
|
const outputPhysicalColumns = outputPhysicalSheetColumnProjections(
|
|
6645
6677
|
input.sheetContract,
|
|
6646
6678
|
);
|
|
@@ -6650,15 +6682,6 @@ export async function startRuntimeSheetDataset(
|
|
|
6650
6682
|
const physicalRefreshColumns = physicalColumns.filter(
|
|
6651
6683
|
(column) => !outputPhysicalColumnNames.has(column),
|
|
6652
6684
|
);
|
|
6653
|
-
const physicalRefreshSetSql =
|
|
6654
|
-
physicalRefreshColumns.length > 0
|
|
6655
|
-
? `, ${physicalRefreshColumns
|
|
6656
|
-
.map(
|
|
6657
|
-
(column) =>
|
|
6658
|
-
`${quoteIdentifier(column)} = input_rows.payload -> ${quoteLiteral(column)}`,
|
|
6659
|
-
)
|
|
6660
|
-
.join(', ')}`
|
|
6661
|
-
: '';
|
|
6662
6685
|
const physicalUpsertSetSql =
|
|
6663
6686
|
physicalColumns.length > 0
|
|
6664
6687
|
? `, ${physicalColumns
|
|
@@ -6705,6 +6728,77 @@ export async function startRuntimeSheetDataset(
|
|
|
6705
6728
|
session,
|
|
6706
6729
|
input.writeVersion,
|
|
6707
6730
|
);
|
|
6731
|
+
const columnTypes = await RuntimeSheetColumns.prepareWrite(client, {
|
|
6732
|
+
schema: session.postgres.schema,
|
|
6733
|
+
table: session.postgres.sheetTable,
|
|
6734
|
+
columns: physicalSheetColumnProjections(input.sheetContract).map(
|
|
6735
|
+
(column) => ({ ...column, fieldName: column.sqlName }),
|
|
6736
|
+
),
|
|
6737
|
+
rows: async () => {
|
|
6738
|
+
const existing = await client.query<{
|
|
6739
|
+
_key: string;
|
|
6740
|
+
_status: string;
|
|
6741
|
+
_run_id: string | null;
|
|
6742
|
+
row_write_stamp: string | number;
|
|
6743
|
+
_input_index: string | number | null;
|
|
6744
|
+
}>(
|
|
6745
|
+
`SELECT _key, _status, _run_id, _write_version AS row_write_stamp, _input_index
|
|
6746
|
+
FROM ${sheetTable(session)} WHERE _key = ANY($1::text[]) FOR UPDATE`,
|
|
6747
|
+
[rowEntries.map((entry) => entry.key)],
|
|
6748
|
+
);
|
|
6749
|
+
const current = new Map(existing.rows.map((row) => [row._key, row]));
|
|
6750
|
+
return rowEntries.flatMap((entry) => {
|
|
6751
|
+
const row = current.get(entry.key);
|
|
6752
|
+
if (!row) return [entry.row];
|
|
6753
|
+
if (input.mode === 'net_new') return [];
|
|
6754
|
+
if (row._status === 'stale') return [entry.row];
|
|
6755
|
+
if (input.force !== true) return [];
|
|
6756
|
+
const version = Number(row.row_write_stamp);
|
|
6757
|
+
const refreshes =
|
|
6758
|
+
version < writeVersion ||
|
|
6759
|
+
(version === writeVersion &&
|
|
6760
|
+
(row._status !== 'enriched' ||
|
|
6761
|
+
row._run_id !== input.runId ||
|
|
6762
|
+
row._input_index === null ||
|
|
6763
|
+
Number(row._input_index) !== entry.inputIndex));
|
|
6764
|
+
if (!refreshes) return [];
|
|
6765
|
+
return [
|
|
6766
|
+
Object.fromEntries(
|
|
6767
|
+
Object.entries(entry.row).filter(
|
|
6768
|
+
([field]) => !outputPhysicalColumnNames.has(field),
|
|
6769
|
+
),
|
|
6770
|
+
),
|
|
6771
|
+
];
|
|
6772
|
+
});
|
|
6773
|
+
},
|
|
6774
|
+
});
|
|
6775
|
+
const physicalInsertValuesSql =
|
|
6776
|
+
physicalColumns.length > 0
|
|
6777
|
+
? `, ${physicalColumns
|
|
6778
|
+
.map((column) => {
|
|
6779
|
+
const incoming = RuntimeSheetColumns.jsonValueSql(
|
|
6780
|
+
`input_rows.payload -> ${quoteLiteral(column)}`,
|
|
6781
|
+
sheetTable(session),
|
|
6782
|
+
column,
|
|
6783
|
+
columnTypes,
|
|
6784
|
+
);
|
|
6785
|
+
const preserveExisting =
|
|
6786
|
+
input.mode === 'net_new'
|
|
6787
|
+
? 'existing_input._key IS NOT NULL'
|
|
6788
|
+
: "existing_input._key IS NOT NULL AND existing_input._status <> 'stale'";
|
|
6789
|
+
return `CASE WHEN ${preserveExisting} THEN existing_input.${quoteIdentifier(column)} ELSE ${incoming} END`;
|
|
6790
|
+
})
|
|
6791
|
+
.join(', ')}`
|
|
6792
|
+
: '';
|
|
6793
|
+
const physicalRefreshSetSql =
|
|
6794
|
+
physicalRefreshColumns.length > 0
|
|
6795
|
+
? `, ${physicalRefreshColumns
|
|
6796
|
+
.map(
|
|
6797
|
+
(column) =>
|
|
6798
|
+
`${quoteIdentifier(column)} = ${RuntimeSheetColumns.jsonValueSql(`input_rows.payload -> ${quoteLiteral(column)}`, sheetTable(session), column, columnTypes)}`,
|
|
6799
|
+
)
|
|
6800
|
+
.join(', ')}`
|
|
6801
|
+
: '';
|
|
6708
6802
|
timings.push({
|
|
6709
6803
|
phase: 'attempt_expiry_mint',
|
|
6710
6804
|
ms: Date.now() - attemptExpiryStartedAt,
|
|
@@ -7105,9 +7199,28 @@ export async function releaseRuntimeWorkReceipts(
|
|
|
7105
7199
|
);
|
|
7106
7200
|
}
|
|
7107
7201
|
|
|
7202
|
+
function physicalRuntimeSheetUpdateSql(
|
|
7203
|
+
session: RuntimePostgresSession,
|
|
7204
|
+
projections: readonly PhysicalSheetColumnProjection[],
|
|
7205
|
+
columnTypes: RuntimeSheetColumnTypes,
|
|
7206
|
+
): string {
|
|
7207
|
+
return projections.length > 0
|
|
7208
|
+
? `,\n ${projections
|
|
7209
|
+
.map((column) => {
|
|
7210
|
+
const quoted = quoteIdentifier(column.sqlName);
|
|
7211
|
+
const literal = quoteLiteral(column.fieldName);
|
|
7212
|
+
return `${quoted} = CASE
|
|
7213
|
+
WHEN coalesce(updates.data_patch, '{}'::jsonb) ? ${literal}
|
|
7214
|
+
THEN ${RuntimeSheetColumns.jsonValueSql(`updates.data_patch -> ${literal}`, sheetTable(session), column.sqlName, columnTypes)}
|
|
7215
|
+
ELSE target.${quoted}
|
|
7216
|
+
END`;
|
|
7217
|
+
})
|
|
7218
|
+
.join(',\n ')}`
|
|
7219
|
+
: '';
|
|
7220
|
+
}
|
|
7221
|
+
|
|
7108
7222
|
type CompleteRuntimeMapRowChunksInput = {
|
|
7109
7223
|
chunks: RuntimePreparedCompletedRow[][];
|
|
7110
|
-
physicalUpdateSetSql: string;
|
|
7111
7224
|
physicalColumnProjections: PhysicalSheetColumnProjection[];
|
|
7112
7225
|
runId: string;
|
|
7113
7226
|
attemptId: string | null;
|
|
@@ -7385,12 +7498,7 @@ async function completeRuntimeMapRowChunks(
|
|
|
7385
7498
|
OR coalesce(target._attempt_owner_run_id, target._run_id) IS DISTINCT FROM $10::text
|
|
7386
7499
|
)
|
|
7387
7500
|
)`;
|
|
7388
|
-
const
|
|
7389
|
-
updated: number;
|
|
7390
|
-
matched_keys: string[];
|
|
7391
|
-
fenced_rows: unknown;
|
|
7392
|
-
}>(
|
|
7393
|
-
`WITH updates AS (
|
|
7501
|
+
const matchingUpdatesSql = `WITH mutation_context AS (SELECT $6::text AS play_name, $7::text AS table_namespace, $11::timestamptz AS attempt_expires_at, $12::integer AS attempt_seq), updates AS (
|
|
7394
7502
|
SELECT key_values._key,
|
|
7395
7503
|
input_index_values.input_index,
|
|
7396
7504
|
data_values.data_patch,
|
|
@@ -7414,23 +7522,8 @@ async function completeRuntimeMapRowChunks(
|
|
|
7414
7522
|
FROM updates
|
|
7415
7523
|
JOIN ${sheetTable(session)} AS target
|
|
7416
7524
|
ON target._key = updates._key
|
|
7417
|
-
)
|
|
7418
|
-
|
|
7419
|
-
UPDATE ${sheetTable(session)} AS target
|
|
7420
|
-
SET _status = 'enriched',
|
|
7421
|
-
_run_id = $5::text,
|
|
7422
|
-
_writer_run_id = $5::text,
|
|
7423
|
-
_write_version = COALESCE($13::bigint, target._write_version),
|
|
7424
|
-
_error = NULL,
|
|
7425
|
-
_attempt_id = $9::text,
|
|
7426
|
-
_attempt_owner_run_id = $10::text,
|
|
7427
|
-
_attempt_expires_at = $11::timestamptz,
|
|
7428
|
-
_attempt_seq = $12::integer,
|
|
7429
|
-
_updated_at = now(),
|
|
7430
|
-
_version = ${nextRuntimeSheetVersionExpression(session)},
|
|
7431
|
-
_cell_meta = ${mergeRuntimeCellMetaPatchSql('target._cell_meta', 'updates.cell_meta_patch')}${input.physicalUpdateSetSql}
|
|
7432
|
-
FROM matched_updates AS updates
|
|
7433
|
-
WHERE target._key = updates.matched_key
|
|
7525
|
+
)`;
|
|
7526
|
+
const writableRowsSql = `target._key = updates.matched_key
|
|
7434
7527
|
AND ($13::bigint IS NULL OR target._write_version = $13::bigint)
|
|
7435
7528
|
AND ($13::bigint IS NOT NULL OR target._status <> 'enriched')
|
|
7436
7529
|
AND NOT (${newerTerminalRuntimeSheetRowSql('target', '$11::timestamptz', '$12::integer', '$9::text', '$10::text')})
|
|
@@ -7471,7 +7564,63 @@ async function completeRuntimeMapRowChunks(
|
|
|
7471
7564
|
FROM unnest($8::text[]) AS field_values(field)
|
|
7472
7565
|
WHERE coalesce(target._cell_meta -> field_values.field ->> 'status', '') <> 'completed'
|
|
7473
7566
|
)
|
|
7474
|
-
)
|
|
7567
|
+
)`;
|
|
7568
|
+
const mutationParams = [
|
|
7569
|
+
chunkKeys,
|
|
7570
|
+
chunkInputIndexes,
|
|
7571
|
+
chunkDataPatches,
|
|
7572
|
+
chunkCellMetaPatches,
|
|
7573
|
+
input.runId,
|
|
7574
|
+
input.normalizedPlayName,
|
|
7575
|
+
input.normalizedTableNamespace,
|
|
7576
|
+
[...new Set(input.outputFields)],
|
|
7577
|
+
input.attemptId,
|
|
7578
|
+
input.attemptOwnerRunId,
|
|
7579
|
+
input.attemptExpiresAt,
|
|
7580
|
+
input.attemptSeq,
|
|
7581
|
+
input.writeVersion,
|
|
7582
|
+
];
|
|
7583
|
+
const columnTypes = await RuntimeSheetColumns.prepareWrite(client, {
|
|
7584
|
+
schema: session.postgres.schema,
|
|
7585
|
+
table: session.postgres.sheetTable,
|
|
7586
|
+
columns: input.physicalColumnProjections,
|
|
7587
|
+
rows: async () => {
|
|
7588
|
+
const accepted = await client.query<{
|
|
7589
|
+
data_patch: Record<string, unknown>;
|
|
7590
|
+
}>(
|
|
7591
|
+
`${matchingUpdatesSql}
|
|
7592
|
+
SELECT updates.data_patch
|
|
7593
|
+
FROM matched_updates AS updates
|
|
7594
|
+
JOIN ${sheetTable(session)} AS target ON target._key = updates.matched_key
|
|
7595
|
+
WHERE ${writableRowsSql}
|
|
7596
|
+
FOR UPDATE OF target`,
|
|
7597
|
+
mutationParams,
|
|
7598
|
+
);
|
|
7599
|
+
return accepted.rows.map((row) => row.data_patch);
|
|
7600
|
+
},
|
|
7601
|
+
});
|
|
7602
|
+
const { rows } = await client.query<{
|
|
7603
|
+
updated: number;
|
|
7604
|
+
matched_keys: string[];
|
|
7605
|
+
fenced_rows: unknown;
|
|
7606
|
+
}>(
|
|
7607
|
+
`${matchingUpdatesSql},
|
|
7608
|
+
applied_rows AS (
|
|
7609
|
+
UPDATE ${sheetTable(session)} AS target
|
|
7610
|
+
SET _status = 'enriched',
|
|
7611
|
+
_run_id = $5::text,
|
|
7612
|
+
_writer_run_id = $5::text,
|
|
7613
|
+
_write_version = COALESCE($13::bigint, target._write_version),
|
|
7614
|
+
_error = NULL,
|
|
7615
|
+
_attempt_id = $9::text,
|
|
7616
|
+
_attempt_owner_run_id = $10::text,
|
|
7617
|
+
_attempt_expires_at = $11::timestamptz,
|
|
7618
|
+
_attempt_seq = $12::integer,
|
|
7619
|
+
_updated_at = now(),
|
|
7620
|
+
_version = ${nextRuntimeSheetVersionExpression(session)},
|
|
7621
|
+
_cell_meta = ${mergeRuntimeCellMetaPatchSql('target._cell_meta', 'updates.cell_meta_patch')}${physicalRuntimeSheetUpdateSql(session, input.physicalColumnProjections, columnTypes)}
|
|
7622
|
+
FROM matched_updates AS updates
|
|
7623
|
+
WHERE ${writableRowsSql}
|
|
7475
7624
|
RETURNING target._key, updates.prev_status, updates.prev_cell_meta
|
|
7476
7625
|
),
|
|
7477
7626
|
applied_count AS (
|
|
@@ -7595,21 +7744,7 @@ async function completeRuntimeMapRowChunks(
|
|
|
7595
7744
|
coalesce((SELECT jsonb_agg(jsonb_build_object('key', _key, 'reason', reason, 'rowVersionStamp', row_write_version)) FROM fenced_rows), '[]'::jsonb) AS fenced_rows,
|
|
7596
7745
|
(SELECT count(*)::int FROM summary_delta) AS summary_delta_count,
|
|
7597
7746
|
(SELECT count(*)::int FROM column_delta) AS column_delta_count`,
|
|
7598
|
-
|
|
7599
|
-
chunkKeys,
|
|
7600
|
-
chunkInputIndexes,
|
|
7601
|
-
chunkDataPatches,
|
|
7602
|
-
chunkCellMetaPatches,
|
|
7603
|
-
input.runId,
|
|
7604
|
-
input.normalizedPlayName,
|
|
7605
|
-
input.normalizedTableNamespace,
|
|
7606
|
-
[...new Set(input.outputFields)],
|
|
7607
|
-
input.attemptId,
|
|
7608
|
-
input.attemptOwnerRunId,
|
|
7609
|
-
input.attemptExpiresAt,
|
|
7610
|
-
input.attemptSeq,
|
|
7611
|
-
input.writeVersion,
|
|
7612
|
-
],
|
|
7747
|
+
mutationParams,
|
|
7613
7748
|
);
|
|
7614
7749
|
const matchedKeys = new Set(rows[0]?.matched_keys ?? []);
|
|
7615
7750
|
const chunkFencedRows = parseRuntimeMapRowsFencedRows(rows[0]?.fenced_rows);
|
|
@@ -7663,12 +7798,7 @@ async function completeRuntimeMapRowChunksWithInputIndexRepair(
|
|
|
7663
7798
|
'$11::timestamptz',
|
|
7664
7799
|
'$12',
|
|
7665
7800
|
);
|
|
7666
|
-
const
|
|
7667
|
-
_key?: string;
|
|
7668
|
-
fenced_rows?: unknown;
|
|
7669
|
-
updated?: number;
|
|
7670
|
-
}>(
|
|
7671
|
-
`WITH updates AS (
|
|
7801
|
+
const matchingUpdatesSql = `WITH mutation_context AS (SELECT $6::text AS play_name, $7::text AS table_namespace, $11::timestamptz AS attempt_expires_at, $12::integer AS attempt_seq), updates AS (
|
|
7672
7802
|
SELECT key_values._key,
|
|
7673
7803
|
input_index_values.input_index,
|
|
7674
7804
|
data_values.data_patch,
|
|
@@ -7696,24 +7826,8 @@ async function completeRuntimeMapRowChunksWithInputIndexRepair(
|
|
|
7696
7826
|
AND target._input_index = updates.input_index
|
|
7697
7827
|
)
|
|
7698
7828
|
ORDER BY target._key, (target._key = updates._key) DESC
|
|
7699
|
-
)
|
|
7700
|
-
|
|
7701
|
-
UPDATE ${sheetTable(session)} AS target
|
|
7702
|
-
SET _status = 'enriched',
|
|
7703
|
-
_run_id = $5::text,
|
|
7704
|
-
_writer_run_id = $5::text,
|
|
7705
|
-
_write_version = COALESCE($13::bigint, target._write_version),
|
|
7706
|
-
_error = NULL,
|
|
7707
|
-
_attempt_id = $9::text,
|
|
7708
|
-
_attempt_owner_run_id = $10::text,
|
|
7709
|
-
_attempt_expires_at = $11::timestamptz,
|
|
7710
|
-
_attempt_seq = $12::integer,
|
|
7711
|
-
_updated_at = now(),
|
|
7712
|
-
_version = ${nextRuntimeSheetVersionExpression(session)},
|
|
7713
|
-
_cell_meta = ${mergeRuntimeCellMetaPatchSql('target._cell_meta', 'updates.cell_meta_patch')}${input.physicalUpdateSetSql}
|
|
7714
|
-
FROM matched_updates AS updates, ${sheetTable(session)} AS prev
|
|
7715
|
-
WHERE target._key = updates.matched_key
|
|
7716
|
-
AND prev._key = target._key
|
|
7829
|
+
)`;
|
|
7830
|
+
const writableRowsSql = `target._key = updates.matched_key
|
|
7717
7831
|
AND ($13::bigint IS NULL OR target._write_version = $13::bigint)
|
|
7718
7832
|
AND ($13::bigint IS NOT NULL OR target._status <> 'enriched')
|
|
7719
7833
|
AND NOT (${newerTerminalRuntimeSheetRowSql('target', '$11::timestamptz', '$12::integer', '$9::text', '$10::text')})
|
|
@@ -7749,7 +7863,64 @@ async function completeRuntimeMapRowChunksWithInputIndexRepair(
|
|
|
7749
7863
|
FROM unnest($8::text[]) AS field_values(field)
|
|
7750
7864
|
WHERE coalesce(target._cell_meta -> field_values.field ->> 'status', '') <> 'completed'
|
|
7751
7865
|
)
|
|
7752
|
-
)
|
|
7866
|
+
)`;
|
|
7867
|
+
const mutationParams = [
|
|
7868
|
+
chunkKeys,
|
|
7869
|
+
chunkInputIndexes,
|
|
7870
|
+
chunkDataPatches,
|
|
7871
|
+
chunkCellMetaPatches,
|
|
7872
|
+
input.runId,
|
|
7873
|
+
input.normalizedPlayName,
|
|
7874
|
+
input.normalizedTableNamespace,
|
|
7875
|
+
[...new Set(input.outputFields)],
|
|
7876
|
+
input.attemptId,
|
|
7877
|
+
input.attemptOwnerRunId,
|
|
7878
|
+
input.attemptExpiresAt,
|
|
7879
|
+
input.attemptSeq,
|
|
7880
|
+
input.writeVersion,
|
|
7881
|
+
];
|
|
7882
|
+
const columnTypes = await RuntimeSheetColumns.prepareWrite(client, {
|
|
7883
|
+
schema: session.postgres.schema,
|
|
7884
|
+
table: session.postgres.sheetTable,
|
|
7885
|
+
columns: input.physicalColumnProjections,
|
|
7886
|
+
rows: async () => {
|
|
7887
|
+
const accepted = await client.query<{
|
|
7888
|
+
data_patch: Record<string, unknown>;
|
|
7889
|
+
}>(
|
|
7890
|
+
`${matchingUpdatesSql}
|
|
7891
|
+
SELECT updates.data_patch
|
|
7892
|
+
FROM matched_updates AS updates
|
|
7893
|
+
JOIN ${sheetTable(session)} AS target ON target._key = updates.matched_key
|
|
7894
|
+
WHERE ${writableRowsSql}
|
|
7895
|
+
FOR UPDATE OF target`,
|
|
7896
|
+
mutationParams,
|
|
7897
|
+
);
|
|
7898
|
+
return accepted.rows.map((row) => row.data_patch);
|
|
7899
|
+
},
|
|
7900
|
+
});
|
|
7901
|
+
const { rows } = await client.query<{
|
|
7902
|
+
_key?: string;
|
|
7903
|
+
fenced_rows?: unknown;
|
|
7904
|
+
updated?: number;
|
|
7905
|
+
}>(
|
|
7906
|
+
`${matchingUpdatesSql},
|
|
7907
|
+
applied_rows AS (
|
|
7908
|
+
UPDATE ${sheetTable(session)} AS target
|
|
7909
|
+
SET _status = 'enriched',
|
|
7910
|
+
_run_id = $5::text,
|
|
7911
|
+
_writer_run_id = $5::text,
|
|
7912
|
+
_write_version = COALESCE($13::bigint, target._write_version),
|
|
7913
|
+
_error = NULL,
|
|
7914
|
+
_attempt_id = $9::text,
|
|
7915
|
+
_attempt_owner_run_id = $10::text,
|
|
7916
|
+
_attempt_expires_at = $11::timestamptz,
|
|
7917
|
+
_attempt_seq = $12::integer,
|
|
7918
|
+
_updated_at = now(),
|
|
7919
|
+
_version = ${nextRuntimeSheetVersionExpression(session)},
|
|
7920
|
+
_cell_meta = ${mergeRuntimeCellMetaPatchSql('target._cell_meta', 'updates.cell_meta_patch')}${physicalRuntimeSheetUpdateSql(session, input.physicalColumnProjections, columnTypes)}
|
|
7921
|
+
FROM matched_updates AS updates, ${sheetTable(session)} AS prev
|
|
7922
|
+
WHERE ${writableRowsSql}
|
|
7923
|
+
AND prev._key = target._key
|
|
7753
7924
|
RETURNING target._key, prev._status AS prev_status, prev._cell_meta AS prev_cell_meta
|
|
7754
7925
|
),
|
|
7755
7926
|
applied_count AS (
|
|
@@ -7868,21 +8039,7 @@ async function completeRuntimeMapRowChunksWithInputIndexRepair(
|
|
|
7868
8039
|
SELECT
|
|
7869
8040
|
(SELECT count(*)::int FROM applied_rows) AS updated,
|
|
7870
8041
|
coalesce((SELECT jsonb_agg(jsonb_build_object('key', _key, 'reason', reason, 'rowVersionStamp', row_write_version)) FROM fenced_rows), '[]'::jsonb) AS fenced_rows`,
|
|
7871
|
-
|
|
7872
|
-
chunkKeys,
|
|
7873
|
-
chunkInputIndexes,
|
|
7874
|
-
chunkDataPatches,
|
|
7875
|
-
chunkCellMetaPatches,
|
|
7876
|
-
input.runId,
|
|
7877
|
-
input.normalizedPlayName,
|
|
7878
|
-
input.normalizedTableNamespace,
|
|
7879
|
-
[...new Set(input.outputFields)],
|
|
7880
|
-
input.attemptId,
|
|
7881
|
-
input.attemptOwnerRunId,
|
|
7882
|
-
input.attemptExpiresAt,
|
|
7883
|
-
input.attemptSeq,
|
|
7884
|
-
input.writeVersion,
|
|
7885
|
-
],
|
|
8042
|
+
mutationParams,
|
|
7886
8043
|
);
|
|
7887
8044
|
updated += Number(rows[0]?.updated ?? 0);
|
|
7888
8045
|
fencedRows.push(...parseRuntimeMapRowsFencedRows(rows[0]?.fenced_rows));
|
|
@@ -7902,21 +8059,56 @@ async function insertMissingCompletedMapRowChunks(
|
|
|
7902
8059
|
.map((column) => quoteIdentifier(column.sqlName))
|
|
7903
8060
|
.join(', ')}`
|
|
7904
8061
|
: '';
|
|
7905
|
-
const physicalInsertValuesSql =
|
|
7906
|
-
input.physicalColumnProjections.length > 0
|
|
7907
|
-
? `, ${input.physicalColumnProjections
|
|
7908
|
-
.map(
|
|
7909
|
-
(column) =>
|
|
7910
|
-
`missing_rows.data_patch -> ${quoteLiteral(column.fieldName)}`,
|
|
7911
|
-
)
|
|
7912
|
-
.join(', ')}`
|
|
7913
|
-
: '';
|
|
7914
8062
|
|
|
7915
8063
|
for (const chunk of input.chunks) {
|
|
7916
8064
|
const chunkKeys = chunk.map((row) => row.key);
|
|
7917
8065
|
const chunkInputIndexes = chunk.map((row) => row.input_index);
|
|
7918
8066
|
const chunkDataPatches = chunk.map((row) => row.data_patch_json);
|
|
7919
8067
|
const chunkCellMetaPatches = chunk.map((row) => row.cell_meta_patch_json);
|
|
8068
|
+
const columnTypes = await RuntimeSheetColumns.prepareWrite(client, {
|
|
8069
|
+
schema: session.postgres.schema,
|
|
8070
|
+
table: session.postgres.sheetTable,
|
|
8071
|
+
columns: input.physicalColumnProjections,
|
|
8072
|
+
rows: async () => {
|
|
8073
|
+
const accepted = await client.query<{
|
|
8074
|
+
data_patch: Record<string, unknown>;
|
|
8075
|
+
}>(
|
|
8076
|
+
`SELECT incoming.data_patch FROM jsonb_to_recordset($1::jsonb)
|
|
8077
|
+
AS incoming(key text, input_index bigint, data_patch jsonb)
|
|
8078
|
+
WHERE NOT EXISTS (
|
|
8079
|
+
SELECT 1 FROM ${sheetTable(session)} AS target
|
|
8080
|
+
WHERE target._key = incoming.key
|
|
8081
|
+
OR (incoming.input_index IS NOT NULL AND target._run_id = $2::text
|
|
8082
|
+
AND target._input_index = incoming.input_index)
|
|
8083
|
+
)`,
|
|
8084
|
+
[
|
|
8085
|
+
stringifyPostgresJson(
|
|
8086
|
+
chunk.map((row) => ({
|
|
8087
|
+
key: row.key,
|
|
8088
|
+
input_index: row.input_index,
|
|
8089
|
+
data_patch: JSON.parse(row.data_patch_json),
|
|
8090
|
+
})),
|
|
8091
|
+
),
|
|
8092
|
+
input.runId,
|
|
8093
|
+
],
|
|
8094
|
+
);
|
|
8095
|
+
return accepted.rows.map((row) => row.data_patch);
|
|
8096
|
+
},
|
|
8097
|
+
});
|
|
8098
|
+
const physicalInsertValuesSql =
|
|
8099
|
+
input.physicalColumnProjections.length > 0
|
|
8100
|
+
? `, ${input.physicalColumnProjections
|
|
8101
|
+
.map((column) =>
|
|
8102
|
+
RuntimeSheetColumns.jsonValueSql(
|
|
8103
|
+
`missing_rows.data_patch -> ${quoteLiteral(column.fieldName)}`,
|
|
8104
|
+
sheetTable(session),
|
|
8105
|
+
column.sqlName,
|
|
8106
|
+
columnTypes,
|
|
8107
|
+
),
|
|
8108
|
+
)
|
|
8109
|
+
.join(', ')}`
|
|
8110
|
+
: '';
|
|
8111
|
+
|
|
7920
8112
|
const { rows } = await client.query<{ inserted: number }>(
|
|
7921
8113
|
`WITH input_rows AS (
|
|
7922
8114
|
SELECT key_values._key,
|
|
@@ -8068,7 +8260,6 @@ async function failRuntimeMapRowChunks(
|
|
|
8068
8260
|
session: RuntimePostgresSession,
|
|
8069
8261
|
input: {
|
|
8070
8262
|
chunks: RuntimePreparedFailedRow[][];
|
|
8071
|
-
physicalUpdateSetSql: string;
|
|
8072
8263
|
physicalColumnProjections: PhysicalSheetColumnProjection[];
|
|
8073
8264
|
forceTerminal?: boolean;
|
|
8074
8265
|
runId: string;
|
|
@@ -8112,11 +8303,7 @@ async function failRuntimeMapRowChunks(
|
|
|
8112
8303
|
const failedCellTotals = failedCellFields.map(
|
|
8113
8304
|
(field) => failedCellCounts.get(field) ?? 0,
|
|
8114
8305
|
);
|
|
8115
|
-
const
|
|
8116
|
-
updated?: number;
|
|
8117
|
-
fenced_rows?: unknown;
|
|
8118
|
-
}>(
|
|
8119
|
-
`WITH updates AS (
|
|
8306
|
+
const matchingUpdatesSql = `WITH mutation_context AS (SELECT $7::text AS play_name, $8::text AS table_namespace, $9::text[] AS failed_fields, $10::int[] AS failed_totals, $12::text AS attempt_owner_run_id, $13::timestamptz AS attempt_expires_at, $14::integer AS attempt_seq), updates AS (
|
|
8120
8307
|
SELECT key_values._key,
|
|
8121
8308
|
input_index_values.input_index,
|
|
8122
8309
|
data_values.data_patch,
|
|
@@ -8148,25 +8335,9 @@ async function failRuntimeMapRowChunks(
|
|
|
8148
8335
|
AND target._input_index = updates.input_index
|
|
8149
8336
|
)
|
|
8150
8337
|
ORDER BY target._key, (target._key = updates._key) DESC
|
|
8151
|
-
)
|
|
8152
|
-
|
|
8153
|
-
UPDATE ${sheetTable(session)} AS target
|
|
8154
|
-
SET _status = 'failed',
|
|
8155
|
-
_run_id = $6::text,
|
|
8156
|
-
_writer_run_id = $6::text,
|
|
8157
|
-
_write_version = COALESCE($16::bigint, target._write_version),
|
|
8158
|
-
_error = updates.error,
|
|
8159
|
-
_attempt_id = $11::text,
|
|
8160
|
-
_attempt_owner_run_id = $12::text,
|
|
8161
|
-
_attempt_expires_at = $13::timestamptz,
|
|
8162
|
-
_attempt_seq = $14::integer,
|
|
8163
|
-
_updated_at = now(),
|
|
8164
|
-
_version = ${nextRuntimeSheetVersionExpression(session)},
|
|
8165
|
-
_cell_meta = ${mergeRuntimeCellMetaPatchSql('target._cell_meta', 'updates.cell_meta_patch')}${input.physicalUpdateSetSql}
|
|
8166
|
-
FROM matched_updates AS updates, ${sheetTable(session)} AS prev
|
|
8167
|
-
WHERE target._key = updates.matched_key
|
|
8338
|
+
)`;
|
|
8339
|
+
const writableRowsSql = `target._key = updates.matched_key
|
|
8168
8340
|
AND ($16::bigint IS NULL OR target._write_version = $16::bigint)
|
|
8169
|
-
AND prev._key = target._key
|
|
8170
8341
|
AND ($15::boolean OR target._status <> 'enriched')
|
|
8171
8342
|
AND NOT (${newerTerminalRuntimeSheetRowSql('target', '$13::timestamptz', '$14::integer', '$11::text', '$12::text')})
|
|
8172
8343
|
AND (
|
|
@@ -8183,7 +8354,66 @@ async function failRuntimeMapRowChunks(
|
|
|
8183
8354
|
AND target._run_id = $6::text
|
|
8184
8355
|
AND target._status IN ('failed', 'enriched')
|
|
8185
8356
|
AND updates.submitted_key = target._key
|
|
8186
|
-
)
|
|
8357
|
+
)`;
|
|
8358
|
+
const mutationParams = [
|
|
8359
|
+
chunkKeys,
|
|
8360
|
+
chunkInputIndexes,
|
|
8361
|
+
chunkDataPatches,
|
|
8362
|
+
chunkCellMetaPatches,
|
|
8363
|
+
chunkErrors,
|
|
8364
|
+
input.runId,
|
|
8365
|
+
input.normalizedPlayName,
|
|
8366
|
+
input.normalizedTableNamespace,
|
|
8367
|
+
failedCellFields,
|
|
8368
|
+
failedCellTotals,
|
|
8369
|
+
input.attemptId,
|
|
8370
|
+
input.attemptOwnerRunId,
|
|
8371
|
+
input.attemptExpiresAt,
|
|
8372
|
+
input.attemptSeq,
|
|
8373
|
+
input.forceTerminal === true,
|
|
8374
|
+
input.writeVersion,
|
|
8375
|
+
];
|
|
8376
|
+
const columnTypes = await RuntimeSheetColumns.prepareWrite(client, {
|
|
8377
|
+
schema: session.postgres.schema,
|
|
8378
|
+
table: session.postgres.sheetTable,
|
|
8379
|
+
columns: input.physicalColumnProjections,
|
|
8380
|
+
rows: async () => {
|
|
8381
|
+
const accepted = await client.query<{
|
|
8382
|
+
data_patch: Record<string, unknown>;
|
|
8383
|
+
}>(
|
|
8384
|
+
`${matchingUpdatesSql}
|
|
8385
|
+
SELECT updates.data_patch
|
|
8386
|
+
FROM matched_updates AS updates
|
|
8387
|
+
JOIN ${sheetTable(session)} AS target ON target._key = updates.matched_key
|
|
8388
|
+
WHERE ${writableRowsSql}
|
|
8389
|
+
FOR UPDATE OF target`,
|
|
8390
|
+
mutationParams,
|
|
8391
|
+
);
|
|
8392
|
+
return accepted.rows.map((row) => row.data_patch);
|
|
8393
|
+
},
|
|
8394
|
+
});
|
|
8395
|
+
const { rows } = await client.query<{
|
|
8396
|
+
updated?: number;
|
|
8397
|
+
fenced_rows?: unknown;
|
|
8398
|
+
}>(
|
|
8399
|
+
`${matchingUpdatesSql},
|
|
8400
|
+
applied_rows AS (
|
|
8401
|
+
UPDATE ${sheetTable(session)} AS target
|
|
8402
|
+
SET _status = 'failed',
|
|
8403
|
+
_run_id = $6::text,
|
|
8404
|
+
_writer_run_id = $6::text,
|
|
8405
|
+
_write_version = COALESCE($16::bigint, target._write_version),
|
|
8406
|
+
_error = updates.error,
|
|
8407
|
+
_attempt_id = $11::text,
|
|
8408
|
+
_attempt_owner_run_id = $12::text,
|
|
8409
|
+
_attempt_expires_at = $13::timestamptz,
|
|
8410
|
+
_attempt_seq = $14::integer,
|
|
8411
|
+
_updated_at = now(),
|
|
8412
|
+
_version = ${nextRuntimeSheetVersionExpression(session)},
|
|
8413
|
+
_cell_meta = ${mergeRuntimeCellMetaPatchSql('target._cell_meta', 'updates.cell_meta_patch')}${physicalRuntimeSheetUpdateSql(session, input.physicalColumnProjections, columnTypes)}
|
|
8414
|
+
FROM matched_updates AS updates, ${sheetTable(session)} AS prev
|
|
8415
|
+
WHERE ${writableRowsSql}
|
|
8416
|
+
AND prev._key = target._key
|
|
8187
8417
|
RETURNING target._key, prev._status AS prev_status
|
|
8188
8418
|
),
|
|
8189
8419
|
applied_count AS (
|
|
@@ -8280,24 +8510,7 @@ async function failRuntimeMapRowChunks(
|
|
|
8280
8510
|
SELECT
|
|
8281
8511
|
(SELECT count(*)::int FROM applied_rows) AS updated,
|
|
8282
8512
|
coalesce((SELECT jsonb_agg(jsonb_build_object('key', _key, 'reason', reason, 'rowVersionStamp', row_write_version)) FROM fenced_rows), '[]'::jsonb) AS fenced_rows`,
|
|
8283
|
-
|
|
8284
|
-
chunkKeys,
|
|
8285
|
-
chunkInputIndexes,
|
|
8286
|
-
chunkDataPatches,
|
|
8287
|
-
chunkCellMetaPatches,
|
|
8288
|
-
chunkErrors,
|
|
8289
|
-
input.runId,
|
|
8290
|
-
input.normalizedPlayName,
|
|
8291
|
-
input.normalizedTableNamespace,
|
|
8292
|
-
failedCellFields,
|
|
8293
|
-
failedCellTotals,
|
|
8294
|
-
input.attemptId,
|
|
8295
|
-
input.attemptOwnerRunId,
|
|
8296
|
-
input.attemptExpiresAt,
|
|
8297
|
-
input.attemptSeq,
|
|
8298
|
-
input.forceTerminal === true,
|
|
8299
|
-
input.writeVersion,
|
|
8300
|
-
],
|
|
8513
|
+
mutationParams,
|
|
8301
8514
|
);
|
|
8302
8515
|
const appliedCount = Number(rows[0]?.updated ?? 0);
|
|
8303
8516
|
const chunkFencedRows = parseRuntimeMapRowsFencedRows(rows[0]?.fenced_rows);
|
|
@@ -8433,20 +8646,6 @@ export async function completeRuntimeMapRows(
|
|
|
8433
8646
|
}
|
|
8434
8647
|
|
|
8435
8648
|
const projections = physicalSheetColumnProjections(sheetContract);
|
|
8436
|
-
const physicalUpdateSetSql =
|
|
8437
|
-
projections.length > 0
|
|
8438
|
-
? `,\n ${projections
|
|
8439
|
-
.map((column) => {
|
|
8440
|
-
const quoted = quoteIdentifier(column.sqlName);
|
|
8441
|
-
const literal = quoteLiteral(column.fieldName);
|
|
8442
|
-
return `${quoted} = CASE
|
|
8443
|
-
WHEN coalesce(updates.data_patch, '{}'::jsonb) ? ${literal}
|
|
8444
|
-
THEN updates.data_patch -> ${literal}
|
|
8445
|
-
ELSE target.${quoted}
|
|
8446
|
-
END`;
|
|
8447
|
-
})
|
|
8448
|
-
.join(',\n ')}`
|
|
8449
|
-
: '';
|
|
8450
8649
|
|
|
8451
8650
|
const { completedRows, failedRows } = prepareRuntimeSheetRowTransitions({
|
|
8452
8651
|
rows: uniqueRows.values(),
|
|
@@ -8455,7 +8654,7 @@ export async function completeRuntimeMapRows(
|
|
|
8455
8654
|
});
|
|
8456
8655
|
const chunks = chunkValues(completedRows, DIRECT_POSTGRES_BATCH_SIZE);
|
|
8457
8656
|
const failedChunks = chunkValues(failedRows, DIRECT_POSTGRES_BATCH_SIZE);
|
|
8458
|
-
const needsTransaction =
|
|
8657
|
+
const needsTransaction = true;
|
|
8459
8658
|
const outputFields = [...new Set(input.outputFields ?? [])];
|
|
8460
8659
|
const attemptId = input.attemptId?.trim() || null;
|
|
8461
8660
|
const attemptOwnerRunId =
|
|
@@ -8488,7 +8687,6 @@ export async function completeRuntimeMapRows(
|
|
|
8488
8687
|
? await (async () => {
|
|
8489
8688
|
const chunkInput = {
|
|
8490
8689
|
chunks,
|
|
8491
|
-
physicalUpdateSetSql,
|
|
8492
8690
|
physicalColumnProjections: projections,
|
|
8493
8691
|
runId: input.runId,
|
|
8494
8692
|
attemptId,
|
|
@@ -8522,7 +8720,6 @@ export async function completeRuntimeMapRows(
|
|
|
8522
8720
|
failedRows.length > 0
|
|
8523
8721
|
? await failRuntimeMapRowChunks(client, session, {
|
|
8524
8722
|
chunks: failedChunks,
|
|
8525
|
-
physicalUpdateSetSql,
|
|
8526
8723
|
physicalColumnProjections: projections,
|
|
8527
8724
|
forceTerminal: input.forceFailedRows === true,
|
|
8528
8725
|
runId: input.runId,
|