@duckcodeailabs/dql-cli 1.6.4 → 1.6.5
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/apps-api.d.ts +19 -0
- package/dist/apps-api.d.ts.map +1 -1
- package/dist/apps-api.js +279 -9
- package/dist/apps-api.js.map +1 -1
- package/dist/assets/dql-notebook/assets/index-L-zyCapt.js +3636 -0
- package/dist/assets/dql-notebook/index.html +1 -1
- package/dist/block-studio-import.js +23 -4
- package/dist/block-studio-import.js.map +1 -1
- package/dist/commands/import.js +6 -6
- package/dist/commands/import.js.map +1 -1
- package/dist/index.js +6 -6
- package/dist/local-runtime.d.ts +8 -1
- package/dist/local-runtime.d.ts.map +1 -1
- package/dist/local-runtime.js +217 -29
- package/dist/local-runtime.js.map +1 -1
- package/dist/package.json +10 -10
- package/package.json +11 -11
- package/dist/assets/dql-notebook/assets/index-BFUUTIWF.js +0 -3618
package/dist/apps-api.d.ts
CHANGED
|
@@ -143,6 +143,19 @@ export declare function createAppPackage(projectRoot: string, input: AppCreateRe
|
|
|
143
143
|
ok: false;
|
|
144
144
|
error: string;
|
|
145
145
|
};
|
|
146
|
+
declare function selectedBlockContext(context: unknown): Record<string, unknown> | null;
|
|
147
|
+
declare function buildPreviewMetricSnapshot(preview: Record<string, unknown>, fallbackTitle?: string): Record<string, unknown>;
|
|
148
|
+
declare function buildPreviewDriverCards(preview: Record<string, unknown>, intent: LocalAppInvestigationIntent): Array<Record<string, unknown>>;
|
|
149
|
+
declare function buildDeterministicInvestigationSql(projectRoot: string, input: {
|
|
150
|
+
question: string;
|
|
151
|
+
intent: LocalAppInvestigationIntent;
|
|
152
|
+
selected: Record<string, unknown> | null;
|
|
153
|
+
sourceBlockId?: string;
|
|
154
|
+
}): {
|
|
155
|
+
sql: string;
|
|
156
|
+
sourceBlockPath: string;
|
|
157
|
+
sourceBlockName: string;
|
|
158
|
+
} | undefined;
|
|
146
159
|
declare function loadAppById(projectRoot: string, id: string): {
|
|
147
160
|
app: AppDocument;
|
|
148
161
|
dashboards: Array<{
|
|
@@ -187,5 +200,11 @@ export declare function previewNotebookForApp(projectRoot: string, appId: string
|
|
|
187
200
|
status: number;
|
|
188
201
|
error: string;
|
|
189
202
|
};
|
|
203
|
+
export declare const __test__: {
|
|
204
|
+
buildPreviewDriverCards: typeof buildPreviewDriverCards;
|
|
205
|
+
buildPreviewMetricSnapshot: typeof buildPreviewMetricSnapshot;
|
|
206
|
+
buildDeterministicInvestigationSql: typeof buildDeterministicInvestigationSql;
|
|
207
|
+
selectedBlockContext: typeof selectedBlockContext;
|
|
208
|
+
};
|
|
190
209
|
export {};
|
|
191
210
|
//# sourceMappingURL=apps-api.d.ts.map
|
package/dist/apps-api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps-api.d.ts","sourceRoot":"","sources":["../src/apps-api.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"apps-api.d.ts","sourceRoot":"","sources":["../src/apps-api.ts"],"names":[],"mappings":"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"}
|
package/dist/apps-api.js
CHANGED
|
@@ -1063,13 +1063,24 @@ async function runAppInvestigation(ctx, storage, investigation, input = {}) {
|
|
|
1063
1063
|
const previews = buildContextPreviews(selected);
|
|
1064
1064
|
let metricSnapshot = buildMetricSnapshot(selected);
|
|
1065
1065
|
let driverCards = buildDriverCards(selected, intent);
|
|
1066
|
+
const sourceTileId = investigation.sourceTileId ?? selectedContextString(context, 'tileId');
|
|
1067
|
+
const sourceBlockId = investigation.sourceBlockId ?? selectedContextString(context, 'blockId');
|
|
1068
|
+
const deterministicGeneration = generatedSql
|
|
1069
|
+
? undefined
|
|
1070
|
+
: buildDeterministicInvestigationSql(ctx.projectRoot, {
|
|
1071
|
+
question,
|
|
1072
|
+
intent,
|
|
1073
|
+
selected,
|
|
1074
|
+
sourceBlockId,
|
|
1075
|
+
});
|
|
1076
|
+
generatedSql = generatedSql || deterministicGeneration?.sql;
|
|
1066
1077
|
const agentGeneration = generatedSql
|
|
1067
1078
|
? undefined
|
|
1068
1079
|
: await generateInvestigationSql(ctx, {
|
|
1069
1080
|
appId: investigation.appId,
|
|
1070
1081
|
dashboardId: investigation.dashboardId ?? selectedString(context, 'dashboardId'),
|
|
1071
|
-
sourceTileId
|
|
1072
|
-
sourceBlockId
|
|
1082
|
+
sourceTileId,
|
|
1083
|
+
sourceBlockId,
|
|
1073
1084
|
title: investigation.title,
|
|
1074
1085
|
question,
|
|
1075
1086
|
intent,
|
|
@@ -1095,6 +1106,9 @@ async function runAppInvestigation(ctx, storage, investigation, input = {}) {
|
|
|
1095
1106
|
generatedSql: generatedSql || undefined,
|
|
1096
1107
|
sqlExecuted: Boolean(sqlEvidence.preview),
|
|
1097
1108
|
sqlError,
|
|
1109
|
+
generationSource: deterministicGeneration ? 'selected_block_metadata' : agentGeneration?.providerUsed ? 'ai_provider' : generatedSql ? 'provided_sql' : 'context_only',
|
|
1110
|
+
sourceBlockPath: deterministicGeneration?.sourceBlockPath,
|
|
1111
|
+
sourceBlockName: deterministicGeneration?.sourceBlockName,
|
|
1098
1112
|
providerUsed: agentGeneration?.providerUsed,
|
|
1099
1113
|
},
|
|
1100
1114
|
certifiedContext: {
|
|
@@ -1102,8 +1116,9 @@ async function runAppInvestigation(ctx, storage, investigation, input = {}) {
|
|
|
1102
1116
|
appName: appInfo?.app.name,
|
|
1103
1117
|
dashboardId: investigation.dashboardId,
|
|
1104
1118
|
dashboardTitle: selectedString(context, 'dashboardTitle'),
|
|
1105
|
-
sourceTileId
|
|
1106
|
-
sourceBlockId
|
|
1119
|
+
sourceTileId,
|
|
1120
|
+
sourceBlockId,
|
|
1121
|
+
sourceBlockPath: deterministicGeneration?.sourceBlockPath ?? selectedString(selected, 'blockPath'),
|
|
1107
1122
|
certificationStatus: selectedString(selected, 'certificationStatus'),
|
|
1108
1123
|
},
|
|
1109
1124
|
assumptions: investigationAssumptions(intent, selected, generatedSql, sqlError),
|
|
@@ -1174,7 +1189,14 @@ function safeIntentContext(context) {
|
|
|
1174
1189
|
}
|
|
1175
1190
|
function selectedBlockContext(context) {
|
|
1176
1191
|
const root = asRecord(context);
|
|
1177
|
-
|
|
1192
|
+
const selected = asRecord(root?.selectedBlock);
|
|
1193
|
+
if (selected)
|
|
1194
|
+
return selected;
|
|
1195
|
+
if (!root)
|
|
1196
|
+
return null;
|
|
1197
|
+
const hasSelectedTileContext = ['blockId', 'blockPath', 'tileId', 'certificationStatus', 'resultSample', 'rowCount']
|
|
1198
|
+
.some((key) => root[key] !== undefined && root[key] !== null);
|
|
1199
|
+
return hasSelectedTileContext ? root : null;
|
|
1178
1200
|
}
|
|
1179
1201
|
function selectedContextString(context, key) {
|
|
1180
1202
|
return selectedString(selectedBlockContext(context), key);
|
|
@@ -1274,7 +1296,8 @@ function buildPreviewMetricSnapshot(preview, fallbackTitle) {
|
|
|
1274
1296
|
};
|
|
1275
1297
|
}
|
|
1276
1298
|
const currentColumn = pickColumn(numericColumns, [/^current_/i, /current.*(revenue|value|amount|total|orders?)/i])
|
|
1277
|
-
?? pickColumn(numericColumns, [/(revenue|value|amount|total|orders?|
|
|
1299
|
+
?? pickColumn(numericColumns, [/^total_/i, /(revenue|value|amount|total|orders?|points?|goals?|assists?|rebounds?|score|games_played)$/i])
|
|
1300
|
+
?? pickColumn(numericColumns, [/(count|row_count)$/i])
|
|
1278
1301
|
?? numericColumns[0];
|
|
1279
1302
|
const baselineColumn = pickColumn(numericColumns, [/^baseline_/i, /baseline.*(revenue|value|amount|total|orders?)/i]);
|
|
1280
1303
|
const deltaColumn = pickColumn(numericColumns, [/(delta|change|variance|diff|contribution)/i]);
|
|
@@ -1302,7 +1325,8 @@ function buildPreviewDriverCards(preview, intent) {
|
|
|
1302
1325
|
}
|
|
1303
1326
|
const numericColumns = columns.filter((column) => rows.some((row) => typeofNumber(row[column]) !== null));
|
|
1304
1327
|
const contributionColumn = pickColumn(numericColumns, [/(delta|change|variance|diff|contribution)/i])
|
|
1305
|
-
?? pickColumn(numericColumns, [/^current_/i, /(revenue|value|amount|total|orders?|
|
|
1328
|
+
?? pickColumn(numericColumns, [/^current_/i, /^total_/i, /(revenue|value|amount|total|orders?|points?|goals?|assists?|rebounds?|score|games_played)$/i])
|
|
1329
|
+
?? pickColumn(numericColumns, [/(count|row_count)$/i])
|
|
1306
1330
|
?? numericColumns[0];
|
|
1307
1331
|
const dimensionColumn = columns.find((column) => column !== contributionColumn && rows.some((row) => typeof row[column] === 'string'));
|
|
1308
1332
|
if (!contributionColumn) {
|
|
@@ -1355,6 +1379,229 @@ function sumNumericRows(rows, column) {
|
|
|
1355
1379
|
}
|
|
1356
1380
|
return found ? total : null;
|
|
1357
1381
|
}
|
|
1382
|
+
function buildDeterministicInvestigationSql(projectRoot, input) {
|
|
1383
|
+
if (input.intent === 'trust_gap_review')
|
|
1384
|
+
return undefined;
|
|
1385
|
+
const block = resolveSelectedBlock(projectRoot, input.selected, input.sourceBlockId);
|
|
1386
|
+
if (!block)
|
|
1387
|
+
return undefined;
|
|
1388
|
+
const source = readFileSync(join(projectRoot, block.path), 'utf-8');
|
|
1389
|
+
const blockSql = extractDqlQuery(source);
|
|
1390
|
+
if (!blockSql || /\{\{/.test(blockSql) || !isReadOnlySql(blockSql))
|
|
1391
|
+
return undefined;
|
|
1392
|
+
const rows = selectedRows(input.selected);
|
|
1393
|
+
const columns = selectedColumns(input.selected, rows);
|
|
1394
|
+
const sourceSql = stripTopLevelOrderAndLimit(blockSql);
|
|
1395
|
+
const profile = profileResultColumns(columns, rows);
|
|
1396
|
+
const measure = chooseMeasureColumn(profile);
|
|
1397
|
+
if (!measure)
|
|
1398
|
+
return undefined;
|
|
1399
|
+
const dimension = chooseDimensionColumn(input.question, profile, input.intent);
|
|
1400
|
+
const sourceCte = `WITH dql_source AS (\n${sourceSql}\n)`;
|
|
1401
|
+
if (input.intent === 'entity_drilldown') {
|
|
1402
|
+
const entity = inferEntityFilter(input.question, profile, rows);
|
|
1403
|
+
const orderBy = `ORDER BY ${quoteSqlIdentifier(measure.name)} DESC`;
|
|
1404
|
+
const where = entity ? `\nWHERE ${quoteSqlIdentifier(entity.column)} IS NOT NULL AND LOWER(CAST(${quoteSqlIdentifier(entity.column)} AS VARCHAR)) LIKE ${sqlStringLiteral(`%${entity.value.toLowerCase()}%`)}` : '';
|
|
1405
|
+
return {
|
|
1406
|
+
sql: `${sourceCte}\nSELECT *\nFROM dql_source${where}\n${orderBy}\nLIMIT 100`,
|
|
1407
|
+
sourceBlockPath: block.path,
|
|
1408
|
+
sourceBlockName: block.name,
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
if (input.intent === 'anomaly_investigation') {
|
|
1412
|
+
const timeDimension = chooseTimeDimension(profile) ?? dimension;
|
|
1413
|
+
const rankExpr = `${measureAgg(measure)}(${quoteSqlIdentifier(measure.name)})`;
|
|
1414
|
+
if (timeDimension) {
|
|
1415
|
+
return {
|
|
1416
|
+
sql: [
|
|
1417
|
+
sourceCte,
|
|
1418
|
+
', dql_trend AS (',
|
|
1419
|
+
` SELECT ${quoteSqlIdentifier(timeDimension.name)} AS ${quoteSqlIdentifier(timeDimension.name)}, ${rankExpr} AS ${quoteSqlIdentifier(measure.name)}`,
|
|
1420
|
+
' FROM dql_source',
|
|
1421
|
+
` GROUP BY ${quoteSqlIdentifier(timeDimension.name)}`,
|
|
1422
|
+
'), dql_deltas AS (',
|
|
1423
|
+
` SELECT ${quoteSqlIdentifier(timeDimension.name)}, ${quoteSqlIdentifier(measure.name)}, LAG(${quoteSqlIdentifier(measure.name)}) OVER (ORDER BY ${quoteSqlIdentifier(timeDimension.name)}) AS baseline_${safeAlias(measure.name)}`,
|
|
1424
|
+
' FROM dql_trend',
|
|
1425
|
+
')',
|
|
1426
|
+
`SELECT *, ${quoteSqlIdentifier(measure.name)} - baseline_${safeAlias(measure.name)} AS delta_${safeAlias(measure.name)}`,
|
|
1427
|
+
'FROM dql_deltas',
|
|
1428
|
+
`ORDER BY ABS(COALESCE(delta_${safeAlias(measure.name)}, 0)) DESC`,
|
|
1429
|
+
'LIMIT 20',
|
|
1430
|
+
].join('\n'),
|
|
1431
|
+
sourceBlockPath: block.path,
|
|
1432
|
+
sourceBlockName: block.name,
|
|
1433
|
+
};
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
if (!dimension)
|
|
1437
|
+
return undefined;
|
|
1438
|
+
const aggregate = `${measureAgg(measure)}(${quoteSqlIdentifier(measure.name)})`;
|
|
1439
|
+
const label = quoteSqlIdentifier(dimension.name);
|
|
1440
|
+
return {
|
|
1441
|
+
sql: [
|
|
1442
|
+
sourceCte,
|
|
1443
|
+
`SELECT ${label} AS ${label}, ${aggregate} AS ${quoteSqlIdentifier(measure.name)}, COUNT(*) AS ${quoteSqlIdentifier('row_count')}`,
|
|
1444
|
+
'FROM dql_source',
|
|
1445
|
+
`GROUP BY ${label}`,
|
|
1446
|
+
`ORDER BY ABS(COALESCE(${quoteSqlIdentifier(measure.name)}, 0)) DESC`,
|
|
1447
|
+
'LIMIT 20',
|
|
1448
|
+
].join('\n'),
|
|
1449
|
+
sourceBlockPath: block.path,
|
|
1450
|
+
sourceBlockName: block.name,
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
function resolveSelectedBlock(projectRoot, selected, sourceBlockId) {
|
|
1454
|
+
const selectedPath = selectedString(selected, 'blockPath');
|
|
1455
|
+
const candidates = collectBlockCandidates(projectRoot);
|
|
1456
|
+
if (selectedPath) {
|
|
1457
|
+
const normalizedPath = selectedPath.replace(/^\/+/, '');
|
|
1458
|
+
const found = candidates.find((block) => block.path === normalizedPath);
|
|
1459
|
+
if (found)
|
|
1460
|
+
return found;
|
|
1461
|
+
if (normalizedPath.startsWith('blocks/') && existsSync(join(projectRoot, normalizedPath))) {
|
|
1462
|
+
const source = readFileSync(join(projectRoot, normalizedPath), 'utf-8');
|
|
1463
|
+
const name = matchString(source, /block\s+"([^"]+)"/) ?? titleFromPath(normalizedPath);
|
|
1464
|
+
return {
|
|
1465
|
+
id: name,
|
|
1466
|
+
name,
|
|
1467
|
+
domain: matchString(source, /domain\s*=\s*"([^"]+)"/) ?? 'uncategorized',
|
|
1468
|
+
status: matchString(source, /status\s*=\s*"([^"]+)"/) ?? 'draft',
|
|
1469
|
+
owner: matchString(source, /owner\s*=\s*"([^"]+)"/),
|
|
1470
|
+
tags: matchArray(source, /tags\s*=\s*\[([^\]]*)\]/),
|
|
1471
|
+
path: normalizedPath,
|
|
1472
|
+
lastModified: statSyncSafe(join(projectRoot, normalizedPath))?.mtime.toISOString() ?? new Date(0).toISOString(),
|
|
1473
|
+
description: matchString(source, /description\s*=\s*"((?:[^"\\]|\\.)*)"/) ?? '',
|
|
1474
|
+
llmContext: matchString(source, /llmContext\s*=\s*"((?:[^"\\]|\\.)*)"/),
|
|
1475
|
+
chartType: matchString(source, /chart\s*=\s*"([^"]+)"/) ?? undefined,
|
|
1476
|
+
score: 0,
|
|
1477
|
+
reasons: [],
|
|
1478
|
+
};
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
const id = cleanString(sourceBlockId) || selectedString(selected, 'blockId');
|
|
1482
|
+
if (!id)
|
|
1483
|
+
return undefined;
|
|
1484
|
+
return candidates.find((block) => block.id === id || block.name === id || block.path === id);
|
|
1485
|
+
}
|
|
1486
|
+
function profileResultColumns(columns, rows) {
|
|
1487
|
+
return columns.map((name) => {
|
|
1488
|
+
const lower = name.toLowerCase();
|
|
1489
|
+
const numeric = rows.length === 0 ? !isLikelyTextColumn(lower) : rows.some((row) => typeofNumber(row[name]) !== null);
|
|
1490
|
+
const text = rows.some((row) => typeof row[name] === 'string' && String(row[name]).trim().length > 0);
|
|
1491
|
+
const time = /\b(season|year|month|week|quarter|date|day)\b/i.test(lower);
|
|
1492
|
+
const identifier = /\b(id|key|uuid|number)\b/i.test(lower) && !time;
|
|
1493
|
+
const measureName = /\b(total|sum|amount|revenue|sales|points?|goals?|assists?|rebounds?|count|avg|average|rate|pct|percent|score|value|delta|change|variance)\b/i.test(lower);
|
|
1494
|
+
const dimensionName = /\b(name|type|segment|region|market|category|status|player|customer|account|team|season|year|month|week|quarter|date)\b/i.test(lower);
|
|
1495
|
+
const measure = numeric && measureName && !identifier && !time;
|
|
1496
|
+
const dimension = !measure && (text || time || dimensionName || !numeric);
|
|
1497
|
+
return { name, lower, numeric, text, dimension, measure, time };
|
|
1498
|
+
});
|
|
1499
|
+
}
|
|
1500
|
+
function chooseMeasureColumn(columns) {
|
|
1501
|
+
const candidates = columns.filter((column) => column.measure);
|
|
1502
|
+
return candidates.find((column) => /\b(delta|change|variance|contribution)\b/i.test(column.lower))
|
|
1503
|
+
?? candidates.find((column) => /\b(total_points|total_revenue|total_amount|total|revenue|amount|sales|points|goals)\b/i.test(column.lower))
|
|
1504
|
+
?? candidates.find((column) => /\b(count|value|score|avg|average|rate|pct|percent)\b/i.test(column.lower))
|
|
1505
|
+
?? columns.find((column) => column.numeric && !column.dimension);
|
|
1506
|
+
}
|
|
1507
|
+
function chooseDimensionColumn(question, columns, intent) {
|
|
1508
|
+
const dimensions = columns.filter((column) => column.dimension);
|
|
1509
|
+
const questionTokens = new Set(question.toLowerCase().split(/[^a-z0-9]+/).filter(Boolean));
|
|
1510
|
+
const mentioned = dimensions.find((column) => column.lower.split(/[^a-z0-9]+/).some((token) => questionTokens.has(token)));
|
|
1511
|
+
if (mentioned)
|
|
1512
|
+
return mentioned;
|
|
1513
|
+
const timeDimension = chooseTimeDimension(columns);
|
|
1514
|
+
if ((intent === 'diagnose_change' || intent === 'segment_compare' || intent === 'anomaly_investigation') && timeDimension)
|
|
1515
|
+
return timeDimension;
|
|
1516
|
+
return dimensions.find((column) => column.text && !column.time)
|
|
1517
|
+
?? timeDimension
|
|
1518
|
+
?? dimensions[0];
|
|
1519
|
+
}
|
|
1520
|
+
function chooseTimeDimension(columns) {
|
|
1521
|
+
return columns.find((column) => column.time);
|
|
1522
|
+
}
|
|
1523
|
+
function inferEntityFilter(question, columns, rows) {
|
|
1524
|
+
const textDimensions = columns.filter((column) => column.dimension && (column.text || /\b(name|player|customer|account|team)\b/i.test(column.lower)));
|
|
1525
|
+
const lowerQuestion = question.toLowerCase();
|
|
1526
|
+
for (const column of textDimensions) {
|
|
1527
|
+
for (const row of rows) {
|
|
1528
|
+
const value = cleanString(row[column.name]);
|
|
1529
|
+
if (value && lowerQuestion.includes(value.toLowerCase()))
|
|
1530
|
+
return { column: column.name, value };
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
const named = question.match(/\b([A-Z][a-z]+(?:\s+[A-Z][a-z]+)+)\b/);
|
|
1534
|
+
const value = named?.[1]?.trim();
|
|
1535
|
+
const column = textDimensions[0];
|
|
1536
|
+
return value && column ? { column: column.name, value } : undefined;
|
|
1537
|
+
}
|
|
1538
|
+
function measureAgg(column) {
|
|
1539
|
+
return /\b(avg|average|rate|pct|percent|per_)\b/i.test(column.lower) ? 'AVG' : 'SUM';
|
|
1540
|
+
}
|
|
1541
|
+
function extractDqlQuery(source) {
|
|
1542
|
+
const tripleQuoteMatch = source.match(/query\s*=\s*"""([\s\S]*?)"""/i);
|
|
1543
|
+
if (tripleQuoteMatch)
|
|
1544
|
+
return tripleQuoteMatch[1].trim() || null;
|
|
1545
|
+
const singleQuoteMatch = source.match(/query\s*=\s*"((?:[^"\\]|\\.)*)"/i);
|
|
1546
|
+
if (singleQuoteMatch)
|
|
1547
|
+
return singleQuoteMatch[1].replace(/\\"/g, '"').trim() || null;
|
|
1548
|
+
return null;
|
|
1549
|
+
}
|
|
1550
|
+
function stripTopLevelOrderAndLimit(sql) {
|
|
1551
|
+
let next = sql.trim().replace(/;+\s*$/g, '');
|
|
1552
|
+
const limitIndex = findLastTopLevelKeyword(next, 'limit');
|
|
1553
|
+
if (limitIndex >= 0 && /^\s+limit\s+\d+\s*$/i.test(next.slice(limitIndex))) {
|
|
1554
|
+
next = next.slice(0, limitIndex).trim();
|
|
1555
|
+
}
|
|
1556
|
+
const orderIndex = findLastTopLevelKeyword(next, 'order by');
|
|
1557
|
+
if (orderIndex >= 0)
|
|
1558
|
+
next = next.slice(0, orderIndex).trim();
|
|
1559
|
+
return next;
|
|
1560
|
+
}
|
|
1561
|
+
function findLastTopLevelKeyword(sql, keyword) {
|
|
1562
|
+
const lower = sql.toLowerCase();
|
|
1563
|
+
const target = keyword.toLowerCase();
|
|
1564
|
+
let depth = 0;
|
|
1565
|
+
let quote = null;
|
|
1566
|
+
let last = -1;
|
|
1567
|
+
for (let i = 0; i < lower.length; i += 1) {
|
|
1568
|
+
const char = lower[i];
|
|
1569
|
+
if (quote) {
|
|
1570
|
+
if (char === quote && lower[i - 1] !== '\\')
|
|
1571
|
+
quote = null;
|
|
1572
|
+
continue;
|
|
1573
|
+
}
|
|
1574
|
+
if (char === '"' || char === "'" || char === '`') {
|
|
1575
|
+
quote = char;
|
|
1576
|
+
continue;
|
|
1577
|
+
}
|
|
1578
|
+
if (char === '(')
|
|
1579
|
+
depth += 1;
|
|
1580
|
+
if (char === ')')
|
|
1581
|
+
depth = Math.max(0, depth - 1);
|
|
1582
|
+
if (depth === 0 && lower.startsWith(target, i) && isKeywordBoundary(lower, i - 1) && isKeywordBoundary(lower, i + target.length)) {
|
|
1583
|
+
last = i;
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
return last;
|
|
1587
|
+
}
|
|
1588
|
+
function isKeywordBoundary(value, index) {
|
|
1589
|
+
if (index < 0 || index >= value.length)
|
|
1590
|
+
return true;
|
|
1591
|
+
return /[^a-z0-9_]/i.test(value[index]);
|
|
1592
|
+
}
|
|
1593
|
+
function quoteSqlIdentifier(identifier) {
|
|
1594
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
1595
|
+
}
|
|
1596
|
+
function sqlStringLiteral(value) {
|
|
1597
|
+
return `'${value.replace(/'/g, "''")}'`;
|
|
1598
|
+
}
|
|
1599
|
+
function safeAlias(identifier) {
|
|
1600
|
+
return identifier.replace(/[^a-z0-9_]+/gi, '_').replace(/^_+|_+$/g, '') || 'value';
|
|
1601
|
+
}
|
|
1602
|
+
function isLikelyTextColumn(value) {
|
|
1603
|
+
return /\b(name|type|segment|region|market|category|status|player|customer|account|team)\b/i.test(value);
|
|
1604
|
+
}
|
|
1358
1605
|
async function generateInvestigationSql(ctx, input) {
|
|
1359
1606
|
if (!ctx.generateInvestigationSql)
|
|
1360
1607
|
return undefined;
|
|
@@ -1432,13 +1679,26 @@ function buildGeneratedSqlPreview(result, generatedSql) {
|
|
|
1432
1679
|
};
|
|
1433
1680
|
}
|
|
1434
1681
|
function isReadOnlySql(sql) {
|
|
1435
|
-
const trimmed = sql
|
|
1682
|
+
const trimmed = stripLeadingSqlComments(sql).replace(/;+\s*$/g, '');
|
|
1436
1683
|
if (!/^(select|with)\b/i.test(trimmed))
|
|
1437
1684
|
return false;
|
|
1438
1685
|
if (/;\s*\S/.test(trimmed))
|
|
1439
1686
|
return false;
|
|
1440
1687
|
return !/\b(insert|update|delete|merge|drop|alter|create|truncate|copy|grant|revoke|call|execute|attach|detach)\b/i.test(trimmed);
|
|
1441
1688
|
}
|
|
1689
|
+
function stripLeadingSqlComments(sql) {
|
|
1690
|
+
let next = sql.trim();
|
|
1691
|
+
while (next.startsWith('--') || next.startsWith('/*')) {
|
|
1692
|
+
if (next.startsWith('--')) {
|
|
1693
|
+
const lineEnd = next.indexOf('\n');
|
|
1694
|
+
next = lineEnd >= 0 ? next.slice(lineEnd + 1).trimStart() : '';
|
|
1695
|
+
continue;
|
|
1696
|
+
}
|
|
1697
|
+
const blockEnd = next.indexOf('*/');
|
|
1698
|
+
next = blockEnd >= 0 ? next.slice(blockEnd + 2).trimStart() : '';
|
|
1699
|
+
}
|
|
1700
|
+
return next;
|
|
1701
|
+
}
|
|
1442
1702
|
function boundedPreviewSql(sql) {
|
|
1443
1703
|
return `SELECT * FROM (${sql.trim().replace(/;+\s*$/g, '')}) AS dql_research_preview LIMIT 100`;
|
|
1444
1704
|
}
|
|
@@ -1525,7 +1785,11 @@ function titleFromInvestigation(question, selected) {
|
|
|
1525
1785
|
return base.replace(/\s+/g, ' ').slice(0, 90);
|
|
1526
1786
|
}
|
|
1527
1787
|
function selectedRows(selected) {
|
|
1528
|
-
const rows = Array.isArray(selected?.sampleRows)
|
|
1788
|
+
const rows = Array.isArray(selected?.sampleRows)
|
|
1789
|
+
? selected?.sampleRows
|
|
1790
|
+
: Array.isArray(selected?.resultSample)
|
|
1791
|
+
? selected?.resultSample
|
|
1792
|
+
: selected?.rows;
|
|
1529
1793
|
if (!Array.isArray(rows))
|
|
1530
1794
|
return [];
|
|
1531
1795
|
return rows.map(asRecord).filter((row) => Boolean(row)).slice(0, 100);
|
|
@@ -2209,6 +2473,12 @@ async function readJson(req) {
|
|
|
2209
2473
|
req.on('error', reject);
|
|
2210
2474
|
});
|
|
2211
2475
|
}
|
|
2476
|
+
export const __test__ = {
|
|
2477
|
+
buildPreviewDriverCards,
|
|
2478
|
+
buildPreviewMetricSnapshot,
|
|
2479
|
+
buildDeterministicInvestigationSql,
|
|
2480
|
+
selectedBlockContext,
|
|
2481
|
+
};
|
|
2212
2482
|
// reference unused parseAppDocument/readFileSync to keep import stable for forward use
|
|
2213
2483
|
void parseAppDocument;
|
|
2214
2484
|
void readFileSync;
|