@exabugs/dynamodb-client 1.3.39 → 1.3.40
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 +27 -0
- package/dist/server/handler.cjs +90 -19
- package/dist/server/handler.cjs.map +3 -3
- package/dist/server/operations/updateMany.d.ts.map +1 -1
- package/dist/server/operations/updateMany.js +95 -18
- package/dist/server/operations/updateMany.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,33 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.3.40] - 2026-01-11
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **updateMany upsert: true サポート**: 存在しないレコードの新規作成機能を実装
|
|
15
|
+
- `upsert: true`オプションで存在しないレコードを自動作成
|
|
16
|
+
- `$set`と`$setOnInsert`オペレーターのサポート
|
|
17
|
+
- `$set`が`$setOnInsert`より優先される仕様
|
|
18
|
+
- サーバー側ユニットテスト追加(8テスト)
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- **updateMany upsert: true バグ修正**: 存在しないレコードで`ITEM_NOT_FOUND`エラーが発生していた問題を修正
|
|
23
|
+
- 新規レコード作成処理を実装
|
|
24
|
+
- `createdAt`/`updatedAt`タイムスタンプを自動追加
|
|
25
|
+
- シャドーレコードを自動生成
|
|
26
|
+
- レスポンス形式を修正(新規作成時は`$set`と`$setOnInsert`をマージ)
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **テストカバレッジ向上**: サーバー側の`updateMany`ユニットテストを追加
|
|
31
|
+
- 基本的な更新テスト
|
|
32
|
+
- `upsert: false`のテスト
|
|
33
|
+
- `upsert: true`(insert case)のテスト
|
|
34
|
+
- `upsert: true`(update case)のテスト
|
|
35
|
+
- `upsert: true`(混在ケース)のテスト
|
|
36
|
+
|
|
10
37
|
## [1.3.39] - 2026-01-11
|
|
11
38
|
|
|
12
39
|
### Fixed
|
package/dist/server/handler.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// @exabugs/dynamodb-client v1.3.
|
|
2
|
-
// Built: 2026-01-
|
|
1
|
+
// @exabugs/dynamodb-client v1.3.40
|
|
2
|
+
// Built: 2026-01-11T00:55:44.277Z
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
@@ -31344,6 +31344,12 @@ var init_findOne = __esm({
|
|
|
31344
31344
|
});
|
|
31345
31345
|
|
|
31346
31346
|
// src/server/utils/timestamps.ts
|
|
31347
|
+
var timestamps_exports = {};
|
|
31348
|
+
__export(timestamps_exports, {
|
|
31349
|
+
addCreateTimestamps: () => addCreateTimestamps,
|
|
31350
|
+
addUpdateTimestamp: () => addUpdateTimestamp,
|
|
31351
|
+
getTimestampFields: () => getTimestampFields
|
|
31352
|
+
});
|
|
31347
31353
|
function getTimestampFields() {
|
|
31348
31354
|
const shadowConfig = getShadowConfig();
|
|
31349
31355
|
return {
|
|
@@ -31757,6 +31763,15 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
31757
31763
|
// 最初の10件のみログ
|
|
31758
31764
|
});
|
|
31759
31765
|
}
|
|
31766
|
+
if (upsert && notFoundIds.length > 0) {
|
|
31767
|
+
logger18.info("Creating new records (upsert: true)", {
|
|
31768
|
+
requestId,
|
|
31769
|
+
resource,
|
|
31770
|
+
notFoundCount: notFoundIds.length,
|
|
31771
|
+
notFoundIds: notFoundIds.slice(0, 10)
|
|
31772
|
+
// 最初の10件のみログ
|
|
31773
|
+
});
|
|
31774
|
+
}
|
|
31760
31775
|
const shadowConfig = getShadowConfig();
|
|
31761
31776
|
const preparedRecords = [];
|
|
31762
31777
|
const preparationFailedIds = [];
|
|
@@ -31801,6 +31816,47 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
31801
31816
|
});
|
|
31802
31817
|
}
|
|
31803
31818
|
}
|
|
31819
|
+
if (upsert && notFoundIds.length > 0) {
|
|
31820
|
+
const { addCreateTimestamps: addCreateTimestamps2 } = await Promise.resolve().then(() => (init_timestamps(), timestamps_exports));
|
|
31821
|
+
for (const id of notFoundIds) {
|
|
31822
|
+
try {
|
|
31823
|
+
const setData = patchData.$set ? patchData.$set : patchData;
|
|
31824
|
+
const setOnInsertData2 = patchData.$setOnInsert ? patchData.$setOnInsert : {};
|
|
31825
|
+
const mergedData = {
|
|
31826
|
+
...setOnInsertData2,
|
|
31827
|
+
...setData,
|
|
31828
|
+
id
|
|
31829
|
+
};
|
|
31830
|
+
const newData = addCreateTimestamps2(mergedData);
|
|
31831
|
+
const newShadowRecords = generateShadowRecords(newData, resource, shadowConfig);
|
|
31832
|
+
const newShadowKeys = newShadowRecords.map((shadow) => shadow.SK);
|
|
31833
|
+
const mainSK = generateMainRecordSK2(id);
|
|
31834
|
+
preparedRecords.push({
|
|
31835
|
+
id,
|
|
31836
|
+
updatedData: newData,
|
|
31837
|
+
oldShadowKeys: [],
|
|
31838
|
+
// 新規作成なので空
|
|
31839
|
+
newShadowKeys,
|
|
31840
|
+
mainSK
|
|
31841
|
+
});
|
|
31842
|
+
} catch (error2) {
|
|
31843
|
+
const errorMessage = error2 instanceof Error ? error2.message : "Unknown preparation error";
|
|
31844
|
+
const errorCode = getPreparationErrorCode2(error2);
|
|
31845
|
+
logger18.error("Failed to prepare new record for upsert", {
|
|
31846
|
+
requestId,
|
|
31847
|
+
recordId: id,
|
|
31848
|
+
error: errorMessage,
|
|
31849
|
+
errorCode
|
|
31850
|
+
});
|
|
31851
|
+
preparationFailedIds.push(id);
|
|
31852
|
+
preparationErrors.push({
|
|
31853
|
+
id,
|
|
31854
|
+
code: errorCode,
|
|
31855
|
+
message: errorMessage
|
|
31856
|
+
});
|
|
31857
|
+
}
|
|
31858
|
+
}
|
|
31859
|
+
}
|
|
31804
31860
|
const getItemCount = /* @__PURE__ */ __name((record) => {
|
|
31805
31861
|
const shadowDiff = calculateShadowDiff(record.oldShadowKeys, record.newShadowKeys);
|
|
31806
31862
|
return 1 + shadowDiff.toDelete.length + shadowDiff.toAdd.length;
|
|
@@ -31875,26 +31931,37 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
31875
31931
|
const failedIdsMap = {};
|
|
31876
31932
|
const errorsMap = {};
|
|
31877
31933
|
const actualPatchData = patchData.$set ? patchData.$set : patchData;
|
|
31934
|
+
const setOnInsertData = patchData.$setOnInsert ? patchData.$setOnInsert : {};
|
|
31878
31935
|
const successIdSet = new Set(successRecords.map((r4) => r4.id));
|
|
31879
31936
|
for (let i4 = 0; i4 < ids.length; i4++) {
|
|
31880
31937
|
const id = ids[i4];
|
|
31881
31938
|
if (successIdSet.has(id)) {
|
|
31882
31939
|
successIds[i4] = id;
|
|
31883
|
-
|
|
31884
|
-
|
|
31885
|
-
|
|
31886
|
-
|
|
31940
|
+
if (upsert && notFoundIds.includes(id)) {
|
|
31941
|
+
items.push({
|
|
31942
|
+
id,
|
|
31943
|
+
...setOnInsertData,
|
|
31944
|
+
...actualPatchData
|
|
31945
|
+
});
|
|
31946
|
+
} else {
|
|
31947
|
+
items.push({
|
|
31948
|
+
id,
|
|
31949
|
+
...actualPatchData
|
|
31950
|
+
});
|
|
31951
|
+
}
|
|
31887
31952
|
}
|
|
31888
31953
|
}
|
|
31889
|
-
|
|
31890
|
-
|
|
31891
|
-
|
|
31892
|
-
|
|
31893
|
-
|
|
31894
|
-
|
|
31895
|
-
|
|
31896
|
-
|
|
31897
|
-
|
|
31954
|
+
if (!upsert) {
|
|
31955
|
+
for (let i4 = 0; i4 < ids.length; i4++) {
|
|
31956
|
+
const id = ids[i4];
|
|
31957
|
+
if (notFoundIds.includes(id)) {
|
|
31958
|
+
failedIdsMap[i4] = id;
|
|
31959
|
+
errorsMap[i4] = {
|
|
31960
|
+
id,
|
|
31961
|
+
code: "ITEM_NOT_FOUND",
|
|
31962
|
+
message: `Record not found: ${id}`
|
|
31963
|
+
};
|
|
31964
|
+
}
|
|
31898
31965
|
}
|
|
31899
31966
|
}
|
|
31900
31967
|
for (let i4 = 0; i4 < ids.length; i4++) {
|
|
@@ -31934,9 +32001,12 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
31934
32001
|
completionRiskInfo,
|
|
31935
32002
|
{
|
|
31936
32003
|
updated: count,
|
|
31937
|
-
notFound: notFoundIds.length,
|
|
32004
|
+
notFound: upsert ? 0 : notFoundIds.length,
|
|
32005
|
+
// upsert: true の場合は0
|
|
31938
32006
|
preparationFailed: preparationFailedIds.length,
|
|
31939
|
-
chunkExecutionFailed: chunkFailedIds.length
|
|
32007
|
+
chunkExecutionFailed: chunkFailedIds.length,
|
|
32008
|
+
upserted: upsert ? notFoundIds.length : 0
|
|
32009
|
+
// upsert: true の場合は新規作成数
|
|
31940
32010
|
}
|
|
31941
32011
|
);
|
|
31942
32012
|
if (allFailedIds.length > 0) {
|
|
@@ -31949,7 +32019,8 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
31949
32019
|
allFailedIds.length,
|
|
31950
32020
|
Object.values(errorsMap).map((e4) => e4.code),
|
|
31951
32021
|
{
|
|
31952
|
-
notFoundCount: notFoundIds.length,
|
|
32022
|
+
notFoundCount: upsert ? 0 : notFoundIds.length,
|
|
32023
|
+
// upsert: true の場合は0
|
|
31953
32024
|
preparationFailures: preparationFailedIds.length,
|
|
31954
32025
|
chunkExecutionFailures: chunkFailedIds.length
|
|
31955
32026
|
}
|
|
@@ -33927,7 +33998,7 @@ async function handler(event) {
|
|
|
33927
33998
|
return createCorsResponse(HTTP_STATUS.OK);
|
|
33928
33999
|
}
|
|
33929
34000
|
if (event.requestContext.http.method === "GET" && event.requestContext.http.path === "/version") {
|
|
33930
|
-
const version = "1.3.
|
|
34001
|
+
const version = "1.3.40";
|
|
33931
34002
|
return createSuccessResponse({ version, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, requestId);
|
|
33932
34003
|
}
|
|
33933
34004
|
if (event.requestContext.http.method !== "POST") {
|