@exabugs/dynamodb-client 1.3.40 → 1.3.42

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 CHANGED
@@ -7,6 +7,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [1.3.42] - 2026-01-15
11
+
12
+ ### Added
13
+
14
+ - **ドット記法サポート**: `$set`オペレーターでドット記法(例: `"settings.locationEnabled"`)をサポート
15
+ - ネストされたオブジェクトとして正しく保存される(例: `settings: { locationEnabled: true }`)
16
+ - `expandDotNotation`ヘルパー関数を追加
17
+ - `applyJsonMergePatch`関数を更新してドット記法を展開
18
+ - ユニットテスト追加(10テスト)
19
+
20
+ ### Fixed
21
+
22
+ - **ドット記法の文字列キー問題**: `$set: { "settings.locationEnabled": true }`が文字列キーとして保存されていた問題を修正
23
+ - 以前: `{ "settings.locationEnabled": true }` (文字列キー)
24
+ - 修正後: `{ settings: { locationEnabled: true } }` (ネストされたオブジェクト)
25
+
26
+ ## [1.3.41] - 2026-01-11
27
+
28
+ ### Added
29
+
30
+ - **updateOne filter版 upsert: true サポート**: filterで検索して存在しない場合に新規作成する機能を実装
31
+ - filter版で`upsert: true`オプションをサポート
32
+ - filterの条件を`$setOnInsert`に自動マージ
33
+ - 新規IDを自動生成(UUID)
34
+ - サーバー側ユニットテスト追加(8テスト)
35
+
36
+ ### Fixed
37
+
38
+ - **updateOne filter版 upsert: true バグ修正**: filterで検索して存在しない場合に`No records found matching filter`エラーが発生していた問題を修正
39
+ - `updateMany`のfilter版でレコードが見つからない場合の処理を実装
40
+ - 新規レコード作成時にfilterの条件を`$setOnInsert`にマージ
41
+ - FCMトークン登録(`{ token: "..." }`でupsert)が正常に動作するように修正
42
+
43
+ ### Changed
44
+
45
+ - **テストカバレッジ向上**: サーバー側の`updateOne`ユニットテストを追加(全707テスト成功)
46
+
10
47
  ## [1.3.40] - 2026-01-11
11
48
 
12
49
  ### Added
@@ -1,5 +1,5 @@
1
- // @exabugs/dynamodb-client v1.3.40
2
- // Built: 2026-01-11T00:55:44.277Z
1
+ // @exabugs/dynamodb-client v1.3.42
2
+ // Built: 2026-01-15T00:42:00.085Z
3
3
  "use strict";
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -31670,9 +31670,33 @@ var updateMany_exports = {};
31670
31670
  __export(updateMany_exports, {
31671
31671
  handleUpdateMany: () => handleUpdateMany
31672
31672
  });
31673
+ function expandDotNotation(patch) {
31674
+ const result = {};
31675
+ for (const [key, value] of Object.entries(patch)) {
31676
+ if (key.includes(".")) {
31677
+ const keys = key.split(".");
31678
+ let current = result;
31679
+ for (let i4 = 0; i4 < keys.length - 1; i4++) {
31680
+ const k4 = keys[i4];
31681
+ if (!(k4 in current)) {
31682
+ current[k4] = {};
31683
+ } else if (typeof current[k4] !== "object" || Array.isArray(current[k4])) {
31684
+ current[k4] = {};
31685
+ }
31686
+ current = current[k4];
31687
+ }
31688
+ const lastKey = keys[keys.length - 1];
31689
+ current[lastKey] = value;
31690
+ } else {
31691
+ result[key] = value;
31692
+ }
31693
+ }
31694
+ return result;
31695
+ }
31673
31696
  function applyJsonMergePatch(target, patch) {
31697
+ const expandedPatch = expandDotNotation(patch);
31674
31698
  const result = { ...target };
31675
- for (const [key, value] of Object.entries(patch)) {
31699
+ for (const [key, value] of Object.entries(expandedPatch)) {
31676
31700
  if (value === null) {
31677
31701
  delete result[key];
31678
31702
  } else if (typeof value === "object" && !Array.isArray(value) && value !== null && typeof result[key] === "object" && !Array.isArray(result[key]) && result[key] !== null) {
@@ -31717,14 +31741,36 @@ async function handleUpdateMany(resource, params, requestId) {
31717
31741
  resource,
31718
31742
  count: ids.length
31719
31743
  });
31720
- }
31721
- if (ids.length === 0) {
31722
- return {
31723
- count: 0,
31724
- successIds: {},
31725
- failedIds: {},
31726
- errors: {}
31727
- };
31744
+ if (ids.length === 0) {
31745
+ if (upsert) {
31746
+ const { randomUUID } = await import("crypto");
31747
+ const newId = randomUUID();
31748
+ ids = [newId];
31749
+ logger18.info("Creating new record with filter (upsert: true)", {
31750
+ requestId,
31751
+ resource,
31752
+ newId,
31753
+ filter: params.filter
31754
+ });
31755
+ if (patchData.$setOnInsert) {
31756
+ patchData.$setOnInsert = {
31757
+ ...params.filter,
31758
+ ...patchData.$setOnInsert
31759
+ };
31760
+ } else if (patchData.$set) {
31761
+ patchData.$setOnInsert = params.filter;
31762
+ } else {
31763
+ patchData.$setOnInsert = params.filter;
31764
+ }
31765
+ } else {
31766
+ return {
31767
+ count: 0,
31768
+ successIds: {},
31769
+ failedIds: {},
31770
+ errors: {}
31771
+ };
31772
+ }
31773
+ }
31728
31774
  }
31729
31775
  logLargeBatchWarning("updateMany", ids.length, requestId, resource);
31730
31776
  const dbClient2 = getDBClient();
@@ -32059,6 +32105,7 @@ var init_updateMany = __esm({
32059
32105
  init_dynamodb3();
32060
32106
  init_timestamps();
32061
32107
  logger18 = createLogger({ service: "records-lambda" });
32108
+ __name(expandDotNotation, "expandDotNotation");
32062
32109
  __name(applyJsonMergePatch, "applyJsonMergePatch");
32063
32110
  __name(handleUpdateMany, "handleUpdateMany");
32064
32111
  __name(getPreparationErrorCode2, "getPreparationErrorCode");
@@ -33998,7 +34045,7 @@ async function handler(event) {
33998
34045
  return createCorsResponse(HTTP_STATUS.OK);
33999
34046
  }
34000
34047
  if (event.requestContext.http.method === "GET" && event.requestContext.http.path === "/version") {
34001
- const version = "1.3.40";
34048
+ const version = "1.3.42";
34002
34049
  return createSuccessResponse({ version, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, requestId);
34003
34050
  }
34004
34051
  if (event.requestContext.http.method !== "POST") {