@rex0220/kintone-sql-tools 3.29.0 → 3.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-cli/ksql.js +221 -18
- package/dist-engine/index.cjs +9 -9
- package/dist-engine/index.d.ts +1 -1
- package/dist-engine/index.mjs +9 -9
- package/dist-engine/ksql-engine.umd.js +9 -9
- package/dist-engine/meta/bundle-baseline.json +7 -7
- package/dist-engine/meta/cjs.json +10 -10
- package/dist-engine/meta/esm.json +10 -10
- package/dist-engine/meta/umd.json +10 -10
- package/dist-engine/publicTypes.d.ts +25 -0
- package/dist-mcp/ksql-mcp.js +227 -23
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -5341,20 +5341,36 @@ function caseResultHasAggregate(result) {
|
|
|
5341
5341
|
if (result.type === "ARRAY" || result.type === "FIELD_REF" || result.type === "ARITH") return false;
|
|
5342
5342
|
return scalarValueHasAggregate(result);
|
|
5343
5343
|
}
|
|
5344
|
-
function
|
|
5344
|
+
function collectSelectFieldReferencesBySource(stmt, plainGroupByPlan) {
|
|
5345
|
+
const unqualified = /* @__PURE__ */ new Set();
|
|
5346
|
+
const states = collectRequiredFieldsByTable(stmt, plainGroupByPlan, {
|
|
5347
|
+
includeMaterialized: true,
|
|
5348
|
+
unqualified
|
|
5349
|
+
});
|
|
5350
|
+
return {
|
|
5351
|
+
bySource: new Map(
|
|
5352
|
+
[...states.entries()].map(([table, state]) => [table, new Set(state.fields)])
|
|
5353
|
+
),
|
|
5354
|
+
unqualified
|
|
5355
|
+
};
|
|
5356
|
+
}
|
|
5357
|
+
function collectRequiredFieldsByTable(stmt, plainGroupByPlan, sourceAware) {
|
|
5345
5358
|
const allTables = [stmt.from, ...stmt.joins.map((j) => j.table)];
|
|
5346
5359
|
const physicalTables = [stmt.from, ...stmt.joins.map((j) => j.table)].filter((t) => t.cteName === null);
|
|
5360
|
+
const targetTables = sourceAware ? allTables : physicalTables;
|
|
5347
5361
|
const states = /* @__PURE__ */ new Map();
|
|
5348
|
-
for (const table of
|
|
5362
|
+
for (const table of targetTables) {
|
|
5349
5363
|
states.set(table, { table, allFields: false, fields: /* @__PURE__ */ new Set() });
|
|
5350
5364
|
}
|
|
5351
5365
|
if (states.size === 0) return states;
|
|
5352
|
-
const
|
|
5353
|
-
const subtableTable =
|
|
5366
|
+
const firstTargetTable = targetTables[0] ?? null;
|
|
5367
|
+
const subtableTable = targetTables.find((t) => !!t.subtableCode) ?? null;
|
|
5354
5368
|
const aliasToTable = /* @__PURE__ */ new Map();
|
|
5355
|
-
for (const table of
|
|
5369
|
+
for (const table of targetTables) {
|
|
5356
5370
|
if (table.alias) aliasToTable.set(table.alias, table);
|
|
5357
|
-
if (
|
|
5371
|
+
if (table.cteName !== null) {
|
|
5372
|
+
aliasToTable.set(table.cteName, table);
|
|
5373
|
+
} else if (!table.subtableCode) {
|
|
5358
5374
|
aliasToTable.set(`APP${table.appId}`, table);
|
|
5359
5375
|
aliasToTable.set(`app${table.appId}`, table);
|
|
5360
5376
|
}
|
|
@@ -5366,11 +5382,11 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5366
5382
|
st.allFields = true;
|
|
5367
5383
|
st.fields.clear();
|
|
5368
5384
|
};
|
|
5369
|
-
const
|
|
5370
|
-
for (const t of
|
|
5385
|
+
const markAllTargetTables = () => {
|
|
5386
|
+
for (const t of targetTables) markAll(t);
|
|
5371
5387
|
};
|
|
5372
5388
|
const markAllSubtableTables = () => {
|
|
5373
|
-
for (const t of
|
|
5389
|
+
for (const t of targetTables) {
|
|
5374
5390
|
if (t.subtableCode) markAll(t);
|
|
5375
5391
|
}
|
|
5376
5392
|
};
|
|
@@ -5400,7 +5416,7 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5400
5416
|
if (rawName.endsWith(".*")) {
|
|
5401
5417
|
const qualifier = rawName.slice(0, -2);
|
|
5402
5418
|
if (!qualifier) {
|
|
5403
|
-
|
|
5419
|
+
markAllTargetTables();
|
|
5404
5420
|
return;
|
|
5405
5421
|
}
|
|
5406
5422
|
if (qualifier === "_p") {
|
|
@@ -5417,7 +5433,7 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5417
5433
|
if (phase === "groupBy" && groupResolution !== void 0) {
|
|
5418
5434
|
if (groupResolution.kind === "PHYSICAL") {
|
|
5419
5435
|
const source = allTables[groupResolution.sourceIndex];
|
|
5420
|
-
if (source
|
|
5436
|
+
if (source && (sourceAware || source.cteName === null)) {
|
|
5421
5437
|
addFieldToTable(source, groupResolution.fieldCode);
|
|
5422
5438
|
}
|
|
5423
5439
|
}
|
|
@@ -5442,8 +5458,13 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5442
5458
|
addFieldToTable(target, field);
|
|
5443
5459
|
return;
|
|
5444
5460
|
}
|
|
5461
|
+
if (sourceAware) return;
|
|
5462
|
+
}
|
|
5463
|
+
if (sourceAware) {
|
|
5464
|
+
sourceAware.unqualified.add(rawName);
|
|
5465
|
+
} else if (firstTargetTable) {
|
|
5466
|
+
addFieldToTable(firstTargetTable, rawName);
|
|
5445
5467
|
}
|
|
5446
|
-
if (firstPhysicalTable) addFieldToTable(firstPhysicalTable, rawName);
|
|
5447
5468
|
};
|
|
5448
5469
|
const addFieldRef = (field, tableAlias, phase = "select") => {
|
|
5449
5470
|
if (tableAlias) {
|
|
@@ -5456,6 +5477,7 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5456
5477
|
addFieldToTable(target, field);
|
|
5457
5478
|
return;
|
|
5458
5479
|
}
|
|
5480
|
+
if (sourceAware) return;
|
|
5459
5481
|
}
|
|
5460
5482
|
addFieldName(field, phase);
|
|
5461
5483
|
};
|
|
@@ -5611,7 +5633,7 @@ function collectRequiredFieldsByTable(stmt, plainGroupByPlan) {
|
|
|
5611
5633
|
for (const col of stmt.columns) {
|
|
5612
5634
|
switch (col.type) {
|
|
5613
5635
|
case "WILDCARD":
|
|
5614
|
-
|
|
5636
|
+
markAllTargetTables();
|
|
5615
5637
|
break;
|
|
5616
5638
|
case "PARENT_WILDCARD":
|
|
5617
5639
|
markAllSubtableTables();
|
|
@@ -9490,6 +9512,20 @@ function renderValidationValue(value) {
|
|
|
9490
9512
|
}
|
|
9491
9513
|
|
|
9492
9514
|
// src/core/existingRecordValidation.ts
|
|
9515
|
+
var VALIDATE_CONSTRAINT_CATEGORIES = [
|
|
9516
|
+
"required",
|
|
9517
|
+
"length",
|
|
9518
|
+
"range",
|
|
9519
|
+
"choice"
|
|
9520
|
+
];
|
|
9521
|
+
function getAuditableConstraintCategories(field) {
|
|
9522
|
+
return [
|
|
9523
|
+
...field.required === true ? ["required"] : [],
|
|
9524
|
+
...field.minLength !== void 0 || field.maxLength !== void 0 ? ["length"] : [],
|
|
9525
|
+
...field.minValue !== void 0 || field.maxValue !== void 0 ? ["range"] : [],
|
|
9526
|
+
...field.optionOrder !== void 0 ? ["choice"] : []
|
|
9527
|
+
];
|
|
9528
|
+
}
|
|
9493
9529
|
function buildValidationFieldMetadataIndex(fieldInfos) {
|
|
9494
9530
|
const topLevel = fieldInfos.filter((field) => !field.inSubtable);
|
|
9495
9531
|
const childrenByTable = /* @__PURE__ */ new Map();
|
|
@@ -9506,7 +9542,7 @@ function buildValidationFieldMetadataIndex(fieldInfos) {
|
|
|
9506
9542
|
};
|
|
9507
9543
|
}
|
|
9508
9544
|
function hasAuditableConstraint(field) {
|
|
9509
|
-
return field.
|
|
9545
|
+
return getAuditableConstraintCategories(field).length > 0;
|
|
9510
9546
|
}
|
|
9511
9547
|
function isExistingValidationAuditable(field) {
|
|
9512
9548
|
return field.fieldType === "NUMBER" || hasAuditableConstraint(field);
|
|
@@ -15629,6 +15665,13 @@ async function executeExistingRecordValidationCore(stmt, client, options, cacheC
|
|
|
15629
15665
|
const infoByCode = new Map(fieldInfos.filter((field) => !field.inSubtable).map((field) => [field.code, field]));
|
|
15630
15666
|
const childCodes = new Set(fieldInfos.filter((field) => field.inSubtable).map((field) => field.code));
|
|
15631
15667
|
const targets = resolveExistingValidationTargets(stmt, fieldInfos);
|
|
15668
|
+
const presentConstraintCategories = new Set(
|
|
15669
|
+
targets.flatMap((target) => getAuditableConstraintCategories(target.field))
|
|
15670
|
+
);
|
|
15671
|
+
const constraintMetadata = {
|
|
15672
|
+
present: VALIDATE_CONSTRAINT_CATEGORIES.filter((category) => presentConstraintCategories.has(category)),
|
|
15673
|
+
absent: VALIDATE_CONSTRAINT_CATEGORIES.filter((category) => !presentConstraintCategories.has(category))
|
|
15674
|
+
};
|
|
15632
15675
|
const checkGroups = stmt.checkGroups ?? [];
|
|
15633
15676
|
const checkRefs2 = collectCheckFieldRefs(checkGroups);
|
|
15634
15677
|
for (const ref of checkRefs2) {
|
|
@@ -15785,7 +15828,11 @@ async function executeExistingRecordValidationCore(stmt, client, options, cacheC
|
|
|
15785
15828
|
columns: [...columns],
|
|
15786
15829
|
rows,
|
|
15787
15830
|
rowCount: rows.length,
|
|
15788
|
-
validateStats: {
|
|
15831
|
+
validateStats: {
|
|
15832
|
+
errorRecords: errorRecordIds.size,
|
|
15833
|
+
errorCount,
|
|
15834
|
+
constraintMetadata
|
|
15835
|
+
}
|
|
15789
15836
|
};
|
|
15790
15837
|
materializedMetaBySelectResult.set(result, existingValidationColumnMeta(stmt.summary === true));
|
|
15791
15838
|
return result;
|
|
@@ -17093,6 +17140,159 @@ async function validateSelectFieldCodes(stmt, mode, client, cacheContext) {
|
|
|
17093
17140
|
}
|
|
17094
17141
|
}
|
|
17095
17142
|
}
|
|
17143
|
+
function b86SourceLabel(table) {
|
|
17144
|
+
return table.cteName ?? `APP${table.appId}`;
|
|
17145
|
+
}
|
|
17146
|
+
function b86SourceAliases(table) {
|
|
17147
|
+
if (table.alias) return [table.alias];
|
|
17148
|
+
if (table.cteName !== null) return [table.cteName];
|
|
17149
|
+
return [`APP${table.appId}`, `app${table.appId}`];
|
|
17150
|
+
}
|
|
17151
|
+
function b86PhysicalFieldExists(schema, field) {
|
|
17152
|
+
return isSystemLikeFieldCode(field) || schema.validCodes.has(field);
|
|
17153
|
+
}
|
|
17154
|
+
function b86FieldExists(schema, field) {
|
|
17155
|
+
if (schema.table.cteName !== null) return schema.validCodes.has(field);
|
|
17156
|
+
return b86PhysicalFieldExists(schema, field);
|
|
17157
|
+
}
|
|
17158
|
+
function collectB86Subqueries(stmt) {
|
|
17159
|
+
const queries = [];
|
|
17160
|
+
const visitWhere = (where) => {
|
|
17161
|
+
if (where === null) return;
|
|
17162
|
+
switch (where.type) {
|
|
17163
|
+
case "BINARY":
|
|
17164
|
+
if (where.right.type === "SUBQUERY_IN_LIST" || where.right.type === "SCALAR_SUBQUERY") {
|
|
17165
|
+
queries.push(where.right.query);
|
|
17166
|
+
}
|
|
17167
|
+
return;
|
|
17168
|
+
case "EXISTS":
|
|
17169
|
+
queries.push(where.query);
|
|
17170
|
+
return;
|
|
17171
|
+
case "LOGICAL":
|
|
17172
|
+
visitWhere(where.left);
|
|
17173
|
+
visitWhere(where.right);
|
|
17174
|
+
return;
|
|
17175
|
+
case "NOT":
|
|
17176
|
+
case "GROUP":
|
|
17177
|
+
visitWhere(where.expr);
|
|
17178
|
+
return;
|
|
17179
|
+
case "NULL_CHECK":
|
|
17180
|
+
case "BOOLEAN":
|
|
17181
|
+
return;
|
|
17182
|
+
}
|
|
17183
|
+
};
|
|
17184
|
+
visitWhere(stmt.where);
|
|
17185
|
+
visitWhere(stmt.having);
|
|
17186
|
+
for (const column of stmt.columns) {
|
|
17187
|
+
if (column.type === "SCALAR_SUBQUERY_COL") {
|
|
17188
|
+
queries.push(column.query);
|
|
17189
|
+
} else if (column.type === "CASE_COL") {
|
|
17190
|
+
for (const branch of column.expr.branches) visitWhere(branch.condition);
|
|
17191
|
+
}
|
|
17192
|
+
}
|
|
17193
|
+
return queries;
|
|
17194
|
+
}
|
|
17195
|
+
async function validateB86SelectFieldCodes(stmt, client, cteCache, cacheContext) {
|
|
17196
|
+
const tables = [stmt.from, ...stmt.joins.map((join2) => join2.table)];
|
|
17197
|
+
const materializedByTable = /* @__PURE__ */ new Map();
|
|
17198
|
+
const effectiveAliases = /* @__PURE__ */ new Set();
|
|
17199
|
+
for (const table of tables) {
|
|
17200
|
+
const alias = effectiveTableAlias(table);
|
|
17201
|
+
if (alias === null) continue;
|
|
17202
|
+
if (effectiveAliases.has(alias)) {
|
|
17203
|
+
throw new Error(`ArgumentError: effective alias ${alias} is used by multiple tables.`);
|
|
17204
|
+
}
|
|
17205
|
+
effectiveAliases.add(alias);
|
|
17206
|
+
}
|
|
17207
|
+
for (const table of tables) {
|
|
17208
|
+
if (table.cteName === null || table.cteName === NO_FROM_CTE_NAME) continue;
|
|
17209
|
+
const materialized = cteCache.get(table.cteName);
|
|
17210
|
+
if (!materialized) {
|
|
17211
|
+
throw new Error(`ArgumentError: materialized source ${table.cteName} is not available.`);
|
|
17212
|
+
}
|
|
17213
|
+
if (materialized.rows.length > 0 && materialized.columns.length === 0) {
|
|
17214
|
+
throw new Error(
|
|
17215
|
+
`InternalError: materialized source ${table.cteName} has rows but no column schema.`
|
|
17216
|
+
);
|
|
17217
|
+
}
|
|
17218
|
+
if (stmt.joins.length > 0 && materialized.rows.length === 0 && materialized.columns.length === 0) {
|
|
17219
|
+
throw new Error(
|
|
17220
|
+
`ArgumentError: column schema is unavailable for materialized JOIN source ${table.cteName}.`
|
|
17221
|
+
);
|
|
17222
|
+
}
|
|
17223
|
+
materializedByTable.set(table, materialized);
|
|
17224
|
+
}
|
|
17225
|
+
const schemas = /* @__PURE__ */ new Map();
|
|
17226
|
+
await Promise.all(tables.map(async (table) => {
|
|
17227
|
+
const materialized = materializedByTable.get(table);
|
|
17228
|
+
if (materialized) {
|
|
17229
|
+
schemas.set(table, {
|
|
17230
|
+
table,
|
|
17231
|
+
label: b86SourceLabel(table),
|
|
17232
|
+
validCodes: new Set(materialized.columns),
|
|
17233
|
+
authoritative: true,
|
|
17234
|
+
schemaUnavailable: materialized.rows.length === 0 && materialized.columns.length === 0
|
|
17235
|
+
});
|
|
17236
|
+
return;
|
|
17237
|
+
}
|
|
17238
|
+
if (table.cteName === NO_FROM_CTE_NAME) return;
|
|
17239
|
+
const defs = await getFieldsCached(table.appId, client, cacheContext);
|
|
17240
|
+
schemas.set(table, {
|
|
17241
|
+
table,
|
|
17242
|
+
label: b86SourceLabel(table),
|
|
17243
|
+
validCodes: new Set(defs.map((def) => def.code)),
|
|
17244
|
+
authoritative: defs.length > 0,
|
|
17245
|
+
schemaUnavailable: false
|
|
17246
|
+
});
|
|
17247
|
+
}));
|
|
17248
|
+
const sourceByAlias = /* @__PURE__ */ new Map();
|
|
17249
|
+
for (const schema of schemas.values()) {
|
|
17250
|
+
for (const alias of b86SourceAliases(schema.table)) sourceByAlias.set(alias, schema);
|
|
17251
|
+
}
|
|
17252
|
+
for (const join2 of stmt.joins) {
|
|
17253
|
+
for (const ref of [join2.on.left, join2.on.right]) {
|
|
17254
|
+
if (!ref.tableAlias) continue;
|
|
17255
|
+
const schema = sourceByAlias.get(ref.tableAlias);
|
|
17256
|
+
if (schema && schema.table.cteName !== null && !schema.schemaUnavailable && !b86FieldExists(schema, ref.field)) {
|
|
17257
|
+
throw new Error(
|
|
17258
|
+
`ArgumentError: JOIN key ${ref.tableAlias}.${ref.field} is not available in the materialized table.`
|
|
17259
|
+
);
|
|
17260
|
+
}
|
|
17261
|
+
}
|
|
17262
|
+
}
|
|
17263
|
+
const references = collectSelectFieldReferencesBySource(stmt);
|
|
17264
|
+
for (const [table, fields] of references.bySource) {
|
|
17265
|
+
const schema = schemas.get(table);
|
|
17266
|
+
if (!schema || schema.schemaUnavailable || !schema.authoritative) continue;
|
|
17267
|
+
const unknown = [...fields].filter((field) => !b86FieldExists(schema, field));
|
|
17268
|
+
if (unknown.length > 0) {
|
|
17269
|
+
throw new Error(
|
|
17270
|
+
`ArgumentError: unknown field code(s): ${unknown.join(", ")} (${schema.label})`
|
|
17271
|
+
);
|
|
17272
|
+
}
|
|
17273
|
+
}
|
|
17274
|
+
for (const field of references.unqualified) {
|
|
17275
|
+
const candidates = [...schemas.values()].filter((schema) => !schema.schemaUnavailable);
|
|
17276
|
+
if (candidates.some((schema) => b86FieldExists(schema, field))) continue;
|
|
17277
|
+
if ([...schemas.values()].some((schema) => schema.schemaUnavailable)) continue;
|
|
17278
|
+
if (candidates.some((schema) => schema.table.cteName === null && !schema.authoritative)) continue;
|
|
17279
|
+
const labels = candidates.map((schema) => schema.label).join(", ");
|
|
17280
|
+
throw new Error(`ArgumentError: unknown field code(s): ${field} (${labels})`);
|
|
17281
|
+
}
|
|
17282
|
+
}
|
|
17283
|
+
async function preflightB86QueryWithCte(query, client, cteCache, cacheContext, seen = /* @__PURE__ */ new Set()) {
|
|
17284
|
+
if (seen.has(query)) return;
|
|
17285
|
+
seen.add(query);
|
|
17286
|
+
if (query.type === "UNION") {
|
|
17287
|
+
await preflightB86QueryWithCte(query.left, client, cteCache, cacheContext, seen);
|
|
17288
|
+
await preflightB86QueryWithCte(query.right, client, cteCache, cacheContext, seen);
|
|
17289
|
+
return;
|
|
17290
|
+
}
|
|
17291
|
+
await validateB86SelectFieldCodes(query, client, cteCache, cacheContext);
|
|
17292
|
+
for (const subquery of collectB86Subqueries(query)) {
|
|
17293
|
+
await preflightB86QueryWithCte(subquery, client, cteCache, cacheContext, seen);
|
|
17294
|
+
}
|
|
17295
|
+
}
|
|
17096
17296
|
function extractMainTypedPushdownCandidate(stmt) {
|
|
17097
17297
|
if (stmt.where === null || stmt.from.subtableCode || stmt.from.cteName !== null) return null;
|
|
17098
17298
|
if (stmt.joins.length === 0) {
|
|
@@ -17954,11 +18154,14 @@ async function executeWith(stmt, client, options, cacheContext, seed, captureCol
|
|
|
17954
18154
|
}
|
|
17955
18155
|
return executeQueryWithCte(stmt.query, client, options, cteCache, cacheContext, captureColumnMeta);
|
|
17956
18156
|
}
|
|
17957
|
-
async function executeQueryWithCte(query, client, options, cteCache, cacheContext, captureColumnMeta = false) {
|
|
18157
|
+
async function executeQueryWithCte(query, client, options, cteCache, cacheContext, captureColumnMeta = false, b86PreflightComplete = false) {
|
|
18158
|
+
if (!b86PreflightComplete) {
|
|
18159
|
+
await preflightB86QueryWithCte(query, client, cteCache, cacheContext);
|
|
18160
|
+
}
|
|
17958
18161
|
if (query.type === "UNION") {
|
|
17959
18162
|
const [leftResult, rightResult] = await Promise.all([
|
|
17960
|
-
executeQueryWithCte(query.left, client, options, cteCache, cacheContext, captureColumnMeta),
|
|
17961
|
-
executeQueryWithCte(query.right, client, options, cteCache, cacheContext, captureColumnMeta)
|
|
18163
|
+
executeQueryWithCte(query.left, client, options, cteCache, cacheContext, captureColumnMeta, true),
|
|
18164
|
+
executeQueryWithCte(query.right, client, options, cteCache, cacheContext, captureColumnMeta, true)
|
|
17962
18165
|
]);
|
|
17963
18166
|
const leftCols = leftResult.columns;
|
|
17964
18167
|
const rightCols = rightResult.columns;
|