@rex0220/kintone-sql-tools 3.8.0 → 3.9.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 +642 -58
- package/dist-mcp/ksql-mcp.js +2041 -278
- package/dist-mcpb/ksql-mcp.mcpb +0 -0
- package/package.json +1 -1
package/dist-cli/ksql.js
CHANGED
|
@@ -7904,26 +7904,55 @@ var VALIDATION_META_COLUMNS = [
|
|
|
7904
7904
|
"$err_row",
|
|
7905
7905
|
"$err_field",
|
|
7906
7906
|
"$err_code",
|
|
7907
|
-
"$err_message"
|
|
7907
|
+
"$err_message",
|
|
7908
|
+
"$err_value",
|
|
7909
|
+
"$err_subtable",
|
|
7910
|
+
"$err_subrow",
|
|
7911
|
+
"$err_subrow_id"
|
|
7908
7912
|
];
|
|
7909
|
-
function
|
|
7913
|
+
function materializeDmlUpdateModeSparseRecords(candidates, targetFields, fieldInfos) {
|
|
7914
|
+
const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
|
|
7915
|
+
for (const candidate of candidates) {
|
|
7916
|
+
if (candidate.mode !== "update") continue;
|
|
7917
|
+
candidate.record ??= {};
|
|
7918
|
+
for (const code of targetFields) {
|
|
7919
|
+
if (!candidate.payload.has(code)) continue;
|
|
7920
|
+
const original = candidate.payload.get(code);
|
|
7921
|
+
const type = infoByCode.get(code).fieldType;
|
|
7922
|
+
const preserveCodes = ["USER_SELECT", "ORGANIZATION_SELECT", "GROUP_SELECT"].includes(type) && Array.isArray(original) && original.every((item) => typeof item === "object" && item !== null && "code" in item);
|
|
7923
|
+
let normalized = original;
|
|
7924
|
+
try {
|
|
7925
|
+
normalized = normalizeRaw(original, type);
|
|
7926
|
+
} catch {
|
|
7927
|
+
}
|
|
7928
|
+
candidate.record[code] = { value: preserveCodes ? original : normalized };
|
|
7929
|
+
}
|
|
7930
|
+
}
|
|
7931
|
+
}
|
|
7932
|
+
function validateDmlCandidates(candidates, operation, payloadFields, targetFields, fieldInfos, statementNumber, numberPrecision, checkGroups = [], validateMissingCreateFields = true, includePreErrors = true, validationOptions = {}) {
|
|
7910
7933
|
const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
|
|
7911
7934
|
const errors = [];
|
|
7912
7935
|
const invalid = /* @__PURE__ */ new Set();
|
|
7936
|
+
const candidateResults = [];
|
|
7937
|
+
if (validationOptions.validateUpdateBuiltIns === false) {
|
|
7938
|
+
materializeDmlUpdateModeSparseRecords(candidates, targetFields, fieldInfos);
|
|
7939
|
+
}
|
|
7913
7940
|
let firstEvaluationError;
|
|
7914
7941
|
for (const candidate of candidates) {
|
|
7915
7942
|
candidate.record ??= {};
|
|
7916
|
-
const
|
|
7943
|
+
const preErrors = includePreErrors ? [...candidate.preErrors] : [];
|
|
7944
|
+
const builtInErrors = [];
|
|
7945
|
+
const checkErrors = [];
|
|
7946
|
+
const validateBuiltIns = candidate.mode === "create" || validationOptions.validateUpdateBuiltIns !== false;
|
|
7917
7947
|
for (const code of targetFields) {
|
|
7918
7948
|
if (!candidate.payload.has(code)) continue;
|
|
7919
|
-
const
|
|
7920
|
-
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
|
|
7925
|
-
|
|
7926
|
-
}
|
|
7949
|
+
const original = candidate.payload.get(code);
|
|
7950
|
+
const type = infoByCode.get(code).fieldType;
|
|
7951
|
+
const preserveCodes = ["USER_SELECT", "ORGANIZATION_SELECT", "GROUP_SELECT"].includes(type) && Array.isArray(original) && original.every((item) => typeof item === "object" && item !== null && "code" in item);
|
|
7952
|
+
if (!validateBuiltIns) continue;
|
|
7953
|
+
const result = validateAndNormalizeDmlValue(original, infoByCode.get(code), numberPrecision);
|
|
7954
|
+
if (!result.ok) builtInErrors.push({ field: code, code: result.code, message: result.message });
|
|
7955
|
+
else candidate.record[code] = { value: preserveCodes ? original : result.value };
|
|
7927
7956
|
}
|
|
7928
7957
|
if (validateMissingCreateFields && candidate.mode === "create") {
|
|
7929
7958
|
for (const info of fieldInfos) {
|
|
@@ -7932,7 +7961,7 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
|
|
|
7932
7961
|
const emptyDefault = isEmptyDmlValue(info.defaultValue);
|
|
7933
7962
|
if (!emptyDefault) {
|
|
7934
7963
|
const defaultResult = validateAndNormalizeDmlValue(info.defaultValue, info, numberPrecision);
|
|
7935
|
-
if (!defaultResult.ok)
|
|
7964
|
+
if (!defaultResult.ok) builtInErrors.push({
|
|
7936
7965
|
field: info.code,
|
|
7937
7966
|
code: defaultResult.code,
|
|
7938
7967
|
message: `\u65E2\u5B9A\u5024: ${defaultResult.message}`
|
|
@@ -7940,9 +7969,9 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
|
|
|
7940
7969
|
} else {
|
|
7941
7970
|
const emptyResult = validateAndNormalizeDmlValue("", info, numberPrecision);
|
|
7942
7971
|
if (!emptyResult.ok) {
|
|
7943
|
-
|
|
7972
|
+
builtInErrors.push({ field: info.code, code: emptyResult.code, message: emptyResult.message });
|
|
7944
7973
|
} else if (info.required) {
|
|
7945
|
-
|
|
7974
|
+
builtInErrors.push({ field: info.code, code: "ERR_REQUIRED", message: `${info.code} \u306F\u5FC5\u9808\u3067\u3059` });
|
|
7946
7975
|
}
|
|
7947
7976
|
}
|
|
7948
7977
|
}
|
|
@@ -7958,14 +7987,13 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
|
|
|
7958
7987
|
};
|
|
7959
7988
|
try {
|
|
7960
7989
|
for (const custom of evaluateCustomChecks(checkGroups, row, resolveType)) {
|
|
7961
|
-
|
|
7990
|
+
checkErrors.push({ field: "", code: "ERR_CHECK", message: custom.message });
|
|
7962
7991
|
}
|
|
7963
7992
|
} catch (error) {
|
|
7964
7993
|
firstEvaluationError ??= error;
|
|
7965
7994
|
}
|
|
7966
7995
|
}
|
|
7967
|
-
|
|
7968
|
-
for (const error of rowErrors) {
|
|
7996
|
+
const materializeErrors = (source) => source.map((error) => {
|
|
7969
7997
|
const row = {};
|
|
7970
7998
|
for (const field of payloadFields) row[field] = renderValidationValue(candidate.payload.get(field));
|
|
7971
7999
|
row["$err_statement"] = String(statementNumber);
|
|
@@ -7974,11 +8002,25 @@ function validateDmlCandidates(candidates, operation, payloadFields, targetField
|
|
|
7974
8002
|
row["$err_field"] = error.field;
|
|
7975
8003
|
row["$err_code"] = error.code;
|
|
7976
8004
|
row["$err_message"] = error.message;
|
|
7977
|
-
|
|
7978
|
-
|
|
8005
|
+
row["$err_value"] = "";
|
|
8006
|
+
row["$err_subtable"] = "";
|
|
8007
|
+
row["$err_subrow"] = "";
|
|
8008
|
+
row["$err_subrow_id"] = "";
|
|
8009
|
+
return row;
|
|
8010
|
+
});
|
|
8011
|
+
const materialized = {
|
|
8012
|
+
rowNumber: candidate.rowNumber,
|
|
8013
|
+
preErrors: materializeErrors(preErrors),
|
|
8014
|
+
builtInErrors: materializeErrors(builtInErrors),
|
|
8015
|
+
checkErrors: materializeErrors(checkErrors)
|
|
8016
|
+
};
|
|
8017
|
+
candidateResults.push(materialized);
|
|
8018
|
+
const rowErrors = [...materialized.preErrors, ...materialized.builtInErrors, ...materialized.checkErrors];
|
|
8019
|
+
if (rowErrors.length > 0) invalid.add(candidate.rowNumber);
|
|
8020
|
+
errors.push(...rowErrors);
|
|
7979
8021
|
}
|
|
7980
8022
|
if (firstEvaluationError !== void 0) throw firstEvaluationError;
|
|
7981
|
-
return { errors, invalidRows: invalid.size, invalidRowNumbers: invalid };
|
|
8023
|
+
return { errors, invalidRows: invalid.size, invalidRowNumbers: invalid, candidateResults };
|
|
7982
8024
|
}
|
|
7983
8025
|
function renderValidationValue(value) {
|
|
7984
8026
|
if (value == null) return "";
|
|
@@ -8085,13 +8127,7 @@ var NON_AUDIT_SYSTEM_TYPES = /* @__PURE__ */ new Set([
|
|
|
8085
8127
|
"CATEGORY",
|
|
8086
8128
|
"REFERENCE_TABLE"
|
|
8087
8129
|
]);
|
|
8088
|
-
var POST_IMAGE_VALIDATION_SUFFIX_COLUMNS =
|
|
8089
|
-
...VALIDATION_META_COLUMNS,
|
|
8090
|
-
"$err_value",
|
|
8091
|
-
"$err_subtable",
|
|
8092
|
-
"$err_subrow",
|
|
8093
|
-
"$err_subrow_id"
|
|
8094
|
-
];
|
|
8130
|
+
var POST_IMAGE_VALIDATION_SUFFIX_COLUMNS = VALIDATION_META_COLUMNS;
|
|
8095
8131
|
function buildPostImageFieldIndex(fieldInfos, payloadFields = ["$id"]) {
|
|
8096
8132
|
const metadata = buildValidationFieldMetadataIndex(fieldInfos);
|
|
8097
8133
|
const topLevel = metadata.topLevel.filter((field) => field.fieldType !== "SUBTABLE" && field.fieldType !== "FILE" && !NON_AUDIT_SYSTEM_TYPES.has(field.fieldType));
|
|
@@ -10299,6 +10335,71 @@ function toFlatString(value) {
|
|
|
10299
10335
|
}
|
|
10300
10336
|
}
|
|
10301
10337
|
|
|
10338
|
+
// src/core/dmlPrevalidation.ts
|
|
10339
|
+
function collectDmlPrevalidationSnapshotFields(fieldIndex) {
|
|
10340
|
+
return [
|
|
10341
|
+
"$id",
|
|
10342
|
+
.../* @__PURE__ */ new Set([
|
|
10343
|
+
...fieldIndex.topLevel.map((field) => field.code).filter((code) => code !== "$id" && code !== "$revision"),
|
|
10344
|
+
...fieldIndex.subtables.keys()
|
|
10345
|
+
])
|
|
10346
|
+
];
|
|
10347
|
+
}
|
|
10348
|
+
function buildDmlValidationPostImage(snapshot, sparseRecord) {
|
|
10349
|
+
const postImage = deepClone(snapshot);
|
|
10350
|
+
for (const [field, cell] of Object.entries(sparseRecord)) {
|
|
10351
|
+
postImage[field] = deepClone(cell);
|
|
10352
|
+
}
|
|
10353
|
+
return postImage;
|
|
10354
|
+
}
|
|
10355
|
+
function mergeDmlCandidateValidation(input) {
|
|
10356
|
+
const errors = [
|
|
10357
|
+
...input.preErrors.map((row) => normalizePlainError(row)),
|
|
10358
|
+
...input.postImageErrors.map((row) => normalizePlainError(row, row["$err_subtable"] !== "")),
|
|
10359
|
+
...input.checkErrors.map((row) => normalizePlainError(row))
|
|
10360
|
+
];
|
|
10361
|
+
const invalidRowNumbers = /* @__PURE__ */ new Set();
|
|
10362
|
+
if (errors.length > 0) invalidRowNumbers.add(input.rowNumber);
|
|
10363
|
+
const writeRecord = {};
|
|
10364
|
+
for (const field of new Set(input.setFields)) {
|
|
10365
|
+
if (!Object.prototype.hasOwnProperty.call(input.normalizedPostImage, field)) {
|
|
10366
|
+
throw new Error(`InternalError: normalized post-image is missing SET field: ${field}`);
|
|
10367
|
+
}
|
|
10368
|
+
writeRecord[field] = deepClone(input.normalizedPostImage[field]);
|
|
10369
|
+
}
|
|
10370
|
+
return {
|
|
10371
|
+
errors,
|
|
10372
|
+
invalidRows: invalidRowNumbers.size,
|
|
10373
|
+
invalidRowNumbers,
|
|
10374
|
+
writeRecord
|
|
10375
|
+
};
|
|
10376
|
+
}
|
|
10377
|
+
function normalizePlainError(row, childCell = false) {
|
|
10378
|
+
return {
|
|
10379
|
+
...row,
|
|
10380
|
+
$err_value: childCell ? row["$err_value"] ?? "" : "",
|
|
10381
|
+
$err_subtable: childCell ? row["$err_subtable"] ?? "" : "",
|
|
10382
|
+
$err_subrow: childCell ? row["$err_subrow"] ?? "" : "",
|
|
10383
|
+
$err_subrow_id: childCell ? row["$err_subrow_id"] ?? "" : ""
|
|
10384
|
+
};
|
|
10385
|
+
}
|
|
10386
|
+
function deepClone(value, seen = /* @__PURE__ */ new Map()) {
|
|
10387
|
+
if (value === null || typeof value !== "object") return value;
|
|
10388
|
+
const object = value;
|
|
10389
|
+
const existing = seen.get(object);
|
|
10390
|
+
if (existing !== void 0) return existing;
|
|
10391
|
+
if (Array.isArray(value)) {
|
|
10392
|
+
const clone2 = [];
|
|
10393
|
+
seen.set(object, clone2);
|
|
10394
|
+
for (const item of value) clone2.push(deepClone(item, seen));
|
|
10395
|
+
return clone2;
|
|
10396
|
+
}
|
|
10397
|
+
const clone = {};
|
|
10398
|
+
seen.set(object, clone);
|
|
10399
|
+
for (const [key, child] of Object.entries(value)) clone[key] = deepClone(child, seen);
|
|
10400
|
+
return clone;
|
|
10401
|
+
}
|
|
10402
|
+
|
|
10302
10403
|
// src/core/optimization/whereCapability.ts
|
|
10303
10404
|
var RANGE_AND_EQUALITY = ["=", "!=", ">", "<", ">=", "<="];
|
|
10304
10405
|
var EQUALITY_IN = ["=", "!=", "in", "not in"];
|
|
@@ -14501,15 +14602,72 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
|
|
|
14501
14602
|
await assertDmlWhereCapability(stmt, client, cacheContext);
|
|
14502
14603
|
}
|
|
14503
14604
|
const infoByCode = new Map(fieldInfos.map((field) => [field.code, field]));
|
|
14504
|
-
|
|
14605
|
+
let numberPrecision = await loadNumberPrecisionForTargets(
|
|
14505
14606
|
stmt.appId,
|
|
14506
14607
|
targetFields,
|
|
14507
14608
|
fieldInfos,
|
|
14508
14609
|
client,
|
|
14509
14610
|
cacheContext
|
|
14510
14611
|
);
|
|
14511
|
-
const
|
|
14512
|
-
const
|
|
14612
|
+
const fieldIndex = buildPostImageFieldIndex(fieldInfos, payloadFields);
|
|
14613
|
+
const snapshotFields = collectDmlPrevalidationSnapshotFields(fieldIndex);
|
|
14614
|
+
const candidates = (await materializeValidationCandidates(
|
|
14615
|
+
stmt,
|
|
14616
|
+
operation,
|
|
14617
|
+
client,
|
|
14618
|
+
options,
|
|
14619
|
+
cacheContext,
|
|
14620
|
+
tempTables,
|
|
14621
|
+
infoByCode,
|
|
14622
|
+
stmt.type === "UPDATE" ? snapshotFields : void 0
|
|
14623
|
+
)).sort((left, right) => left.rowNumber - right.rowNumber);
|
|
14624
|
+
const updateCandidates = candidates.filter((candidate) => candidate.mode === "update");
|
|
14625
|
+
const productionUpdateLoader = stmt.type === "UPDATE" ? loadMaterializedUpdateSnapshots : stmt.type.startsWith("UPSERT") ? (input) => loadUpsertValidationSnapshots(
|
|
14626
|
+
input,
|
|
14627
|
+
client,
|
|
14628
|
+
options.maxRecords ?? 1e4
|
|
14629
|
+
) : void 0;
|
|
14630
|
+
const updateSnapshotLoader = options.loadUpdateModeSnapshots ?? productionUpdateLoader;
|
|
14631
|
+
const usePreparedPostImages = updateCandidates.length > 0 && updateSnapshotLoader !== void 0;
|
|
14632
|
+
const preparedPostImages = /* @__PURE__ */ new Map();
|
|
14633
|
+
if (usePreparedPostImages) {
|
|
14634
|
+
materializeDmlUpdateModeSparseRecords(updateCandidates, targetFields, fieldInfos);
|
|
14635
|
+
const snapshots = await updateSnapshotLoader({
|
|
14636
|
+
appId: stmt.appId,
|
|
14637
|
+
candidates: updateCandidates,
|
|
14638
|
+
fields: snapshotFields
|
|
14639
|
+
});
|
|
14640
|
+
const postImages = /* @__PURE__ */ new Map();
|
|
14641
|
+
for (const candidate of updateCandidates) {
|
|
14642
|
+
if (candidate.targetId === void 0) {
|
|
14643
|
+
throw new Error(`InternalError: update-mode validation candidate has no targetId (row=${candidate.rowNumber}).`);
|
|
14644
|
+
}
|
|
14645
|
+
const snapshot = snapshots.get(candidate.targetId);
|
|
14646
|
+
if (!snapshot) {
|
|
14647
|
+
throw new Error(`InternalError: update-mode snapshot is missing for record ${candidate.targetId}.`);
|
|
14648
|
+
}
|
|
14649
|
+
const postImage = buildDmlValidationPostImage(snapshot, candidate.record ?? {});
|
|
14650
|
+
postImages.set(candidate.rowNumber, postImage);
|
|
14651
|
+
}
|
|
14652
|
+
if (numberPrecision === void 0 && [...postImages.values()].some(
|
|
14653
|
+
(record) => postImageNeedsNumberPrecision(record, fieldIndex)
|
|
14654
|
+
)) {
|
|
14655
|
+
numberPrecision = await getNumberPrecisionCached(stmt.appId, client, cacheContext);
|
|
14656
|
+
}
|
|
14657
|
+
for (const candidate of updateCandidates) {
|
|
14658
|
+
const postImage = postImages.get(candidate.rowNumber);
|
|
14659
|
+
if (!postImage) throw new Error(`InternalError: validation post-image is missing for row ${candidate.rowNumber}.`);
|
|
14660
|
+
preparedPostImages.set(candidate.rowNumber, validatePostImage(
|
|
14661
|
+
postImage,
|
|
14662
|
+
fieldIndex,
|
|
14663
|
+
numberPrecision,
|
|
14664
|
+
statementNumber,
|
|
14665
|
+
candidate.rowNumber,
|
|
14666
|
+
operation
|
|
14667
|
+
));
|
|
14668
|
+
}
|
|
14669
|
+
}
|
|
14670
|
+
const candidateValidation = validateDmlCandidates(
|
|
14513
14671
|
candidates,
|
|
14514
14672
|
operation,
|
|
14515
14673
|
payloadFields,
|
|
@@ -14519,8 +14677,41 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
|
|
|
14519
14677
|
numberPrecision,
|
|
14520
14678
|
stmt.checkGroups ?? [],
|
|
14521
14679
|
validateMissingCreateFields,
|
|
14522
|
-
includePreErrors
|
|
14680
|
+
includePreErrors,
|
|
14681
|
+
{ validateUpdateBuiltIns: !usePreparedPostImages }
|
|
14523
14682
|
);
|
|
14683
|
+
let { errors, invalidRows, invalidRowNumbers } = candidateValidation;
|
|
14684
|
+
if (usePreparedPostImages) {
|
|
14685
|
+
const detailsByRow = new Map(candidateValidation.candidateResults.map((detail) => [detail.rowNumber, detail]));
|
|
14686
|
+
errors = [];
|
|
14687
|
+
invalidRowNumbers = /* @__PURE__ */ new Set();
|
|
14688
|
+
for (const candidate of candidates) {
|
|
14689
|
+
const detail = detailsByRow.get(candidate.rowNumber);
|
|
14690
|
+
if (!detail) throw new Error(`InternalError: validation detail is missing for row ${candidate.rowNumber}.`);
|
|
14691
|
+
if (candidate.mode === "create") {
|
|
14692
|
+
const candidateErrors = [...detail.preErrors, ...detail.builtInErrors, ...detail.checkErrors];
|
|
14693
|
+
errors.push(...candidateErrors);
|
|
14694
|
+
if (candidateErrors.length > 0) invalidRowNumbers.add(candidate.rowNumber);
|
|
14695
|
+
continue;
|
|
14696
|
+
}
|
|
14697
|
+
const postImageValidation = preparedPostImages.get(candidate.rowNumber);
|
|
14698
|
+
if (!postImageValidation) {
|
|
14699
|
+
throw new Error(`InternalError: prepared post-image validation is missing for row ${candidate.rowNumber}.`);
|
|
14700
|
+
}
|
|
14701
|
+
const merged = mergeDmlCandidateValidation({
|
|
14702
|
+
rowNumber: candidate.rowNumber,
|
|
14703
|
+
setFields: targetFields,
|
|
14704
|
+
normalizedPostImage: postImageValidation.normalizedRecord,
|
|
14705
|
+
preErrors: detail.preErrors,
|
|
14706
|
+
postImageErrors: postImageValidation.errors,
|
|
14707
|
+
checkErrors: detail.checkErrors
|
|
14708
|
+
});
|
|
14709
|
+
candidate.record = merged.writeRecord;
|
|
14710
|
+
errors.push(...merged.errors);
|
|
14711
|
+
for (const rowNumber of merged.invalidRowNumbers) invalidRowNumbers.add(rowNumber);
|
|
14712
|
+
}
|
|
14713
|
+
invalidRows = invalidRowNumbers.size;
|
|
14714
|
+
}
|
|
14524
14715
|
const columns = [...payloadFields, ...VALIDATION_META_COLUMNS];
|
|
14525
14716
|
const result = {
|
|
14526
14717
|
type: "VALIDATION",
|
|
@@ -14546,12 +14737,10 @@ async function prepareDmlValidation(stmt, client, options, cacheContext, tempTab
|
|
|
14546
14737
|
const info = infoByCode.get(column);
|
|
14547
14738
|
if (info) columnMeta.set(column, materializedMetaFromFieldInfo(info, stmt.appId));
|
|
14548
14739
|
}
|
|
14549
|
-
|
|
14550
|
-
|
|
14551
|
-
|
|
14552
|
-
|
|
14553
|
-
columnMeta.set("$err_code", syntheticColumnMeta("string"));
|
|
14554
|
-
columnMeta.set("$err_message", syntheticColumnMeta("string"));
|
|
14740
|
+
const numericValidationMeta = /* @__PURE__ */ new Set(["$err_statement", "$err_row"]);
|
|
14741
|
+
for (const column of VALIDATION_META_COLUMNS) {
|
|
14742
|
+
columnMeta.set(column, syntheticColumnMeta(numericValidationMeta.has(column) ? "number" : "string"));
|
|
14743
|
+
}
|
|
14555
14744
|
materializedMetaByValidationResult.set(result, columnMeta);
|
|
14556
14745
|
return { result, candidates, invalidRowNumbers, columnMeta };
|
|
14557
14746
|
}
|
|
@@ -14626,8 +14815,17 @@ async function executeOnErrorSkip(stmt, client, options, cacheContext, tempTable
|
|
|
14626
14815
|
}
|
|
14627
14816
|
return { type: "UPSERT", insertedCount, updatedCount: updates.length, ...common };
|
|
14628
14817
|
}
|
|
14629
|
-
async function materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode) {
|
|
14630
|
-
if (stmt.type === "UPDATE")
|
|
14818
|
+
async function materializeValidationCandidates(stmt, operation, client, options, cacheContext, tempTables, infoByCode, updateSnapshotFields) {
|
|
14819
|
+
if (stmt.type === "UPDATE") {
|
|
14820
|
+
return materializeUpdateValidationCandidates(
|
|
14821
|
+
stmt,
|
|
14822
|
+
client,
|
|
14823
|
+
options,
|
|
14824
|
+
cacheContext,
|
|
14825
|
+
tempTables,
|
|
14826
|
+
updateSnapshotFields
|
|
14827
|
+
);
|
|
14828
|
+
}
|
|
14631
14829
|
let rows;
|
|
14632
14830
|
let sourceRows;
|
|
14633
14831
|
let sourcePresence;
|
|
@@ -14740,40 +14938,70 @@ function assertCheckComparisonTypes(stmt, types) {
|
|
|
14740
14938
|
}
|
|
14741
14939
|
}
|
|
14742
14940
|
}
|
|
14743
|
-
async function materializeUpdateValidationCandidates(stmt, client, options, cacheContext, tempTables) {
|
|
14744
|
-
if (stmt.from)
|
|
14941
|
+
async function materializeUpdateValidationCandidates(stmt, client, options, cacheContext, tempTables, snapshotFields) {
|
|
14942
|
+
if (stmt.from) {
|
|
14943
|
+
return materializeUpdateFromValidationCandidates(
|
|
14944
|
+
stmt,
|
|
14945
|
+
stmt.from,
|
|
14946
|
+
client,
|
|
14947
|
+
options,
|
|
14948
|
+
cacheContext,
|
|
14949
|
+
tempTables,
|
|
14950
|
+
snapshotFields
|
|
14951
|
+
);
|
|
14952
|
+
}
|
|
14745
14953
|
await resolveSetSubqueries(stmt.assignments, client, options, cacheContext);
|
|
14746
14954
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
14747
14955
|
const checkTargetFields = assertUpdateCheckRefs(stmt, fieldTypes);
|
|
14748
14956
|
assertCheckComparisonTypes(stmt, updateEvaluationTypes(fieldTypes, stmt.appId));
|
|
14749
14957
|
let records;
|
|
14750
14958
|
let evaluationById = /* @__PURE__ */ new Map();
|
|
14959
|
+
let snapshotsById = /* @__PURE__ */ new Map();
|
|
14751
14960
|
if (hasRowDependentAssignment(stmt)) {
|
|
14752
14961
|
const getParams = updateToGetQueryForArith(stmt);
|
|
14753
|
-
const fields = [.../* @__PURE__ */ new Set([...getParams.fields, ...checkTargetFields])];
|
|
14962
|
+
const fields = [.../* @__PURE__ */ new Set([...getParams.fields, ...checkTargetFields, ...snapshotFields ?? []])];
|
|
14754
14963
|
const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, fields, {
|
|
14755
14964
|
maxRecords: options.maxRecords ?? 1e4,
|
|
14756
14965
|
parallel: options.fetchParallel ?? 1,
|
|
14757
14966
|
onLimit: "error"
|
|
14758
14967
|
});
|
|
14759
|
-
|
|
14968
|
+
snapshotsById = indexDmlUpdateSnapshots(resolved.records);
|
|
14969
|
+
evaluationById = snapshotsById;
|
|
14760
14970
|
records = updateToPutBatchesArith(stmt, resolved.records, fieldTypes).flatMap((batch) => batch.records);
|
|
14761
14971
|
} else {
|
|
14762
14972
|
const getParams = updateToGetQuery(stmt);
|
|
14763
14973
|
if (checkTargetFields.length > 0) {
|
|
14764
|
-
const
|
|
14974
|
+
const fields = [.../* @__PURE__ */ new Set(["$id", ...checkTargetFields, ...snapshotFields ?? []])];
|
|
14975
|
+
const resolved = await fetchRecordsForSharedPlan(client.getRecords, getParams.app, getParams.query, fields, {
|
|
14765
14976
|
maxRecords: options.maxRecords ?? 1e4,
|
|
14766
14977
|
parallel: options.fetchParallel ?? 1,
|
|
14767
14978
|
onLimit: "error"
|
|
14768
14979
|
});
|
|
14769
|
-
|
|
14980
|
+
snapshotsById = indexDmlUpdateSnapshots(resolved.records);
|
|
14981
|
+
evaluationById = snapshotsById;
|
|
14770
14982
|
records = updateToPutBatches(stmt, [...evaluationById.keys()], fieldTypes).flatMap((batch) => batch.records);
|
|
14771
14983
|
} else {
|
|
14772
|
-
|
|
14773
|
-
|
|
14774
|
-
|
|
14775
|
-
|
|
14776
|
-
|
|
14984
|
+
if (snapshotFields) {
|
|
14985
|
+
const resolved = await fetchRecordsForSharedPlan(
|
|
14986
|
+
client.getRecords,
|
|
14987
|
+
getParams.app,
|
|
14988
|
+
getParams.query,
|
|
14989
|
+
[...snapshotFields],
|
|
14990
|
+
{
|
|
14991
|
+
maxRecords: options.maxRecords ?? 1e4,
|
|
14992
|
+
parallel: options.fetchParallel ?? 1,
|
|
14993
|
+
onLimit: "error"
|
|
14994
|
+
}
|
|
14995
|
+
);
|
|
14996
|
+
snapshotsById = indexDmlUpdateSnapshots(resolved.records);
|
|
14997
|
+
records = updateToPutBatches(stmt, [...snapshotsById.keys()], fieldTypes).flatMap((batch) => batch.records);
|
|
14998
|
+
} else {
|
|
14999
|
+
const resolved = await resolveDmlTargetIds(client.getRecords, getParams.app, getParams.query, {
|
|
15000
|
+
maxRecords: options.maxRecords ?? 1e4,
|
|
15001
|
+
parallel: options.fetchParallel ?? 1
|
|
15002
|
+
});
|
|
15003
|
+
records = updateToPutBatches(stmt, resolved.ids, fieldTypes).flatMap((batch) => batch.records);
|
|
15004
|
+
}
|
|
14777
15005
|
}
|
|
14778
15006
|
}
|
|
14779
15007
|
return records.sort((a, b) => a.id - b.id).map((entry, index) => ({
|
|
@@ -14784,10 +15012,86 @@ async function materializeUpdateValidationCandidates(stmt, client, options, cach
|
|
|
14784
15012
|
preErrors: [],
|
|
14785
15013
|
record: entry.record,
|
|
14786
15014
|
targetId: entry.id,
|
|
15015
|
+
validationSnapshot: snapshotsById.get(entry.id),
|
|
14787
15016
|
evaluationRow: updateEvaluationRow(evaluationById.get(entry.id), stmt.appId),
|
|
14788
15017
|
evaluationFieldTypes: updateEvaluationTypes(fieldTypes, stmt.appId)
|
|
14789
15018
|
}));
|
|
14790
15019
|
}
|
|
15020
|
+
function indexDmlUpdateSnapshots(records) {
|
|
15021
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
15022
|
+
for (const record of records) {
|
|
15023
|
+
const rawId = record["$id"]?.value;
|
|
15024
|
+
const id = Number(rawId);
|
|
15025
|
+
if (!Number.isSafeInteger(id) || id <= 0) {
|
|
15026
|
+
throw new Error(`InternalError: invalid $id in UPDATE validation snapshot: ${String(rawId)}.`);
|
|
15027
|
+
}
|
|
15028
|
+
if (snapshots.has(id)) {
|
|
15029
|
+
throw new Error(`InternalError: duplicate $id in UPDATE validation snapshot: ${id}.`);
|
|
15030
|
+
}
|
|
15031
|
+
snapshots.set(id, record);
|
|
15032
|
+
}
|
|
15033
|
+
return snapshots;
|
|
15034
|
+
}
|
|
15035
|
+
async function loadMaterializedUpdateSnapshots(input) {
|
|
15036
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
15037
|
+
for (const candidate of input.candidates) {
|
|
15038
|
+
if (candidate.targetId === void 0 || !candidate.validationSnapshot) {
|
|
15039
|
+
throw new Error(
|
|
15040
|
+
`InternalError: update-mode snapshot is missing for record ${String(candidate.targetId)}.`
|
|
15041
|
+
);
|
|
15042
|
+
}
|
|
15043
|
+
if (snapshots.has(candidate.targetId)) {
|
|
15044
|
+
throw new Error(`InternalError: duplicate UPDATE validation candidate target: ${candidate.targetId}.`);
|
|
15045
|
+
}
|
|
15046
|
+
snapshots.set(candidate.targetId, candidate.validationSnapshot);
|
|
15047
|
+
}
|
|
15048
|
+
return snapshots;
|
|
15049
|
+
}
|
|
15050
|
+
async function loadUpsertValidationSnapshots(input, client, maxRecords) {
|
|
15051
|
+
const updateIds = [...new Set(input.candidates.map((candidate) => {
|
|
15052
|
+
const id = candidate.targetId;
|
|
15053
|
+
if (!Number.isSafeInteger(id) || id === void 0 || id <= 0) {
|
|
15054
|
+
throw new Error(
|
|
15055
|
+
`InternalError: invalid targetId in UPSERT validation candidate: ${String(id)}.`
|
|
15056
|
+
);
|
|
15057
|
+
}
|
|
15058
|
+
return id;
|
|
15059
|
+
}))];
|
|
15060
|
+
if (updateIds.length > maxRecords) {
|
|
15061
|
+
throw new FetchAllLimitError(
|
|
15062
|
+
`\u53D6\u5F97\u4EF6\u6570\u304C\u4E0A\u9650\uFF08${maxRecords} \u4EF6\uFF09\u3092\u8D85\u3048\u307E\u3057\u305F\u3002WHERE \u53E5\u3067\u7D5E\u308A\u8FBC\u3080\u304B\u3001maxRecords \u3092\u5F15\u304D\u4E0A\u3052\u3066\u304F\u3060\u3055\u3044\u3002`
|
|
15063
|
+
);
|
|
15064
|
+
}
|
|
15065
|
+
const requestedIds = new Set(updateIds);
|
|
15066
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
15067
|
+
for (const ids of splitChunks(updateIds, 100)) {
|
|
15068
|
+
const response = await client.getRecords({
|
|
15069
|
+
app: input.appId,
|
|
15070
|
+
query: `$id in (${ids.join(",")}) limit 500`,
|
|
15071
|
+
fields: [...new Set(input.fields)]
|
|
15072
|
+
});
|
|
15073
|
+
for (const snapshot of response.records) {
|
|
15074
|
+
const rawId = snapshot["$id"]?.value;
|
|
15075
|
+
const id = Number(rawId);
|
|
15076
|
+
if (!Number.isSafeInteger(id) || id <= 0) {
|
|
15077
|
+
throw new Error(`InternalError: invalid $id in UPSERT validation snapshot: ${String(rawId)}.`);
|
|
15078
|
+
}
|
|
15079
|
+
if (!requestedIds.has(id)) {
|
|
15080
|
+
throw new Error(`InternalError: unexpected $id in UPSERT validation snapshot: ${id}.`);
|
|
15081
|
+
}
|
|
15082
|
+
if (snapshots.has(id)) {
|
|
15083
|
+
throw new Error(`InternalError: duplicate $id in UPSERT validation snapshot: ${id}.`);
|
|
15084
|
+
}
|
|
15085
|
+
snapshots.set(id, snapshot);
|
|
15086
|
+
}
|
|
15087
|
+
}
|
|
15088
|
+
for (const id of updateIds) {
|
|
15089
|
+
if (!snapshots.has(id)) {
|
|
15090
|
+
throw new Error(`InternalError: update-mode snapshot is missing for record ${id}.`);
|
|
15091
|
+
}
|
|
15092
|
+
}
|
|
15093
|
+
return snapshots;
|
|
15094
|
+
}
|
|
14791
15095
|
function assertUpdateCheckRefs(stmt, targetTypes) {
|
|
14792
15096
|
if (stmt.from) return [];
|
|
14793
15097
|
const fields = /* @__PURE__ */ new Set();
|
|
@@ -14818,13 +15122,22 @@ function updateEvaluationTypes(types, appId) {
|
|
|
14818
15122
|
[`APP${appId}.$id`, "RECORD_NUMBER"]
|
|
14819
15123
|
]);
|
|
14820
15124
|
}
|
|
14821
|
-
async function materializeUpdateFromValidationCandidates(stmt, from, client, options, cacheContext, tempTables) {
|
|
15125
|
+
async function materializeUpdateFromValidationCandidates(stmt, from, client, options, cacheContext, tempTables, snapshotFields) {
|
|
14822
15126
|
const scope = await resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables);
|
|
14823
15127
|
assertCheckComparisonTypes(stmt, scope.evaluationTypes);
|
|
14824
|
-
const matched = await resolveUpdateFromMatchedRecords(
|
|
15128
|
+
const matched = await resolveUpdateFromMatchedRecords(
|
|
15129
|
+
stmt,
|
|
15130
|
+
from,
|
|
15131
|
+
client,
|
|
15132
|
+
options,
|
|
15133
|
+
cacheContext,
|
|
15134
|
+
tempTables,
|
|
15135
|
+
snapshotFields
|
|
15136
|
+
);
|
|
14825
15137
|
const fieldTypes = await getFieldTypeMap(stmt.appId, client, cacheContext);
|
|
14826
15138
|
const records = updateFromToPutBatches(stmt, matched, fieldTypes).flatMap((batch) => batch.records);
|
|
14827
15139
|
const matchedById = new Map(matched.map((pair) => [Number(pair.target["$id"]?.value), pair]));
|
|
15140
|
+
const snapshotsById = snapshotFields ? indexDmlUpdateSnapshots(matched.map((pair) => pair.target)) : /* @__PURE__ */ new Map();
|
|
14828
15141
|
return records.sort((a, b) => a.id - b.id).map((entry, index) => ({
|
|
14829
15142
|
rowNumber: index + 1,
|
|
14830
15143
|
operation: "UPDATE",
|
|
@@ -14833,6 +15146,7 @@ async function materializeUpdateFromValidationCandidates(stmt, from, client, opt
|
|
|
14833
15146
|
preErrors: [],
|
|
14834
15147
|
record: entry.record,
|
|
14835
15148
|
targetId: entry.id,
|
|
15149
|
+
validationSnapshot: snapshotsById.get(entry.id),
|
|
14836
15150
|
evaluationRow: updateFromEvaluationRow(matchedById.get(entry.id), stmt.appId, from.alias),
|
|
14837
15151
|
evaluationFieldTypes: scope.evaluationTypes
|
|
14838
15152
|
}));
|
|
@@ -14846,7 +15160,7 @@ var UPDATE_FROM_UNSUPPORTED_SOURCE_TYPES = /* @__PURE__ */ new Set([
|
|
|
14846
15160
|
"GROUP_SELECT",
|
|
14847
15161
|
"FILE"
|
|
14848
15162
|
]);
|
|
14849
|
-
async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables) {
|
|
15163
|
+
async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cacheContext, tempTables, snapshotFields) {
|
|
14850
15164
|
const joinKind = await resolveUpdateFromTargetJoinKind(stmt, from, client, cacheContext);
|
|
14851
15165
|
const checkScope = await resolveUpdateFromCheckScope(stmt, from, client, cacheContext, tempTables);
|
|
14852
15166
|
const sourceFields = [...new Set(stmt.assignments.filter((a) => a.value.type === "SOURCE_FIELD").map((a) => a.value.type === "SOURCE_FIELD" ? a.value.field : "").concat(checkScope.sourceFields))];
|
|
@@ -14875,7 +15189,11 @@ async function resolveUpdateFromMatchedRecords(stmt, from, client, options, cach
|
|
|
14875
15189
|
}
|
|
14876
15190
|
if (sourceByKey.size === 0) return [];
|
|
14877
15191
|
const maxRecords = options.maxRecords ?? 1e4;
|
|
14878
|
-
const targetFields = [.../* @__PURE__ */ new Set([
|
|
15192
|
+
const targetFields = [.../* @__PURE__ */ new Set([
|
|
15193
|
+
...collectUpdateFromTargetFields(stmt),
|
|
15194
|
+
...checkScope.targetFields,
|
|
15195
|
+
...snapshotFields ?? []
|
|
15196
|
+
])];
|
|
14879
15197
|
const filterQuery = from.targetFilter === null ? "" : updateToGetQuery({ ...stmt, from: null, where: from.targetFilter, checkGroups: void 0 }).query;
|
|
14880
15198
|
const targetRecords = [];
|
|
14881
15199
|
const seenTargetIds = /* @__PURE__ */ new Set();
|
|
@@ -18484,6 +18802,189 @@ function getCursorLeaseManager(host, maxActive = DEFAULT_MAX_ACTIVE) {
|
|
|
18484
18802
|
return manager;
|
|
18485
18803
|
}
|
|
18486
18804
|
|
|
18805
|
+
// src/node/kintoneMetadata.ts
|
|
18806
|
+
var KINTONE_METADATA_RESOURCES = [
|
|
18807
|
+
"app",
|
|
18808
|
+
"fields",
|
|
18809
|
+
"layout",
|
|
18810
|
+
"settings",
|
|
18811
|
+
"status",
|
|
18812
|
+
"views",
|
|
18813
|
+
"reports",
|
|
18814
|
+
"customize"
|
|
18815
|
+
];
|
|
18816
|
+
var KINTONE_METADATA_LANGS = ["default", "user", "ja", "en", "zh"];
|
|
18817
|
+
var KINTONE_METADATA_MAX_RESPONSE_BYTES = 2097152;
|
|
18818
|
+
var ResponseTooLargeError = class extends Error {
|
|
18819
|
+
constructor(maxBytes = KINTONE_METADATA_MAX_RESPONSE_BYTES, responseBytes) {
|
|
18820
|
+
super(`ResponseTooLargeError: kintone metadata response exceeds ${maxBytes} bytes.`);
|
|
18821
|
+
this.maxBytes = maxBytes;
|
|
18822
|
+
this.responseBytes = responseBytes;
|
|
18823
|
+
this.name = "ResponseTooLargeError";
|
|
18824
|
+
}
|
|
18825
|
+
};
|
|
18826
|
+
var InvalidJsonResponseError = class extends Error {
|
|
18827
|
+
constructor(cause) {
|
|
18828
|
+
super("InvalidJsonResponseError: kintone metadata response is not valid JSON.");
|
|
18829
|
+
this.name = "InvalidJsonResponseError";
|
|
18830
|
+
this.cause = cause;
|
|
18831
|
+
}
|
|
18832
|
+
};
|
|
18833
|
+
var ArgumentError = class extends Error {
|
|
18834
|
+
constructor(message) {
|
|
18835
|
+
super(`ArgumentError: ${message}`);
|
|
18836
|
+
this.name = "ArgumentError";
|
|
18837
|
+
}
|
|
18838
|
+
};
|
|
18839
|
+
var CapabilityError = class extends Error {
|
|
18840
|
+
constructor(message) {
|
|
18841
|
+
super(`CapabilityError: ${message}`);
|
|
18842
|
+
this.name = "CapabilityError";
|
|
18843
|
+
}
|
|
18844
|
+
};
|
|
18845
|
+
var RESOURCE_DEFINITIONS = {
|
|
18846
|
+
app: {
|
|
18847
|
+
productionPath: "/app.json",
|
|
18848
|
+
appParameter: "id",
|
|
18849
|
+
allowsLang: false,
|
|
18850
|
+
authCapability: "token|userpass"
|
|
18851
|
+
},
|
|
18852
|
+
fields: {
|
|
18853
|
+
productionPath: "/app/form/fields.json",
|
|
18854
|
+
previewPath: "/preview/app/form/fields.json",
|
|
18855
|
+
appParameter: "app",
|
|
18856
|
+
allowsLang: true,
|
|
18857
|
+
authCapability: "token|userpass"
|
|
18858
|
+
},
|
|
18859
|
+
layout: {
|
|
18860
|
+
productionPath: "/app/form/layout.json",
|
|
18861
|
+
previewPath: "/preview/app/form/layout.json",
|
|
18862
|
+
appParameter: "app",
|
|
18863
|
+
allowsLang: false,
|
|
18864
|
+
authCapability: "token|userpass"
|
|
18865
|
+
},
|
|
18866
|
+
settings: {
|
|
18867
|
+
productionPath: "/app/settings.json",
|
|
18868
|
+
previewPath: "/preview/app/settings.json",
|
|
18869
|
+
appParameter: "app",
|
|
18870
|
+
allowsLang: true,
|
|
18871
|
+
authCapability: "token|userpass"
|
|
18872
|
+
},
|
|
18873
|
+
status: {
|
|
18874
|
+
productionPath: "/app/status.json",
|
|
18875
|
+
previewPath: "/preview/app/status.json",
|
|
18876
|
+
appParameter: "app",
|
|
18877
|
+
allowsLang: true,
|
|
18878
|
+
authCapability: "token|userpass"
|
|
18879
|
+
},
|
|
18880
|
+
views: {
|
|
18881
|
+
productionPath: "/app/views.json",
|
|
18882
|
+
previewPath: "/preview/app/views.json",
|
|
18883
|
+
appParameter: "app",
|
|
18884
|
+
allowsLang: true,
|
|
18885
|
+
authCapability: "token|userpass"
|
|
18886
|
+
},
|
|
18887
|
+
reports: {
|
|
18888
|
+
productionPath: "/app/reports.json",
|
|
18889
|
+
previewPath: "/preview/app/reports.json",
|
|
18890
|
+
appParameter: "app",
|
|
18891
|
+
allowsLang: true,
|
|
18892
|
+
authCapability: "token|userpass"
|
|
18893
|
+
},
|
|
18894
|
+
customize: {
|
|
18895
|
+
productionPath: "/app/customize.json",
|
|
18896
|
+
previewPath: "/preview/app/customize.json",
|
|
18897
|
+
appParameter: "app",
|
|
18898
|
+
allowsLang: false,
|
|
18899
|
+
authCapability: "userpass-only"
|
|
18900
|
+
}
|
|
18901
|
+
};
|
|
18902
|
+
var RESOURCE_SET = new Set(KINTONE_METADATA_RESOURCES);
|
|
18903
|
+
var LANG_SET = new Set(KINTONE_METADATA_LANGS);
|
|
18904
|
+
var API_BASE_PATH_PATTERN = /^\/k\/(?:guest\/([1-9]\d*)\/)?v1$/;
|
|
18905
|
+
function assertResolvedAppId(resolvedAppId) {
|
|
18906
|
+
if (!Number.isSafeInteger(resolvedAppId) || resolvedAppId <= 0) {
|
|
18907
|
+
throw new ArgumentError("resolved app ID must be a positive safe integer.");
|
|
18908
|
+
}
|
|
18909
|
+
}
|
|
18910
|
+
function assertApiBasePath(apiBasePath) {
|
|
18911
|
+
const match = API_BASE_PATH_PATTERN.exec(apiBasePath);
|
|
18912
|
+
if (!match) {
|
|
18913
|
+
throw new ArgumentError("apiBasePath must be /k/v1 or /k/guest/<positive safe integer>/v1.");
|
|
18914
|
+
}
|
|
18915
|
+
if (match[1] !== void 0) {
|
|
18916
|
+
const guestSpaceId = Number(match[1]);
|
|
18917
|
+
if (!Number.isSafeInteger(guestSpaceId) || guestSpaceId <= 0) {
|
|
18918
|
+
throw new ArgumentError("apiBasePath guest space ID must be a positive safe integer.");
|
|
18919
|
+
}
|
|
18920
|
+
}
|
|
18921
|
+
}
|
|
18922
|
+
function validateRequest(request) {
|
|
18923
|
+
if (typeof request !== "object" || request === null || Array.isArray(request)) {
|
|
18924
|
+
throw new ArgumentError("metadata request must be an object.");
|
|
18925
|
+
}
|
|
18926
|
+
const candidate = request;
|
|
18927
|
+
const resource = candidate.resource;
|
|
18928
|
+
if (typeof resource !== "string" || !RESOURCE_SET.has(resource)) {
|
|
18929
|
+
throw new ArgumentError(`unsupported metadata resource: ${String(resource)}.`);
|
|
18930
|
+
}
|
|
18931
|
+
const typedResource = resource;
|
|
18932
|
+
const definition = RESOURCE_DEFINITIONS[typedResource];
|
|
18933
|
+
const allowedKeys = definition.allowsLang ? /* @__PURE__ */ new Set(["resource", "preview", "lang"]) : /* @__PURE__ */ new Set(["resource", "preview"]);
|
|
18934
|
+
const unexpectedKey = Object.keys(candidate).find((key) => !allowedKeys.has(key));
|
|
18935
|
+
if (unexpectedKey !== void 0) {
|
|
18936
|
+
throw new ArgumentError(`parameter "${unexpectedKey}" is not allowed for resource "${resource}".`);
|
|
18937
|
+
}
|
|
18938
|
+
if (candidate.preview !== void 0 && typeof candidate.preview !== "boolean") {
|
|
18939
|
+
throw new ArgumentError("preview must be a boolean when specified.");
|
|
18940
|
+
}
|
|
18941
|
+
const preview = candidate.preview === true;
|
|
18942
|
+
if (preview && definition.previewPath === void 0) {
|
|
18943
|
+
throw new ArgumentError(`preview is not supported for resource "${resource}".`);
|
|
18944
|
+
}
|
|
18945
|
+
const rawLang = candidate.lang;
|
|
18946
|
+
if (rawLang !== void 0) {
|
|
18947
|
+
if (!definition.allowsLang) {
|
|
18948
|
+
throw new ArgumentError(`lang is not allowed for resource "${resource}".`);
|
|
18949
|
+
}
|
|
18950
|
+
if (typeof rawLang !== "string" || !LANG_SET.has(rawLang)) {
|
|
18951
|
+
throw new ArgumentError(`unsupported lang: ${String(rawLang)}.`);
|
|
18952
|
+
}
|
|
18953
|
+
}
|
|
18954
|
+
return {
|
|
18955
|
+
resource: typedResource,
|
|
18956
|
+
preview,
|
|
18957
|
+
lang: rawLang,
|
|
18958
|
+
definition
|
|
18959
|
+
};
|
|
18960
|
+
}
|
|
18961
|
+
function mapKintoneMetadataRequest(request, resolvedAppId, apiBasePath, authType) {
|
|
18962
|
+
assertResolvedAppId(resolvedAppId);
|
|
18963
|
+
assertApiBasePath(apiBasePath);
|
|
18964
|
+
if (authType !== "token" && authType !== "userpass") {
|
|
18965
|
+
throw new ArgumentError(`unsupported auth type: ${String(authType)}.`);
|
|
18966
|
+
}
|
|
18967
|
+
const { resource, preview, lang, definition } = validateRequest(request);
|
|
18968
|
+
if (definition.authCapability === "userpass-only" && authType === "token") {
|
|
18969
|
+
throw new CapabilityError(`resource "${resource}" requires userpass authentication.`);
|
|
18970
|
+
}
|
|
18971
|
+
const params = new URLSearchParams();
|
|
18972
|
+
params.set(definition.appParameter, String(resolvedAppId));
|
|
18973
|
+
if (lang !== void 0) params.set("lang", lang);
|
|
18974
|
+
const pathFragment = preview ? definition.previewPath : definition.productionPath;
|
|
18975
|
+
if (pathFragment === void 0) {
|
|
18976
|
+
throw new ArgumentError(`preview is not supported for resource "${resource}".`);
|
|
18977
|
+
}
|
|
18978
|
+
return {
|
|
18979
|
+
method: "GET",
|
|
18980
|
+
path: `${apiBasePath}${pathFragment}`,
|
|
18981
|
+
params,
|
|
18982
|
+
environment: preview ? "preview" : "production",
|
|
18983
|
+
resource,
|
|
18984
|
+
authCapability: definition.authCapability
|
|
18985
|
+
};
|
|
18986
|
+
}
|
|
18987
|
+
|
|
18487
18988
|
// src/cli/nodeKintoneClient.ts
|
|
18488
18989
|
var KintoneApiError = class extends Error {
|
|
18489
18990
|
constructor(status, code, bodyText) {
|
|
@@ -18494,10 +18995,10 @@ var KintoneApiError = class extends Error {
|
|
|
18494
18995
|
}
|
|
18495
18996
|
};
|
|
18496
18997
|
var SEARCH_ABORTED_HEADER_VALUE = "Filter aborted because of too many search results";
|
|
18497
|
-
function
|
|
18998
|
+
function createNodeKintoneConnection(baseUrl, tokenResolver) {
|
|
18498
18999
|
const normalizedBaseUrl = baseUrl.replace(/\/+$/, "");
|
|
18499
19000
|
const apiBasePath = tokenResolver.guestSpaceId && tokenResolver.guestSpaceId > 0 ? `/k/guest/${tokenResolver.guestSpaceId}/v1` : "/k/v1";
|
|
18500
|
-
async function
|
|
19001
|
+
async function requestResponse(path, init, appIdForToken) {
|
|
18501
19002
|
const headers = new Headers(init.headers ?? {});
|
|
18502
19003
|
if (tokenResolver.auth.type === "token") {
|
|
18503
19004
|
headers.set("X-Cybozu-API-Token", tokenResolver.auth.resolveToken(appIdForToken));
|
|
@@ -18553,13 +19054,68 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
18553
19054
|
}
|
|
18554
19055
|
const warning = res.headers.get("X-Cybozu-Warning") ?? "";
|
|
18555
19056
|
return {
|
|
18556
|
-
|
|
19057
|
+
response: res,
|
|
18557
19058
|
searchAborted: warning.includes(SEARCH_ABORTED_HEADER_VALUE)
|
|
18558
19059
|
};
|
|
18559
19060
|
}
|
|
19061
|
+
async function requestJsonResponse(path, init, appIdForToken) {
|
|
19062
|
+
const { response, searchAborted } = await requestResponse(path, init, appIdForToken);
|
|
19063
|
+
return {
|
|
19064
|
+
body: await response.json(),
|
|
19065
|
+
searchAborted
|
|
19066
|
+
};
|
|
19067
|
+
}
|
|
18560
19068
|
async function requestJson(path, init, appIdForToken) {
|
|
18561
19069
|
return (await requestJsonResponse(path, init, appIdForToken)).body;
|
|
18562
19070
|
}
|
|
19071
|
+
async function requestCappedMetadataJson(path, init, appIdForToken) {
|
|
19072
|
+
const { response } = await requestResponse(path, init, appIdForToken);
|
|
19073
|
+
const contentLength = response.headers.get("Content-Length");
|
|
19074
|
+
if (contentLength !== null && /^\d+$/.test(contentLength.trim())) {
|
|
19075
|
+
const declaredBytes = Number(contentLength);
|
|
19076
|
+
if (declaredBytes > KINTONE_METADATA_MAX_RESPONSE_BYTES) {
|
|
19077
|
+
try {
|
|
19078
|
+
await response.body?.cancel();
|
|
19079
|
+
} catch {
|
|
19080
|
+
}
|
|
19081
|
+
throw new ResponseTooLargeError(KINTONE_METADATA_MAX_RESPONSE_BYTES, declaredBytes);
|
|
19082
|
+
}
|
|
19083
|
+
}
|
|
19084
|
+
const chunks = [];
|
|
19085
|
+
let responseBytes = 0;
|
|
19086
|
+
if (response.body !== null) {
|
|
19087
|
+
const reader = response.body.getReader();
|
|
19088
|
+
while (true) {
|
|
19089
|
+
const { done, value } = await reader.read();
|
|
19090
|
+
if (done) break;
|
|
19091
|
+
responseBytes += value.byteLength;
|
|
19092
|
+
if (responseBytes > KINTONE_METADATA_MAX_RESPONSE_BYTES) {
|
|
19093
|
+
try {
|
|
19094
|
+
await reader.cancel();
|
|
19095
|
+
} catch {
|
|
19096
|
+
}
|
|
19097
|
+
throw new ResponseTooLargeError(KINTONE_METADATA_MAX_RESPONSE_BYTES, responseBytes);
|
|
19098
|
+
}
|
|
19099
|
+
chunks.push(value);
|
|
19100
|
+
}
|
|
19101
|
+
}
|
|
19102
|
+
const bytes = new Uint8Array(responseBytes);
|
|
19103
|
+
let offset = 0;
|
|
19104
|
+
for (const chunk3 of chunks) {
|
|
19105
|
+
bytes.set(chunk3, offset);
|
|
19106
|
+
offset += chunk3.byteLength;
|
|
19107
|
+
}
|
|
19108
|
+
let data;
|
|
19109
|
+
try {
|
|
19110
|
+
data = JSON.parse(new TextDecoder("utf-8").decode(bytes));
|
|
19111
|
+
} catch (cause) {
|
|
19112
|
+
throw new InvalidJsonResponseError(cause);
|
|
19113
|
+
}
|
|
19114
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) {
|
|
19115
|
+
throw new InvalidJsonResponseError();
|
|
19116
|
+
}
|
|
19117
|
+
return { data, responseBytes };
|
|
19118
|
+
}
|
|
18563
19119
|
function shouldRetryWithRecordNumberOrder(path, bodyText) {
|
|
18564
19120
|
if (!path.includes("/v1/records.json?")) return false;
|
|
18565
19121
|
if (!bodyText.includes('"code":"CB_IL02"')) return false;
|
|
@@ -18579,7 +19135,7 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
18579
19135
|
const nextQuery = encodeURIComponent(rewritten);
|
|
18580
19136
|
return `${base}query=${nextQuery}${tail.length > 0 ? `&${tail.join("&")}` : ""}`;
|
|
18581
19137
|
}
|
|
18582
|
-
|
|
19138
|
+
const client = {
|
|
18583
19139
|
async getRecords(params) {
|
|
18584
19140
|
const queryPart = `query=${encodeURIComponent(params.query)}`;
|
|
18585
19141
|
const appPart = `app=${encodeURIComponent(String(params.app))}`;
|
|
@@ -18751,6 +19307,34 @@ function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
|
18751
19307
|
};
|
|
18752
19308
|
}
|
|
18753
19309
|
};
|
|
19310
|
+
const metadataReader = {
|
|
19311
|
+
async getMetadata(request, resolvedAppId) {
|
|
19312
|
+
const plan = mapKintoneMetadataRequest(
|
|
19313
|
+
request,
|
|
19314
|
+
resolvedAppId,
|
|
19315
|
+
apiBasePath,
|
|
19316
|
+
tokenResolver.auth.type
|
|
19317
|
+
);
|
|
19318
|
+
const query = plan.params.toString();
|
|
19319
|
+
const { data, responseBytes } = await requestCappedMetadataJson(
|
|
19320
|
+
`${plan.path}${query.length > 0 ? `?${query}` : ""}`,
|
|
19321
|
+
{ method: "GET" },
|
|
19322
|
+
resolvedAppId
|
|
19323
|
+
);
|
|
19324
|
+
return {
|
|
19325
|
+
resource: plan.resource,
|
|
19326
|
+
environment: plan.environment,
|
|
19327
|
+
path: plan.path,
|
|
19328
|
+
params: Object.fromEntries(plan.params.entries()),
|
|
19329
|
+
responseBytes,
|
|
19330
|
+
data
|
|
19331
|
+
};
|
|
19332
|
+
}
|
|
19333
|
+
};
|
|
19334
|
+
return { client, metadataReader };
|
|
19335
|
+
}
|
|
19336
|
+
function createNodeKintoneClient(baseUrl, tokenResolver) {
|
|
19337
|
+
return createNodeKintoneConnection(baseUrl, tokenResolver).client;
|
|
18754
19338
|
}
|
|
18755
19339
|
|
|
18756
19340
|
// src/node/appProfiles.ts
|