@exabugs/dynamodb-client 1.3.34 → 1.3.36
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 +31 -0
- package/dist/server/handler.cjs +736 -1638
- package/dist/server/handler.cjs.map +4 -4
- package/dist/server/operations/deleteOne.d.ts +4 -5
- package/dist/server/operations/deleteOne.d.ts.map +1 -1
- package/dist/server/operations/deleteOne.js +51 -71
- package/dist/server/operations/deleteOne.js.map +1 -1
- package/dist/server/operations/findMany.d.ts +4 -2
- package/dist/server/operations/findMany.d.ts.map +1 -1
- package/dist/server/operations/findMany.js +66 -39
- package/dist/server/operations/findMany.js.map +1 -1
- package/dist/server/operations/findOne.d.ts +5 -3
- package/dist/server/operations/findOne.d.ts.map +1 -1
- package/dist/server/operations/findOne.js +54 -37
- package/dist/server/operations/findOne.js.map +1 -1
- package/dist/server/operations/insertOne.d.ts +4 -5
- package/dist/server/operations/insertOne.d.ts.map +1 -1
- package/dist/server/operations/insertOne.js +33 -48
- package/dist/server/operations/insertOne.js.map +1 -1
- package/dist/server/operations/parameterConverter.d.ts +2 -1
- package/dist/server/operations/parameterConverter.d.ts.map +1 -1
- package/dist/server/operations/parameterConverter.js +25 -10
- package/dist/server/operations/parameterConverter.js.map +1 -1
- package/dist/server/operations/updateOne.d.ts +4 -6
- package/dist/server/operations/updateOne.d.ts.map +1 -1
- package/dist/server/operations/updateOne.js +53 -266
- package/dist/server/operations/updateOne.js.map +1 -1
- package/dist/server/types.d.ts +2 -8
- package/dist/server/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -3,75 +3,60 @@
|
|
|
3
3
|
* 単一レコードを作成する
|
|
4
4
|
*
|
|
5
5
|
* 要件: 4.1, 4.2, 5.2, 5.3
|
|
6
|
+
*
|
|
7
|
+
* リファクタリング: insertManyを内部で使用
|
|
6
8
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import { createLogger, ulid } from '../../shared/index.js';
|
|
9
|
-
import { generateShadowRecords, getShadowConfig } from '../shadow/index.js';
|
|
10
|
-
import { generateMainRecordSK } from '../shadow/index.js';
|
|
11
|
-
import { executeDynamoDBOperation, getDBClient, getTableName, } from '../utils/dynamodb.js';
|
|
12
|
-
import { addCreateTimestamps } from '../utils/timestamps.js';
|
|
13
|
-
import { addTTL } from '../utils/ttl.js';
|
|
9
|
+
import { createLogger } from '../../shared/index.js';
|
|
14
10
|
const logger = createLogger({ service: 'records-lambda' });
|
|
15
11
|
/**
|
|
16
12
|
* insertOne 操作を実行する
|
|
17
13
|
*
|
|
18
14
|
* 処理フロー:
|
|
19
|
-
* 1.
|
|
20
|
-
* 2.
|
|
21
|
-
* 3.
|
|
22
|
-
* 4. メインレコードをPutItemで保存
|
|
23
|
-
* 5. シャドーレコードをPutItemで保存
|
|
15
|
+
* 1. insertMany([data])を呼び出す
|
|
16
|
+
* 2. 結果を検証し、失敗した場合は通常のErrorをスロー
|
|
17
|
+
* 3. 成功した場合は作成されたレコードをfindOneで取得して返却
|
|
24
18
|
*
|
|
25
19
|
* @param resource - リソース名
|
|
26
20
|
* @param params - insertOneパラメータ
|
|
27
21
|
* @param requestId - リクエストID
|
|
28
22
|
* @returns 作成されたレコード
|
|
23
|
+
* @throws {Error} レコード作成に失敗した場合
|
|
29
24
|
*/
|
|
30
25
|
export async function handleInsertOne(resource, params, requestId) {
|
|
31
26
|
logger.debug('Executing insertOne', {
|
|
32
27
|
requestId,
|
|
33
28
|
resource,
|
|
34
29
|
});
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
//
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
PK: resource,
|
|
57
|
-
SK: mainSK,
|
|
58
|
-
data: recordData,
|
|
59
|
-
},
|
|
60
|
-
})), 'PutItem');
|
|
61
|
-
// シャドーレコードを保存
|
|
62
|
-
for (const shadowRecord of shadowRecords) {
|
|
63
|
-
await executeDynamoDBOperation(() => dbClient.send(new PutCommand({
|
|
64
|
-
TableName: tableName,
|
|
65
|
-
Item: shadowRecord,
|
|
66
|
-
})), 'PutItem');
|
|
30
|
+
// insertManyをインポート
|
|
31
|
+
const { handleInsertMany } = await import('./insertMany.js');
|
|
32
|
+
// insertMany([data])を呼び出す
|
|
33
|
+
const insertManyResult = await handleInsertMany(resource, {
|
|
34
|
+
data: [params.data],
|
|
35
|
+
}, requestId);
|
|
36
|
+
// 結果を検証
|
|
37
|
+
if (insertManyResult.count === 0) {
|
|
38
|
+
// 作成に失敗した場合
|
|
39
|
+
const error = Object.values(insertManyResult.errors)[0];
|
|
40
|
+
if (error) {
|
|
41
|
+
throw new Error(`Failed to create record: ${error.message}`);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
throw new Error('Failed to create record');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// 成功した場合は作成されたレコードのIDを取得
|
|
48
|
+
const createdId = Object.values(insertManyResult.successIds)[0];
|
|
49
|
+
if (!createdId) {
|
|
50
|
+
throw new Error('Failed to get created record ID');
|
|
67
51
|
}
|
|
52
|
+
// 既存のインターフェースを維持: 作成されたレコードを取得して返す
|
|
53
|
+
const { handleFindOne } = await import('./findOne.js');
|
|
54
|
+
const createdRecord = await handleFindOne(resource, { id: createdId }, requestId);
|
|
68
55
|
logger.info('insertOne succeeded', {
|
|
69
56
|
requestId,
|
|
70
57
|
resource,
|
|
71
|
-
id,
|
|
72
|
-
shadowCount: shadowRecords.length,
|
|
58
|
+
id: createdId,
|
|
73
59
|
});
|
|
74
|
-
|
|
75
|
-
return recordData;
|
|
60
|
+
return createdRecord;
|
|
76
61
|
}
|
|
77
62
|
//# sourceMappingURL=insertOne.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"insertOne.js","sourceRoot":"","sources":["../../../src/server/operations/insertOne.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"insertOne.js","sourceRoot":"","sources":["../../../src/server/operations/insertOne.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAGrD,MAAM,MAAM,GAAG,YAAY,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAE3D;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB,EAChB,MAAuB,EACvB,SAAiB;IAEjB,MAAM,CAAC,KAAK,CAAC,qBAAqB,EAAE;QAClC,SAAS;QACT,QAAQ;KACT,CAAC,CAAC;IAEH,mBAAmB;IACnB,MAAM,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,iBAAiB,CAAC,CAAC;IAE7D,0BAA0B;IAC1B,MAAM,gBAAgB,GAAG,MAAM,gBAAgB,CAC7C,QAAQ,EACR;QACE,IAAI,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC;KACpB,EACD,SAAS,CACV,CAAC;IAEF,QAAQ;IACR,IAAI,gBAAgB,CAAC,KAAK,KAAK,CAAC,EAAE,CAAC;QACjC,YAAY;QACZ,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CAAC,4BAA4B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC/D,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,yBAAyB;IACzB,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,mCAAmC;IACnC,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IACvD,MAAM,aAAa,GAAG,MAAM,aAAa,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,SAAS,CAAC,CAAC;IAElF,MAAM,CAAC,IAAI,CAAC,qBAAqB,EAAE;QACjC,SAAS;QACT,QAAQ;QACR,EAAE,EAAE,SAAS;KACd,CAAC,CAAC;IAEH,OAAO,aAAa,CAAC;AACvB,CAAC"}
|
|
@@ -60,7 +60,7 @@ export declare function convertFindParams(mongoParams: MongoFindParams): FindPar
|
|
|
60
60
|
*
|
|
61
61
|
* @param mongoParams - MongoDB風のfindOneパラメータ
|
|
62
62
|
* @returns 内部形式のfindOneパラメータ
|
|
63
|
-
* @throws {Error}
|
|
63
|
+
* @throws {Error} filterが指定されていない場合
|
|
64
64
|
*/
|
|
65
65
|
export declare function convertFindOneParams(mongoParams: MongoFilterParams): FindOneParams;
|
|
66
66
|
/**
|
|
@@ -68,6 +68,7 @@ export declare function convertFindOneParams(mongoParams: MongoFilterParams): Fi
|
|
|
68
68
|
*
|
|
69
69
|
* @param mongoParams - MongoDB風のfindManyパラメータ
|
|
70
70
|
* @returns 内部形式のfindManyパラメータ
|
|
71
|
+
* @throws {Error} filterが指定されていない場合
|
|
71
72
|
*/
|
|
72
73
|
export declare function convertFindManyParams(mongoParams: MongoFilterParams): FindManyParams;
|
|
73
74
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parameterConverter.d.ts","sourceRoot":"","sources":["../../../src/server/operations/parameterConverter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,UAAU,eAAe;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED;;GAEG;AACH,UAAU,iBAAiB;IACzB,MAAM,CAAC,EAAE;QACP,EAAE,CAAC,EAAE,MAAM,GAAG;YAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC;KAClC,CAAC;CACH;AAED;;GAEG;AACH,UAAU,iBAAkB,SAAQ,iBAAiB;IACnD,MAAM,CAAC,EACH;QACE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC,GACD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED;;GAEG;AACH,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,UAAU,oBAAoB;IAC5B,SAAS,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC5C;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,eAAe,GAAG,UAAU,CAsB1E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,iBAAiB,GAAG,aAAa,
|
|
1
|
+
{"version":3,"file":"parameterConverter.d.ts","sourceRoot":"","sources":["../../../src/server/operations/parameterConverter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EACV,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,aAAa,EACb,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,gBAAgB,EAChB,eAAe,EAChB,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,UAAU,eAAe;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC/C,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;CACH;AAED;;GAEG;AACH,UAAU,iBAAiB;IACzB,MAAM,CAAC,EAAE;QACP,EAAE,CAAC,EAAE,MAAM,GAAG;YAAE,GAAG,CAAC,EAAE,MAAM,EAAE,CAAA;SAAE,CAAC;KAClC,CAAC;CACH;AAED;;GAEG;AACH,UAAU,iBAAkB,SAAQ,iBAAiB;IACnD,MAAM,CAAC,EACH;QACE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KAChC,GACD,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5B,OAAO,CAAC,EAAE;QACR,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED;;GAEG;AACH,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,UAAU,oBAAoB;IAC5B,SAAS,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CAC5C;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,eAAe,GAAG,UAAU,CAsB1E;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,iBAAiB,GAAG,aAAa,CAgBlF;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,iBAAiB,GAAG,cAAc,CAgBpF;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,mBAAmB,GAAG,eAAe,CAOxF;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,iBAAiB,GAAG,eAAe,CAuCtF;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,iBAAiB,GAAG,gBAAgB,CAiBxF;AAED;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,iBAAiB,GAAG,eAAe,CAMtF;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,iBAAiB,GAAG,gBAAgB,CAOxF;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,oBAAoB,GAAG,gBAAgB,CAO3F"}
|
|
@@ -30,27 +30,42 @@ export function convertFindParams(mongoParams) {
|
|
|
30
30
|
*
|
|
31
31
|
* @param mongoParams - MongoDB風のfindOneパラメータ
|
|
32
32
|
* @returns 内部形式のfindOneパラメータ
|
|
33
|
-
* @throws {Error}
|
|
33
|
+
* @throws {Error} filterが指定されていない場合
|
|
34
34
|
*/
|
|
35
35
|
export function convertFindOneParams(mongoParams) {
|
|
36
|
-
|
|
37
|
-
if (!
|
|
38
|
-
throw new Error('findOne requires filter
|
|
36
|
+
// filterが存在しない場合はエラー
|
|
37
|
+
if (!mongoParams.filter) {
|
|
38
|
+
throw new Error('findOne requires filter');
|
|
39
39
|
}
|
|
40
|
-
|
|
40
|
+
// filter.idが存在する場合はidとして使用(後方互換性)
|
|
41
|
+
const id = typeof mongoParams.filter.id === 'string' ? mongoParams.filter.id : undefined;
|
|
42
|
+
if (id) {
|
|
43
|
+
// idが存在する場合は従来通りの形式
|
|
44
|
+
return { id };
|
|
45
|
+
}
|
|
46
|
+
// idが存在しない場合はfilter全体を使用
|
|
47
|
+
return { filter: mongoParams.filter };
|
|
41
48
|
}
|
|
42
49
|
/**
|
|
43
50
|
* MongoDB風のfindManyパラメータを内部形式に変換する
|
|
44
51
|
*
|
|
45
52
|
* @param mongoParams - MongoDB風のfindManyパラメータ
|
|
46
53
|
* @returns 内部形式のfindManyパラメータ
|
|
54
|
+
* @throws {Error} filterが指定されていない場合
|
|
47
55
|
*/
|
|
48
56
|
export function convertFindManyParams(mongoParams) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
57
|
+
// filterが存在しない場合はエラー
|
|
58
|
+
if (!mongoParams.filter) {
|
|
59
|
+
throw new Error('findMany requires filter');
|
|
60
|
+
}
|
|
61
|
+
const idFilter = mongoParams.filter.id;
|
|
62
|
+
// filter.id.$inが存在する場合はidsとして使用(後方互換性)
|
|
63
|
+
if (typeof idFilter === 'object' && idFilter !== null && '$in' in idFilter) {
|
|
64
|
+
const ids = idFilter.$in || [];
|
|
65
|
+
return { ids };
|
|
66
|
+
}
|
|
67
|
+
// idが存在しない場合はfilter全体を使用
|
|
68
|
+
return { filter: mongoParams.filter };
|
|
54
69
|
}
|
|
55
70
|
/**
|
|
56
71
|
* MongoDB風のinsertOneパラメータを内部形式に変換する
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parameterConverter.js","sourceRoot":"","sources":["../../../src/server/operations/parameterConverter.ts"],"names":[],"mappings":"AAkEA;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,WAA4B;IAC5D,MAAM,EAAE,MAAM,GAAG,EAAE,EAAE,OAAO,GAAG,EAAE,EAAE,GAAG,WAAW,CAAC;IAClD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC;IAE3C,MAAM,cAAc,GAAe;QACjC,MAAM;QACN,GAAG,CAAC,IAAI;YACN,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI;YAC9B,IAAI,EAAE;gBACJ,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;aAC1D;SACF,CAAC;QACJ,GAAG,CAAC,CAAC,KAAK,IAAI,SAAS,CAAC,IAAI;YAC1B,UAAU,EAAE;gBACV,GAAG,CAAC,KAAK,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;gBAChC,GAAG,CAAC,SAAS,IAAI,EAAE,SAAS,EAAE,CAAC;aAChC;SACF,CAAC;KACH,CAAC;IAEF,OAAO,cAAc,CAAC;AACxB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAA8B;IACjE,MAAM,EAAE,GAAG,OAAO,WAAW,CAAC,MAAM,
|
|
1
|
+
{"version":3,"file":"parameterConverter.js","sourceRoot":"","sources":["../../../src/server/operations/parameterConverter.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,17 +3,15 @@ import type { UpdateOneParams, UpdateOneResult } from '../types.js';
|
|
|
3
3
|
* updateOne 操作を実行する
|
|
4
4
|
*
|
|
5
5
|
* 処理フロー:
|
|
6
|
-
* 1. filter
|
|
7
|
-
* 2.
|
|
8
|
-
*
|
|
9
|
-
* - upsert=trueの場合は新規作成
|
|
10
|
-
* 3. レコードが存在する場合は更新
|
|
6
|
+
* 1. updateMany([id], data)を呼び出す(idまたはfilterから対象を特定)
|
|
7
|
+
* 2. 結果を検証し、失敗した場合は通常のErrorをスロー
|
|
8
|
+
* 3. 成功した場合は更新されたレコードをfindOneで取得して返却
|
|
11
9
|
*
|
|
12
10
|
* @param resource - リソース名
|
|
13
11
|
* @param params - updateOneパラメータ
|
|
14
12
|
* @param requestId - リクエストID
|
|
15
13
|
* @returns 更新されたレコード
|
|
16
|
-
* @throws {
|
|
14
|
+
* @throws {Error} レコードが存在しない場合、または更新に失敗した場合
|
|
17
15
|
*/
|
|
18
16
|
export declare function handleUpdateOne(resource: string, params: UpdateOneParams, requestId: string): Promise<UpdateOneResult>;
|
|
19
17
|
//# sourceMappingURL=updateOne.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updateOne.d.ts","sourceRoot":"","sources":["../../../src/server/operations/updateOne.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"updateOne.d.ts","sourceRoot":"","sources":["../../../src/server/operations/updateOne.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAIpE;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CAwF1B"}
|
|
@@ -3,71 +3,31 @@
|
|
|
3
3
|
* 単一レコードを更新する(JSON Merge Patch形式)
|
|
4
4
|
*
|
|
5
5
|
* 要件: 4.2, 4.4, 5.2, 5.3
|
|
6
|
-
*/
|
|
7
|
-
import { GetCommand, TransactWriteCommand } from '@aws-sdk/lib-dynamodb';
|
|
8
|
-
import { ItemNotFoundError, createLogger } from '../../shared/index.js';
|
|
9
|
-
import { generateShadowRecords, getShadowConfig } from '../shadow/index.js';
|
|
10
|
-
import { calculateShadowDiff, generateMainRecordSK, isDiffEmpty } from '../shadow/index.js';
|
|
11
|
-
import { executeDynamoDBOperation, getDBClient, getTableName, removeShadowKeys, } from '../utils/dynamodb.js';
|
|
12
|
-
import { addCreateTimestamps, addUpdateTimestamp } from '../utils/timestamps.js';
|
|
13
|
-
const logger = createLogger({ service: 'records-lambda' });
|
|
14
|
-
/**
|
|
15
|
-
* JSON Merge Patch (RFC 7396) を適用する
|
|
16
6
|
*
|
|
17
|
-
*
|
|
18
|
-
* - null値はフィールド削除を意味する
|
|
19
|
-
* - 配列は完全置換される
|
|
20
|
-
* - オブジェクトは再帰的にマージされる
|
|
21
|
-
*
|
|
22
|
-
* @param target - 対象オブジェクト
|
|
23
|
-
* @param patch - パッチオブジェクト
|
|
24
|
-
* @returns マージされたオブジェクト
|
|
7
|
+
* リファクタリング: updateManyを内部で使用
|
|
25
8
|
*/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
for (const [key, value] of Object.entries(patch)) {
|
|
29
|
-
if (value === null) {
|
|
30
|
-
// null値はフィールド削除
|
|
31
|
-
delete result[key];
|
|
32
|
-
}
|
|
33
|
-
else if (typeof value === 'object' &&
|
|
34
|
-
!Array.isArray(value) &&
|
|
35
|
-
value !== null &&
|
|
36
|
-
typeof result[key] === 'object' &&
|
|
37
|
-
!Array.isArray(result[key]) &&
|
|
38
|
-
result[key] !== null) {
|
|
39
|
-
// オブジェクトは再帰的にマージ
|
|
40
|
-
result[key] = applyJsonMergePatch(result[key], value);
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
// その他(配列、プリミティブ)は完全置換
|
|
44
|
-
result[key] = value;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
return result;
|
|
48
|
-
}
|
|
9
|
+
import { createLogger } from '../../shared/index.js';
|
|
10
|
+
const logger = createLogger({ service: 'records-lambda' });
|
|
49
11
|
/**
|
|
50
12
|
* updateOne 操作を実行する
|
|
51
13
|
*
|
|
52
14
|
* 処理フロー:
|
|
53
|
-
* 1. filter
|
|
54
|
-
* 2.
|
|
55
|
-
*
|
|
56
|
-
* - upsert=trueの場合は新規作成
|
|
57
|
-
* 3. レコードが存在する場合は更新
|
|
15
|
+
* 1. updateMany([id], data)を呼び出す(idまたはfilterから対象を特定)
|
|
16
|
+
* 2. 結果を検証し、失敗した場合は通常のErrorをスロー
|
|
17
|
+
* 3. 成功した場合は更新されたレコードをfindOneで取得して返却
|
|
58
18
|
*
|
|
59
19
|
* @param resource - リソース名
|
|
60
20
|
* @param params - updateOneパラメータ
|
|
61
21
|
* @param requestId - リクエストID
|
|
62
22
|
* @returns 更新されたレコード
|
|
63
|
-
* @throws {
|
|
23
|
+
* @throws {Error} レコードが存在しない場合、または更新に失敗した場合
|
|
64
24
|
*/
|
|
65
25
|
export async function handleUpdateOne(resource, params, requestId) {
|
|
66
26
|
const { data: patchData, options } = params;
|
|
67
|
-
|
|
27
|
+
// updateManyをインポート
|
|
28
|
+
const { handleUpdateMany } = await import('./updateMany.js');
|
|
68
29
|
// idまたはfilterから対象レコードを特定
|
|
69
30
|
let targetId;
|
|
70
|
-
let existingItem;
|
|
71
31
|
if ('id' in params) {
|
|
72
32
|
// idが指定されている場合
|
|
73
33
|
targetId = params.id;
|
|
@@ -75,21 +35,28 @@ export async function handleUpdateOne(resource, params, requestId) {
|
|
|
75
35
|
requestId,
|
|
76
36
|
resource,
|
|
77
37
|
id: targetId,
|
|
78
|
-
upsert,
|
|
38
|
+
upsert: options?.upsert,
|
|
79
39
|
});
|
|
80
|
-
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
40
|
+
// updateMany([id], data)を呼び出す
|
|
41
|
+
const updateManyResult = await handleUpdateMany(resource, {
|
|
42
|
+
ids: [targetId],
|
|
43
|
+
data: patchData,
|
|
44
|
+
}, requestId);
|
|
45
|
+
// 結果を検証
|
|
46
|
+
if (updateManyResult.count === 0) {
|
|
47
|
+
// 更新に失敗した場合
|
|
48
|
+
const error = Object.values(updateManyResult.errors)[0];
|
|
49
|
+
if (error) {
|
|
50
|
+
throw new Error(`Failed to update record: ${error.message}`);
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
throw new Error(`Failed to update record: ${targetId}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
// 成功した場合は更新されたレコードをfindOneで取得
|
|
57
|
+
const { handleFindOne } = await import('./findOne.js');
|
|
58
|
+
const updatedRecord = await handleFindOne(resource, { id: targetId }, requestId);
|
|
59
|
+
return updatedRecord;
|
|
93
60
|
}
|
|
94
61
|
else {
|
|
95
62
|
// filterが指定されている場合
|
|
@@ -97,213 +64,33 @@ export async function handleUpdateOne(resource, params, requestId) {
|
|
|
97
64
|
requestId,
|
|
98
65
|
resource,
|
|
99
66
|
filter: params.filter,
|
|
100
|
-
upsert,
|
|
67
|
+
upsert: options?.upsert,
|
|
101
68
|
});
|
|
102
|
-
// filter
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
SK: mainSK,
|
|
117
|
-
},
|
|
118
|
-
ConsistentRead: true,
|
|
119
|
-
})), 'GetItem');
|
|
120
|
-
existingItem = getResult.Item;
|
|
121
|
-
}
|
|
122
|
-
else {
|
|
123
|
-
// レコードが見つからない場合
|
|
124
|
-
if (!upsert) {
|
|
125
|
-
throw new ItemNotFoundError(`Record not found with filter`, {
|
|
126
|
-
resource,
|
|
127
|
-
filter: params.filter,
|
|
128
|
-
});
|
|
69
|
+
// updateMany({ filter }, data)を呼び出す
|
|
70
|
+
const updateManyResult = await handleUpdateMany(resource, {
|
|
71
|
+
filter: params.filter,
|
|
72
|
+
data: patchData,
|
|
73
|
+
}, requestId);
|
|
74
|
+
// 結果を検証
|
|
75
|
+
if (updateManyResult.count === 0) {
|
|
76
|
+
// 更新に失敗した場合
|
|
77
|
+
const error = Object.values(updateManyResult.errors)[0];
|
|
78
|
+
if (error) {
|
|
79
|
+
throw new Error(`Failed to update record: ${error.message}`);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
throw new Error(`No records found matching filter`);
|
|
129
83
|
}
|
|
130
|
-
// upsert=trueの場合、新しいIDを生成
|
|
131
|
-
const { ulid } = await import('../../shared/index.js');
|
|
132
|
-
targetId = ulid();
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
// レコードが存在しない場合の処理
|
|
136
|
-
if (!existingItem) {
|
|
137
|
-
if (!upsert) {
|
|
138
|
-
// upsert=falseの場合はエラー
|
|
139
|
-
throw new ItemNotFoundError(`Record not found: ${targetId}`, { resource, id: targetId });
|
|
140
84
|
}
|
|
141
|
-
//
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
return await handleUpsertUpdate(resource, targetId, existingItem, patchData, requestId);
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* upsertで新規作成
|
|
149
|
-
*
|
|
150
|
-
* 処理フロー:
|
|
151
|
-
* 1. $set と $setOnInsert をマージ($set が優先)
|
|
152
|
-
* 2. createdAt と updatedAt を自動設定
|
|
153
|
-
* 3. シャドーレコードを生成
|
|
154
|
-
* 4. TransactWriteItemsでメインレコード + シャドーレコードを一括作成
|
|
155
|
-
*
|
|
156
|
-
* @param resource - リソース名
|
|
157
|
-
* @param id - レコードID
|
|
158
|
-
* @param data - レコードデータ(UpdateOperators形式)
|
|
159
|
-
* @param requestId - リクエストID
|
|
160
|
-
* @returns 作成されたレコード(__upsertedIdフラグ付き)
|
|
161
|
-
*/
|
|
162
|
-
async function handleUpsertCreate(resource, id, data, requestId) {
|
|
163
|
-
// UpdateOperators形式の場合、$set と $setOnInsert をマージ
|
|
164
|
-
const $set = data.$set || {};
|
|
165
|
-
const $setOnInsert = data.$setOnInsert || {};
|
|
166
|
-
// $set が $setOnInsert より優先される
|
|
167
|
-
const mergedData = {
|
|
168
|
-
...$setOnInsert,
|
|
169
|
-
...$set,
|
|
170
|
-
};
|
|
171
|
-
// createdAt と updatedAt を自動設定
|
|
172
|
-
const recordData = addCreateTimestamps({ ...mergedData, id });
|
|
173
|
-
// シャドー設定を取得
|
|
174
|
-
const shadowConfig = getShadowConfig();
|
|
175
|
-
// シャドウレコードを生成
|
|
176
|
-
const shadowRecords = generateShadowRecords(recordData, resource, shadowConfig);
|
|
177
|
-
const shadowKeys = shadowRecords.map((shadow) => shadow.SK);
|
|
178
|
-
// TransactWriteItemsで一括作成
|
|
179
|
-
const transactItems = [];
|
|
180
|
-
// メインレコードを作成
|
|
181
|
-
transactItems.push({
|
|
182
|
-
Put: {
|
|
183
|
-
TableName: getTableName(),
|
|
184
|
-
Item: {
|
|
185
|
-
PK: resource,
|
|
186
|
-
SK: generateMainRecordSK(id),
|
|
187
|
-
data: {
|
|
188
|
-
...recordData,
|
|
189
|
-
__shadowKeys: shadowKeys,
|
|
190
|
-
},
|
|
191
|
-
},
|
|
192
|
-
},
|
|
193
|
-
});
|
|
194
|
-
// シャドウレコードを作成
|
|
195
|
-
for (const shadowRecord of shadowRecords) {
|
|
196
|
-
transactItems.push({
|
|
197
|
-
Put: {
|
|
198
|
-
TableName: getTableName(),
|
|
199
|
-
Item: shadowRecord,
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
}
|
|
203
|
-
// トランザクション実行
|
|
204
|
-
await executeDynamoDBOperation(() => getDBClient().send(new TransactWriteCommand({
|
|
205
|
-
TransactItems: transactItems,
|
|
206
|
-
})), 'TransactWriteItems');
|
|
207
|
-
logger.info('updateOne upsert created', {
|
|
208
|
-
requestId,
|
|
209
|
-
resource,
|
|
210
|
-
id,
|
|
211
|
-
shadowsCreated: shadowKeys.length,
|
|
212
|
-
});
|
|
213
|
-
// upsertedIdフラグを付けて返す(クライアント側で変換)
|
|
214
|
-
return {
|
|
215
|
-
...removeShadowKeys(recordData),
|
|
216
|
-
__upsertedId: id,
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
/**
|
|
220
|
-
* upsertで更新
|
|
221
|
-
*
|
|
222
|
-
* 処理フロー:
|
|
223
|
-
* 1. UpdateOperators形式の場合、$set のみを抽出($setOnInsert は無視)
|
|
224
|
-
* 2. JSON Merge Patchを適用
|
|
225
|
-
* 3. updatedAt を更新
|
|
226
|
-
* 4. 新しいシャドーSKを生成
|
|
227
|
-
* 5. 旧シャドーと新シャドーの差分を計算
|
|
228
|
-
* 6. TransactWriteItemsでメインレコード更新 + 旧シャドー削除 + 新シャドー追加
|
|
229
|
-
*
|
|
230
|
-
* @param resource - リソース名
|
|
231
|
-
* @param id - レコードID
|
|
232
|
-
* @param existingItem - 既存のDynamoDBアイテム
|
|
233
|
-
* @param patchData - パッチデータ(UpdateOperators形式または通常のパッチ)
|
|
234
|
-
* @param requestId - リクエストID
|
|
235
|
-
* @returns 更新されたレコード
|
|
236
|
-
*/
|
|
237
|
-
async function handleUpsertUpdate(resource, id, existingItem, patchData, requestId) {
|
|
238
|
-
const existingData = existingItem.data;
|
|
239
|
-
const oldShadowKeys = existingData.__shadowKeys || [];
|
|
240
|
-
// UpdateOperators形式の場合、$set のみを抽出($setOnInsert は無視)
|
|
241
|
-
const actualPatchData = patchData.$set ? patchData.$set : patchData;
|
|
242
|
-
// JSON Merge Patchを適用
|
|
243
|
-
const mergedData = applyJsonMergePatch(removeShadowKeys(existingData), actualPatchData);
|
|
244
|
-
// updatedAt を更新
|
|
245
|
-
const updatedData = addUpdateTimestamp({
|
|
246
|
-
...mergedData,
|
|
247
|
-
id, // IDは変更不可
|
|
248
|
-
});
|
|
249
|
-
// シャドー設定を取得
|
|
250
|
-
const shadowConfig = getShadowConfig();
|
|
251
|
-
// 新しいシャドーレコードを生成
|
|
252
|
-
const newShadowRecords = generateShadowRecords(updatedData, resource, shadowConfig);
|
|
253
|
-
const newShadowKeys = newShadowRecords.map((shadow) => shadow.SK);
|
|
254
|
-
// シャドー差分を計算
|
|
255
|
-
const shadowDiff = calculateShadowDiff(oldShadowKeys, newShadowKeys);
|
|
256
|
-
// TransactWriteItemsで一括更新
|
|
257
|
-
const transactItems = [];
|
|
258
|
-
// メインレコードを更新
|
|
259
|
-
transactItems.push({
|
|
260
|
-
Put: {
|
|
261
|
-
TableName: getTableName(),
|
|
262
|
-
Item: {
|
|
263
|
-
PK: resource,
|
|
264
|
-
SK: generateMainRecordSK(id),
|
|
265
|
-
data: {
|
|
266
|
-
...updatedData,
|
|
267
|
-
__shadowKeys: newShadowKeys,
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
});
|
|
272
|
-
// 旧シャドーを削除
|
|
273
|
-
for (const shadowSK of shadowDiff.toDelete) {
|
|
274
|
-
transactItems.push({
|
|
275
|
-
Delete: {
|
|
276
|
-
TableName: getTableName(),
|
|
277
|
-
Key: {
|
|
278
|
-
PK: resource,
|
|
279
|
-
SK: shadowSK,
|
|
280
|
-
},
|
|
281
|
-
},
|
|
282
|
-
});
|
|
283
|
-
}
|
|
284
|
-
// 新シャドーを追加
|
|
285
|
-
for (const shadowRecord of newShadowRecords) {
|
|
286
|
-
if (shadowDiff.toAdd.includes(shadowRecord.SK)) {
|
|
287
|
-
transactItems.push({
|
|
288
|
-
Put: {
|
|
289
|
-
TableName: getTableName(),
|
|
290
|
-
Item: shadowRecord,
|
|
291
|
-
},
|
|
292
|
-
});
|
|
85
|
+
// 成功した場合は更新されたレコードのIDを取得
|
|
86
|
+
const updatedId = Object.values(updateManyResult.successIds)[0];
|
|
87
|
+
if (!updatedId) {
|
|
88
|
+
throw new Error('Failed to get updated record ID');
|
|
293
89
|
}
|
|
90
|
+
// findOneで更新されたレコードを取得
|
|
91
|
+
const { handleFindOne } = await import('./findOne.js');
|
|
92
|
+
const updatedRecord = await handleFindOne(resource, { id: updatedId }, requestId);
|
|
93
|
+
return updatedRecord;
|
|
294
94
|
}
|
|
295
|
-
// トランザクション実行
|
|
296
|
-
await executeDynamoDBOperation(() => getDBClient().send(new TransactWriteCommand({
|
|
297
|
-
TransactItems: transactItems,
|
|
298
|
-
})), 'TransactWriteItems');
|
|
299
|
-
logger.info('updateOne upsert updated', {
|
|
300
|
-
requestId,
|
|
301
|
-
resource,
|
|
302
|
-
id,
|
|
303
|
-
shadowDiffEmpty: isDiffEmpty(shadowDiff),
|
|
304
|
-
shadowsDeleted: shadowDiff.toDelete.length,
|
|
305
|
-
shadowsAdded: shadowDiff.toAdd.length,
|
|
306
|
-
});
|
|
307
|
-
return removeShadowKeys(updatedData);
|
|
308
95
|
}
|
|
309
96
|
//# sourceMappingURL=updateOne.js.map
|