@rex0220/kintone-sql-tools 3.72.0 → 3.73.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/README.md +9 -0
- package/dist-cli/ksql.js +320 -14
- package/dist-engine/index.cjs +14 -14
- package/dist-engine/index.mjs +14 -14
- package/dist-engine/ksql-engine.umd.js +14 -14
- package/dist-engine/meta/bundle-baseline.json +7 -7
- package/dist-engine/meta/cjs.json +8 -8
- package/dist-engine/meta/esm.json +8 -8
- package/dist-engine/meta/umd.json +8 -8
- package/dist-flow/flow-library/index.d.ts +1 -1
- package/dist-flow/flow-library/publicTypes.d.ts +31 -1
- package/dist-flow/index.cjs +12 -12
- package/dist-flow/index.mjs +12 -12
- package/dist-flow/meta/cjs.json +8 -8
- package/dist-flow/meta/esm.json +8 -8
- package/dist-mcp/ksql-mcp.js +286 -10
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -289,6 +289,15 @@ try {
|
|
|
289
289
|
}
|
|
290
290
|
```
|
|
291
291
|
|
|
292
|
+
読取上限は既定 10,000 件(`maxRecords`)です。一時テーブルの実体化には**独立の** `tempTableMaxRows`(既定 10,000 行・超過は常にエラー)が適用されるため、大きなバッチでは両方を併せて指定してください:
|
|
293
|
+
|
|
294
|
+
```ts
|
|
295
|
+
const ctx = createExecutionContext({ client, script: source, maxRecords: 25000, tempTableMaxRows: 25000 });
|
|
296
|
+
await explainScript(source, { client, maxRecords: 25000 }); // EXPLAIN 面にも同じ上限を渡せる
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
`executeStatement` / `previewStatement` は実行コンテキストの `maxRecords` を共有します(3 面同値)。詳細は[言語リファレンス §27.9](docs/ksql_language_reference.md)。
|
|
300
|
+
|
|
292
301
|
### エンジンバージョン × dialect 対応表
|
|
293
302
|
|
|
294
303
|
| エンジン | dialect 0(既定・宣言なし) | dialect 1(`-- @ksql dialect: 1`) | ksql-flow |
|
package/dist-cli/ksql.js
CHANGED
|
@@ -18466,6 +18466,24 @@ var materializedMetaBySelectResult = /* @__PURE__ */ new WeakMap();
|
|
|
18466
18466
|
var materializedMetaByValidationResult = /* @__PURE__ */ new WeakMap();
|
|
18467
18467
|
var importSourceByDmlStatement = /* @__PURE__ */ new WeakMap();
|
|
18468
18468
|
var statementEvaluationContextKey = /* @__PURE__ */ Symbol("statementEvaluationContext");
|
|
18469
|
+
var nativeUpsertExecutionKey = /* @__PURE__ */ Symbol("nativeUpsertExecution");
|
|
18470
|
+
var nativeUpsertExplainCapabilityKey = /* @__PURE__ */ Symbol("nativeUpsertExplainCapability");
|
|
18471
|
+
function withNativeUpsertExecutionOption(options, enabled, explainClientCapability) {
|
|
18472
|
+
return {
|
|
18473
|
+
...options,
|
|
18474
|
+
[nativeUpsertExecutionKey]: enabled,
|
|
18475
|
+
...explainClientCapability === void 0 ? {} : { [nativeUpsertExplainCapabilityKey]: explainClientCapability }
|
|
18476
|
+
};
|
|
18477
|
+
}
|
|
18478
|
+
function nativeUpsertExecutionEnabled(options) {
|
|
18479
|
+
return options[nativeUpsertExecutionKey] === true;
|
|
18480
|
+
}
|
|
18481
|
+
function hasNativeUpsertExecutionOption(options) {
|
|
18482
|
+
return nativeUpsertExecutionKey in options;
|
|
18483
|
+
}
|
|
18484
|
+
function nativeUpsertExplainClientCapability(options) {
|
|
18485
|
+
return options[nativeUpsertExplainCapabilityKey];
|
|
18486
|
+
}
|
|
18469
18487
|
function bindStatementEvaluationContext(options) {
|
|
18470
18488
|
const internal = options;
|
|
18471
18489
|
if (internal[statementEvaluationContextKey]) return options;
|
|
@@ -18530,6 +18548,7 @@ function createEmptyMetrics() {
|
|
|
18530
18548
|
getCalls: 0,
|
|
18531
18549
|
postCalls: 0,
|
|
18532
18550
|
putCalls: 0,
|
|
18551
|
+
nativeUpsertCalls: 0,
|
|
18533
18552
|
deleteCalls: 0,
|
|
18534
18553
|
fieldCalls: 0,
|
|
18535
18554
|
numberPrecisionCalls: 0,
|
|
@@ -18558,7 +18577,7 @@ function markLimitReached(client, appId) {
|
|
|
18558
18577
|
if (!metrics.limitReachedApps.includes(appId)) metrics.limitReachedApps.push(appId);
|
|
18559
18578
|
}
|
|
18560
18579
|
function wrapClientWithMetrics(client, metrics) {
|
|
18561
|
-
|
|
18580
|
+
const wrapped = {
|
|
18562
18581
|
[LIMIT_METRICS_SINK]: metrics,
|
|
18563
18582
|
getRecords: async (params) => {
|
|
18564
18583
|
metrics.getCalls += 1;
|
|
@@ -18637,6 +18656,14 @@ function wrapClientWithMetrics(client, metrics) {
|
|
|
18637
18656
|
return client.getProcessStatuses(appId);
|
|
18638
18657
|
}
|
|
18639
18658
|
};
|
|
18659
|
+
if (clientHasNativeUpsert(client)) {
|
|
18660
|
+
wrapped.upsertRecords = (params) => {
|
|
18661
|
+
metrics.putCalls += 1;
|
|
18662
|
+
metrics.nativeUpsertCalls += 1;
|
|
18663
|
+
return client.upsertRecords(params);
|
|
18664
|
+
};
|
|
18665
|
+
}
|
|
18666
|
+
return wrapped;
|
|
18640
18667
|
}
|
|
18641
18668
|
var SEARCH_ABORT_FAIL_CLOSED = /* @__PURE__ */ Symbol("searchAbortFailClosed");
|
|
18642
18669
|
function wrapClientWithSearchAbort(client, collector, failClosed) {
|
|
@@ -18809,7 +18836,12 @@ async function executeParsedStatement(stmt, client, options, cacheContext) {
|
|
|
18809
18836
|
relativeDatePlan,
|
|
18810
18837
|
options.recursiveCteMaxDepth,
|
|
18811
18838
|
options.recursiveCteMaxRows,
|
|
18812
|
-
options.recursiveCteMaxExpansions
|
|
18839
|
+
options.recursiveCteMaxExpansions,
|
|
18840
|
+
hasNativeUpsertExecutionOption(options) ? {
|
|
18841
|
+
surface: "CLI",
|
|
18842
|
+
enableNativeUpsert: nativeUpsertExecutionEnabled(options),
|
|
18843
|
+
clientHasNativeUpsert: nativeUpsertExplainClientCapability(options) ?? clientHasNativeUpsert(client)
|
|
18844
|
+
} : { surface: "DOCUMENT_ONLY" }
|
|
18813
18845
|
);
|
|
18814
18846
|
// 一時テーブルはバッチスコープのため単文実行では拒否する(executeBatch を使う)
|
|
18815
18847
|
case "CREATE_TEMP_TABLE":
|
|
@@ -22813,6 +22845,206 @@ function upsertCompositeKey(parts) {
|
|
|
22813
22845
|
function upsertNormalizedKey(parts, numericKey) {
|
|
22814
22846
|
return JSON.stringify(parts.map((p, i) => numericKey[i] ? normalizeKeyPart(p) : p));
|
|
22815
22847
|
}
|
|
22848
|
+
var NATIVE_UPSERT_CONDITION_NAMES = {
|
|
22849
|
+
1: "CLIENT_CAPABILITY",
|
|
22850
|
+
2: "OPT_IN",
|
|
22851
|
+
3: "KEY_SCHEMA",
|
|
22852
|
+
4: "PLAIN_UPSERT",
|
|
22853
|
+
5: "EMPTY_KEY",
|
|
22854
|
+
6: "SOURCE_DUPLICATE"
|
|
22855
|
+
};
|
|
22856
|
+
function nativeUpsertExplainReason(condition, unknown, surface, unknownConditions = []) {
|
|
22857
|
+
if (unknown) {
|
|
22858
|
+
if (condition === 1) return "\u901A\u5E38\u5B9F\u884C client \u306E native \u80FD\u529B\u304C\u4E0D\u660E";
|
|
22859
|
+
if (condition === 2) return "native \u8A2D\u5B9A\u304C\u4E0D\u660E";
|
|
22860
|
+
if (condition === 3) return "\u30D5\u30A9\u30FC\u30E0\u30E1\u30BF\u30C7\u30FC\u30BF\u672A\u53D6\u5F97";
|
|
22861
|
+
if (condition === 5 || unknownConditions.includes(5)) return "\u30BD\u30FC\u30B9\u884C\u672A materialize";
|
|
22862
|
+
if (condition === 6) return "\u30AD\u30FC\u578B\u60C5\u5831\u304C\u672A\u78BA\u5B9A\u306E\u305F\u3081\u91CD\u8907\u5224\u5B9A\u4E0D\u80FD";
|
|
22863
|
+
}
|
|
22864
|
+
if (condition === 1) return "client \u304C upsertRecords \u80FD\u529B\u3092\u6301\u305F\u306A\u3044";
|
|
22865
|
+
if (condition === 2) return surface === "CLI" ? "--native-upsert \u304C\u6307\u5B9A\u3055\u308C\u3066\u3044\u306A\u3044" : "enableNativeUpsert \u304C false";
|
|
22866
|
+
if (condition === 3) return "\u30AD\u30FC\u9805\u76EE\u306F\u91CD\u8907\u7981\u6B62\u306E SINGLE_LINE_TEXT \u307E\u305F\u306F NUMBER \u3067\u306F\u306A\u3044";
|
|
22867
|
+
if (condition === 4) return "CHECK / APPLY / IMPORT / VALIDATE ONLY / ON ERROR SKIP \u3092\u4F34\u3046\u7D20\u3067\u306A\u3044 UPSERT";
|
|
22868
|
+
if (condition === 5) return "\u30BD\u30FC\u30B9\u306B\u7A7A\u6587\u5B57\u30AD\u30FC\u304C\u3042\u308B";
|
|
22869
|
+
return "\u30BD\u30FC\u30B9\u5185\u306B\u540C\u4E00\u30AD\u30FC\u304C\u3042\u308B";
|
|
22870
|
+
}
|
|
22871
|
+
function renderNativeUpsertEligibilityResult(label, result, surface) {
|
|
22872
|
+
if (result.status === "ELIGIBLE") {
|
|
22873
|
+
return ` ${label}: ELIGIBLE\uFF08${label.includes("statement/data") ? "\u6761\u4EF6 3\u301C6 \u3092" : "6 \u6761\u4EF6\u3092\u3059\u3079\u3066"}\u6E80\u305F\u3059\uFF09`;
|
|
22874
|
+
}
|
|
22875
|
+
if (result.status === "INELIGIBLE") {
|
|
22876
|
+
return ` ${label}: INELIGIBLE\uFF08\u6761\u4EF6 ${result.condition}: ${NATIVE_UPSERT_CONDITION_NAMES[result.condition]} \u2014 ${nativeUpsertExplainReason(result.condition, false, surface)}\uFF09`;
|
|
22877
|
+
}
|
|
22878
|
+
const unknownConditionNumbers = result.unknownConditions.map(({ condition }) => condition);
|
|
22879
|
+
const details = result.unknownConditions.map(
|
|
22880
|
+
({ condition }) => `\u6761\u4EF6 ${condition}: ${NATIVE_UPSERT_CONDITION_NAMES[condition]} \u2014 ${nativeUpsertExplainReason(condition, true, surface, unknownConditionNumbers)}`
|
|
22881
|
+
);
|
|
22882
|
+
return ` ${label}: UNKNOWN\uFF08${details.join("; ")}\uFF09`;
|
|
22883
|
+
}
|
|
22884
|
+
function renderNativeUpsertEligibility(evaluation, surface) {
|
|
22885
|
+
if (surface === "DOCUMENT_ONLY") {
|
|
22886
|
+
return [
|
|
22887
|
+
renderNativeUpsertEligibilityResult("native UPSERT statement/data eligibility", evaluation.statement, surface),
|
|
22888
|
+
` native UPSERT execution surface: NOT_APPLICABLE\uFF08\u3053\u306E\u9762\u3067\u306F\u5B9F\u884C\u3057\u306A\u3044${evaluation.statement.status === "ELIGIBLE" ? "\u3002/flow \u307E\u305F\u306F CLI --native-upsert \u3067\u306F native \u5019\u88DC" : ""}\uFF09`
|
|
22889
|
+
];
|
|
22890
|
+
}
|
|
22891
|
+
const lines = [renderNativeUpsertEligibilityResult("native UPSERT eligibility", evaluation.execution, surface)];
|
|
22892
|
+
if (evaluation.conditions[1].state === "FAIL" || evaluation.conditions[2].state === "FAIL") {
|
|
22893
|
+
lines.push(renderNativeUpsertEligibilityResult("native UPSERT statement/data eligibility", evaluation.statement, surface));
|
|
22894
|
+
}
|
|
22895
|
+
return lines;
|
|
22896
|
+
}
|
|
22897
|
+
function explainNativeUpsertStatement(statement) {
|
|
22898
|
+
const candidate = statement.type === "EXPLAIN" ? statement.query : statement;
|
|
22899
|
+
return candidate.type === "UPSERT" || candidate.type === "UPSERT_SELECT" ? candidate : null;
|
|
22900
|
+
}
|
|
22901
|
+
function nativeUpsertExplainEvaluation(statement, fieldInfos, options) {
|
|
22902
|
+
let rowKeyValues = null;
|
|
22903
|
+
if (statement.type === "UPSERT") {
|
|
22904
|
+
try {
|
|
22905
|
+
rowKeyValues = buildUpsertRowKeyValues(statement);
|
|
22906
|
+
} catch {
|
|
22907
|
+
}
|
|
22908
|
+
}
|
|
22909
|
+
return evaluateNativeUpsertEligibility({
|
|
22910
|
+
surface: options.surface === "DOCUMENT_ONLY" ? "DOCUMENT_ONLY" : "EXECUTION",
|
|
22911
|
+
clientCapability: options.surface === "DOCUMENT_ONLY" ? null : options.clientHasNativeUpsert ?? null,
|
|
22912
|
+
enabled: options.surface === "DOCUMENT_ONLY" ? null : options.surface === "FLOW" ? options.enableNativeUpsert !== false : options.enableNativeUpsert === true,
|
|
22913
|
+
statement: {
|
|
22914
|
+
kind: statement.type === "UPSERT" ? "VALUES" : "SELECT",
|
|
22915
|
+
keyFields: statement.keyFields,
|
|
22916
|
+
hasCheck: Boolean(statement.checkGroups?.length),
|
|
22917
|
+
hasApply: statement.type === "UPSERT" && Boolean(statement.onInsertApplyBlocks?.length || statement.onUpdateApplyBlocks?.length),
|
|
22918
|
+
validateOnly: statement.validateOnly === true,
|
|
22919
|
+
onErrorSkip: statement.onErrorSkip === true,
|
|
22920
|
+
importDerived: importSourceByDmlStatement.has(statement)
|
|
22921
|
+
},
|
|
22922
|
+
fieldInfos,
|
|
22923
|
+
rowKeyValues
|
|
22924
|
+
});
|
|
22925
|
+
}
|
|
22926
|
+
async function nativeUpsertExplainLines(statement, cacheContext, options) {
|
|
22927
|
+
const upsert = explainNativeUpsertStatement(statement);
|
|
22928
|
+
if (!upsert) return [];
|
|
22929
|
+
const fieldInfos = await getFieldsIfCached(upsert.appId, cacheContext);
|
|
22930
|
+
return renderNativeUpsertEligibility(
|
|
22931
|
+
nativeUpsertExplainEvaluation(upsert, fieldInfos, options),
|
|
22932
|
+
options.surface
|
|
22933
|
+
);
|
|
22934
|
+
}
|
|
22935
|
+
function evaluateNativeUpsertEligibility(input) {
|
|
22936
|
+
const keyField = input.statement.keyFields.length === 1 ? input.statement.keyFields[0] : void 0;
|
|
22937
|
+
const keyInfo = keyField === void 0 || input.fieldInfos === null ? void 0 : input.fieldInfos.find((field) => field.code === keyField);
|
|
22938
|
+
const supportedKeyType = keyInfo?.fieldType === "SINGLE_LINE_TEXT" || keyInfo?.fieldType === "NUMBER";
|
|
22939
|
+
const schemaPass = input.fieldInfos === null ? null : Boolean(
|
|
22940
|
+
keyField !== void 0 && keyInfo && supportedKeyType && keyInfo.isUnique === true
|
|
22941
|
+
);
|
|
22942
|
+
const plain = !input.statement.hasCheck && !input.statement.hasApply && !input.statement.validateOnly && !input.statement.onErrorSkip && !(input.statement.kind === "SELECT" && input.statement.importDerived);
|
|
22943
|
+
const rows = input.rowKeyValues;
|
|
22944
|
+
const noEmpty = rows === null ? null : rows.every((parts) => parts.every((part) => part !== ""));
|
|
22945
|
+
let noDuplicates = null;
|
|
22946
|
+
if (rows !== null && keyField !== void 0 && supportedKeyType) {
|
|
22947
|
+
const seen = /* @__PURE__ */ new Set();
|
|
22948
|
+
noDuplicates = true;
|
|
22949
|
+
for (const parts of rows) {
|
|
22950
|
+
const normalized = upsertNormalizedKey([...parts], [keyInfo.fieldType === "NUMBER"]);
|
|
22951
|
+
if (seen.has(normalized)) {
|
|
22952
|
+
noDuplicates = false;
|
|
22953
|
+
break;
|
|
22954
|
+
}
|
|
22955
|
+
seen.add(normalized);
|
|
22956
|
+
}
|
|
22957
|
+
}
|
|
22958
|
+
const state = (value, reason) => ({
|
|
22959
|
+
state: value === null ? "UNKNOWN" : value ? "PASS" : "FAIL",
|
|
22960
|
+
reason
|
|
22961
|
+
});
|
|
22962
|
+
const conditions = {
|
|
22963
|
+
1: input.surface === "DOCUMENT_ONLY" ? { state: "NOT_APPLICABLE", reason: "client capability is not applicable on this surface" } : state(input.clientCapability, "client does not provide upsertRecords"),
|
|
22964
|
+
2: input.surface === "DOCUMENT_ONLY" ? { state: "NOT_APPLICABLE", reason: "native setting is not applicable on this surface" } : state(input.enabled, "native UPSERT is disabled"),
|
|
22965
|
+
3: state(schemaPass, "update key schema is not a single unique text or number field"),
|
|
22966
|
+
4: state(plain, "statement is not a plain UPSERT"),
|
|
22967
|
+
5: state(noEmpty, "source contains an empty update key"),
|
|
22968
|
+
6: state(noDuplicates, "source contains duplicate update keys")
|
|
22969
|
+
};
|
|
22970
|
+
const summarize = (ordered) => {
|
|
22971
|
+
const failed = ordered.find((condition) => conditions[condition].state === "FAIL");
|
|
22972
|
+
if (failed !== void 0) return { status: "INELIGIBLE", condition: failed, reason: conditions[failed].reason };
|
|
22973
|
+
const unknownConditions = ordered.filter((condition) => conditions[condition].state === "UNKNOWN").map((condition) => ({ condition, reason: conditions[condition].reason }));
|
|
22974
|
+
return unknownConditions.length > 0 ? { status: "UNKNOWN", unknownConditions } : { status: "ELIGIBLE" };
|
|
22975
|
+
};
|
|
22976
|
+
return {
|
|
22977
|
+
conditions,
|
|
22978
|
+
execution: summarize([1, 2, 3, 4, 5, 6]),
|
|
22979
|
+
statement: summarize([3, 4, 5, 6])
|
|
22980
|
+
};
|
|
22981
|
+
}
|
|
22982
|
+
function clientHasNativeUpsert(client) {
|
|
22983
|
+
return "upsertRecords" in client && typeof client.upsertRecords === "function";
|
|
22984
|
+
}
|
|
22985
|
+
function nativeEligibilityInput(stmt, client, options, fieldInfos, rowKeyValues) {
|
|
22986
|
+
return {
|
|
22987
|
+
surface: "EXECUTION",
|
|
22988
|
+
clientCapability: clientHasNativeUpsert(client),
|
|
22989
|
+
enabled: nativeUpsertExecutionEnabled(options),
|
|
22990
|
+
statement: {
|
|
22991
|
+
kind: stmt.type === "UPSERT" ? "VALUES" : "SELECT",
|
|
22992
|
+
keyFields: stmt.keyFields,
|
|
22993
|
+
hasCheck: Boolean(stmt.checkGroups?.length),
|
|
22994
|
+
hasApply: stmt.type === "UPSERT" && Boolean(stmt.onInsertApplyBlocks?.length || stmt.onUpdateApplyBlocks?.length),
|
|
22995
|
+
validateOnly: stmt.validateOnly === true,
|
|
22996
|
+
onErrorSkip: stmt.onErrorSkip === true,
|
|
22997
|
+
importDerived: importSourceByDmlStatement.has(stmt)
|
|
22998
|
+
},
|
|
22999
|
+
fieldInfos,
|
|
23000
|
+
rowKeyValues
|
|
23001
|
+
};
|
|
23002
|
+
}
|
|
23003
|
+
var NativeUpsertResponseError = class extends Error {
|
|
23004
|
+
constructor() {
|
|
23005
|
+
super("NativeUpsertResponseError: upsertRecords returned an invalid response.");
|
|
23006
|
+
this.name = "NativeUpsertResponseError";
|
|
23007
|
+
}
|
|
23008
|
+
};
|
|
23009
|
+
function validateNativeUpsertResponse(response, expectedRecords) {
|
|
23010
|
+
if (!response || !Array.isArray(response.records) || response.records.length !== expectedRecords) {
|
|
23011
|
+
throw new NativeUpsertResponseError();
|
|
23012
|
+
}
|
|
23013
|
+
let insertedCount = 0;
|
|
23014
|
+
let updatedCount = 0;
|
|
23015
|
+
for (const record of response.records) {
|
|
23016
|
+
if (!record || typeof record.id !== "string" || typeof record.revision !== "string" || record.operation !== "INSERT" && record.operation !== "UPDATE") {
|
|
23017
|
+
throw new NativeUpsertResponseError();
|
|
23018
|
+
}
|
|
23019
|
+
if (record.operation === "INSERT") insertedCount += 1;
|
|
23020
|
+
else updatedCount += 1;
|
|
23021
|
+
}
|
|
23022
|
+
return { insertedCount, updatedCount };
|
|
23023
|
+
}
|
|
23024
|
+
async function executeNativeUpsertRecords(appId, keyField, records, rowKeyValues, client, options) {
|
|
23025
|
+
if (records.length === 0) return { type: "UPSERT", insertedCount: 0, updatedCount: 0 };
|
|
23026
|
+
if (options.confirm) {
|
|
23027
|
+
const ok = await options.confirm(records.length, "UPDATE");
|
|
23028
|
+
if (!ok) throw new OperationCancelledError("UPDATE", records.length);
|
|
23029
|
+
}
|
|
23030
|
+
let insertedCount = 0;
|
|
23031
|
+
let updatedCount = 0;
|
|
23032
|
+
for (let offset = 0; offset < records.length; offset += 100) {
|
|
23033
|
+
const nativeRecords = records.slice(offset, offset + 100).map((record, index) => {
|
|
23034
|
+
const payload = {};
|
|
23035
|
+
for (const [field, value] of Object.entries(record)) if (field !== keyField) payload[field] = value;
|
|
23036
|
+
return {
|
|
23037
|
+
updateKey: { field: keyField, value: rowKeyValues[offset + index][0] },
|
|
23038
|
+
record: payload
|
|
23039
|
+
};
|
|
23040
|
+
});
|
|
23041
|
+
const response = await client.upsertRecords({ app: appId, upsert: true, records: nativeRecords });
|
|
23042
|
+
const counts = validateNativeUpsertResponse(response, nativeRecords.length);
|
|
23043
|
+
insertedCount += counts.insertedCount;
|
|
23044
|
+
updatedCount += counts.updatedCount;
|
|
23045
|
+
}
|
|
23046
|
+
return { type: "UPSERT", insertedCount, updatedCount };
|
|
23047
|
+
}
|
|
22816
23048
|
function lookupUpsertTarget(index, keyParts) {
|
|
22817
23049
|
const exact = index.raw.get(upsertCompositeKey(keyParts));
|
|
22818
23050
|
if (exact !== void 0) return exact;
|
|
@@ -23029,6 +23261,10 @@ async function getFieldsCached(appId, client, cacheContext) {
|
|
|
23029
23261
|
setScopedCacheValue(fieldInfoCache, cacheContext, appId, loading);
|
|
23030
23262
|
return loading;
|
|
23031
23263
|
}
|
|
23264
|
+
async function getFieldsIfCached(appId, cacheContext) {
|
|
23265
|
+
const cached = getScopedCacheValue(fieldInfoCache, cacheContext, appId);
|
|
23266
|
+
return cached ? await cached : null;
|
|
23267
|
+
}
|
|
23032
23268
|
async function getNumberPrecisionCached(appId, client, cacheContext) {
|
|
23033
23269
|
const cached = getScopedCacheValue(numberPrecisionCache, cacheContext, appId);
|
|
23034
23270
|
if (cached) return cached;
|
|
@@ -25596,6 +25832,16 @@ async function executeDelete(stmt, client, options, cacheContext) {
|
|
|
25596
25832
|
}
|
|
25597
25833
|
return { type: "DELETE", deletedCount: ids.length };
|
|
25598
25834
|
}
|
|
25835
|
+
function materializeUpsertValueRecords(stmt, fieldTypes, options) {
|
|
25836
|
+
return stmt.values.map((row) => {
|
|
25837
|
+
const record = {};
|
|
25838
|
+
stmt.fields.forEach((field, index) => {
|
|
25839
|
+
const value = row[index];
|
|
25840
|
+
record[field] = { value: value.type === "CASE_VALUE" ? evalCaseWhenValue(value.expr, {}, fieldTypes.get(field), statementEvaluationContext(options)) : toKintoneValue(value, fieldTypes.get(field)) };
|
|
25841
|
+
});
|
|
25842
|
+
return record;
|
|
25843
|
+
});
|
|
25844
|
+
}
|
|
25599
25845
|
async function executeUpsert(stmt, client, options, cacheContext) {
|
|
25600
25846
|
if (stmt.onInsertApplyBlocks?.length || stmt.onUpdateApplyBlocks?.length) {
|
|
25601
25847
|
return executeApplyUpsert(stmt, client, options, cacheContext);
|
|
@@ -25607,6 +25853,14 @@ async function executeUpsert(stmt, client, options, cacheContext) {
|
|
|
25607
25853
|
const toUpdate = [];
|
|
25608
25854
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
25609
25855
|
const rowKeyValues = buildUpsertRowKeyValues(stmt);
|
|
25856
|
+
const nativeEligibility = evaluateNativeUpsertEligibility(
|
|
25857
|
+
nativeEligibilityInput(stmt, client, options, fieldInfos, rowKeyValues)
|
|
25858
|
+
);
|
|
25859
|
+
if (nativeEligibility.execution.status === "ELIGIBLE") {
|
|
25860
|
+
const records = materializeUpsertValueRecords(stmt, fieldTypes, options);
|
|
25861
|
+
assertValidDmlRecords(records, stmt.fields, fieldInfos, numberPrecision);
|
|
25862
|
+
return executeNativeUpsertRecords(stmt.appId, stmt.keyFields[0], records, rowKeyValues, client, options);
|
|
25863
|
+
}
|
|
25610
25864
|
const targetIndex = await resolveUpsertTargets(stmt.appId, stmt.keyFields, rowKeyValues, client, options, fieldTypes);
|
|
25611
25865
|
stmt.values.forEach((row, rowIdx) => {
|
|
25612
25866
|
const record = {};
|
|
@@ -26095,6 +26349,12 @@ async function executeUpsertSelect(stmt, client, options, cacheContext, cteCache
|
|
|
26095
26349
|
const rowKeyValues = records.map(
|
|
26096
26350
|
(record) => stmt.keyFields.map((key) => String(record[key]?.value ?? ""))
|
|
26097
26351
|
);
|
|
26352
|
+
const nativeEligibility = evaluateNativeUpsertEligibility(
|
|
26353
|
+
nativeEligibilityInput(stmt, client, options, fieldInfos, rowKeyValues)
|
|
26354
|
+
);
|
|
26355
|
+
if (nativeEligibility.execution.status === "ELIGIBLE") {
|
|
26356
|
+
return executeNativeUpsertRecords(stmt.appId, stmt.keyFields[0], records, rowKeyValues, client, options);
|
|
26357
|
+
}
|
|
26098
26358
|
if (importSourceByDmlStatement.has(stmt)) {
|
|
26099
26359
|
const numericKey = stmt.keyFields.map((key) => fieldTypes.get(key) === "NUMBER");
|
|
26100
26360
|
const sourceKeys = /* @__PURE__ */ new Set();
|
|
@@ -27146,7 +27406,7 @@ var EXPLAIN_FETCH_PLAN = /* @__PURE__ */ Symbol("ksql.explainFetchPlan");
|
|
|
27146
27406
|
function setExplainFetchPlan(result, plan) {
|
|
27147
27407
|
result[EXPLAIN_FETCH_PLAN] = plan;
|
|
27148
27408
|
}
|
|
27149
|
-
async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords = 1e4, cursorMaxActive = 2, enableImport = false, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, resolveMetadata = true, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions, asOf, timezone) {
|
|
27409
|
+
async function buildBatchExplainPlans(sql, client, injectedVariables, cacheContext = "batch-explain", maxRecords = 1e4, cursorMaxActive = 2, enableImport = false, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, resolveMetadata = true, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions, asOf, timezone, nativeUpsertOptions = { surface: "DOCUMENT_ONLY" }) {
|
|
27150
27410
|
const asOfClock = createAsOfClock(asOf ?? /* @__PURE__ */ new Date(), timezone);
|
|
27151
27411
|
const recursiveLimits = resolveRecursiveCteLimits({
|
|
27152
27412
|
recursiveCteMaxDepth,
|
|
@@ -27245,10 +27505,15 @@ async function buildBatchExplainPlans(sql, client, injectedVariables, cacheConte
|
|
|
27245
27505
|
maxRecords,
|
|
27246
27506
|
dmlMaxRows
|
|
27247
27507
|
) : [];
|
|
27508
|
+
const nativeUpsertPlan = await nativeUpsertExplainLines(
|
|
27509
|
+
planStmt,
|
|
27510
|
+
invocationCacheContext,
|
|
27511
|
+
nativeUpsertOptions
|
|
27512
|
+
);
|
|
27248
27513
|
plans.push({
|
|
27249
27514
|
index: i,
|
|
27250
27515
|
type: analysis.statements[i].statementType,
|
|
27251
|
-
plan: statementPlan.length === 0 ? [...metadataPlan, ...dialect1Estimate] : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1), ...dialect1Estimate]
|
|
27516
|
+
plan: statementPlan.length === 0 ? [...metadataPlan, ...nativeUpsertPlan, ...dialect1Estimate] : [statementPlan[0], ...metadataPlan, ...statementPlan.slice(1), ...nativeUpsertPlan, ...dialect1Estimate]
|
|
27252
27517
|
});
|
|
27253
27518
|
fetchStatements.push({
|
|
27254
27519
|
index: i,
|
|
@@ -27562,7 +27827,7 @@ var explainMaterializedTables = /* @__PURE__ */ new WeakMap();
|
|
|
27562
27827
|
function defaultRecursiveExplainContext() {
|
|
27563
27828
|
return { maxRecords: 1e4, recursiveLimits: resolveRecursiveCteLimits({}) };
|
|
27564
27829
|
}
|
|
27565
|
-
async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxActive, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, relativeDatePlan, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions) {
|
|
27830
|
+
async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxActive, dmlMaxRows = 100, dmlMaxSubtableRows = DEFAULT_APPLY_MAX_SUBTABLE_ROWS, relativeDatePlan, recursiveCteMaxDepth, recursiveCteMaxRows, recursiveCteMaxExpansions, nativeUpsertOptions = { surface: "DOCUMENT_ONLY" }) {
|
|
27566
27831
|
const recursiveLimits = resolveRecursiveCteLimits({
|
|
27567
27832
|
recursiveCteMaxDepth,
|
|
27568
27833
|
recursiveCteMaxRows,
|
|
@@ -27600,7 +27865,8 @@ async function executeExplain(stmt, client, cacheContext, maxRecords, cursorMaxA
|
|
|
27600
27865
|
cursorMaxActive
|
|
27601
27866
|
)
|
|
27602
27867
|
];
|
|
27603
|
-
const
|
|
27868
|
+
const nativeUpsertPlan = await nativeUpsertExplainLines(stmt, cacheContext, nativeUpsertOptions);
|
|
27869
|
+
const lines = addFetchSummary([...planLines, ...nativeUpsertPlan], fetchCollector.sources);
|
|
27604
27870
|
const result = {
|
|
27605
27871
|
type: "SELECT",
|
|
27606
27872
|
columns: ["plan"],
|
|
@@ -29523,7 +29789,7 @@ var RequestGate = class {
|
|
|
29523
29789
|
}
|
|
29524
29790
|
};
|
|
29525
29791
|
function withRequestGate(client, gate) {
|
|
29526
|
-
|
|
29792
|
+
const wrapped = {
|
|
29527
29793
|
getRecords: (params) => gate.runReadOnly(() => client.getRecords(params)),
|
|
29528
29794
|
openCursor: async (params) => {
|
|
29529
29795
|
const handle = await gate.runCursorStep(() => client.openCursor(params));
|
|
@@ -29541,6 +29807,10 @@ function withRequestGate(client, gate) {
|
|
|
29541
29807
|
putRecords: (params) => gate.runMutation(() => client.putRecords(params)),
|
|
29542
29808
|
deleteRecords: (params) => gate.runMutation(() => client.deleteRecords(params))
|
|
29543
29809
|
};
|
|
29810
|
+
if ("upsertRecords" in client && typeof client.upsertRecords === "function") {
|
|
29811
|
+
wrapped.upsertRecords = (params) => gate.runMutation(() => client.upsertRecords(params));
|
|
29812
|
+
}
|
|
29813
|
+
return wrapped;
|
|
29544
29814
|
}
|
|
29545
29815
|
var globalGate = null;
|
|
29546
29816
|
function getGlobalRequestGate(options) {
|
|
@@ -30297,6 +30567,16 @@ function createNodeKintoneConnection(baseUrl, tokenResolver) {
|
|
|
30297
30567
|
_params.app
|
|
30298
30568
|
);
|
|
30299
30569
|
},
|
|
30570
|
+
async upsertRecords(_params) {
|
|
30571
|
+
return requestJson(
|
|
30572
|
+
`${apiBasePath}/records.json`,
|
|
30573
|
+
{
|
|
30574
|
+
method: "PUT",
|
|
30575
|
+
body: JSON.stringify({ app: _params.app, upsert: true, records: _params.records })
|
|
30576
|
+
},
|
|
30577
|
+
_params.app
|
|
30578
|
+
);
|
|
30579
|
+
},
|
|
30300
30580
|
async deleteRecords(_params) {
|
|
30301
30581
|
await requestJson(
|
|
30302
30582
|
`${apiBasePath}/records.json`,
|
|
@@ -30696,6 +30976,9 @@ var CLI_HELP_TEXT = HELP_TEXT.replace(
|
|
|
30696
30976
|
" --max-records <n> Max records to fetch (default: 500)",
|
|
30697
30977
|
` --max-records <n> Max records to fetch (default: 500)
|
|
30698
30978
|
${RECURSIVE_CTE_HELP_LINES}`
|
|
30979
|
+
).replace(
|
|
30980
|
+
" --allow-dml Enable UPDATE/DELETE/INSERT/UPSERT/REORDER execution",
|
|
30981
|
+
" --allow-dml Enable UPDATE/DELETE/INSERT/UPSERT/REORDER execution\n --native-upsert Allow eligible plain UPSERT to use kintone native UPSERT"
|
|
30699
30982
|
);
|
|
30700
30983
|
var CLI_IMPORT_SOURCE_REQUIRED_MESSAGE = "IMPORT \u306B\u306F\u30BD\u30FC\u30B9\u304C\u5FC5\u8981\u3067\u3059\u3002--import-csv <name=path> \u307E\u305F\u306F --import-json <name=path> \u3067\u30D5\u30A1\u30A4\u30EB\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002";
|
|
30701
30984
|
function toCliImportError(error, importEnabled) {
|
|
@@ -30747,6 +31030,7 @@ function parseArgs(argv) {
|
|
|
30747
31030
|
debugHeaders: false,
|
|
30748
31031
|
exitOnEmpty: false,
|
|
30749
31032
|
allowDml: false,
|
|
31033
|
+
nativeUpsert: false,
|
|
30750
31034
|
yes: false,
|
|
30751
31035
|
allowWithoutWhere: false,
|
|
30752
31036
|
continueOnError: false,
|
|
@@ -30819,6 +31103,10 @@ function parseArgs(argv) {
|
|
|
30819
31103
|
out.allowDml = true;
|
|
30820
31104
|
continue;
|
|
30821
31105
|
}
|
|
31106
|
+
if (a === "--native-upsert") {
|
|
31107
|
+
out.nativeUpsert = true;
|
|
31108
|
+
continue;
|
|
31109
|
+
}
|
|
30822
31110
|
if (a === "--yes") {
|
|
30823
31111
|
out.yes = true;
|
|
30824
31112
|
continue;
|
|
@@ -31656,6 +31944,7 @@ function buildReplExecArgv(base, sql, dryRun, format) {
|
|
|
31656
31944
|
if (base.exitOnEmpty) argv.push("--exit-on-empty");
|
|
31657
31945
|
if (base.allowDml) argv.push("--yes");
|
|
31658
31946
|
if (base.allowDml) argv.push("--allow-dml");
|
|
31947
|
+
if (base.nativeUpsert) argv.push("--native-upsert");
|
|
31659
31948
|
if (base.allowWithoutWhere) argv.push("--allow-without-where");
|
|
31660
31949
|
if (base.continueOnError) argv.push("--continue-on-error");
|
|
31661
31950
|
return argv;
|
|
@@ -31832,7 +32121,8 @@ async function runConsole(base) {
|
|
|
31832
32121
|
` auth=${base.auth ?? "(auto)"}`,
|
|
31833
32122
|
` format=${format ?? "(default)"}`,
|
|
31834
32123
|
` dryrun=${dryRun ? "on" : "off"}`,
|
|
31835
|
-
` allow-dml=${base.allowDml ? "on" : "off"}
|
|
32124
|
+
` allow-dml=${base.allowDml ? "on" : "off"}`,
|
|
32125
|
+
` native-upsert=${base.nativeUpsert ? "on" : "off"}`
|
|
31836
32126
|
].join("\n") + "\n"
|
|
31837
32127
|
);
|
|
31838
32128
|
try {
|
|
@@ -31963,6 +32253,7 @@ async function runConsole(base) {
|
|
|
31963
32253
|
`app=${base.app ?? "(from SQL or config)"}`,
|
|
31964
32254
|
`resolved-app-profiles=${lastResolvedProfiles}`,
|
|
31965
32255
|
`allow-dml=${base.allowDml ? "on" : "off"}`,
|
|
32256
|
+
`native-upsert=${base.nativeUpsert ? "on" : "off"}`,
|
|
31966
32257
|
`dml-max-rows=${base.dmlMaxRows ?? "(default)"}`,
|
|
31967
32258
|
`dml-max-subtable-rows=${base.dmlMaxSubtableRows ?? "(default)"}`
|
|
31968
32259
|
];
|
|
@@ -32545,6 +32836,14 @@ async function run() {
|
|
|
32545
32836
|
if (!routed) throw new Error(`AuthError: profile "${pName}" is not resolved for APP${params.app}.`);
|
|
32546
32837
|
return routed.putRecords({ ...params, app: binding.appId });
|
|
32547
32838
|
},
|
|
32839
|
+
upsertRecords: (params) => {
|
|
32840
|
+
const binding = appBindingByMappedApp.get(params.app) ?? { appId: params.app, profile: profileName.toLowerCase() };
|
|
32841
|
+
const routed = profileClientMap.get(binding.profile);
|
|
32842
|
+
if (!routed || typeof routed.upsertRecords !== "function") {
|
|
32843
|
+
throw new Error(`AuthError: native UPSERT client is not resolved for APP${params.app}.`);
|
|
32844
|
+
}
|
|
32845
|
+
return routed.upsertRecords({ ...params, app: binding.appId });
|
|
32846
|
+
},
|
|
32548
32847
|
deleteRecords: (params) => {
|
|
32549
32848
|
const binding = appBindingByMappedApp.get(params.app) ?? { appId: params.app, profile: profileName.toLowerCase() };
|
|
32550
32849
|
const pName = binding.profile;
|
|
@@ -32598,7 +32897,14 @@ async function run() {
|
|
|
32598
32897
|
!dryRunUsesStaticTypedPlan,
|
|
32599
32898
|
recursiveCteMaxDepth,
|
|
32600
32899
|
recursiveCteMaxRows,
|
|
32601
|
-
recursiveCteMaxExpansions
|
|
32900
|
+
recursiveCteMaxExpansions,
|
|
32901
|
+
void 0,
|
|
32902
|
+
void 0,
|
|
32903
|
+
{
|
|
32904
|
+
surface: "CLI",
|
|
32905
|
+
enableNativeUpsert: args.nativeUpsert,
|
|
32906
|
+
clientHasNativeUpsert: true
|
|
32907
|
+
}
|
|
32602
32908
|
);
|
|
32603
32909
|
const out = [];
|
|
32604
32910
|
const restoredStatements = sqlDiagnosticContext ? restoreSqlDiagnosticValue(plans.statements, sqlDiagnosticContext.appBindingByMappedApp) : plans.statements;
|
|
@@ -32679,7 +32985,7 @@ query=${label}`);
|
|
|
32679
32985
|
return 2;
|
|
32680
32986
|
}
|
|
32681
32987
|
}
|
|
32682
|
-
let batchResult = await executeBatch(sql, client, {
|
|
32988
|
+
let batchResult = await executeBatch(sql, client, withNativeUpsertExecutionOption({
|
|
32683
32989
|
maxRecords,
|
|
32684
32990
|
fetchParallel,
|
|
32685
32991
|
onLimitReached: effectiveOnLimit,
|
|
@@ -32717,7 +33023,7 @@ query=${label}`);
|
|
|
32717
33023
|
}
|
|
32718
33024
|
return true;
|
|
32719
33025
|
} : void 0
|
|
32720
|
-
});
|
|
33026
|
+
}, args.nativeUpsert, true));
|
|
32721
33027
|
if (sqlDiagnosticContext) {
|
|
32722
33028
|
batchResult = {
|
|
32723
33029
|
...batchResult,
|
|
@@ -32734,7 +33040,7 @@ query=${label}`);
|
|
|
32734
33040
|
}
|
|
32735
33041
|
return writeBatchOutput(batchResult, { format, noHeader, pretty, displayOptions, outputPath, quiet });
|
|
32736
33042
|
}
|
|
32737
|
-
let result = args.dryRun ? await execute(`EXPLAIN ${sql}`, client, {
|
|
33043
|
+
let result = args.dryRun ? await execute(`EXPLAIN ${sql}`, client, withNativeUpsertExecutionOption({
|
|
32738
33044
|
maxRecords,
|
|
32739
33045
|
onLimitReached: onLimit,
|
|
32740
33046
|
cacheContext,
|
|
@@ -32746,7 +33052,7 @@ query=${label}`);
|
|
|
32746
33052
|
recursiveCteMaxDepth,
|
|
32747
33053
|
recursiveCteMaxRows,
|
|
32748
33054
|
recursiveCteMaxExpansions
|
|
32749
|
-
}) : await execute(sql, client, {
|
|
33055
|
+
}, args.nativeUpsert, true)) : await execute(sql, client, withNativeUpsertExecutionOption({
|
|
32750
33056
|
maxRecords,
|
|
32751
33057
|
fetchParallel,
|
|
32752
33058
|
onLimitReached: effectiveOnLimit,
|
|
@@ -32764,7 +33070,7 @@ query=${label}`);
|
|
|
32764
33070
|
dmlMaxSubtableRows
|
|
32765
33071
|
} : {},
|
|
32766
33072
|
...containsApplyMutation ? { allowApplyMutation: true } : {}
|
|
32767
|
-
});
|
|
33073
|
+
}, args.nativeUpsert, true));
|
|
32768
33074
|
if ((args.dryRun || parsedStatements[0]?.type === "EXPLAIN") && sqlDiagnosticContext) {
|
|
32769
33075
|
result = restoreSqlDiagnosticValue(result, sqlDiagnosticContext.appBindingByMappedApp);
|
|
32770
33076
|
}
|