@exabugs/dynamodb-client 1.24.1 → 1.25.1
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/CHANGELOG.md +41 -0
- package/dist/integrations/react-admin/dataProvider.d.ts +9 -0
- package/dist/integrations/react-admin/dataProvider.d.ts.map +1 -1
- package/dist/integrations/react-admin/dataProvider.js +24 -3
- package/dist/integrations/react-admin/dataProvider.js.map +1 -1
- package/dist/server/handler.cjs +400 -188
- package/dist/server/handler.cjs.map +4 -4
- package/dist/server/media-handler.cjs +17 -12
- package/dist/server/media-handler.cjs.map +3 -3
- package/dist/server/media-process-handler-dlq.cjs +17 -12
- package/dist/server/media-process-handler-dlq.cjs.map +3 -3
- package/dist/server/media-process-handler.cjs +17 -12
- package/dist/server/media-process-handler.cjs.map +3 -3
- package/dist/server/operations/deleteMany.d.ts.map +1 -1
- package/dist/server/operations/deleteMany.js +26 -2
- package/dist/server/operations/deleteMany.js.map +1 -1
- package/dist/server/operations/find/shadowQuery.d.ts.map +1 -1
- package/dist/server/operations/find/shadowQuery.js +59 -50
- package/dist/server/operations/find/shadowQuery.js.map +1 -1
- package/dist/server/operations/find/utils.d.ts.map +1 -1
- package/dist/server/operations/find/utils.js +19 -2
- package/dist/server/operations/find/utils.js.map +1 -1
- package/dist/server/operations/insertMany.d.ts.map +1 -1
- package/dist/server/operations/insertMany.js +36 -2
- package/dist/server/operations/insertMany.js.map +1 -1
- package/dist/server/operations/updateMany.d.ts.map +1 -1
- package/dist/server/operations/updateMany.js +134 -133
- package/dist/server/operations/updateMany.js.map +1 -1
- package/dist/server/utils/revision.d.ts +49 -0
- package/dist/server/utils/revision.d.ts.map +1 -0
- package/dist/server/utils/revision.js +92 -0
- package/dist/server/utils/revision.js.map +1 -0
- package/dist/server/utils/updateOperators.d.ts +25 -0
- package/dist/server/utils/updateOperators.d.ts.map +1 -0
- package/dist/server/utils/updateOperators.js +76 -0
- package/dist/server/utils/updateOperators.js.map +1 -0
- package/dist/sharp-layer.zip +0 -0
- package/package.json +1 -1
package/dist/server/handler.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// @exabugs/dynamodb-client v1.
|
|
2
|
-
// Built: 2026-11-
|
|
1
|
+
// @exabugs/dynamodb-client v1.25.1
|
|
2
|
+
// Built: 2026-11-13T23:34:00.545Z
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
@@ -3429,13 +3429,13 @@ var init_parse_utils = __esm({
|
|
|
3429
3429
|
if (value === null || value === void 0) {
|
|
3430
3430
|
return void 0;
|
|
3431
3431
|
}
|
|
3432
|
-
const
|
|
3432
|
+
const asObject2 = expectObject(value);
|
|
3433
3433
|
const setKeys = [];
|
|
3434
|
-
for (const k5 in
|
|
3435
|
-
if (!hasOwn(
|
|
3434
|
+
for (const k5 in asObject2) {
|
|
3435
|
+
if (!hasOwn(asObject2, k5)) {
|
|
3436
3436
|
continue;
|
|
3437
3437
|
}
|
|
3438
|
-
if (
|
|
3438
|
+
if (asObject2[k5] != null) {
|
|
3439
3439
|
setKeys.push(k5);
|
|
3440
3440
|
}
|
|
3441
3441
|
}
|
|
@@ -3445,7 +3445,7 @@ var init_parse_utils = __esm({
|
|
|
3445
3445
|
if (setKeys.length > 1) {
|
|
3446
3446
|
throw new TypeError(`Unions must have exactly one non-null member. Keys ${setKeys} were not null.`);
|
|
3447
3447
|
}
|
|
3448
|
-
return
|
|
3448
|
+
return asObject2;
|
|
3449
3449
|
}, "expectUnion");
|
|
3450
3450
|
strictParseDouble = /* @__PURE__ */ __name((value) => {
|
|
3451
3451
|
if (typeof value == "string") {
|
|
@@ -38724,22 +38724,24 @@ var require_main = __commonJS({
|
|
|
38724
38724
|
var decode_bbox_int = /* @__PURE__ */ __name(function(hashInt, bitDepth) {
|
|
38725
38725
|
bitDepth = bitDepth || 52;
|
|
38726
38726
|
var maxLat = MAX_LAT, minLat = MIN_LAT, maxLon = MAX_LON, minLon = MIN_LON;
|
|
38727
|
-
var
|
|
38728
|
-
var
|
|
38729
|
-
for (var i6 = 0; i6 <
|
|
38730
|
-
lonBit = get_bit(hashInt,
|
|
38731
|
-
latBit = get_bit(hashInt, (step - i6) * 2 - 2);
|
|
38732
|
-
if (latBit === 0) {
|
|
38733
|
-
maxLat = (maxLat + minLat) / 2;
|
|
38734
|
-
} else {
|
|
38735
|
-
minLat = (maxLat + minLat) / 2;
|
|
38736
|
-
}
|
|
38727
|
+
var lonBits = Math.ceil(bitDepth / 2);
|
|
38728
|
+
var latBits = Math.floor(bitDepth / 2);
|
|
38729
|
+
for (var i6 = 0; i6 < lonBits; i6++) {
|
|
38730
|
+
var lonBit = get_bit(hashInt, bitDepth - 1 - i6 * 2);
|
|
38737
38731
|
if (lonBit === 0) {
|
|
38738
38732
|
maxLon = (maxLon + minLon) / 2;
|
|
38739
38733
|
} else {
|
|
38740
38734
|
minLon = (maxLon + minLon) / 2;
|
|
38741
38735
|
}
|
|
38742
38736
|
}
|
|
38737
|
+
for (var j5 = 0; j5 < latBits; j5++) {
|
|
38738
|
+
var latBit = get_bit(hashInt, bitDepth - 2 - j5 * 2);
|
|
38739
|
+
if (latBit === 0) {
|
|
38740
|
+
maxLat = (maxLat + minLat) / 2;
|
|
38741
|
+
} else {
|
|
38742
|
+
minLat = (maxLat + minLat) / 2;
|
|
38743
|
+
}
|
|
38744
|
+
}
|
|
38743
38745
|
return [minLat, minLon, maxLat, maxLon];
|
|
38744
38746
|
}, "decode_bbox_int");
|
|
38745
38747
|
function get_bit(bits, position) {
|
|
@@ -38844,6 +38846,9 @@ var require_main = __commonJS({
|
|
|
38844
38846
|
return neighborHashIntList;
|
|
38845
38847
|
}, "neighbors_int");
|
|
38846
38848
|
var bboxes = /* @__PURE__ */ __name(function(minLat, minLon, maxLat, maxLon, numberOfChars) {
|
|
38849
|
+
if (numberOfChars <= 0) {
|
|
38850
|
+
throw new Error("numberOfChars must be strictly positive");
|
|
38851
|
+
}
|
|
38847
38852
|
numberOfChars = numberOfChars || 9;
|
|
38848
38853
|
var hashSouthWest = encode(minLat, minLon, numberOfChars);
|
|
38849
38854
|
var hashNorthEast = encode(maxLat, maxLon, numberOfChars);
|
|
@@ -39030,16 +39035,9 @@ var init_shared = __esm({
|
|
|
39030
39035
|
});
|
|
39031
39036
|
|
|
39032
39037
|
// src/shared/constants/formatting.ts
|
|
39033
|
-
var NUMBER_FORMAT;
|
|
39034
39038
|
var init_formatting = __esm({
|
|
39035
39039
|
"src/shared/constants/formatting.ts"() {
|
|
39036
39040
|
"use strict";
|
|
39037
|
-
NUMBER_FORMAT = {
|
|
39038
|
-
/** シャドウSKで使用する数値の桁数(20桁ゼロ埋め) */
|
|
39039
|
-
SHADOW_SK_DIGITS: 20,
|
|
39040
|
-
/** ゼロ埋め文字 */
|
|
39041
|
-
ZERO_PAD_CHAR: "0"
|
|
39042
|
-
};
|
|
39043
39041
|
}
|
|
39044
39042
|
});
|
|
39045
39043
|
|
|
@@ -39752,6 +39750,71 @@ var init_cost_tracker = __esm({
|
|
|
39752
39750
|
}
|
|
39753
39751
|
});
|
|
39754
39752
|
|
|
39753
|
+
// src/server/utils/revision.ts
|
|
39754
|
+
function revisionOf(item) {
|
|
39755
|
+
const rev = item[REVISION_ATTRIBUTE];
|
|
39756
|
+
return typeof rev === "number" ? rev : void 0;
|
|
39757
|
+
}
|
|
39758
|
+
function nextRevision(current) {
|
|
39759
|
+
return (current ?? 0) + 1;
|
|
39760
|
+
}
|
|
39761
|
+
function notExistsCondition() {
|
|
39762
|
+
return { ConditionExpression: "attribute_not_exists(PK)" };
|
|
39763
|
+
}
|
|
39764
|
+
function unchangedCondition(revision) {
|
|
39765
|
+
const names = { "#rev": REVISION_ATTRIBUTE };
|
|
39766
|
+
if (revision === void 0) {
|
|
39767
|
+
return {
|
|
39768
|
+
ConditionExpression: "attribute_exists(PK) AND attribute_not_exists(#rev)",
|
|
39769
|
+
ExpressionAttributeNames: names
|
|
39770
|
+
};
|
|
39771
|
+
}
|
|
39772
|
+
return {
|
|
39773
|
+
ConditionExpression: "#rev = :rev",
|
|
39774
|
+
ExpressionAttributeNames: names,
|
|
39775
|
+
ExpressionAttributeValues: { ":rev": revision }
|
|
39776
|
+
};
|
|
39777
|
+
}
|
|
39778
|
+
function isWriteConflict(error2) {
|
|
39779
|
+
if (!error2 || typeof error2 !== "object") return false;
|
|
39780
|
+
const { name, CancellationReasons } = error2;
|
|
39781
|
+
if (name === "TransactionConflictException") return true;
|
|
39782
|
+
if (name !== "TransactionCanceledException" || !Array.isArray(CancellationReasons)) return false;
|
|
39783
|
+
const codes = CancellationReasons.map((r5) => r5?.Code).filter((c5) => c5 && c5 !== "None");
|
|
39784
|
+
return codes.length > 0 && codes.every((c5) => c5 === "ConditionalCheckFailed" || c5 === "TransactionConflict");
|
|
39785
|
+
}
|
|
39786
|
+
function sleep3(ms) {
|
|
39787
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
39788
|
+
}
|
|
39789
|
+
async function writeWithConflictRetry(initial, write, refresh, baseDelayMs = 20) {
|
|
39790
|
+
let records = initial;
|
|
39791
|
+
for (let attempt = 0; ; attempt++) {
|
|
39792
|
+
try {
|
|
39793
|
+
if (records.length > 0) await write(records);
|
|
39794
|
+
return records;
|
|
39795
|
+
} catch (error2) {
|
|
39796
|
+
if (!isWriteConflict(error2) || attempt >= MAX_CONFLICT_RETRIES) throw error2;
|
|
39797
|
+
await sleep3(baseDelayMs * 2 ** attempt * (0.5 + Math.random() / 2));
|
|
39798
|
+
records = await refresh(records);
|
|
39799
|
+
}
|
|
39800
|
+
}
|
|
39801
|
+
}
|
|
39802
|
+
var REVISION_ATTRIBUTE, MAX_CONFLICT_RETRIES;
|
|
39803
|
+
var init_revision = __esm({
|
|
39804
|
+
"src/server/utils/revision.ts"() {
|
|
39805
|
+
"use strict";
|
|
39806
|
+
REVISION_ATTRIBUTE = "__rev";
|
|
39807
|
+
MAX_CONFLICT_RETRIES = 5;
|
|
39808
|
+
__name(revisionOf, "revisionOf");
|
|
39809
|
+
__name(nextRevision, "nextRevision");
|
|
39810
|
+
__name(notExistsCondition, "notExistsCondition");
|
|
39811
|
+
__name(unchangedCondition, "unchangedCondition");
|
|
39812
|
+
__name(isWriteConflict, "isWriteConflict");
|
|
39813
|
+
__name(sleep3, "sleep");
|
|
39814
|
+
__name(writeWithConflictRetry, "writeWithConflictRetry");
|
|
39815
|
+
}
|
|
39816
|
+
});
|
|
39817
|
+
|
|
39755
39818
|
// src/server/utils/validation.ts
|
|
39756
39819
|
function validateSortField(_config, _resource, _sort) {
|
|
39757
39820
|
return;
|
|
@@ -40194,6 +40257,12 @@ function normalizeFindParams(config, resource, params) {
|
|
|
40194
40257
|
schema: params.schema
|
|
40195
40258
|
};
|
|
40196
40259
|
}
|
|
40260
|
+
function withInferredType(parsed, fieldKey, value) {
|
|
40261
|
+
if (fieldKey.split(":").length >= 3) return parsed;
|
|
40262
|
+
if (typeof value === "number") return { ...parsed, type: "number" };
|
|
40263
|
+
if (typeof value === "boolean") return { ...parsed, type: "boolean" };
|
|
40264
|
+
return parsed;
|
|
40265
|
+
}
|
|
40197
40266
|
function parseFilters(filter) {
|
|
40198
40267
|
const parsedFilters = [];
|
|
40199
40268
|
if (!filter || Object.keys(filter).length === 0) {
|
|
@@ -40204,11 +40273,14 @@ function parseFilters(filter) {
|
|
|
40204
40273
|
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
40205
40274
|
for (const [operator, operatorValue] of Object.entries(value)) {
|
|
40206
40275
|
const parsed = parseFilterField(`${fieldKey}:${operator}`);
|
|
40207
|
-
parsedFilters.push({
|
|
40276
|
+
parsedFilters.push({
|
|
40277
|
+
parsed: withInferredType(parsed, fieldKey, operatorValue),
|
|
40278
|
+
value: operatorValue
|
|
40279
|
+
});
|
|
40208
40280
|
}
|
|
40209
40281
|
} else {
|
|
40210
40282
|
const parsed = parseFilterField(fieldKey);
|
|
40211
|
-
parsedFilters.push({ parsed, value });
|
|
40283
|
+
parsedFilters.push({ parsed: withInferredType(parsed, fieldKey, value), value });
|
|
40212
40284
|
}
|
|
40213
40285
|
} catch (error2) {
|
|
40214
40286
|
logger7.error("Invalid filter field syntax", {
|
|
@@ -40295,6 +40367,7 @@ var init_utils6 = __esm({
|
|
|
40295
40367
|
});
|
|
40296
40368
|
__name(initializeFindConfig, "initializeFindConfig");
|
|
40297
40369
|
__name(normalizeFindParams, "normalizeFindParams");
|
|
40370
|
+
__name(withInferredType, "withInferredType");
|
|
40298
40371
|
__name(parseFilters, "parseFilters");
|
|
40299
40372
|
__name(findOptimizableFilter, "findOptimizableFilter");
|
|
40300
40373
|
__name(matchesAllFilters, "matchesAllFilters");
|
|
@@ -41092,51 +41165,39 @@ function buildKeyCondition(resource, sortField, optimizableFilter) {
|
|
|
41092
41165
|
}
|
|
41093
41166
|
const { operator, type } = optimizableFilter.parsed;
|
|
41094
41167
|
const value = optimizableFilter.value;
|
|
41095
|
-
const
|
|
41096
|
-
const skValue = `${sortField}#${
|
|
41168
|
+
const { encoded, exact } = encodeValueForShadowSK(value, type, operator);
|
|
41169
|
+
const skValue = `${sortField}#${encoded}`;
|
|
41170
|
+
const afterValue = `${skValue}#id#~`;
|
|
41171
|
+
const beforeValue = `${skValue}#id#`;
|
|
41097
41172
|
switch (operator) {
|
|
41098
41173
|
case "$eq":
|
|
41099
41174
|
return {
|
|
41100
41175
|
keyConditionExpression: "PK = :pk AND begins_with(SK, :skValue)",
|
|
41101
41176
|
expressionAttributeValues: {
|
|
41102
41177
|
...expressionAttributeValues,
|
|
41103
|
-
":skValue":
|
|
41178
|
+
":skValue": beforeValue
|
|
41104
41179
|
}
|
|
41105
41180
|
};
|
|
41181
|
+
// 範囲検索は SK BETWEEN の 1 条件にする。
|
|
41182
|
+
// - DynamoDB はソートキーに 1 つの条件しか許さない(begins_with と比較を並べると ValidationException)
|
|
41183
|
+
// - 上限・下限を sortField の範囲に閉じないと、他の項目のシャドー(や本体 id#…)まで読む
|
|
41184
|
+
// BETWEEN は両端を含むが、端の値(`…#id#`、`…#id#~`、`{sortField}$`)と一致する SK は実在しない
|
|
41106
41185
|
case "$gt":
|
|
41107
|
-
return
|
|
41108
|
-
|
|
41109
|
-
|
|
41110
|
-
|
|
41111
|
-
|
|
41112
|
-
}
|
|
41113
|
-
};
|
|
41186
|
+
return rangeCondition(
|
|
41187
|
+
expressionAttributeValues,
|
|
41188
|
+
exact ? afterValue : beforeValue,
|
|
41189
|
+
fieldUpperBound(sortField)
|
|
41190
|
+
);
|
|
41114
41191
|
case "$gte":
|
|
41115
|
-
return
|
|
41116
|
-
keyConditionExpression: "PK = :pk AND SK >= :skValue",
|
|
41117
|
-
expressionAttributeValues: {
|
|
41118
|
-
...expressionAttributeValues,
|
|
41119
|
-
":skValue": `${skValue}#id#`
|
|
41120
|
-
}
|
|
41121
|
-
};
|
|
41192
|
+
return rangeCondition(expressionAttributeValues, beforeValue, fieldUpperBound(sortField));
|
|
41122
41193
|
case "$lt":
|
|
41123
|
-
return
|
|
41124
|
-
|
|
41125
|
-
|
|
41126
|
-
|
|
41127
|
-
|
|
41128
|
-
":skValue": `${skValue}#id#`
|
|
41129
|
-
}
|
|
41130
|
-
};
|
|
41194
|
+
return rangeCondition(
|
|
41195
|
+
expressionAttributeValues,
|
|
41196
|
+
`${sortField}#`,
|
|
41197
|
+
exact ? beforeValue : afterValue
|
|
41198
|
+
);
|
|
41131
41199
|
case "$lte":
|
|
41132
|
-
return {
|
|
41133
|
-
keyConditionExpression: "PK = :pk AND begins_with(SK, :skPrefix) AND SK <= :skValue",
|
|
41134
|
-
expressionAttributeValues: {
|
|
41135
|
-
...expressionAttributeValues,
|
|
41136
|
-
":skPrefix": `${sortField}#`,
|
|
41137
|
-
":skValue": `${skValue}#id#~`
|
|
41138
|
-
}
|
|
41139
|
-
};
|
|
41200
|
+
return rangeCondition(expressionAttributeValues, `${sortField}#`, afterValue);
|
|
41140
41201
|
case "$starts":
|
|
41141
41202
|
return {
|
|
41142
41203
|
keyConditionExpression: "PK = :pk AND begins_with(SK, :skValue)",
|
|
@@ -41155,16 +41216,35 @@ function buildKeyCondition(resource, sortField, optimizableFilter) {
|
|
|
41155
41216
|
};
|
|
41156
41217
|
}
|
|
41157
41218
|
}
|
|
41158
|
-
function
|
|
41159
|
-
|
|
41160
|
-
|
|
41161
|
-
|
|
41162
|
-
|
|
41163
|
-
|
|
41164
|
-
|
|
41165
|
-
}
|
|
41166
|
-
|
|
41219
|
+
function fieldUpperBound(sortField) {
|
|
41220
|
+
return `${sortField}$`;
|
|
41221
|
+
}
|
|
41222
|
+
function rangeCondition(base, low, high) {
|
|
41223
|
+
return {
|
|
41224
|
+
keyConditionExpression: "PK = :pk AND SK BETWEEN :skLow AND :skHigh",
|
|
41225
|
+
expressionAttributeValues: { ...base, ":skLow": low, ":skHigh": high }
|
|
41226
|
+
};
|
|
41227
|
+
}
|
|
41228
|
+
function encodeValueForShadowSK(value, type, operator) {
|
|
41229
|
+
const config = getShadowConfig();
|
|
41230
|
+
if (type === "number" || typeof value === "number") {
|
|
41231
|
+
const num = Number(value);
|
|
41232
|
+
return { encoded: formatFieldValue2("number", num, config), exact: false };
|
|
41167
41233
|
}
|
|
41234
|
+
if (type === "boolean" || typeof value === "boolean") {
|
|
41235
|
+
const bool = typeof value === "boolean" ? value : String(value).toLowerCase() === "true";
|
|
41236
|
+
return { encoded: formatFieldValue2("boolean", bool, config), exact: true };
|
|
41237
|
+
}
|
|
41238
|
+
const str = String(value);
|
|
41239
|
+
if (operator !== "$starts" && (type === "date" || inferFieldType(str) === "datetime")) {
|
|
41240
|
+
return { encoded: formatFieldValue2("datetime", str, config), exact: true };
|
|
41241
|
+
}
|
|
41242
|
+
const encoded = formatFieldValue2("string", str, config);
|
|
41243
|
+
const bytes = new TextEncoder().encode(str).length;
|
|
41244
|
+
return {
|
|
41245
|
+
encoded,
|
|
41246
|
+
exact: encoded === escapeString2(str) && bytes < config.stringMaxBytes - 3
|
|
41247
|
+
};
|
|
41168
41248
|
}
|
|
41169
41249
|
function extractRecordIds(shadowRecords) {
|
|
41170
41250
|
return shadowRecords.map((record) => {
|
|
@@ -41191,8 +41271,8 @@ var init_shadowQuery = __esm({
|
|
|
41191
41271
|
"src/server/operations/find/shadowQuery.ts"() {
|
|
41192
41272
|
"use strict";
|
|
41193
41273
|
import_lib_dynamodb5 = __toESM(require_dist_cjs22(), 1);
|
|
41194
|
-
init_formatting();
|
|
41195
41274
|
init_shared();
|
|
41275
|
+
init_shadow();
|
|
41196
41276
|
init_batchGet();
|
|
41197
41277
|
init_cost_tracker();
|
|
41198
41278
|
init_dynamodb3();
|
|
@@ -41212,6 +41292,8 @@ var init_shadowQuery = __esm({
|
|
|
41212
41292
|
__name(sortInMemory, "sortInMemory");
|
|
41213
41293
|
__name(executeShadowRecordQuery, "executeShadowRecordQuery");
|
|
41214
41294
|
__name(buildKeyCondition, "buildKeyCondition");
|
|
41295
|
+
__name(fieldUpperBound, "fieldUpperBound");
|
|
41296
|
+
__name(rangeCondition, "rangeCondition");
|
|
41215
41297
|
__name(encodeValueForShadowSK, "encodeValueForShadowSK");
|
|
41216
41298
|
__name(extractRecordIds, "extractRecordIds");
|
|
41217
41299
|
__name(fetchMainRecords, "fetchMainRecords");
|
|
@@ -41406,7 +41488,8 @@ async function handleDeleteMany(resource, params, requestId) {
|
|
|
41406
41488
|
preparedRecords.push({
|
|
41407
41489
|
id,
|
|
41408
41490
|
mainSK: generateMainRecordSK2(id),
|
|
41409
|
-
shadowKeys
|
|
41491
|
+
shadowKeys,
|
|
41492
|
+
revision: revisionOf(item)
|
|
41410
41493
|
});
|
|
41411
41494
|
}
|
|
41412
41495
|
const notFoundIds = ids.filter((id) => !existingIds.has(id));
|
|
@@ -41454,16 +41537,20 @@ async function handleDeleteMany(resource, params, requestId) {
|
|
|
41454
41537
|
chunks.length,
|
|
41455
41538
|
preparationRiskInfo
|
|
41456
41539
|
);
|
|
41457
|
-
const
|
|
41540
|
+
const writeChunk = /* @__PURE__ */ __name(async (chunk) => {
|
|
41458
41541
|
const transactItems = [];
|
|
41459
41542
|
for (const record of chunk) {
|
|
41543
|
+
if (record.gone) continue;
|
|
41460
41544
|
transactItems.push({
|
|
41461
41545
|
Delete: {
|
|
41462
41546
|
TableName: tableName,
|
|
41463
41547
|
Key: {
|
|
41464
41548
|
PK: resource,
|
|
41465
41549
|
SK: record.mainSK
|
|
41466
|
-
}
|
|
41550
|
+
},
|
|
41551
|
+
// 読んでから消すまでの間に、ほかの書き込みが入っていないこと(楽観ロック)。
|
|
41552
|
+
// 古い一覧のままシャドーを消すと、新しく増えたシャドーが残る
|
|
41553
|
+
...unchangedCondition(record.revision)
|
|
41467
41554
|
}
|
|
41468
41555
|
});
|
|
41469
41556
|
for (const shadowSK of record.shadowKeys) {
|
|
@@ -41478,6 +41565,7 @@ async function handleDeleteMany(resource, params, requestId) {
|
|
|
41478
41565
|
});
|
|
41479
41566
|
}
|
|
41480
41567
|
}
|
|
41568
|
+
if (transactItems.length === 0) return;
|
|
41481
41569
|
const result = await executeDynamoDBOperation(
|
|
41482
41570
|
() => dbClient2.send(
|
|
41483
41571
|
new import_lib_dynamodb6.TransactWriteCommand({
|
|
@@ -41494,8 +41582,24 @@ async function handleDeleteMany(resource, params, requestId) {
|
|
|
41494
41582
|
} else {
|
|
41495
41583
|
costTracker.add(result.ConsumedCapacity);
|
|
41496
41584
|
}
|
|
41497
|
-
|
|
41498
|
-
|
|
41585
|
+
}, "writeChunk");
|
|
41586
|
+
const executeChunk = /* @__PURE__ */ __name((chunk) => writeWithConflictRetry(chunk, writeChunk, async (stale) => {
|
|
41587
|
+
const items = await batchGetAll(
|
|
41588
|
+
stale.map((record) => ({ PK: resource, SK: record.mainSK })),
|
|
41589
|
+
{ consistentRead: true, costTracker, requestId }
|
|
41590
|
+
);
|
|
41591
|
+
const fresh = new Map(items.map((item) => [item.SK, item]));
|
|
41592
|
+
return stale.map((record) => {
|
|
41593
|
+
const item = fresh.get(record.mainSK);
|
|
41594
|
+
if (!item) return { ...record, gone: true };
|
|
41595
|
+
const data = item.data;
|
|
41596
|
+
return {
|
|
41597
|
+
...record,
|
|
41598
|
+
shadowKeys: item.__shadowKeys ?? data.__shadowKeys ?? [],
|
|
41599
|
+
revision: revisionOf(item)
|
|
41600
|
+
};
|
|
41601
|
+
});
|
|
41602
|
+
}), "executeChunk");
|
|
41499
41603
|
const {
|
|
41500
41604
|
successRecords,
|
|
41501
41605
|
failedIds: chunkFailedIds,
|
|
@@ -41587,6 +41691,7 @@ var init_deleteMany = __esm({
|
|
|
41587
41691
|
init_chunking();
|
|
41588
41692
|
init_cost_tracker();
|
|
41589
41693
|
init_dynamodb3();
|
|
41694
|
+
init_revision();
|
|
41590
41695
|
init_findAll();
|
|
41591
41696
|
logger12 = createLogger({ service: "records-lambda" });
|
|
41592
41697
|
__name(handleDeleteMany, "handleDeleteMany");
|
|
@@ -41881,7 +41986,7 @@ async function handleInsertMany(resource, params, requestId) {
|
|
|
41881
41986
|
chunks.length,
|
|
41882
41987
|
preparationRiskInfo
|
|
41883
41988
|
);
|
|
41884
|
-
const
|
|
41989
|
+
const writeChunk = /* @__PURE__ */ __name(async (chunk) => {
|
|
41885
41990
|
const transactItems = [];
|
|
41886
41991
|
for (const record of chunk) {
|
|
41887
41992
|
transactItems.push({
|
|
@@ -41891,12 +41996,23 @@ async function handleInsertMany(resource, params, requestId) {
|
|
|
41891
41996
|
PK: resource,
|
|
41892
41997
|
SK: record.mainSK,
|
|
41893
41998
|
__shadowKeys: record.shadowKeys,
|
|
41999
|
+
[REVISION_ATTRIBUTE]: nextRevision(record.existing?.revision),
|
|
41894
42000
|
data: {
|
|
41895
42001
|
...record.fullRecordData
|
|
41896
42002
|
}
|
|
41897
|
-
}
|
|
42003
|
+
},
|
|
42004
|
+
// 既存の id への挿入は上書きになる。既存を知らずに上書きすると、古いシャドーが残るので、
|
|
42005
|
+
// まず「無い」ことを条件に書き、外れたら既存を読んで、古いシャドーも一緒に消す
|
|
42006
|
+
...record.existing ? unchangedCondition(record.existing.revision) : notExistsCondition()
|
|
41898
42007
|
}
|
|
41899
42008
|
});
|
|
42009
|
+
const newShadowKeys = new Set(record.shadowKeys);
|
|
42010
|
+
for (const shadowSK of record.existing?.shadowKeys ?? []) {
|
|
42011
|
+
if (newShadowKeys.has(shadowSK)) continue;
|
|
42012
|
+
transactItems.push({
|
|
42013
|
+
Delete: { TableName: tableName, Key: { PK: resource, SK: shadowSK } }
|
|
42014
|
+
});
|
|
42015
|
+
}
|
|
41900
42016
|
for (const shadowSK of record.shadowKeys) {
|
|
41901
42017
|
transactItems.push({
|
|
41902
42018
|
Put: {
|
|
@@ -41926,8 +42042,26 @@ async function handleInsertMany(resource, params, requestId) {
|
|
|
41926
42042
|
} else {
|
|
41927
42043
|
costTracker.add(result.ConsumedCapacity);
|
|
41928
42044
|
}
|
|
41929
|
-
|
|
41930
|
-
|
|
42045
|
+
}, "writeChunk");
|
|
42046
|
+
const executeChunk = /* @__PURE__ */ __name((chunk) => writeWithConflictRetry(chunk, writeChunk, async (stale) => {
|
|
42047
|
+
const items = await batchGetAll(
|
|
42048
|
+
stale.map((record) => ({ PK: resource, SK: record.mainSK })),
|
|
42049
|
+
{ consistentRead: true, costTracker, requestId }
|
|
42050
|
+
);
|
|
42051
|
+
const fresh = new Map(items.map((item) => [item.SK, item]));
|
|
42052
|
+
return stale.map((record) => {
|
|
42053
|
+
const item = fresh.get(record.mainSK);
|
|
42054
|
+
if (!item) return { ...record, existing: void 0 };
|
|
42055
|
+
const data = item.data;
|
|
42056
|
+
return {
|
|
42057
|
+
...record,
|
|
42058
|
+
existing: {
|
|
42059
|
+
revision: revisionOf(item),
|
|
42060
|
+
shadowKeys: item.__shadowKeys ?? data?.__shadowKeys ?? []
|
|
42061
|
+
}
|
|
42062
|
+
};
|
|
42063
|
+
});
|
|
42064
|
+
}), "executeChunk");
|
|
41931
42065
|
const {
|
|
41932
42066
|
successRecords,
|
|
41933
42067
|
failedIds: chunkFailedIds,
|
|
@@ -42027,10 +42161,12 @@ var init_insertMany = __esm({
|
|
|
42027
42161
|
init_shared();
|
|
42028
42162
|
init_shadow();
|
|
42029
42163
|
init_shadow();
|
|
42164
|
+
init_batchGet();
|
|
42030
42165
|
init_bulkOperations();
|
|
42031
42166
|
init_chunking();
|
|
42032
42167
|
init_cost_tracker();
|
|
42033
42168
|
init_dynamodb3();
|
|
42169
|
+
init_revision();
|
|
42034
42170
|
init_timestamps();
|
|
42035
42171
|
init_ttl();
|
|
42036
42172
|
logger18 = createLogger({ service: "records-lambda" });
|
|
@@ -42146,6 +42282,71 @@ var init_mergePatch = __esm({
|
|
|
42146
42282
|
}
|
|
42147
42283
|
});
|
|
42148
42284
|
|
|
42285
|
+
// src/server/utils/updateOperators.ts
|
|
42286
|
+
function invalid(message) {
|
|
42287
|
+
return new AppError("VALIDATION_ERROR" /* VALIDATION_ERROR */, message, 400);
|
|
42288
|
+
}
|
|
42289
|
+
function asObject(value, operator) {
|
|
42290
|
+
if (value === void 0) return {};
|
|
42291
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
42292
|
+
throw invalid(`${operator} must be an object`);
|
|
42293
|
+
}
|
|
42294
|
+
return value;
|
|
42295
|
+
}
|
|
42296
|
+
function unsetFields(value) {
|
|
42297
|
+
if (value === void 0) return [];
|
|
42298
|
+
if (Array.isArray(value)) {
|
|
42299
|
+
if (!value.every((f5) => typeof f5 === "string")) {
|
|
42300
|
+
throw invalid("$unset must be an array of field names or an object");
|
|
42301
|
+
}
|
|
42302
|
+
return value;
|
|
42303
|
+
}
|
|
42304
|
+
return Object.keys(asObject(value, "$unset"));
|
|
42305
|
+
}
|
|
42306
|
+
function resolveUpdateOperators(data) {
|
|
42307
|
+
const operators = Object.keys(data).filter((key) => key.startsWith("$"));
|
|
42308
|
+
if (operators.length === 0) {
|
|
42309
|
+
return { patch: data, setOnInsert: {}, returned: data };
|
|
42310
|
+
}
|
|
42311
|
+
const unsupported = operators.filter((op2) => !SUPPORTED_OPERATORS.includes(op2));
|
|
42312
|
+
if (unsupported.length > 0) {
|
|
42313
|
+
throw invalid(
|
|
42314
|
+
`Unsupported update operator: ${unsupported.join(", ")} (supported: ${SUPPORTED_OPERATORS.join(", ")})`
|
|
42315
|
+
);
|
|
42316
|
+
}
|
|
42317
|
+
const set = asObject(data.$set, "$set");
|
|
42318
|
+
const patch = { ...set };
|
|
42319
|
+
for (const field of unsetFields(data.$unset)) {
|
|
42320
|
+
if (field in set) {
|
|
42321
|
+
throw invalid(`Field "${field}" is in both $set and $unset`);
|
|
42322
|
+
}
|
|
42323
|
+
patch[field] = null;
|
|
42324
|
+
}
|
|
42325
|
+
return { patch, setOnInsert: asObject(data.$setOnInsert, "$setOnInsert"), returned: set };
|
|
42326
|
+
}
|
|
42327
|
+
function equalityFieldsOf(filter) {
|
|
42328
|
+
const fields = {};
|
|
42329
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
42330
|
+
if (key.includes(":") || key.startsWith("$")) continue;
|
|
42331
|
+
if (typeof value === "object" && value !== null) continue;
|
|
42332
|
+
fields[key] = value;
|
|
42333
|
+
}
|
|
42334
|
+
return fields;
|
|
42335
|
+
}
|
|
42336
|
+
var SUPPORTED_OPERATORS;
|
|
42337
|
+
var init_updateOperators = __esm({
|
|
42338
|
+
"src/server/utils/updateOperators.ts"() {
|
|
42339
|
+
"use strict";
|
|
42340
|
+
init_shared();
|
|
42341
|
+
SUPPORTED_OPERATORS = ["$set", "$setOnInsert", "$unset"];
|
|
42342
|
+
__name(invalid, "invalid");
|
|
42343
|
+
__name(asObject, "asObject");
|
|
42344
|
+
__name(unsetFields, "unsetFields");
|
|
42345
|
+
__name(resolveUpdateOperators, "resolveUpdateOperators");
|
|
42346
|
+
__name(equalityFieldsOf, "equalityFieldsOf");
|
|
42347
|
+
}
|
|
42348
|
+
});
|
|
42349
|
+
|
|
42149
42350
|
// src/server/operations/updateMany.ts
|
|
42150
42351
|
var updateMany_exports = {};
|
|
42151
42352
|
__export(updateMany_exports, {
|
|
@@ -42156,6 +42357,7 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42156
42357
|
const upsert = options?.upsert ?? false;
|
|
42157
42358
|
const startTime = Date.now();
|
|
42158
42359
|
const costTracker = new CostTracker();
|
|
42360
|
+
const update = resolveUpdateOperators(patchData);
|
|
42159
42361
|
logger20.debug("Executing updateMany", {
|
|
42160
42362
|
requestId,
|
|
42161
42363
|
resource,
|
|
@@ -42203,16 +42405,10 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42203
42405
|
newId,
|
|
42204
42406
|
filter: params.filter
|
|
42205
42407
|
});
|
|
42206
|
-
|
|
42207
|
-
|
|
42208
|
-
|
|
42209
|
-
|
|
42210
|
-
};
|
|
42211
|
-
} else if (patchData.$set) {
|
|
42212
|
-
patchData.$setOnInsert = params.filter;
|
|
42213
|
-
} else {
|
|
42214
|
-
patchData.$setOnInsert = params.filter;
|
|
42215
|
-
}
|
|
42408
|
+
update.setOnInsert = {
|
|
42409
|
+
...equalityFieldsOf(params.filter),
|
|
42410
|
+
...update.setOnInsert
|
|
42411
|
+
};
|
|
42216
42412
|
} else {
|
|
42217
42413
|
return {
|
|
42218
42414
|
count: 0,
|
|
@@ -42227,118 +42423,121 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42227
42423
|
logLargeBatchWarning("updateMany", ids.length, requestId, resource);
|
|
42228
42424
|
const dbClient2 = getDBClient();
|
|
42229
42425
|
const tableName = getTableName();
|
|
42230
|
-
const
|
|
42231
|
-
|
|
42232
|
-
|
|
42233
|
-
|
|
42234
|
-
|
|
42235
|
-
|
|
42236
|
-
|
|
42237
|
-
|
|
42238
|
-
|
|
42239
|
-
|
|
42240
|
-
|
|
42241
|
-
|
|
42242
|
-
|
|
42243
|
-
|
|
42244
|
-
resource,
|
|
42245
|
-
notFoundCount: notFoundIds.length,
|
|
42246
|
-
notFoundIds: notFoundIds.slice(0, 10)
|
|
42247
|
-
// 最初の10件のみログ
|
|
42248
|
-
});
|
|
42249
|
-
}
|
|
42250
|
-
if (upsert && notFoundIds.length > 0) {
|
|
42251
|
-
logger20.info("Creating new records (upsert: true)", {
|
|
42252
|
-
requestId,
|
|
42253
|
-
resource,
|
|
42254
|
-
notFoundCount: notFoundIds.length,
|
|
42255
|
-
notFoundIds: notFoundIds.slice(0, 10)
|
|
42256
|
-
// 最初の10件のみログ
|
|
42257
|
-
});
|
|
42258
|
-
}
|
|
42259
|
-
const shadowConfig = getShadowConfig();
|
|
42260
|
-
const preparedRecords = [];
|
|
42261
|
-
const preparationFailedIds = [];
|
|
42262
|
-
const preparationErrors = [];
|
|
42263
|
-
for (const item of existingItems) {
|
|
42264
|
-
try {
|
|
42265
|
-
const existingData = item.data;
|
|
42266
|
-
const id = existingData.id;
|
|
42267
|
-
const oldShadowKeys = item.__shadowKeys ?? existingData.__shadowKeys ?? [];
|
|
42268
|
-
const actualPatchData2 = patchData.$set ? patchData.$set : patchData;
|
|
42269
|
-
const timestampedPatch = addUpdateTimestamp(actualPatchData2);
|
|
42270
|
-
const mergedData = applyJsonMergePatch(removeShadowKeys(existingData), timestampedPatch);
|
|
42271
|
-
const updatedData = { ...mergedData, id };
|
|
42272
|
-
const newShadowRecords = generateShadowRecords(updatedData, resource, shadowConfig);
|
|
42273
|
-
const newShadowKeys = newShadowRecords.map((shadow) => shadow.SK);
|
|
42274
|
-
const mainSK = generateMainRecordSK2(id);
|
|
42275
|
-
preparedRecords.push({
|
|
42276
|
-
id,
|
|
42277
|
-
updatedData,
|
|
42278
|
-
oldShadowKeys,
|
|
42279
|
-
newShadowKeys,
|
|
42280
|
-
mainSK
|
|
42281
|
-
});
|
|
42282
|
-
} catch (error2) {
|
|
42283
|
-
const existingData = item.data;
|
|
42284
|
-
const failedId = existingData.id || "unknown-id";
|
|
42285
|
-
const errorMessage = error2 instanceof Error ? error2.message : "Unknown preparation error";
|
|
42286
|
-
const errorCode = getPreparationErrorCode2(error2);
|
|
42287
|
-
logger20.error("Failed to prepare record for update", {
|
|
42426
|
+
const prepare = /* @__PURE__ */ __name(async (targetIds) => {
|
|
42427
|
+
const existingItems = await batchGetAll(
|
|
42428
|
+
targetIds.map((id) => ({ PK: resource, SK: generateMainRecordSK2(id) })),
|
|
42429
|
+
{ consistentRead: true, costTracker, requestId }
|
|
42430
|
+
);
|
|
42431
|
+
const existingIds = new Set(
|
|
42432
|
+
existingItems.map((item) => {
|
|
42433
|
+
const data = item.data;
|
|
42434
|
+
return data.id;
|
|
42435
|
+
})
|
|
42436
|
+
);
|
|
42437
|
+
const notFoundIds2 = targetIds.filter((id) => !existingIds.has(id));
|
|
42438
|
+
if (!upsert && notFoundIds2.length > 0) {
|
|
42439
|
+
logger20.warn("Records not found (upsert: false)", {
|
|
42288
42440
|
requestId,
|
|
42289
|
-
|
|
42290
|
-
|
|
42291
|
-
|
|
42441
|
+
resource,
|
|
42442
|
+
notFoundCount: notFoundIds2.length,
|
|
42443
|
+
notFoundIds: notFoundIds2.slice(0, 10)
|
|
42444
|
+
// 最初の10件のみログ
|
|
42292
42445
|
});
|
|
42293
|
-
|
|
42294
|
-
|
|
42295
|
-
|
|
42296
|
-
|
|
42297
|
-
|
|
42446
|
+
}
|
|
42447
|
+
if (upsert && notFoundIds2.length > 0) {
|
|
42448
|
+
logger20.info("Creating new records (upsert: true)", {
|
|
42449
|
+
requestId,
|
|
42450
|
+
resource,
|
|
42451
|
+
notFoundCount: notFoundIds2.length,
|
|
42452
|
+
notFoundIds: notFoundIds2.slice(0, 10)
|
|
42453
|
+
// 最初の10件のみログ
|
|
42298
42454
|
});
|
|
42299
42455
|
}
|
|
42300
|
-
|
|
42301
|
-
|
|
42302
|
-
const
|
|
42303
|
-
|
|
42456
|
+
const shadowConfig = getShadowConfig();
|
|
42457
|
+
const preparedRecords2 = [];
|
|
42458
|
+
const preparationFailedIds2 = [];
|
|
42459
|
+
const preparationErrors2 = [];
|
|
42460
|
+
for (const item of existingItems) {
|
|
42304
42461
|
try {
|
|
42305
|
-
const
|
|
42306
|
-
const
|
|
42307
|
-
const
|
|
42308
|
-
|
|
42309
|
-
|
|
42310
|
-
|
|
42311
|
-
|
|
42312
|
-
const newData = addCreateTimestamps2(mergedData);
|
|
42313
|
-
const newShadowRecords = generateShadowRecords(newData, resource, shadowConfig);
|
|
42462
|
+
const existingData = item.data;
|
|
42463
|
+
const id = existingData.id;
|
|
42464
|
+
const oldShadowKeys = item.__shadowKeys ?? existingData.__shadowKeys ?? [];
|
|
42465
|
+
const timestampedPatch = addUpdateTimestamp(update.patch);
|
|
42466
|
+
const mergedData = applyJsonMergePatch(removeShadowKeys(existingData), timestampedPatch);
|
|
42467
|
+
const updatedData = { ...mergedData, id };
|
|
42468
|
+
const newShadowRecords = generateShadowRecords(updatedData, resource, shadowConfig);
|
|
42314
42469
|
const newShadowKeys = newShadowRecords.map((shadow) => shadow.SK);
|
|
42315
42470
|
const mainSK = generateMainRecordSK2(id);
|
|
42316
|
-
|
|
42471
|
+
preparedRecords2.push({
|
|
42317
42472
|
id,
|
|
42318
|
-
updatedData
|
|
42319
|
-
oldShadowKeys
|
|
42320
|
-
// 新規作成なので空
|
|
42473
|
+
updatedData,
|
|
42474
|
+
oldShadowKeys,
|
|
42321
42475
|
newShadowKeys,
|
|
42322
|
-
mainSK
|
|
42476
|
+
mainSK,
|
|
42477
|
+
isNew: false,
|
|
42478
|
+
revision: revisionOf(item)
|
|
42323
42479
|
});
|
|
42324
42480
|
} catch (error2) {
|
|
42481
|
+
const existingData = item.data;
|
|
42482
|
+
const failedId = existingData.id || "unknown-id";
|
|
42325
42483
|
const errorMessage = error2 instanceof Error ? error2.message : "Unknown preparation error";
|
|
42326
42484
|
const errorCode = getPreparationErrorCode2(error2);
|
|
42327
|
-
logger20.error("Failed to prepare
|
|
42485
|
+
logger20.error("Failed to prepare record for update", {
|
|
42328
42486
|
requestId,
|
|
42329
|
-
recordId:
|
|
42487
|
+
recordId: failedId,
|
|
42330
42488
|
error: errorMessage,
|
|
42331
42489
|
errorCode
|
|
42332
42490
|
});
|
|
42333
|
-
|
|
42334
|
-
|
|
42335
|
-
id,
|
|
42491
|
+
preparationFailedIds2.push(failedId);
|
|
42492
|
+
preparationErrors2.push({
|
|
42493
|
+
id: failedId,
|
|
42336
42494
|
code: errorCode,
|
|
42337
42495
|
message: errorMessage
|
|
42338
42496
|
});
|
|
42339
42497
|
}
|
|
42340
42498
|
}
|
|
42341
|
-
|
|
42499
|
+
if (upsert && notFoundIds2.length > 0) {
|
|
42500
|
+
const { addCreateTimestamps: addCreateTimestamps2 } = await Promise.resolve().then(() => (init_timestamps(), timestamps_exports));
|
|
42501
|
+
for (const id of notFoundIds2) {
|
|
42502
|
+
try {
|
|
42503
|
+
const mergedData = {
|
|
42504
|
+
...applyJsonMergePatch({}, { ...update.setOnInsert, ...update.patch }),
|
|
42505
|
+
id
|
|
42506
|
+
};
|
|
42507
|
+
const newData = addCreateTimestamps2(mergedData);
|
|
42508
|
+
const newShadowRecords = generateShadowRecords(newData, resource, shadowConfig);
|
|
42509
|
+
const newShadowKeys = newShadowRecords.map((shadow) => shadow.SK);
|
|
42510
|
+
const mainSK = generateMainRecordSK2(id);
|
|
42511
|
+
preparedRecords2.push({
|
|
42512
|
+
id,
|
|
42513
|
+
updatedData: newData,
|
|
42514
|
+
oldShadowKeys: [],
|
|
42515
|
+
// 新規作成なので空
|
|
42516
|
+
newShadowKeys,
|
|
42517
|
+
mainSK,
|
|
42518
|
+
isNew: true
|
|
42519
|
+
});
|
|
42520
|
+
} catch (error2) {
|
|
42521
|
+
const errorMessage = error2 instanceof Error ? error2.message : "Unknown preparation error";
|
|
42522
|
+
const errorCode = getPreparationErrorCode2(error2);
|
|
42523
|
+
logger20.error("Failed to prepare new record for upsert", {
|
|
42524
|
+
requestId,
|
|
42525
|
+
recordId: id,
|
|
42526
|
+
error: errorMessage,
|
|
42527
|
+
errorCode
|
|
42528
|
+
});
|
|
42529
|
+
preparationFailedIds2.push(id);
|
|
42530
|
+
preparationErrors2.push({
|
|
42531
|
+
id,
|
|
42532
|
+
code: errorCode,
|
|
42533
|
+
message: errorMessage
|
|
42534
|
+
});
|
|
42535
|
+
}
|
|
42536
|
+
}
|
|
42537
|
+
}
|
|
42538
|
+
return { preparedRecords: preparedRecords2, notFoundIds: notFoundIds2, preparationFailedIds: preparationFailedIds2, preparationErrors: preparationErrors2 };
|
|
42539
|
+
}, "prepare");
|
|
42540
|
+
const { preparedRecords, notFoundIds, preparationFailedIds, preparationErrors } = await prepare(ids);
|
|
42342
42541
|
const getItemCount = /* @__PURE__ */ __name((record) => {
|
|
42343
42542
|
const shadowDiff = calculateShadowDiff(record.oldShadowKeys, record.newShadowKeys);
|
|
42344
42543
|
return 1 + shadowDiff.toDelete.length + shadowDiff.toAdd.length;
|
|
@@ -42352,7 +42551,7 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42352
42551
|
chunks.length,
|
|
42353
42552
|
preparationRiskInfo
|
|
42354
42553
|
);
|
|
42355
|
-
const
|
|
42554
|
+
const writeChunk = /* @__PURE__ */ __name(async (chunk) => {
|
|
42356
42555
|
const transactItems = [];
|
|
42357
42556
|
for (const record of chunk) {
|
|
42358
42557
|
const shadowDiff = calculateShadowDiff(record.oldShadowKeys, record.newShadowKeys);
|
|
@@ -42363,10 +42562,13 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42363
42562
|
PK: resource,
|
|
42364
42563
|
SK: record.mainSK,
|
|
42365
42564
|
__shadowKeys: record.newShadowKeys,
|
|
42565
|
+
[REVISION_ATTRIBUTE]: nextRevision(record.revision),
|
|
42366
42566
|
data: {
|
|
42367
42567
|
...record.updatedData
|
|
42368
42568
|
}
|
|
42369
|
-
}
|
|
42569
|
+
},
|
|
42570
|
+
// 読んでから書くまでの間に、ほかの書き込みが入っていないこと(楽観ロック)
|
|
42571
|
+
...record.isNew ? notExistsCondition() : unchangedCondition(record.revision)
|
|
42370
42572
|
}
|
|
42371
42573
|
});
|
|
42372
42574
|
for (const shadowSK of shadowDiff.toDelete) {
|
|
@@ -42409,8 +42611,18 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42409
42611
|
} else {
|
|
42410
42612
|
costTracker.add(result.ConsumedCapacity);
|
|
42411
42613
|
}
|
|
42412
|
-
|
|
42413
|
-
|
|
42614
|
+
}, "writeChunk");
|
|
42615
|
+
const executeChunk = /* @__PURE__ */ __name((chunk) => writeWithConflictRetry(chunk, writeChunk, async (stale) => {
|
|
42616
|
+
const fresh = await prepare(stale.map((record) => record.id));
|
|
42617
|
+
if (fresh.preparedRecords.length !== stale.length) {
|
|
42618
|
+
throw new AppError(
|
|
42619
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
42620
|
+
"Records changed concurrently and could not be re-read for update",
|
|
42621
|
+
409
|
|
42622
|
+
);
|
|
42623
|
+
}
|
|
42624
|
+
return fresh.preparedRecords;
|
|
42625
|
+
}), "executeChunk");
|
|
42414
42626
|
const {
|
|
42415
42627
|
successRecords,
|
|
42416
42628
|
failedIds: chunkFailedIds,
|
|
@@ -42420,8 +42632,6 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42420
42632
|
const items = [];
|
|
42421
42633
|
const failedIdsMap = {};
|
|
42422
42634
|
const errorsMap = {};
|
|
42423
|
-
const actualPatchData = patchData.$set ? patchData.$set : patchData;
|
|
42424
|
-
const setOnInsertData = patchData.$setOnInsert ? patchData.$setOnInsert : {};
|
|
42425
42635
|
const successIdSet = new Set(successRecords.map((r5) => r5.id));
|
|
42426
42636
|
for (let i5 = 0; i5 < ids.length; i5++) {
|
|
42427
42637
|
const id = ids[i5];
|
|
@@ -42430,13 +42640,13 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42430
42640
|
if (upsert && notFoundIds.includes(id)) {
|
|
42431
42641
|
items.push({
|
|
42432
42642
|
id,
|
|
42433
|
-
...
|
|
42434
|
-
...
|
|
42643
|
+
...update.setOnInsert,
|
|
42644
|
+
...update.returned
|
|
42435
42645
|
});
|
|
42436
42646
|
} else {
|
|
42437
42647
|
items.push({
|
|
42438
42648
|
id,
|
|
42439
|
-
...
|
|
42649
|
+
...update.returned
|
|
42440
42650
|
});
|
|
42441
42651
|
}
|
|
42442
42652
|
}
|
|
@@ -42551,7 +42761,9 @@ var init_updateMany = __esm({
|
|
|
42551
42761
|
init_cost_tracker();
|
|
42552
42762
|
init_dynamodb3();
|
|
42553
42763
|
init_mergePatch();
|
|
42764
|
+
init_revision();
|
|
42554
42765
|
init_timestamps();
|
|
42766
|
+
init_updateOperators();
|
|
42555
42767
|
init_findAll();
|
|
42556
42768
|
logger20 = createLogger({ service: "records-lambda" });
|
|
42557
42769
|
__name(handleUpdateMany, "handleUpdateMany");
|
|
@@ -44605,7 +44817,7 @@ async function handler(event) {
|
|
|
44605
44817
|
return createCorsResponse(HTTP_STATUS.OK);
|
|
44606
44818
|
}
|
|
44607
44819
|
if (event.requestContext.http.method === "GET" && event.requestContext.http.path === "/version") {
|
|
44608
|
-
const version = "1.
|
|
44820
|
+
const version = "1.25.1";
|
|
44609
44821
|
return createSuccessResponse({ version, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, requestId);
|
|
44610
44822
|
}
|
|
44611
44823
|
if (event.requestContext.http.method !== "POST") {
|