@exabugs/dynamodb-client 0.3.7 → 0.4.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.
Files changed (147) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/client/Collection.d.ts +1 -1
  3. package/dist/client/Collection.d.ts.map +1 -1
  4. package/dist/client/FindCursor.d.ts +1 -1
  5. package/dist/client/FindCursor.d.ts.map +1 -1
  6. package/dist/index.d.ts +1 -7
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +4 -4
  9. package/dist/index.js.map +1 -1
  10. package/dist/server/handler.cjs +683 -553
  11. package/dist/server/handler.cjs.map +4 -4
  12. package/dist/server/handler.d.ts.map +1 -1
  13. package/dist/server/handler.js +1 -2
  14. package/dist/server/handler.js.map +1 -1
  15. package/dist/server/operations/deleteMany.js +1 -1
  16. package/dist/server/operations/deleteMany.js.map +1 -1
  17. package/dist/server/operations/deleteOne.js +1 -1
  18. package/dist/server/operations/deleteOne.js.map +1 -1
  19. package/dist/server/operations/find/handler.d.ts +21 -0
  20. package/dist/server/operations/find/handler.d.ts.map +1 -0
  21. package/dist/server/operations/find/handler.js +53 -0
  22. package/dist/server/operations/find/handler.js.map +1 -0
  23. package/dist/server/operations/find/idQuery.d.ts +16 -0
  24. package/dist/server/operations/find/idQuery.d.ts.map +1 -0
  25. package/dist/server/operations/find/idQuery.js +149 -0
  26. package/dist/server/operations/find/idQuery.js.map +1 -0
  27. package/dist/server/operations/find/index.d.ts +9 -0
  28. package/dist/server/operations/find/index.d.ts.map +1 -0
  29. package/dist/server/operations/find/index.js +9 -0
  30. package/dist/server/operations/find/index.js.map +1 -0
  31. package/dist/server/operations/find/shadowQuery.d.ts +16 -0
  32. package/dist/server/operations/find/shadowQuery.d.ts.map +1 -0
  33. package/dist/server/operations/find/shadowQuery.js +283 -0
  34. package/dist/server/operations/find/shadowQuery.js.map +1 -0
  35. package/dist/server/operations/find/types.d.ts +71 -0
  36. package/dist/server/operations/find/types.d.ts.map +1 -0
  37. package/dist/server/operations/find/types.js +5 -0
  38. package/dist/server/operations/find/types.js.map +1 -0
  39. package/dist/server/operations/find/utils.d.ts +37 -0
  40. package/dist/server/operations/find/utils.d.ts.map +1 -0
  41. package/dist/server/operations/find/utils.js +117 -0
  42. package/dist/server/operations/find/utils.js.map +1 -0
  43. package/dist/server/operations/find.d.ts +4 -14
  44. package/dist/server/operations/find.d.ts.map +1 -1
  45. package/dist/server/operations/find.js +2 -368
  46. package/dist/server/operations/find.js.map +1 -1
  47. package/dist/server/operations/findMany.js +1 -1
  48. package/dist/server/operations/findMany.js.map +1 -1
  49. package/dist/server/operations/findManyReference.d.ts.map +1 -1
  50. package/dist/server/operations/findManyReference.js +2 -1
  51. package/dist/server/operations/findManyReference.js.map +1 -1
  52. package/dist/server/operations/findOne.js +1 -1
  53. package/dist/server/operations/findOne.js.map +1 -1
  54. package/dist/server/operations/insertMany.d.ts.map +1 -1
  55. package/dist/server/operations/insertMany.js +2 -1
  56. package/dist/server/operations/insertMany.js.map +1 -1
  57. package/dist/server/operations/insertOne.d.ts.map +1 -1
  58. package/dist/server/operations/insertOne.js +2 -1
  59. package/dist/server/operations/insertOne.js.map +1 -1
  60. package/dist/server/operations/updateMany.d.ts.map +1 -1
  61. package/dist/server/operations/updateMany.js +2 -1
  62. package/dist/server/operations/updateMany.js.map +1 -1
  63. package/dist/server/operations/updateOne.d.ts.map +1 -1
  64. package/dist/server/operations/updateOne.js +2 -1
  65. package/dist/server/operations/updateOne.js.map +1 -1
  66. package/dist/server/query/converter.d.ts +1 -1
  67. package/dist/server/query/converter.d.ts.map +1 -1
  68. package/dist/server/shadow/differ.d.ts +3 -38
  69. package/dist/server/shadow/differ.d.ts.map +1 -1
  70. package/dist/server/shadow/differ.js +4 -62
  71. package/dist/server/shadow/differ.js.map +1 -1
  72. package/dist/server/shadow/generator.d.ts +1 -1
  73. package/dist/server/shadow/generator.d.ts.map +1 -1
  74. package/dist/server/shadow/generator.js +8 -19
  75. package/dist/server/shadow/generator.js.map +1 -1
  76. package/dist/server/shadow/types.d.ts +4 -17
  77. package/dist/server/shadow/types.d.ts.map +1 -1
  78. package/dist/server/shadow/types.js +5 -0
  79. package/dist/server/shadow/types.js.map +1 -1
  80. package/dist/server/utils/bulkOperations.d.ts +0 -15
  81. package/dist/server/utils/bulkOperations.d.ts.map +1 -1
  82. package/dist/server/utils/bulkOperations.js +1 -16
  83. package/dist/server/utils/bulkOperations.js.map +1 -1
  84. package/dist/server/utils/chunking.d.ts +0 -9
  85. package/dist/server/utils/chunking.d.ts.map +1 -1
  86. package/dist/server/utils/chunking.js +1 -10
  87. package/dist/server/utils/chunking.js.map +1 -1
  88. package/dist/server/utils/dynamodb.js +1 -1
  89. package/dist/server/utils/dynamodb.js.map +1 -1
  90. package/dist/shared/constants/dynamodb.d.ts +36 -0
  91. package/dist/shared/constants/dynamodb.d.ts.map +1 -0
  92. package/dist/shared/constants/dynamodb.js +100 -0
  93. package/dist/shared/constants/dynamodb.js.map +1 -0
  94. package/dist/shared/constants/http.d.ts +48 -0
  95. package/dist/shared/constants/http.d.ts.map +1 -0
  96. package/dist/shared/constants/http.js +48 -0
  97. package/dist/shared/constants/http.js.map +1 -0
  98. package/dist/shared/constants/index.d.ts +7 -0
  99. package/dist/shared/constants/index.d.ts.map +1 -0
  100. package/dist/shared/constants/index.js +7 -0
  101. package/dist/shared/constants/index.js.map +1 -0
  102. package/dist/shared/constants/lambda.d.ts +33 -0
  103. package/dist/shared/constants/lambda.d.ts.map +1 -0
  104. package/dist/shared/constants/lambda.js +33 -0
  105. package/dist/shared/constants/lambda.js.map +1 -0
  106. package/dist/{errors.d.ts → shared/errors/index.d.ts} +7 -1
  107. package/dist/shared/errors/index.d.ts.map +1 -0
  108. package/dist/{errors.js → shared/errors/index.js} +7 -1
  109. package/dist/shared/errors/index.js.map +1 -0
  110. package/dist/shared/index.d.ts +11 -0
  111. package/dist/shared/index.d.ts.map +1 -0
  112. package/dist/shared/index.js +15 -0
  113. package/dist/shared/index.js.map +1 -0
  114. package/dist/{types.d.ts → shared/types/index.d.ts} +7 -1
  115. package/dist/shared/types/index.d.ts.map +1 -0
  116. package/dist/shared/types/index.js +8 -0
  117. package/dist/shared/types/index.js.map +1 -0
  118. package/dist/shared/utils/dynamodb.d.ts +18 -0
  119. package/dist/shared/utils/dynamodb.d.ts.map +1 -0
  120. package/dist/shared/utils/dynamodb.js +32 -0
  121. package/dist/shared/utils/dynamodb.js.map +1 -0
  122. package/dist/shared/utils/index.d.ts +8 -0
  123. package/dist/shared/utils/index.d.ts.map +1 -0
  124. package/dist/shared/utils/index.js +8 -0
  125. package/dist/shared/utils/index.js.map +1 -0
  126. package/dist/{logger.d.ts → shared/utils/logger.d.ts} +7 -1
  127. package/dist/shared/utils/logger.d.ts.map +1 -0
  128. package/dist/{logger.js → shared/utils/logger.js} +7 -1
  129. package/dist/shared/utils/logger.js.map +1 -0
  130. package/dist/shared/utils/ulid.d.ts.map +1 -0
  131. package/dist/{ulid.js → shared/utils/ulid.js} +5 -0
  132. package/dist/shared/utils/ulid.js.map +1 -0
  133. package/dist/shared/utils/validation.d.ts +59 -0
  134. package/dist/shared/utils/validation.d.ts.map +1 -0
  135. package/dist/shared/utils/validation.js +114 -0
  136. package/dist/shared/utils/validation.js.map +1 -0
  137. package/package.json +3 -2
  138. package/dist/errors.d.ts.map +0 -1
  139. package/dist/errors.js.map +0 -1
  140. package/dist/logger.d.ts.map +0 -1
  141. package/dist/logger.js.map +0 -1
  142. package/dist/types.d.ts.map +0 -1
  143. package/dist/types.js +0 -2
  144. package/dist/types.js.map +0 -1
  145. package/dist/ulid.d.ts.map +0 -1
  146. package/dist/ulid.js.map +0 -1
  147. /package/dist/{ulid.d.ts → shared/utils/ulid.d.ts} +0 -0
@@ -0,0 +1,283 @@
1
+ /**
2
+ * シャドウレコードクエリの実装
3
+ *
4
+ * sort.field != 'id'の場合の通常のシャドウレコードクエリを担当します。
5
+ */
6
+ import { QueryCommand, BatchGetCommand } from '@aws-sdk/lib-dynamodb';
7
+ import { createLogger } from '../../../shared/index.js';
8
+ import { getDBClient, getTableName, executeDynamoDBOperation, extractCleanRecord } from '../../utils/dynamodb.js';
9
+ import { encodeNextToken, decodeNextToken } from '../../utils/pagination.js';
10
+ import { findOptimizableFilter, matchesAllFilters } from './utils.js';
11
+ const logger = createLogger({
12
+ service: 'shadow-query',
13
+ level: process.env.LOG_LEVEL || 'info',
14
+ });
15
+ /**
16
+ * シャドウレコードクエリを実行する
17
+ *
18
+ * @param resource - リソース名
19
+ * @param normalizedParams - 正規化されたパラメータ
20
+ * @param requestId - リクエストID
21
+ * @returns クエリ実行結果
22
+ */
23
+ export async function executeShadowQuery(resource, normalizedParams, requestId) {
24
+ const { sort, pagination, parsedFilters } = normalizedParams;
25
+ const { perPage, nextToken } = pagination;
26
+ logger.debug('Executing shadow query', {
27
+ requestId,
28
+ resource,
29
+ sortField: sort.field,
30
+ hasFilters: parsedFilters.length > 0,
31
+ });
32
+ // Query最適化: ソートフィールドと一致するフィルター条件を検出
33
+ const optimizableFilter = findOptimizableFilter(sort.field, parsedFilters);
34
+ // シャドウクエリを実行
35
+ const shadowRecords = await executeShadowRecordQuery(resource, sort, perPage, nextToken, optimizableFilter, requestId);
36
+ // シャドウレコードから本体レコードのIDを抽出
37
+ const recordIds = extractRecordIds(shadowRecords.Items || []);
38
+ if (recordIds.length === 0) {
39
+ return {
40
+ items: [],
41
+ pageInfo: {
42
+ hasNextPage: false,
43
+ hasPreviousPage: false,
44
+ },
45
+ };
46
+ }
47
+ // 本体レコードを取得
48
+ const mainRecords = await fetchMainRecords(resource, recordIds, requestId);
49
+ // IDでマッピングを作成(順序を保持するため)
50
+ const recordMap = new Map(mainRecords.map((item) => {
51
+ const data = item.data;
52
+ return [data.id, extractCleanRecord(item)];
53
+ }));
54
+ // シャドーの順序でレコードを並べる(重複を除去)
55
+ const seenIds = new Set();
56
+ let items = recordIds
57
+ .filter((id) => {
58
+ if (seenIds.has(id)) {
59
+ return false; // 既に処理済みのIDはスキップ
60
+ }
61
+ seenIds.add(id);
62
+ return true;
63
+ })
64
+ .map((id) => recordMap.get(id))
65
+ .filter((record) => record !== undefined);
66
+ // フィルター条件を適用(メモリ内フィルタリング)
67
+ if (parsedFilters.length > 0) {
68
+ items = items.filter((record) => matchesAllFilters(record, parsedFilters));
69
+ }
70
+ // ページネーション情報を生成
71
+ const hasNextPage = (shadowRecords.Items?.length || 0) < perPage
72
+ ? false
73
+ : shadowRecords.LastEvaluatedKey !== undefined;
74
+ const nextTokenValue = hasNextPage && shadowRecords.LastEvaluatedKey
75
+ ? encodeNextToken(shadowRecords.LastEvaluatedKey.PK, shadowRecords.LastEvaluatedKey.SK)
76
+ : undefined;
77
+ logger.info('Shadow query succeeded', {
78
+ requestId,
79
+ resource,
80
+ sortField: sort.field,
81
+ shadowCount: shadowRecords.Items?.length || 0,
82
+ mainCount: items.length,
83
+ hasNextPage,
84
+ });
85
+ return {
86
+ items,
87
+ pageInfo: {
88
+ hasNextPage,
89
+ hasPreviousPage: !!nextToken,
90
+ },
91
+ ...(nextTokenValue && { nextToken: nextTokenValue }),
92
+ };
93
+ }
94
+ /**
95
+ * シャドウレコードクエリを実行する
96
+ *
97
+ * @param resource - リソース名
98
+ * @param sort - ソート条件
99
+ * @param perPage - ページサイズ
100
+ * @param nextToken - 次ページトークン
101
+ * @param optimizableFilter - 最適化可能なフィルター
102
+ * @param requestId - リクエストID
103
+ * @returns DynamoDBクエリ結果
104
+ */
105
+ async function executeShadowRecordQuery(resource, sort, perPage, nextToken, optimizableFilter, _requestId) {
106
+ const dbClient = getDBClient();
107
+ const tableName = getTableName();
108
+ // ExclusiveStartKeyの設定
109
+ let exclusiveStartKey;
110
+ if (nextToken) {
111
+ const decoded = decodeNextToken(nextToken);
112
+ exclusiveStartKey = {
113
+ PK: decoded.PK,
114
+ SK: decoded.SK,
115
+ };
116
+ }
117
+ // KeyConditionExpressionを構築
118
+ const { keyConditionExpression, expressionAttributeValues } = buildKeyCondition(resource, sort.field, optimizableFilter);
119
+ return await executeDynamoDBOperation(() => dbClient.send(new QueryCommand({
120
+ TableName: tableName,
121
+ KeyConditionExpression: keyConditionExpression,
122
+ ExpressionAttributeValues: expressionAttributeValues,
123
+ ScanIndexForward: sort.order === 'ASC',
124
+ Limit: perPage,
125
+ ExclusiveStartKey: exclusiveStartKey,
126
+ ConsistentRead: true,
127
+ })), 'Query');
128
+ }
129
+ /**
130
+ * KeyConditionExpressionを構築する
131
+ *
132
+ * @param resource - リソース名
133
+ * @param sortField - ソートフィールド
134
+ * @param optimizableFilter - 最適化可能なフィルター
135
+ * @returns KeyConditionExpressionと属性値
136
+ */
137
+ function buildKeyCondition(resource, sortField, optimizableFilter) {
138
+ const expressionAttributeValues = {
139
+ ':pk': resource,
140
+ };
141
+ if (!optimizableFilter) {
142
+ // 最適化なし: プレフィックスマッチ
143
+ return {
144
+ keyConditionExpression: 'PK = :pk AND begins_with(SK, :skPrefix)',
145
+ expressionAttributeValues: {
146
+ ...expressionAttributeValues,
147
+ ':skPrefix': `${sortField}#`,
148
+ },
149
+ };
150
+ }
151
+ // 最適化あり: フィルター条件をKeyConditionExpressionに含める
152
+ const { operator, type } = optimizableFilter.parsed;
153
+ const value = optimizableFilter.value;
154
+ // 値をシャドーSK形式にエンコード
155
+ const encodedValue = encodeValueForShadowSK(value, type);
156
+ const skValue = `${sortField}#${encodedValue}`;
157
+ switch (operator) {
158
+ case 'eq':
159
+ return {
160
+ keyConditionExpression: 'PK = :pk AND begins_with(SK, :skValue)',
161
+ expressionAttributeValues: {
162
+ ...expressionAttributeValues,
163
+ ':skValue': `${skValue}#id#`,
164
+ },
165
+ };
166
+ case 'gt':
167
+ return {
168
+ keyConditionExpression: 'PK = :pk AND SK > :skValue',
169
+ expressionAttributeValues: {
170
+ ...expressionAttributeValues,
171
+ ':skValue': `${skValue}#id#~`,
172
+ },
173
+ };
174
+ case 'gte':
175
+ return {
176
+ keyConditionExpression: 'PK = :pk AND SK >= :skValue',
177
+ expressionAttributeValues: {
178
+ ...expressionAttributeValues,
179
+ ':skValue': `${skValue}#id#`,
180
+ },
181
+ };
182
+ case 'lt':
183
+ return {
184
+ keyConditionExpression: 'PK = :pk AND begins_with(SK, :skPrefix) AND SK < :skValue',
185
+ expressionAttributeValues: {
186
+ ...expressionAttributeValues,
187
+ ':skPrefix': `${sortField}#`,
188
+ ':skValue': `${skValue}#id#`,
189
+ },
190
+ };
191
+ case 'lte':
192
+ return {
193
+ keyConditionExpression: 'PK = :pk AND begins_with(SK, :skPrefix) AND SK <= :skValue',
194
+ expressionAttributeValues: {
195
+ ...expressionAttributeValues,
196
+ ':skPrefix': `${sortField}#`,
197
+ ':skValue': `${skValue}#id#~`,
198
+ },
199
+ };
200
+ default:
201
+ // 未対応の演算子の場合はプレフィックスマッチにフォールバック
202
+ return {
203
+ keyConditionExpression: 'PK = :pk AND begins_with(SK, :skPrefix)',
204
+ expressionAttributeValues: {
205
+ ...expressionAttributeValues,
206
+ ':skPrefix': `${sortField}#`,
207
+ },
208
+ };
209
+ }
210
+ }
211
+ /**
212
+ * 値をシャドーSK形式にエンコードする
213
+ *
214
+ * @param value - エンコードする値
215
+ * @param type - 値の型
216
+ * @returns エンコードされた値
217
+ */
218
+ function encodeValueForShadowSK(value, type) {
219
+ if (type === 'number') {
220
+ return String(value).padStart(20, '0');
221
+ }
222
+ else if (type === 'date') {
223
+ return new Date(String(value)).toISOString();
224
+ }
225
+ else if (type === 'boolean') {
226
+ return String(value);
227
+ }
228
+ else {
229
+ // string型: エスケープ処理(# → ##、スペース → #)
230
+ return String(value).replace(/#/g, '##').replace(/ /g, '#');
231
+ }
232
+ }
233
+ /**
234
+ * シャドウレコードから本体レコードのIDを抽出する
235
+ *
236
+ * @param shadowRecords - シャドウレコードの配列
237
+ * @returns レコードIDの配列
238
+ */
239
+ function extractRecordIds(shadowRecords) {
240
+ return shadowRecords
241
+ .map((record) => {
242
+ const sk = record.SK;
243
+ // SK形式: {field}#{value}#id#{recordId}
244
+ const parts = sk.split('#id#');
245
+ return parts.length > 1 ? parts[1] : null;
246
+ })
247
+ .filter((id) => id !== null);
248
+ }
249
+ /**
250
+ * 本体レコードを取得する
251
+ *
252
+ * @param resource - リソース名
253
+ * @param recordIds - レコードIDの配列
254
+ * @param requestId - リクエストID
255
+ * @returns 本体レコードの配列
256
+ */
257
+ async function fetchMainRecords(resource, recordIds, requestId) {
258
+ const dbClient = getDBClient();
259
+ const tableName = getTableName();
260
+ // 重複を除去
261
+ const uniqueRecordIds = Array.from(new Set(recordIds));
262
+ // 本体レコードをBatchGetItemで取得
263
+ const batchGetResult = await executeDynamoDBOperation(() => dbClient.send(new BatchGetCommand({
264
+ RequestItems: {
265
+ [tableName]: {
266
+ Keys: uniqueRecordIds.map((id) => ({
267
+ PK: resource,
268
+ SK: `id#${id}`,
269
+ })),
270
+ ConsistentRead: true,
271
+ },
272
+ },
273
+ })), 'BatchGetItem');
274
+ const mainRecords = batchGetResult.Responses?.[tableName] || [];
275
+ logger.debug('Main records fetched', {
276
+ requestId,
277
+ resource,
278
+ requestedCount: uniqueRecordIds.length,
279
+ fetchedCount: mainRecords.length,
280
+ });
281
+ return mainRecords;
282
+ }
283
+ //# sourceMappingURL=shadowQuery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shadowQuery.js","sourceRoot":"","sources":["../../../../src/server/operations/find/shadowQuery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Find操作の型定義
3
+ */
4
+ import type { FindParams, FindResult } from '../../types.js';
5
+ /**
6
+ * 解析済みフィルター条件
7
+ */
8
+ export interface ParsedFilter {
9
+ parsed: ParsedFilterField;
10
+ value: unknown;
11
+ }
12
+ /**
13
+ * フィルターフィールドの解析結果
14
+ */
15
+ export interface ParsedFilterField {
16
+ field: string;
17
+ operator: string;
18
+ type?: string;
19
+ }
20
+ /**
21
+ * 最適化可能なフィルター条件
22
+ */
23
+ export interface OptimizableFilter {
24
+ parsed: ParsedFilterField;
25
+ value: unknown;
26
+ }
27
+ /**
28
+ * 正規化されたFind操作のパラメータ
29
+ */
30
+ export interface NormalizedFindParams {
31
+ sort: {
32
+ field: string;
33
+ order: 'ASC' | 'DESC';
34
+ };
35
+ pagination: {
36
+ perPage: number;
37
+ nextToken?: string;
38
+ };
39
+ parsedFilters: ParsedFilter[];
40
+ }
41
+ /**
42
+ * Find操作のコンテキスト
43
+ */
44
+ export interface FindContext {
45
+ resource: string;
46
+ params: FindParams;
47
+ requestId: string;
48
+ shadowConfig: any;
49
+ sort: {
50
+ field: string;
51
+ order: 'ASC' | 'DESC';
52
+ };
53
+ pagination: {
54
+ perPage: number;
55
+ nextToken?: string;
56
+ };
57
+ parsedFilters: ParsedFilter[];
58
+ }
59
+ /**
60
+ * クエリ実行結果
61
+ */
62
+ export interface QueryExecutionResult {
63
+ items: any[];
64
+ pageInfo: {
65
+ hasNextPage: boolean;
66
+ hasPreviousPage: boolean;
67
+ };
68
+ nextToken?: string;
69
+ }
70
+ export type { FindParams, FindResult };
71
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/server/operations/find/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE7D;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,iBAAiB,CAAC;IAC1B,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC;KACvB,CAAC;IACF,UAAU,EAAE;QACV,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,UAAU,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,GAAG,CAAC;IAClB,IAAI,EAAE;QACJ,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC;KACvB,CAAC;IACF,UAAU,EAAE;QACV,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;IACF,aAAa,EAAE,YAAY,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,GAAG,EAAE,CAAC;IACb,QAAQ,EAAE;QACR,WAAW,EAAE,OAAO,CAAC;QACrB,eAAe,EAAE,OAAO,CAAC;KAC1B,CAAC;IACF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAGD,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Find操作の型定義
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/server/operations/find/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Find操作のユーティリティ関数
3
+ */
4
+ import type { FindParams } from '../../types.js';
5
+ import type { ParsedFilter, OptimizableFilter, NormalizedFindParams } from './types.js';
6
+ /**
7
+ * Find操作の設定を初期化する
8
+ *
9
+ * @returns シャドウ設定
10
+ */
11
+ export declare function initializeFindConfig(): import("../../index.js").ShadowConfig;
12
+ /**
13
+ * Find操作のパラメータを正規化する
14
+ *
15
+ * @param config - シャドウ設定
16
+ * @param resource - リソース名
17
+ * @param params - Find操作のパラメータ
18
+ * @returns 正規化されたパラメータ
19
+ */
20
+ export declare function normalizeFindParams(config: any, resource: string, params: FindParams): NormalizedFindParams;
21
+ /**
22
+ * 最適化可能なフィルター条件を検索する
23
+ *
24
+ * @param sortField - ソートフィールド
25
+ * @param parsedFilters - 解析済みフィルター条件
26
+ * @returns 最適化可能なフィルター条件(見つからない場合はundefined)
27
+ */
28
+ export declare function findOptimizableFilter(sortField: string, parsedFilters: ParsedFilter[]): OptimizableFilter | undefined;
29
+ /**
30
+ * すべてのフィルター条件にマッチするかチェックする
31
+ *
32
+ * @param record - レコード
33
+ * @param parsedFilters - 解析済みフィルター条件
34
+ * @returns マッチする場合true
35
+ */
36
+ export declare function matchesAllFilters(record: Record<string, unknown>, parsedFilters: ParsedFilter[]): boolean;
37
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../src/server/operations/find/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAYxF;;;;GAIG;AACH,wBAAgB,oBAAoB,0CAEnC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,GAAG,EACX,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,GACjB,oBAAoB,CAetB;AAoCD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,aAAa,EAAE,YAAY,EAAE,GAC5B,iBAAiB,GAAG,SAAS,CAI/B;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,aAAa,EAAE,YAAY,EAAE,GAC5B,OAAO,CA6BT"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Find操作のユーティリティ関数
3
+ */
4
+ import { getShadowConfig } from '../../shadow/index.js';
5
+ import { createLogger } from '../../../shared/index.js';
6
+ import { parseFilterField } from '../../utils/filter.js';
7
+ import { ConfigError } from '../../../shared/errors/index.js';
8
+ import { normalizeSort as originalNormalizeSort, normalizePagination as originalNormalizePagination } from '../../utils/validation.js';
9
+ const logger = createLogger({
10
+ service: 'find-utils',
11
+ level: process.env.LOG_LEVEL || 'info',
12
+ });
13
+ /**
14
+ * Find操作の設定を初期化する
15
+ *
16
+ * @returns シャドウ設定
17
+ */
18
+ export function initializeFindConfig() {
19
+ return getShadowConfig();
20
+ }
21
+ /**
22
+ * Find操作のパラメータを正規化する
23
+ *
24
+ * @param config - シャドウ設定
25
+ * @param resource - リソース名
26
+ * @param params - Find操作のパラメータ
27
+ * @returns 正規化されたパラメータ
28
+ */
29
+ export function normalizeFindParams(config, resource, params) {
30
+ // ソート条件を正規化
31
+ const sort = originalNormalizeSort(config, resource, params.sort);
32
+ // ページネーション条件を正規化
33
+ const pagination = originalNormalizePagination(params.pagination);
34
+ // フィルター条件を解析
35
+ const parsedFilters = parseFilters(params.filter);
36
+ return {
37
+ sort,
38
+ pagination,
39
+ parsedFilters,
40
+ };
41
+ }
42
+ /**
43
+ * フィルター条件を解析する
44
+ *
45
+ * @param filter - フィルター条件
46
+ * @returns 解析済みフィルター条件の配列
47
+ */
48
+ function parseFilters(filter) {
49
+ const parsedFilters = [];
50
+ if (!filter || Object.keys(filter).length === 0) {
51
+ return parsedFilters;
52
+ }
53
+ for (const [fieldKey, value] of Object.entries(filter)) {
54
+ try {
55
+ const parsed = parseFilterField(fieldKey);
56
+ parsedFilters.push({ parsed, value });
57
+ }
58
+ catch (error) {
59
+ logger.error('Invalid filter field syntax', {
60
+ fieldKey,
61
+ error: error instanceof Error ? error.message : String(error),
62
+ });
63
+ throw new ConfigError(`Invalid filter field syntax: ${fieldKey}`, {
64
+ field: fieldKey,
65
+ error: error instanceof Error ? error.message : String(error),
66
+ });
67
+ }
68
+ }
69
+ return parsedFilters;
70
+ }
71
+ /**
72
+ * 最適化可能なフィルター条件を検索する
73
+ *
74
+ * @param sortField - ソートフィールド
75
+ * @param parsedFilters - 解析済みフィルター条件
76
+ * @returns 最適化可能なフィルター条件(見つからない場合はundefined)
77
+ */
78
+ export function findOptimizableFilter(sortField, parsedFilters) {
79
+ return parsedFilters.find((filter) => filter.parsed.field === sortField);
80
+ }
81
+ /**
82
+ * すべてのフィルター条件にマッチするかチェックする
83
+ *
84
+ * @param record - レコード
85
+ * @param parsedFilters - 解析済みフィルター条件
86
+ * @returns マッチする場合true
87
+ */
88
+ export function matchesAllFilters(record, parsedFilters) {
89
+ return parsedFilters.every((filter) => {
90
+ const { field, operator } = filter.parsed;
91
+ const recordValue = record[field];
92
+ const filterValue = filter.value;
93
+ switch (operator) {
94
+ case 'eq':
95
+ return recordValue === filterValue;
96
+ case 'ne':
97
+ return recordValue !== filterValue;
98
+ case 'gt':
99
+ return recordValue != null && recordValue > filterValue;
100
+ case 'gte':
101
+ return recordValue != null && recordValue >= filterValue;
102
+ case 'lt':
103
+ return recordValue != null && recordValue < filterValue;
104
+ case 'lte':
105
+ return recordValue != null && recordValue <= filterValue;
106
+ case 'in':
107
+ return Array.isArray(filterValue) && filterValue.includes(recordValue);
108
+ case 'nin':
109
+ return Array.isArray(filterValue) && !filterValue.includes(recordValue);
110
+ case 'starts':
111
+ return typeof recordValue === 'string' && typeof filterValue === 'string' && recordValue.startsWith(filterValue);
112
+ default:
113
+ return true;
114
+ }
115
+ });
116
+ }
117
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../src/server/operations/find/utils.ts"],"names":[],"mappings":"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"}
@@ -1,18 +1,8 @@
1
- import type { FindParams, FindResult } from '../types.js';
2
1
  /**
3
- * find 操作を実行する
2
+ * find 操作
3
+ * リスト取得(フィルター・ソート・ページネーション対応)
4
4
  *
5
- * 処理フロー:
6
- * 1. シャドー設定を読み込み、ソートフィールドを検証
7
- * 2. シャドーレコードをQueryで取得(ソート済み)
8
- * 3. 本体レコードをBatchGetItemで取得
9
- * 4. フィルター条件を適用
10
- * 5. ページネーション情報を生成してレスポンスを返す
11
- *
12
- * @param resource - リソース名
13
- * @param params - findパラメータ
14
- * @param requestId - リクエストID
15
- * @returns リストデータ
5
+ * 要件: 4.3, 5.4, 5.5, 12.1-12.12
16
6
  */
17
- export declare function handleFind(resource: string, params: FindParams, requestId: string): Promise<FindResult>;
7
+ export { handleFind } from './find/handler.js';
18
8
  //# sourceMappingURL=find.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../../src/server/operations/find.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAkB1D;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,UAAU,CAAC,CAwarB"}
1
+ {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../../src/server/operations/find.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC"}