@exabugs/dynamodb-client 1.4.17 → 1.5.1

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 (45) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/client/FindCursor.d.ts +29 -0
  3. package/dist/client/FindCursor.d.ts.map +1 -1
  4. package/dist/client/FindCursor.js +48 -0
  5. package/dist/client/FindCursor.js.map +1 -1
  6. package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyField.d.ts +4 -0
  7. package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyField.d.ts.map +1 -0
  8. package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyField.js +49 -0
  9. package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyField.js.map +1 -0
  10. package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyInput.d.ts +4 -0
  11. package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyInput.d.ts.map +1 -0
  12. package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyInput.js +34 -0
  13. package/dist/integrations/react-admin/components/ReferenceManyToMany/ReferenceManyToManyInput.js.map +1 -0
  14. package/dist/integrations/react-admin/components/ReferenceManyToMany/index.d.ts +4 -0
  15. package/dist/integrations/react-admin/components/ReferenceManyToMany/index.d.ts.map +1 -0
  16. package/dist/integrations/react-admin/components/ReferenceManyToMany/index.js +3 -0
  17. package/dist/integrations/react-admin/components/ReferenceManyToMany/index.js.map +1 -0
  18. package/dist/integrations/react-admin/components/ReferenceManyToMany/types.d.ts +53 -0
  19. package/dist/integrations/react-admin/components/ReferenceManyToMany/types.d.ts.map +1 -0
  20. package/dist/integrations/react-admin/components/ReferenceManyToMany/types.js +33 -0
  21. package/dist/integrations/react-admin/components/ReferenceManyToMany/types.js.map +1 -0
  22. package/dist/integrations/react-admin/components/index.d.ts +1 -2
  23. package/dist/integrations/react-admin/components/index.d.ts.map +1 -1
  24. package/dist/integrations/react-admin/components/index.js +1 -2
  25. package/dist/integrations/react-admin/components/index.js.map +1 -1
  26. package/dist/integrations/react-admin/dataProvider.js +6 -6
  27. package/dist/scripts/operations/bulkRecordRepair.js +1 -2
  28. package/dist/scripts/operations/bulkRecordRepair.js.map +1 -1
  29. package/dist/server/handler.cjs +194 -36
  30. package/dist/server/handler.cjs.map +3 -3
  31. package/dist/server/operations/find/idQuery.d.ts.map +1 -1
  32. package/dist/server/operations/find/idQuery.js +104 -1
  33. package/dist/server/operations/find/idQuery.js.map +1 -1
  34. package/dist/server/operations/find/shadowQuery.d.ts.map +1 -1
  35. package/dist/server/operations/find/shadowQuery.js +140 -30
  36. package/dist/server/operations/find/shadowQuery.js.map +1 -1
  37. package/package.json +1 -1
  38. package/dist/integrations/react-admin/components/ReferenceManyToManyField.d.ts +0 -13
  39. package/dist/integrations/react-admin/components/ReferenceManyToManyField.d.ts.map +0 -1
  40. package/dist/integrations/react-admin/components/ReferenceManyToManyField.js +0 -171
  41. package/dist/integrations/react-admin/components/ReferenceManyToManyField.js.map +0 -1
  42. package/dist/integrations/react-admin/components/ReferenceManyToManyInput.d.ts +0 -41
  43. package/dist/integrations/react-admin/components/ReferenceManyToManyInput.d.ts.map +0 -1
  44. package/dist/integrations/react-admin/components/ReferenceManyToManyInput.js +0 -119
  45. package/dist/integrations/react-admin/components/ReferenceManyToManyInput.js.map +0 -1
@@ -1,5 +1,5 @@
1
- // @exabugs/dynamodb-client v1.4.17
2
- // Built: 2026-04-25T05:17:24.229Z
1
+ // @exabugs/dynamodb-client v1.5.1
2
+ // Built: 2026-09-27T04:40:22.568Z
3
3
  "use strict";
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -30657,6 +30657,9 @@ async function executeInQuery(resource, targetIds, sort, requestId) {
30657
30657
  };
30658
30658
  }
30659
30659
  async function executeAllRecordsQuery(resource, sort, perPage, nextToken, parsedFilters, requestId) {
30660
+ if (parsedFilters.length > 0) {
30661
+ return executeAllRecordsQueryFullScan(resource, sort, perPage, nextToken, parsedFilters, requestId);
30662
+ }
30660
30663
  const dbClient2 = getDBClient();
30661
30664
  const tableName = getTableName();
30662
30665
  const costTracker = new CostTracker();
@@ -30723,6 +30726,84 @@ async function executeAllRecordsQuery(resource, sort, perPage, nextToken, parsed
30723
30726
  consumedCapacity: costTracker.getAggregated()
30724
30727
  };
30725
30728
  }
30729
+ async function executeAllRecordsQueryFullScan(resource, sort, perPage, nextToken, parsedFilters, requestId) {
30730
+ const dbClient2 = getDBClient();
30731
+ const tableName = getTableName();
30732
+ const costTracker = new CostTracker();
30733
+ const offset = nextToken ? decodeOffsetToken(nextToken) ?? 0 : 0;
30734
+ logger6.debug("Executing full scan query (ID sort)", {
30735
+ requestId,
30736
+ resource,
30737
+ offset
30738
+ });
30739
+ const allRecords = [];
30740
+ let exclusiveStartKey;
30741
+ let previousKeySignature;
30742
+ const MAX_ITERATIONS = 1e4;
30743
+ let iterations = 0;
30744
+ do {
30745
+ if (++iterations > MAX_ITERATIONS) {
30746
+ logger6.error("executeAllRecordsQueryFullScan: \u6700\u5927\u53CD\u5FA9\u56DE\u6570\u3092\u8D85\u904E\u3057\u305F\u305F\u3081\u4E2D\u65AD", {
30747
+ requestId,
30748
+ resource,
30749
+ iterations
30750
+ });
30751
+ break;
30752
+ }
30753
+ const queryResult = await executeDynamoDBOperation(
30754
+ () => dbClient2.send(
30755
+ new import_lib_dynamodb2.QueryCommand({
30756
+ TableName: tableName,
30757
+ KeyConditionExpression: "PK = :pk AND begins_with(SK, :skPrefix)",
30758
+ ExpressionAttributeValues: {
30759
+ ":pk": resource,
30760
+ ":skPrefix": "id#"
30761
+ },
30762
+ ScanIndexForward: sort.order === "ASC",
30763
+ Limit: 1e3,
30764
+ // 大きめの Limit でループ回数を最小化
30765
+ ExclusiveStartKey: exclusiveStartKey,
30766
+ ConsistentRead: true,
30767
+ ReturnConsumedCapacity: "TOTAL"
30768
+ })
30769
+ ),
30770
+ "Query"
30771
+ );
30772
+ costTracker.add(queryResult.ConsumedCapacity);
30773
+ allRecords.push(...queryResult.Items || []);
30774
+ const nextKey = queryResult.LastEvaluatedKey;
30775
+ const nextKeySignature = nextKey ? `${nextKey.PK}#${nextKey.SK}` : void 0;
30776
+ if (nextKeySignature && nextKeySignature === previousKeySignature) {
30777
+ logger6.error("executeAllRecordsQueryFullScan: \u540C\u4E00\u306ELastEvaluatedKey\u304C\u8FD4\u5374\u3055\u308C\u305F\u305F\u3081\u4E2D\u65AD", {
30778
+ requestId,
30779
+ resource,
30780
+ iterations
30781
+ });
30782
+ break;
30783
+ }
30784
+ previousKeySignature = nextKeySignature;
30785
+ exclusiveStartKey = nextKey;
30786
+ } while (exclusiveStartKey);
30787
+ let items = allRecords.map((item) => extractCleanRecord(item));
30788
+ items = items.filter((record) => matchesAllFilters(record, parsedFilters));
30789
+ const page = items.slice(offset, offset + perPage);
30790
+ const hasNextPage = offset + perPage < items.length;
30791
+ const nextTokenValue = hasNextPage ? encodeOffsetToken(offset + perPage) : void 0;
30792
+ logger6.info("ID full scan query succeeded", {
30793
+ requestId,
30794
+ resource,
30795
+ totalMatched: items.length,
30796
+ offset,
30797
+ returned: page.length,
30798
+ hasNextPage
30799
+ });
30800
+ return {
30801
+ items: page,
30802
+ pageInfo: { hasNextPage, hasPreviousPage: offset > 0 },
30803
+ ...nextTokenValue && { nextToken: nextTokenValue },
30804
+ consumedCapacity: costTracker.getAggregated()
30805
+ };
30806
+ }
30726
30807
  var import_lib_dynamodb2, logger6;
30727
30808
  var init_idQuery = __esm({
30728
30809
  "src/server/operations/find/idQuery.ts"() {
@@ -30741,6 +30822,7 @@ var init_idQuery = __esm({
30741
30822
  __name(executeSpecificIdQuery, "executeSpecificIdQuery");
30742
30823
  __name(executeInQuery, "executeInQuery");
30743
30824
  __name(executeAllRecordsQuery, "executeAllRecordsQuery");
30825
+ __name(executeAllRecordsQueryFullScan, "executeAllRecordsQueryFullScan");
30744
30826
  }
30745
30827
  });
30746
30828
 
@@ -30906,6 +30988,19 @@ async function executeShadowQuery(resource, normalizedParams, requestId) {
30906
30988
  );
30907
30989
  }
30908
30990
  const optimizableFilter = findOptimizableFilter(sort.field, parsedFilters);
30991
+ const isKeyConditionOptimized = optimizableFilter !== void 0 && KEY_CONDITION_OPERATORS.has(optimizableFilter.parsed.operator);
30992
+ const residualFilters = parsedFilters.filter(
30993
+ (f4) => !(isKeyConditionOptimized && f4 === optimizableFilter)
30994
+ );
30995
+ if (residualFilters.length > 0) {
30996
+ logger8.debug("Residual filters detected, falling back to full scan", {
30997
+ requestId,
30998
+ resource,
30999
+ sortField: sort.field,
31000
+ residualFilterFields: residualFilters.map((f4) => f4.parsed.field)
31001
+ });
31002
+ return executeFullScanQuery(resource, normalizedParams, costTracker, requestId);
31003
+ }
30909
31004
  logger8.debug("Executing shadow query", {
30910
31005
  requestId,
30911
31006
  resource,
@@ -30918,7 +31013,7 @@ async function executeShadowQuery(resource, normalizedParams, requestId) {
30918
31013
  sort,
30919
31014
  perPage,
30920
31015
  nextToken,
30921
- optimizableFilter,
31016
+ isKeyConditionOptimized ? optimizableFilter : void 0,
30922
31017
  costTracker,
30923
31018
  requestId
30924
31019
  );
@@ -30986,38 +31081,13 @@ async function executeFilterFirstQuery(resource, normalizedParams, filterCandida
30986
31081
  sortField: sort.field,
30987
31082
  offset
30988
31083
  });
30989
- const allShadowItems = [];
30990
- let lastKey;
30991
- do {
30992
- const result = await executeShadowRecordQuery(
30993
- resource,
30994
- filterSort,
30995
- 1e3,
30996
- // 大きめの Limit でループ回数を最小化
30997
- lastKey ? encodeNextToken(lastKey.PK, lastKey.SK) : void 0,
30998
- filterCandidate,
30999
- costTracker,
31000
- requestId
31001
- );
31002
- allShadowItems.push(...result.Items || []);
31003
- lastKey = result.LastEvaluatedKey;
31004
- } while (lastKey);
31005
- const allIds = Array.from(new Set(extractRecordIds(allShadowItems)));
31006
- if (allIds.length === 0) {
31007
- return {
31008
- items: [],
31009
- pageInfo: { hasNextPage: false, hasPreviousPage: offset > 0 },
31010
- consumedCapacity: costTracker.getAggregated()
31011
- };
31012
- }
31013
- const mainRecords = await fetchMainRecords(resource, allIds, costTracker, requestId);
31014
- const recordMap = new Map(
31015
- mainRecords.map((item) => {
31016
- const data2 = item.data;
31017
- return [data2.id, extractCleanRecord(item)];
31018
- })
31084
+ let items = await fetchAllRecordsViaShadowIndex(
31085
+ resource,
31086
+ filterSort,
31087
+ filterCandidate,
31088
+ costTracker,
31089
+ requestId
31019
31090
  );
31020
- let items = allIds.map((id) => recordMap.get(id)).filter((r4) => r4 !== void 0);
31021
31091
  if (remainingFilters.length > 0) {
31022
31092
  items = items.filter((r4) => matchesAllFilters(r4, remainingFilters));
31023
31093
  }
@@ -31042,6 +31112,91 @@ async function executeFilterFirstQuery(resource, normalizedParams, filterCandida
31042
31112
  consumedCapacity: costTracker.getAggregated()
31043
31113
  };
31044
31114
  }
31115
+ async function executeFullScanQuery(resource, normalizedParams, costTracker, requestId) {
31116
+ const { sort, pagination, parsedFilters } = normalizedParams;
31117
+ const { perPage, nextToken } = pagination;
31118
+ const offset = nextToken ? decodeOffsetToken(nextToken) ?? 0 : 0;
31119
+ logger8.debug("Executing full scan query", {
31120
+ requestId,
31121
+ resource,
31122
+ sortField: sort.field,
31123
+ offset
31124
+ });
31125
+ let items = await fetchAllRecordsViaShadowIndex(resource, sort, void 0, costTracker, requestId);
31126
+ if (parsedFilters.length > 0) {
31127
+ items = items.filter((r4) => matchesAllFilters(r4, parsedFilters));
31128
+ }
31129
+ const page = items.slice(offset, offset + perPage);
31130
+ const hasNextPage = offset + perPage < items.length;
31131
+ const nextTokenValue = hasNextPage ? encodeOffsetToken(offset + perPage) : void 0;
31132
+ logger8.info("Full scan query succeeded", {
31133
+ requestId,
31134
+ resource,
31135
+ sortField: sort.field,
31136
+ totalMatched: items.length,
31137
+ offset,
31138
+ returned: page.length,
31139
+ hasNextPage
31140
+ });
31141
+ return {
31142
+ items: page,
31143
+ pageInfo: { hasNextPage, hasPreviousPage: offset > 0 },
31144
+ ...nextTokenValue && { nextToken: nextTokenValue },
31145
+ consumedCapacity: costTracker.getAggregated()
31146
+ };
31147
+ }
31148
+ async function fetchAllRecordsViaShadowIndex(resource, indexSort, indexFilter, costTracker, requestId) {
31149
+ const allShadowItems = [];
31150
+ let lastKey;
31151
+ let previousKeySignature;
31152
+ const MAX_ITERATIONS = 1e4;
31153
+ let iterations = 0;
31154
+ do {
31155
+ if (++iterations > MAX_ITERATIONS) {
31156
+ logger8.error("fetchAllRecordsViaShadowIndex: \u6700\u5927\u53CD\u5FA9\u56DE\u6570\u3092\u8D85\u904E\u3057\u305F\u305F\u3081\u4E2D\u65AD", {
31157
+ requestId,
31158
+ resource,
31159
+ iterations
31160
+ });
31161
+ break;
31162
+ }
31163
+ const result = await executeShadowRecordQuery(
31164
+ resource,
31165
+ indexSort,
31166
+ 1e3,
31167
+ // 大きめの Limit でループ回数を最小化
31168
+ lastKey ? encodeNextToken(lastKey.PK, lastKey.SK) : void 0,
31169
+ indexFilter,
31170
+ costTracker,
31171
+ requestId
31172
+ );
31173
+ allShadowItems.push(...result.Items || []);
31174
+ const nextKey = result.LastEvaluatedKey;
31175
+ const nextKeySignature = nextKey ? `${nextKey.PK}#${nextKey.SK}` : void 0;
31176
+ if (nextKeySignature && nextKeySignature === previousKeySignature) {
31177
+ logger8.error("fetchAllRecordsViaShadowIndex: \u540C\u4E00\u306ELastEvaluatedKey\u304C\u8FD4\u5374\u3055\u308C\u305F\u305F\u3081\u4E2D\u65AD", {
31178
+ requestId,
31179
+ resource,
31180
+ iterations
31181
+ });
31182
+ break;
31183
+ }
31184
+ previousKeySignature = nextKeySignature;
31185
+ lastKey = nextKey;
31186
+ } while (lastKey);
31187
+ const allIds = Array.from(new Set(extractRecordIds(allShadowItems)));
31188
+ if (allIds.length === 0) {
31189
+ return [];
31190
+ }
31191
+ const mainRecords = await fetchMainRecords(resource, allIds, costTracker, requestId);
31192
+ const recordMap = new Map(
31193
+ mainRecords.map((item) => {
31194
+ const data2 = item.data;
31195
+ return [data2.id, extractCleanRecord(item)];
31196
+ })
31197
+ );
31198
+ return allIds.map((id) => recordMap.get(id)).filter((r4) => r4 !== void 0);
31199
+ }
31045
31200
  function selectFilterFirstCandidate(parsedFilters, sortField, schema, perPage) {
31046
31201
  const eqFilters = parsedFilters.filter(
31047
31202
  (f4) => f4.parsed.operator === "$eq" && f4.parsed.field !== sortField
@@ -31238,7 +31393,7 @@ async function fetchMainRecords(resource, recordIds, costTracker, requestId) {
31238
31393
  });
31239
31394
  return allRecords;
31240
31395
  }
31241
- var import_lib_dynamodb4, logger8;
31396
+ var import_lib_dynamodb4, logger8, KEY_CONDITION_OPERATORS;
31242
31397
  var init_shadowQuery = __esm({
31243
31398
  "src/server/operations/find/shadowQuery.ts"() {
31244
31399
  "use strict";
@@ -31253,8 +31408,11 @@ var init_shadowQuery = __esm({
31253
31408
  service: "shadow-query",
31254
31409
  level: process.env.LOG_LEVEL || "info"
31255
31410
  });
31411
+ KEY_CONDITION_OPERATORS = /* @__PURE__ */ new Set(["$eq", "$gt", "$gte", "$lt", "$lte", "$starts"]);
31256
31412
  __name(executeShadowQuery, "executeShadowQuery");
31257
31413
  __name(executeFilterFirstQuery, "executeFilterFirstQuery");
31414
+ __name(executeFullScanQuery, "executeFullScanQuery");
31415
+ __name(fetchAllRecordsViaShadowIndex, "fetchAllRecordsViaShadowIndex");
31258
31416
  __name(selectFilterFirstCandidate, "selectFilterFirstCandidate");
31259
31417
  __name(sortInMemory, "sortInMemory");
31260
31418
  __name(executeShadowRecordQuery, "executeShadowRecordQuery");
@@ -34559,7 +34717,7 @@ async function handler(event) {
34559
34717
  return createCorsResponse(HTTP_STATUS.OK);
34560
34718
  }
34561
34719
  if (event.requestContext.http.method === "GET" && event.requestContext.http.path === "/version") {
34562
- const version = "1.4.17";
34720
+ const version = "1.5.1";
34563
34721
  return createSuccessResponse({ version, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, requestId);
34564
34722
  }
34565
34723
  if (event.requestContext.http.method !== "POST") {