@exabugs/dynamodb-client 1.8.0 → 1.10.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/CHANGELOG.md +36 -0
- package/README.md +1 -0
- package/dist/client/FindCursor.d.ts +11 -6
- package/dist/client/FindCursor.d.ts.map +1 -1
- package/dist/client/FindCursor.js +30 -11
- package/dist/client/FindCursor.js.map +1 -1
- package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyField.d.ts.map +1 -1
- package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyField.js +5 -4
- package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyField.js.map +1 -1
- package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyInput.d.ts.map +1 -1
- package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyInput.js +5 -4
- package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyInput.js.map +1 -1
- package/dist/integrations/react-admin/components/ReferenceManyToMany/useGetListAll.d.ts +19 -0
- package/dist/integrations/react-admin/components/ReferenceManyToMany/useGetListAll.d.ts.map +1 -0
- package/dist/integrations/react-admin/components/ReferenceManyToMany/useGetListAll.js +36 -0
- package/dist/integrations/react-admin/components/ReferenceManyToMany/useGetListAll.js.map +1 -0
- package/dist/integrations/react-admin/dataProvider.d.ts +15 -1
- package/dist/integrations/react-admin/dataProvider.d.ts.map +1 -1
- package/dist/integrations/react-admin/dataProvider.js +61 -4
- package/dist/integrations/react-admin/dataProvider.js.map +1 -1
- package/dist/integrations/react-admin/index.d.ts +1 -0
- package/dist/integrations/react-admin/index.d.ts.map +1 -1
- package/dist/integrations/react-admin/index.js.map +1 -1
- package/dist/server/handler.cjs +683 -499
- package/dist/server/handler.cjs.map +4 -4
- package/dist/server/media-handler.cjs +2 -2
- package/dist/server/media-process-handler-dlq.cjs +544 -344
- package/dist/server/media-process-handler-dlq.cjs.map +4 -4
- package/dist/server/media-process-handler.cjs +543 -343
- package/dist/server/media-process-handler.cjs.map +4 -4
- package/dist/server/operations/deleteMany.d.ts.map +1 -1
- package/dist/server/operations/deleteMany.js +15 -30
- package/dist/server/operations/deleteMany.js.map +1 -1
- package/dist/server/operations/deleteOne.d.ts.map +1 -1
- package/dist/server/operations/deleteOne.js +7 -4
- package/dist/server/operations/deleteOne.js.map +1 -1
- package/dist/server/operations/find/idQuery.d.ts.map +1 -1
- package/dist/server/operations/find/idQuery.js +23 -9
- package/dist/server/operations/find/idQuery.js.map +1 -1
- package/dist/server/operations/find/nearQuery.d.ts.map +1 -1
- package/dist/server/operations/find/nearQuery.js +41 -40
- package/dist/server/operations/find/nearQuery.js.map +1 -1
- package/dist/server/operations/find/shadowQuery.d.ts +7 -0
- package/dist/server/operations/find/shadowQuery.d.ts.map +1 -1
- package/dist/server/operations/find/shadowQuery.js +34 -42
- package/dist/server/operations/find/shadowQuery.js.map +1 -1
- package/dist/server/operations/findAll.d.ts +8 -0
- package/dist/server/operations/findAll.d.ts.map +1 -0
- package/dist/server/operations/findAll.js +46 -0
- package/dist/server/operations/findAll.js.map +1 -0
- package/dist/server/operations/findMany.d.ts.map +1 -1
- package/dist/server/operations/findMany.js +9 -26
- package/dist/server/operations/findMany.js.map +1 -1
- package/dist/server/operations/findManyReference.d.ts.map +1 -1
- package/dist/server/operations/findManyReference.js +4 -14
- package/dist/server/operations/findManyReference.js.map +1 -1
- package/dist/server/operations/parameterConverter.d.ts.map +1 -1
- package/dist/server/operations/parameterConverter.js +16 -8
- package/dist/server/operations/parameterConverter.js.map +1 -1
- package/dist/server/operations/updateMany.d.ts.map +1 -1
- package/dist/server/operations/updateMany.js +15 -30
- package/dist/server/operations/updateMany.js.map +1 -1
- package/dist/server/operations/updateOne.d.ts.map +1 -1
- package/dist/server/operations/updateOne.js +8 -6
- package/dist/server/operations/updateOne.js.map +1 -1
- package/dist/server/utils/batchGet.d.ts +21 -0
- package/dist/server/utils/batchGet.d.ts.map +1 -0
- package/dist/server/utils/batchGet.js +73 -0
- package/dist/server/utils/batchGet.js.map +1 -0
- package/dist/server/utils/scanWarning.d.ts +30 -0
- package/dist/server/utils/scanWarning.d.ts.map +1 -0
- package/dist/server/utils/scanWarning.js +63 -0
- package/dist/server/utils/scanWarning.js.map +1 -0
- package/dist/shared/utils/index.d.ts +1 -0
- package/dist/shared/utils/index.d.ts.map +1 -1
- package/dist/shared/utils/index.js +1 -0
- package/dist/shared/utils/index.js.map +1 -1
- package/dist/shared/utils/scanSort.d.ts +16 -0
- package/dist/shared/utils/scanSort.d.ts.map +1 -0
- package/dist/shared/utils/scanSort.js +33 -0
- package/dist/shared/utils/scanSort.js.map +1 -0
- package/dist/sharp-layer.zip +0 -0
- package/docs/README.md +286 -0
- package/docs/SCAN_WARNING.md +81 -0
- package/package.json +2 -1
- package/terraform/README.md +8 -6
- package/terraform/main.tf +40 -1
- package/terraform/outputs.tf +13 -0
- package/terraform/variables.tf +17 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deleteMany.d.ts","sourceRoot":"","sources":["../../../src/server/operations/deleteMany.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAkB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"deleteMany.d.ts","sourceRoot":"","sources":["../../../src/server/operations/deleteMany.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAkB,MAAM,aAAa,CAAC;AA4BtF;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,gBAAgB,CAAC,CAkT3B"}
|
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
*
|
|
5
5
|
* 要件: 4.4, 5.2, 5.3, 7.4, 13.1, 13.2, 13.3, 13.9, 13.12
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
import { createLogger } from '../../shared/index.js';
|
|
7
|
+
import { TransactWriteCommand } from '@aws-sdk/lib-dynamodb';
|
|
8
|
+
import { AppError, ErrorCode, createLogger } from '../../shared/index.js';
|
|
9
9
|
import { generateMainRecordSK } from '../shadow/index.js';
|
|
10
|
+
import { batchGetAll } from '../utils/batchGet.js';
|
|
10
11
|
import { calculateTimeoutRisk, logBulkOperationComplete, logLargeBatchWarning, logPartialFailure, logPreparationTimeoutRisk, } from '../utils/bulkOperations.js';
|
|
11
12
|
import { calculateChunks, executeChunks } from '../utils/chunking.js';
|
|
12
13
|
import { CostTracker } from '../utils/cost-tracker.js';
|
|
13
14
|
import { executeDynamoDBOperation, getDBClient, getTableName } from '../utils/dynamodb.js';
|
|
15
|
+
import { findAllByFilter } from './findAll.js';
|
|
14
16
|
const logger = createLogger({ service: 'records-lambda' });
|
|
15
17
|
/**
|
|
16
18
|
* deleteMany 操作を実行する
|
|
@@ -49,10 +51,14 @@ export async function handleDeleteMany(resource, params, requestId) {
|
|
|
49
51
|
resource,
|
|
50
52
|
filter: params.filter,
|
|
51
53
|
});
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
// 条件なし(全件)への更新・削除は、意図しない全件操作を防ぐため受け付けない
|
|
55
|
+
// (全件が対象なら、ids を明示するか、find で取得した id を渡すこと)
|
|
56
|
+
if (Object.keys(params.filter).length === 0) {
|
|
57
|
+
throw new AppError(ErrorCode.VALIDATION_ERROR, 'deleteMany requires a non-empty filter or ids', 400);
|
|
58
|
+
}
|
|
59
|
+
// filterに一致する全件を取得する(1ページだけでは対象の一部が漏れる)
|
|
60
|
+
const matched = await findAllByFilter(resource, params.filter, requestId);
|
|
61
|
+
ids = matched.map((item) => item.id);
|
|
56
62
|
logger.debug('Found records with filter', {
|
|
57
63
|
requestId,
|
|
58
64
|
resource,
|
|
@@ -73,30 +79,9 @@ export async function handleDeleteMany(resource, params, requestId) {
|
|
|
73
79
|
logLargeBatchWarning('deleteMany', ids.length, requestId, resource);
|
|
74
80
|
const dbClient = getDBClient();
|
|
75
81
|
const tableName = getTableName();
|
|
76
|
-
// BatchGetItem
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
SK: generateMainRecordSK(id),
|
|
80
|
-
}));
|
|
81
|
-
const batchGetResult = await executeDynamoDBOperation(() => dbClient.send(new BatchGetCommand({
|
|
82
|
-
RequestItems: {
|
|
83
|
-
[tableName]: {
|
|
84
|
-
Keys: keys,
|
|
85
|
-
ConsistentRead: true,
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
ReturnConsumedCapacity: 'TOTAL',
|
|
89
|
-
})), 'BatchGetItem');
|
|
90
|
-
// コスト情報を収集
|
|
91
|
-
if (Array.isArray(batchGetResult.ConsumedCapacity)) {
|
|
92
|
-
for (const capacity of batchGetResult.ConsumedCapacity) {
|
|
93
|
-
costTracker.add(capacity);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
else {
|
|
97
|
-
costTracker.add(batchGetResult.ConsumedCapacity);
|
|
98
|
-
}
|
|
99
|
-
const existingItems = batchGetResult.Responses?.[tableName] || [];
|
|
82
|
+
// BatchGetItemで既存レコードを取得(100件ごとに分割し、UnprocessedKeys は再試行する。
|
|
83
|
+
// 取りこぼすと「存在しない」と誤認して更新・削除の対象から漏れるため、解消しなければエラーにする)
|
|
84
|
+
const existingItems = await batchGetAll(ids.map((id) => ({ PK: resource, SK: generateMainRecordSK(id) })), { consistentRead: true, costTracker, requestId });
|
|
100
85
|
// 存在しないIDを特定
|
|
101
86
|
const existingIds = new Set();
|
|
102
87
|
const preparedRecords = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deleteMany.js","sourceRoot":"","sources":["../../../src/server/operations/deleteMany.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"deleteMany.js","sourceRoot":"","sources":["../../../src/server/operations/deleteMany.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deleteOne.d.ts","sourceRoot":"","sources":["../../../src/server/operations/deleteOne.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"deleteOne.d.ts","sourceRoot":"","sources":["../../../src/server/operations/deleteOne.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAKpE;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe,EACvB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CA8F1B"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* リファクタリング: deleteManyを内部で使用
|
|
8
8
|
*/
|
|
9
9
|
import { createLogger } from '../../shared/index.js';
|
|
10
|
+
import { findOneByFilter } from './findAll.js';
|
|
10
11
|
const logger = createLogger({ service: 'records-lambda' });
|
|
11
12
|
/**
|
|
12
13
|
* deleteOne 操作を実行する
|
|
@@ -65,10 +66,12 @@ export async function handleDeleteOne(resource, params, requestId) {
|
|
|
65
66
|
resource,
|
|
66
67
|
filter: params.filter,
|
|
67
68
|
});
|
|
68
|
-
// deleteMany(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
// deleteOne は 1 件だけを対象にする。一致する 1 件の id を特定して deleteMany([id]) を呼ぶ
|
|
70
|
+
// (filter のまま deleteMany に渡すと、一致する全件が削除されてしまう)
|
|
71
|
+
const target = await findOneByFilter(resource, params.filter, requestId);
|
|
72
|
+
const deleteManyResult = target
|
|
73
|
+
? await handleDeleteMany(resource, { ids: [target.id] }, requestId)
|
|
74
|
+
: await handleDeleteMany(resource, { ids: [] }, requestId);
|
|
72
75
|
// 結果を検証
|
|
73
76
|
if (deleteManyResult.count === 0) {
|
|
74
77
|
// 削除に失敗した場合
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deleteOne.js","sourceRoot":"","sources":["../../../src/server/operations/deleteOne.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"deleteOne.js","sourceRoot":"","sources":["../../../src/server/operations/deleteOne.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idQuery.d.ts","sourceRoot":"","sources":["../../../../src/server/operations/find/idQuery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"idQuery.d.ts","sourceRoot":"","sources":["../../../../src/server/operations/find/idQuery.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAgB,MAAM,YAAY,CAAC;AAQjF;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,oBAAoB,EACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,CAAC,CAwBrB"}
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
* sort.field='id'の場合の特別な処理を担当します。
|
|
5
5
|
*/
|
|
6
6
|
import { QueryCommand } from '@aws-sdk/lib-dynamodb';
|
|
7
|
-
import { createLogger } from '../../../shared/index.js';
|
|
7
|
+
import { AppError, ErrorCode, createLogger } from '../../../shared/index.js';
|
|
8
8
|
import { CostTracker } from '../../utils/cost-tracker.js';
|
|
9
9
|
import { executeDynamoDBOperation, extractCleanRecord, getDBClient, getTableName, } from '../../utils/dynamodb.js';
|
|
10
10
|
import { decodeNextToken, encodeNextToken } from '../../utils/pagination.js';
|
|
11
|
+
import { ScanWatcher } from '../../utils/scanWarning.js';
|
|
11
12
|
import { matchesAllFilters } from './utils.js';
|
|
12
13
|
const logger = createLogger({
|
|
13
14
|
service: 'id-query',
|
|
@@ -229,10 +230,11 @@ const SCAN_MAX_ITERATIONS = 10000;
|
|
|
229
230
|
*
|
|
230
231
|
* - 全ページを通した読み取り量は O(件数)。ページごとに全件を読み直さない
|
|
231
232
|
* - ID は不変なので、走査中にレコードが更新されても、取りこぼしも重複も起きない
|
|
232
|
-
* - ページは「perPage
|
|
233
|
-
*
|
|
234
|
-
* 1
|
|
235
|
-
*
|
|
233
|
+
* - ページは「perPage 件埋まる」か「末尾に達する」まで返さない(途中で打ち切らない。
|
|
234
|
+
* perPage 未満なら最終ページ、という呼び出し側の前提を保つ)。一致が少ないと
|
|
235
|
+
* 1リクエストで多くのレコードを読むので、読んだ件数が閾値(SCAN_WARN_THRESHOLD)を
|
|
236
|
+
* 超えたら SPARSE_SCAN の警告を記録する。警告が出たら、インデックス・スキーマ・
|
|
237
|
+
* ロジックを見直すこと(docs/SCAN_WARNING.md)
|
|
236
238
|
* - hasNextPage は、perPage+1 件目の一致を実際に見つけてから true にする(空の最終ページを出さない)
|
|
237
239
|
*
|
|
238
240
|
* @param resource - リソース名
|
|
@@ -260,14 +262,25 @@ async function executeAllRecordsQueryFullScan(resource, sort, perPage, nextToken
|
|
|
260
262
|
let iterations = 0;
|
|
261
263
|
let previousKeySignature;
|
|
262
264
|
let chunkSize = SCAN_CHUNK_INITIAL;
|
|
265
|
+
const watcher = new ScanWatcher({
|
|
266
|
+
requestId,
|
|
267
|
+
resource,
|
|
268
|
+
path: 'id-filtered-scan',
|
|
269
|
+
sortField: sort.field,
|
|
270
|
+
filters: parsedFilters.map((f) => `${f.parsed.field}:${f.parsed.operator}`),
|
|
271
|
+
});
|
|
263
272
|
scan: while (true) {
|
|
264
273
|
if (++iterations > SCAN_MAX_ITERATIONS) {
|
|
265
|
-
|
|
274
|
+
// 結果が壊れる(途中までを最終ページとして返してしまう)ため、打ち切らずに失敗させる
|
|
275
|
+
logger.error('executeAllRecordsQueryFullScan: 最大反復回数を超過', {
|
|
266
276
|
requestId,
|
|
267
277
|
resource,
|
|
268
278
|
iterations,
|
|
269
279
|
});
|
|
270
|
-
|
|
280
|
+
throw new AppError(ErrorCode.INTERNAL_ERROR, 'ID scan exceeded the iteration limit', 500, {
|
|
281
|
+
resource,
|
|
282
|
+
iterations,
|
|
283
|
+
});
|
|
271
284
|
}
|
|
272
285
|
const queryResult = await executeDynamoDBOperation(() => dbClient.send(new QueryCommand({
|
|
273
286
|
TableName: tableName,
|
|
@@ -283,6 +296,7 @@ async function executeAllRecordsQueryFullScan(resource, sort, perPage, nextToken
|
|
|
283
296
|
ReturnConsumedCapacity: 'TOTAL',
|
|
284
297
|
})), 'Query');
|
|
285
298
|
costTracker.add(queryResult.ConsumedCapacity);
|
|
299
|
+
watcher.add((queryResult.Items || []).length);
|
|
286
300
|
for (const row of queryResult.Items || []) {
|
|
287
301
|
scanned++;
|
|
288
302
|
if (!matchesAllFilters(extractCleanRecord(row), parsedFilters)) {
|
|
@@ -301,12 +315,12 @@ async function executeAllRecordsQueryFullScan(resource, sort, perPage, nextToken
|
|
|
301
315
|
}
|
|
302
316
|
const nextKeySignature = `${nextKey.PK}#${nextKey.SK}`;
|
|
303
317
|
if (nextKeySignature === previousKeySignature) {
|
|
304
|
-
logger.error('executeAllRecordsQueryFullScan: 同一のLastEvaluatedKey
|
|
318
|
+
logger.error('executeAllRecordsQueryFullScan: 同一のLastEvaluatedKeyが返却された', {
|
|
305
319
|
requestId,
|
|
306
320
|
resource,
|
|
307
321
|
iterations,
|
|
308
322
|
});
|
|
309
|
-
|
|
323
|
+
throw new AppError(ErrorCode.INTERNAL_ERROR, 'ID scan received the same LastEvaluatedKey repeatedly', 500, { resource, iterations });
|
|
310
324
|
}
|
|
311
325
|
previousKeySignature = nextKeySignature;
|
|
312
326
|
exclusiveStartKey = nextKey;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idQuery.js","sourceRoot":"","sources":["../../../../src/server/operations/find/idQuery.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"idQuery.js","sourceRoot":"","sources":["../../../../src/server/operations/find/idQuery.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nearQuery.d.ts","sourceRoot":"","sources":["../../../../src/server/operations/find/nearQuery.ts"],"names":[],"mappings":"AAKA,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"nearQuery.d.ts","sourceRoot":"","sources":["../../../../src/server/operations/find/nearQuery.ts"],"names":[],"mappings":"AAKA,OAAO,EAA0B,KAAK,SAAS,EAAE,MAAM,kCAAkC,CAAC;AAY1F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAO7C;;;;;;;;;GASG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,SAAS,EACpB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,CAAC,CA4KrB"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* $near演算子を使用した近隣検索の実装
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { QueryCommand } from '@aws-sdk/lib-dynamodb';
|
|
5
5
|
import { DEFAULT_GEOHASH_CONFIG } from '../../../shared/geohash/index.js';
|
|
6
|
-
import { createLogger } from '../../../shared/index.js';
|
|
6
|
+
import { AppError, ErrorCode, createLogger } from '../../../shared/index.js';
|
|
7
7
|
import { executeNearSearch } from '../../query/nearSearch.js';
|
|
8
|
+
import { batchGetAll } from '../../utils/batchGet.js';
|
|
8
9
|
import { CostTracker } from '../../utils/cost-tracker.js';
|
|
9
10
|
import { executeDynamoDBOperation, extractCleanRecord, getDBClient, getTableName, } from '../../utils/dynamodb.js';
|
|
11
|
+
import { ScanWatcher } from '../../utils/scanWarning.js';
|
|
10
12
|
const logger = createLogger({
|
|
11
13
|
service: 'near-query',
|
|
12
14
|
level: process.env.LOG_LEVEL || 'info',
|
|
@@ -44,19 +46,41 @@ export async function executeNearQuery(resource, fieldName, nearQuery, limit, re
|
|
|
44
46
|
// シャドウレコードを検索
|
|
45
47
|
// SKプレフィックス: location#<geohash>
|
|
46
48
|
// 完全なSK: location#<geohash>#id#<venue-id>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
// 1 回の Query は最大 1MB。LastEvaluatedKey をたどって全件を読む(超過分を黙って捨てない)
|
|
50
|
+
const shadowRecords = [];
|
|
51
|
+
const watcher = new ScanWatcher({
|
|
52
|
+
requestId,
|
|
53
|
+
resource,
|
|
54
|
+
path: 'near-search',
|
|
55
|
+
sortField: fieldName,
|
|
56
|
+
filters: ['$near'],
|
|
57
|
+
});
|
|
58
|
+
let exclusiveStartKey;
|
|
59
|
+
let previousKeySignature;
|
|
60
|
+
do {
|
|
61
|
+
const queryResult = await executeDynamoDBOperation(() => dbClient.send(new QueryCommand({
|
|
62
|
+
TableName: tableName,
|
|
63
|
+
KeyConditionExpression: 'PK = :pk AND begins_with(SK, :skPrefix)',
|
|
64
|
+
ExpressionAttributeValues: {
|
|
65
|
+
':pk': resource,
|
|
66
|
+
':skPrefix': `${fieldName}#${geohashPrefix}`,
|
|
67
|
+
},
|
|
68
|
+
ExclusiveStartKey: exclusiveStartKey,
|
|
69
|
+
ConsistentRead: false, // シャドウレコードは結果整合性で十分
|
|
70
|
+
ReturnConsumedCapacity: 'TOTAL',
|
|
71
|
+
})), 'Query');
|
|
72
|
+
// コスト情報を収集
|
|
73
|
+
costTracker.add(queryResult.ConsumedCapacity);
|
|
74
|
+
shadowRecords.push(...(queryResult.Items || []));
|
|
75
|
+
watcher.add((queryResult.Items || []).length);
|
|
76
|
+
const nextKey = queryResult.LastEvaluatedKey;
|
|
77
|
+
const nextKeySignature = nextKey ? `${nextKey.PK}#${nextKey.SK}` : undefined;
|
|
78
|
+
if (nextKeySignature && nextKeySignature === previousKeySignature) {
|
|
79
|
+
throw new AppError(ErrorCode.INTERNAL_ERROR, 'Near search received the same LastEvaluatedKey repeatedly', 500, { resource, geohashPrefix });
|
|
80
|
+
}
|
|
81
|
+
previousKeySignature = nextKeySignature;
|
|
82
|
+
exclusiveStartKey = nextKey;
|
|
83
|
+
} while (exclusiveStartKey);
|
|
60
84
|
logger.debug('Shadow records found', {
|
|
61
85
|
requestId,
|
|
62
86
|
resource,
|
|
@@ -81,31 +105,8 @@ export async function executeNearQuery(resource, fieldName, nearQuery, limit, re
|
|
|
81
105
|
ids: mainRecordIds,
|
|
82
106
|
});
|
|
83
107
|
// 本体レコードを BatchGetItem で一括取得(N+1 Query を回避)
|
|
84
|
-
//
|
|
85
|
-
const
|
|
86
|
-
const validRecords = [];
|
|
87
|
-
for (let i = 0; i < mainRecordIds.length; i += BATCH_SIZE) {
|
|
88
|
-
const chunk = mainRecordIds.slice(i, i + BATCH_SIZE);
|
|
89
|
-
const batchGetResult = await executeDynamoDBOperation(() => dbClient.send(new BatchGetCommand({
|
|
90
|
-
RequestItems: {
|
|
91
|
-
[tableName]: {
|
|
92
|
-
Keys: chunk.map((id) => ({
|
|
93
|
-
PK: resource,
|
|
94
|
-
SK: `id#${id}`,
|
|
95
|
-
})),
|
|
96
|
-
ConsistentRead: false,
|
|
97
|
-
},
|
|
98
|
-
},
|
|
99
|
-
ReturnConsumedCapacity: 'TOTAL',
|
|
100
|
-
})), 'BatchGetItem');
|
|
101
|
-
// コスト情報を収集
|
|
102
|
-
if (batchGetResult.ConsumedCapacity) {
|
|
103
|
-
for (const capacity of batchGetResult.ConsumedCapacity) {
|
|
104
|
-
costTracker.add(capacity);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
validRecords.push(...(batchGetResult.Responses?.[tableName] || []));
|
|
108
|
-
}
|
|
108
|
+
// 100 件ごとの分割と UnprocessedKeys の再試行は batchGetAll が行う(取りこぼさない)
|
|
109
|
+
const validRecords = await batchGetAll(mainRecordIds.map((id) => ({ PK: resource, SK: `id#${id}` })), { consistentRead: false, costTracker, requestId });
|
|
109
110
|
logger.debug('Main records retrieved', {
|
|
110
111
|
requestId,
|
|
111
112
|
resource,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nearQuery.js","sourceRoot":"","sources":["../../../../src/server/operations/find/nearQuery.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"nearQuery.js","sourceRoot":"","sources":["../../../../src/server/operations/find/nearQuery.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,4 +8,11 @@ import type { FindResult, NormalizedFindParams } from './types.js';
|
|
|
8
8
|
* @returns クエリ実行結果
|
|
9
9
|
*/
|
|
10
10
|
export declare function executeShadowQuery(resource: string, normalizedParams: NormalizedFindParams, requestId: string): Promise<FindResult>;
|
|
11
|
+
/**
|
|
12
|
+
* シャドウレコードから本体レコードのIDを抽出する
|
|
13
|
+
*
|
|
14
|
+
* @param shadowRecords - シャドウレコードの配列
|
|
15
|
+
* @returns レコードIDの配列
|
|
16
|
+
*/
|
|
17
|
+
export declare function extractRecordIds(shadowRecords: Record<string, unknown>[]): string[];
|
|
11
18
|
//# sourceMappingURL=shadowQuery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shadowQuery.d.ts","sourceRoot":"","sources":["../../../../src/server/operations/find/shadowQuery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"shadowQuery.d.ts","sourceRoot":"","sources":["../../../../src/server/operations/find/shadowQuery.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,UAAU,EAAE,oBAAoB,EAAmC,MAAM,YAAY,CAAC;AAkBpG;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,gBAAgB,EAAE,oBAAoB,EACtC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,CAAC,CA0IrB;AA0gBD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,GAAG,MAAM,EAAE,CAWnF"}
|
|
@@ -3,12 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* sort.field != 'id'の場合の通常のシャドウレコードクエリを担当します。
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import { QueryCommand } from '@aws-sdk/lib-dynamodb';
|
|
7
7
|
import { NUMBER_FORMAT } from '../../../shared/constants/formatting.js';
|
|
8
|
-
import { createLogger } from '../../../shared/index.js';
|
|
8
|
+
import { AppError, ErrorCode, createLogger } from '../../../shared/index.js';
|
|
9
|
+
import { batchGetAll } from '../../utils/batchGet.js';
|
|
9
10
|
import { CostTracker } from '../../utils/cost-tracker.js';
|
|
10
11
|
import { executeDynamoDBOperation, extractCleanRecord, getDBClient, getTableName, } from '../../utils/dynamodb.js';
|
|
11
12
|
import { decodeNextToken, decodeOffsetToken, encodeNextToken, encodeOffsetToken, } from '../../utils/pagination.js';
|
|
13
|
+
import { ScanWatcher } from '../../utils/scanWarning.js';
|
|
12
14
|
import { findOptimizableFilter, matchesAllFilters } from './utils.js';
|
|
13
15
|
const logger = createLogger({
|
|
14
16
|
service: 'shadow-query',
|
|
@@ -151,7 +153,7 @@ async function executeFilterFirstQuery(resource, normalizedParams, filterCandida
|
|
|
151
153
|
offset,
|
|
152
154
|
});
|
|
153
155
|
// フィルタシャドウインデックスから全件取得(Limit なし・全ページループ)
|
|
154
|
-
let items = await fetchAllRecordsViaShadowIndex(resource, filterSort, filterCandidate, costTracker, requestId);
|
|
156
|
+
let items = await fetchAllRecordsViaShadowIndex(resource, filterSort, filterCandidate, costTracker, requestId, 'shadow-filter-first', parsedFilters);
|
|
155
157
|
if (remainingFilters.length > 0) {
|
|
156
158
|
items = items.filter((r) => matchesAllFilters(r, remainingFilters));
|
|
157
159
|
}
|
|
@@ -204,7 +206,7 @@ async function executeFullScanQuery(resource, normalizedParams, costTracker, req
|
|
|
204
206
|
});
|
|
205
207
|
// ソートシャドウインデックスから全件取得(Limit なし・全ページループ)
|
|
206
208
|
// 最適化フィルタなし(undefined)= begins_with(SK, `${sort.field}#`) で全件取得
|
|
207
|
-
let items = await fetchAllRecordsViaShadowIndex(resource, sort, undefined, costTracker, requestId);
|
|
209
|
+
let items = await fetchAllRecordsViaShadowIndex(resource, sort, undefined, costTracker, requestId, 'shadow-full-scan', parsedFilters);
|
|
208
210
|
if (parsedFilters.length > 0) {
|
|
209
211
|
items = items.filter((r) => matchesAllFilters(r, parsedFilters));
|
|
210
212
|
}
|
|
@@ -240,10 +242,20 @@ async function executeFullScanQuery(resource, normalizedParams, costTracker, req
|
|
|
240
242
|
* @param indexFilter - シャドウインデックスに適用する最適化フィルタ(undefinedなら全件プレフィックスマッチ)
|
|
241
243
|
* @param costTracker - コスト追跡インスタンス
|
|
242
244
|
* @param requestId - リクエストID
|
|
245
|
+
* @param scanPath - 警告に記録する走査の種類
|
|
246
|
+
* @param parsedFilters - 警告に記録する絞り込み条件
|
|
243
247
|
* @returns ID順に並んだ本体レコードの配列(重複除去済み)
|
|
244
248
|
*/
|
|
245
|
-
async function fetchAllRecordsViaShadowIndex(resource, indexSort, indexFilter, costTracker, requestId) {
|
|
249
|
+
async function fetchAllRecordsViaShadowIndex(resource, indexSort, indexFilter, costTracker, requestId, scanPath, parsedFilters) {
|
|
246
250
|
const allShadowItems = [];
|
|
251
|
+
// 読んだ件数が閾値を超えたら SPARSE_SCAN の警告を記録する(打ち切りはしない)
|
|
252
|
+
const watcher = new ScanWatcher({
|
|
253
|
+
requestId,
|
|
254
|
+
resource,
|
|
255
|
+
path: scanPath,
|
|
256
|
+
sortField: indexSort.field,
|
|
257
|
+
filters: parsedFilters.map((f) => `${f.parsed.field}:${f.parsed.operator}`),
|
|
258
|
+
});
|
|
247
259
|
let lastKey;
|
|
248
260
|
let previousKeySignature;
|
|
249
261
|
// 安全装置: DynamoDBが同一のLastEvaluatedKeyを返し続ける異常系
|
|
@@ -253,25 +265,30 @@ async function fetchAllRecordsViaShadowIndex(resource, indexSort, indexFilter, c
|
|
|
253
265
|
let iterations = 0;
|
|
254
266
|
do {
|
|
255
267
|
if (++iterations > MAX_ITERATIONS) {
|
|
256
|
-
|
|
268
|
+
// 結果が壊れる(途中までを全件として扱ってしまう)ため、打ち切らずに失敗させる
|
|
269
|
+
logger.error('fetchAllRecordsViaShadowIndex: 最大反復回数を超過', {
|
|
257
270
|
requestId,
|
|
258
271
|
resource,
|
|
259
272
|
iterations,
|
|
260
273
|
});
|
|
261
|
-
|
|
274
|
+
throw new AppError(ErrorCode.INTERNAL_ERROR, 'Shadow index scan exceeded the iteration limit', 500, {
|
|
275
|
+
resource,
|
|
276
|
+
iterations,
|
|
277
|
+
});
|
|
262
278
|
}
|
|
263
279
|
const result = await executeShadowRecordQuery(resource, indexSort, 1000, // 大きめの Limit でループ回数を最小化
|
|
264
280
|
lastKey ? encodeNextToken(lastKey.PK, lastKey.SK) : undefined, indexFilter, costTracker, requestId);
|
|
265
281
|
allShadowItems.push(...(result.Items || []));
|
|
282
|
+
watcher.add((result.Items || []).length);
|
|
266
283
|
const nextKey = result.LastEvaluatedKey;
|
|
267
284
|
const nextKeySignature = nextKey ? `${nextKey.PK}#${nextKey.SK}` : undefined;
|
|
268
285
|
if (nextKeySignature && nextKeySignature === previousKeySignature) {
|
|
269
|
-
logger.error('fetchAllRecordsViaShadowIndex: 同一のLastEvaluatedKey
|
|
286
|
+
logger.error('fetchAllRecordsViaShadowIndex: 同一のLastEvaluatedKeyが返却された', {
|
|
270
287
|
requestId,
|
|
271
288
|
resource,
|
|
272
289
|
iterations,
|
|
273
290
|
});
|
|
274
|
-
|
|
291
|
+
throw new AppError(ErrorCode.INTERNAL_ERROR, 'Shadow index scan received the same LastEvaluatedKey repeatedly', 500, { resource, iterations });
|
|
275
292
|
}
|
|
276
293
|
previousKeySignature = nextKeySignature;
|
|
277
294
|
lastKey = nextKey;
|
|
@@ -510,13 +527,15 @@ function encodeValueForShadowSK(value, type) {
|
|
|
510
527
|
* @param shadowRecords - シャドウレコードの配列
|
|
511
528
|
* @returns レコードIDの配列
|
|
512
529
|
*/
|
|
513
|
-
function extractRecordIds(shadowRecords) {
|
|
530
|
+
export function extractRecordIds(shadowRecords) {
|
|
514
531
|
return shadowRecords
|
|
515
532
|
.map((record) => {
|
|
516
533
|
const sk = record.SK;
|
|
517
534
|
// SK形式: {field}#{value}#id#{recordId}
|
|
518
|
-
|
|
519
|
-
|
|
535
|
+
// 値(エスケープ後)に '#id#' が現れうる(例: 値 "x id y" は "x#id#y")ため、最後の区切りを使う。
|
|
536
|
+
// 最初の '#id#' で分けると別の id を取り出し、一致したレコードが黙って結果から消える
|
|
537
|
+
const index = sk.lastIndexOf('#id#');
|
|
538
|
+
return index >= 0 ? sk.slice(index + '#id#'.length) : null;
|
|
520
539
|
})
|
|
521
540
|
.filter((id) => id !== null);
|
|
522
541
|
}
|
|
@@ -530,39 +549,12 @@ function extractRecordIds(shadowRecords) {
|
|
|
530
549
|
* @returns 本体レコードの配列
|
|
531
550
|
*/
|
|
532
551
|
async function fetchMainRecords(resource, recordIds, costTracker, requestId) {
|
|
533
|
-
|
|
534
|
-
const
|
|
535
|
-
// 重複を除去
|
|
536
|
-
const uniqueRecordIds = Array.from(new Set(recordIds));
|
|
537
|
-
// DynamoDB BatchGetItem は最大100件/リクエスト
|
|
538
|
-
const BATCH_SIZE = 100;
|
|
539
|
-
const allRecords = [];
|
|
540
|
-
for (let i = 0; i < uniqueRecordIds.length; i += BATCH_SIZE) {
|
|
541
|
-
const chunk = uniqueRecordIds.slice(i, i + BATCH_SIZE);
|
|
542
|
-
const batchGetResult = await executeDynamoDBOperation(() => dbClient.send(new BatchGetCommand({
|
|
543
|
-
RequestItems: {
|
|
544
|
-
[tableName]: {
|
|
545
|
-
Keys: chunk.map((id) => ({
|
|
546
|
-
PK: resource,
|
|
547
|
-
SK: `id#${id}`,
|
|
548
|
-
})),
|
|
549
|
-
ConsistentRead: true,
|
|
550
|
-
},
|
|
551
|
-
},
|
|
552
|
-
ReturnConsumedCapacity: 'TOTAL',
|
|
553
|
-
})), 'BatchGetItem');
|
|
554
|
-
// コスト情報を収集
|
|
555
|
-
if (batchGetResult.ConsumedCapacity) {
|
|
556
|
-
for (const capacity of batchGetResult.ConsumedCapacity) {
|
|
557
|
-
costTracker.add(capacity);
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
allRecords.push(...(batchGetResult.Responses?.[tableName] || []));
|
|
561
|
-
}
|
|
552
|
+
// 100 件ごとの分割と UnprocessedKeys の再試行は batchGetAll が行う(取りこぼさない)
|
|
553
|
+
const allRecords = await batchGetAll(recordIds.map((id) => ({ PK: resource, SK: `id#${id}` })), { consistentRead: true, costTracker, requestId });
|
|
562
554
|
logger.debug('Main records fetched', {
|
|
563
555
|
requestId,
|
|
564
556
|
resource,
|
|
565
|
-
requestedCount:
|
|
557
|
+
requestedCount: new Set(recordIds).size,
|
|
566
558
|
fetchedCount: allRecords.length,
|
|
567
559
|
});
|
|
568
560
|
return allRecords;
|