@exabugs/dynamodb-client 1.4.7 → 1.4.9
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/dist/server/handler.cjs +112 -17
- package/dist/server/handler.cjs.map +3 -3
- package/dist/server/operations/find/shadowQuery.d.ts.map +1 -1
- package/dist/server/operations/find/shadowQuery.js +98 -31
- package/dist/server/operations/find/shadowQuery.js.map +1 -1
- package/dist/server/utils/pagination.d.ts +9 -0
- package/dist/server/utils/pagination.d.ts.map +1 -1
- package/dist/server/utils/pagination.js +28 -0
- package/dist/server/utils/pagination.js.map +1 -1
- package/package.json +1 -1
package/dist/server/handler.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// @exabugs/dynamodb-client v1.4.
|
|
2
|
-
// Built: 2026-04-
|
|
1
|
+
// @exabugs/dynamodb-client v1.4.9
|
|
2
|
+
// Built: 2026-04-05T13:06:32.256Z
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
@@ -30324,6 +30324,25 @@ function encodeNextToken(pk, sk) {
|
|
|
30324
30324
|
const base64url = base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
30325
30325
|
return base64url;
|
|
30326
30326
|
}
|
|
30327
|
+
function encodeOffsetToken(offset) {
|
|
30328
|
+
const payload2 = { offset };
|
|
30329
|
+
const json = JSON.stringify(payload2);
|
|
30330
|
+
const base64 = Buffer.from(json, "utf-8").toString("base64");
|
|
30331
|
+
return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
30332
|
+
}
|
|
30333
|
+
function decodeOffsetToken(token) {
|
|
30334
|
+
try {
|
|
30335
|
+
let base64 = token.replace(/-/g, "+").replace(/_/g, "/");
|
|
30336
|
+
while (base64.length % 4 !== 0) base64 += "=";
|
|
30337
|
+
const payload2 = JSON.parse(Buffer.from(base64, "base64").toString("utf-8"));
|
|
30338
|
+
if (typeof payload2.offset === "number" && !payload2.PK) {
|
|
30339
|
+
return payload2.offset;
|
|
30340
|
+
}
|
|
30341
|
+
return null;
|
|
30342
|
+
} catch {
|
|
30343
|
+
return null;
|
|
30344
|
+
}
|
|
30345
|
+
}
|
|
30327
30346
|
function decodeNextToken(token) {
|
|
30328
30347
|
try {
|
|
30329
30348
|
let base64 = token.replace(/-/g, "+").replace(/_/g, "/");
|
|
@@ -30349,6 +30368,8 @@ var init_pagination = __esm({
|
|
|
30349
30368
|
init_index2();
|
|
30350
30369
|
init_validation3();
|
|
30351
30370
|
__name(encodeNextToken, "encodeNextToken");
|
|
30371
|
+
__name(encodeOffsetToken, "encodeOffsetToken");
|
|
30372
|
+
__name(decodeOffsetToken, "decodeOffsetToken");
|
|
30352
30373
|
__name(decodeNextToken, "decodeNextToken");
|
|
30353
30374
|
}
|
|
30354
30375
|
});
|
|
@@ -30819,20 +30840,26 @@ async function executeShadowQuery(resource, normalizedParams, requestId) {
|
|
|
30819
30840
|
const costTracker = new CostTracker();
|
|
30820
30841
|
const filterFirstCandidate = selectFilterFirstCandidate(parsedFilters, sort.field, normalizedParams.schema, perPage);
|
|
30821
30842
|
const isFilterFirst = filterFirstCandidate !== void 0;
|
|
30822
|
-
|
|
30823
|
-
|
|
30824
|
-
|
|
30843
|
+
if (isFilterFirst) {
|
|
30844
|
+
return executeFilterFirstQuery(
|
|
30845
|
+
resource,
|
|
30846
|
+
normalizedParams,
|
|
30847
|
+
filterFirstCandidate,
|
|
30848
|
+
costTracker,
|
|
30849
|
+
requestId
|
|
30850
|
+
);
|
|
30851
|
+
}
|
|
30852
|
+
const optimizableFilter = findOptimizableFilter(sort.field, parsedFilters);
|
|
30825
30853
|
logger8.debug("Executing shadow query", {
|
|
30826
30854
|
requestId,
|
|
30827
30855
|
resource,
|
|
30828
30856
|
sortField: sort.field,
|
|
30829
|
-
isFilterFirst,
|
|
30830
|
-
queryField: querySort.field,
|
|
30857
|
+
isFilterFirst: false,
|
|
30831
30858
|
hasFilters: parsedFilters.length > 0
|
|
30832
30859
|
});
|
|
30833
30860
|
const shadowRecords = await executeShadowRecordQuery(
|
|
30834
30861
|
resource,
|
|
30835
|
-
|
|
30862
|
+
sort,
|
|
30836
30863
|
perPage,
|
|
30837
30864
|
nextToken,
|
|
30838
30865
|
optimizableFilter,
|
|
@@ -30863,11 +30890,8 @@ async function executeShadowQuery(resource, normalizedParams, requestId) {
|
|
|
30863
30890
|
seenIds.add(id);
|
|
30864
30891
|
return true;
|
|
30865
30892
|
}).map((id) => recordMap.get(id)).filter((record) => record !== void 0);
|
|
30866
|
-
if (
|
|
30867
|
-
items = items.filter((record) => matchesAllFilters(record,
|
|
30868
|
-
}
|
|
30869
|
-
if (isFilterFirst) {
|
|
30870
|
-
items = sortInMemory(items, sort);
|
|
30893
|
+
if (parsedFilters.length > 0) {
|
|
30894
|
+
items = items.filter((record) => matchesAllFilters(record, parsedFilters));
|
|
30871
30895
|
}
|
|
30872
30896
|
const hasNextPage = (shadowRecords.Items?.length || 0) < perPage ? false : shadowRecords.LastEvaluatedKey !== void 0;
|
|
30873
30897
|
const nextTokenValue = hasNextPage && shadowRecords.LastEvaluatedKey ? encodeNextToken(
|
|
@@ -30878,7 +30902,7 @@ async function executeShadowQuery(resource, normalizedParams, requestId) {
|
|
|
30878
30902
|
requestId,
|
|
30879
30903
|
resource,
|
|
30880
30904
|
sortField: sort.field,
|
|
30881
|
-
isFilterFirst,
|
|
30905
|
+
isFilterFirst: false,
|
|
30882
30906
|
shadowCount: shadowRecords.Items?.length || 0,
|
|
30883
30907
|
mainCount: items.length,
|
|
30884
30908
|
hasNextPage
|
|
@@ -30893,6 +30917,75 @@ async function executeShadowQuery(resource, normalizedParams, requestId) {
|
|
|
30893
30917
|
consumedCapacity: costTracker.getAggregated()
|
|
30894
30918
|
};
|
|
30895
30919
|
}
|
|
30920
|
+
async function executeFilterFirstQuery(resource, normalizedParams, filterCandidate, costTracker, requestId) {
|
|
30921
|
+
const { sort, pagination, parsedFilters } = normalizedParams;
|
|
30922
|
+
const { perPage, nextToken } = pagination;
|
|
30923
|
+
const offset = nextToken ? decodeOffsetToken(nextToken) ?? 0 : 0;
|
|
30924
|
+
const filterSort = { field: filterCandidate.parsed.field, order: "ASC" };
|
|
30925
|
+
const remainingFilters = parsedFilters.filter((f4) => f4 !== filterCandidate);
|
|
30926
|
+
logger8.debug("Executing filter-first query", {
|
|
30927
|
+
requestId,
|
|
30928
|
+
resource,
|
|
30929
|
+
filterField: filterCandidate.parsed.field,
|
|
30930
|
+
sortField: sort.field,
|
|
30931
|
+
offset
|
|
30932
|
+
});
|
|
30933
|
+
const allShadowItems = [];
|
|
30934
|
+
let lastKey;
|
|
30935
|
+
do {
|
|
30936
|
+
const result = await executeShadowRecordQuery(
|
|
30937
|
+
resource,
|
|
30938
|
+
filterSort,
|
|
30939
|
+
1e3,
|
|
30940
|
+
// 大きめの Limit でループ回数を最小化
|
|
30941
|
+
lastKey ? encodeNextToken(lastKey.PK, lastKey.SK) : void 0,
|
|
30942
|
+
filterCandidate,
|
|
30943
|
+
costTracker,
|
|
30944
|
+
requestId
|
|
30945
|
+
);
|
|
30946
|
+
allShadowItems.push(...result.Items || []);
|
|
30947
|
+
lastKey = result.LastEvaluatedKey;
|
|
30948
|
+
} while (lastKey);
|
|
30949
|
+
const allIds = Array.from(new Set(extractRecordIds(allShadowItems)));
|
|
30950
|
+
if (allIds.length === 0) {
|
|
30951
|
+
return {
|
|
30952
|
+
items: [],
|
|
30953
|
+
pageInfo: { hasNextPage: false, hasPreviousPage: offset > 0 },
|
|
30954
|
+
consumedCapacity: costTracker.getAggregated()
|
|
30955
|
+
};
|
|
30956
|
+
}
|
|
30957
|
+
const mainRecords = await fetchMainRecords(resource, allIds, costTracker, requestId);
|
|
30958
|
+
const recordMap = new Map(
|
|
30959
|
+
mainRecords.map((item) => {
|
|
30960
|
+
const data2 = item.data;
|
|
30961
|
+
return [data2.id, extractCleanRecord(item)];
|
|
30962
|
+
})
|
|
30963
|
+
);
|
|
30964
|
+
let items = allIds.map((id) => recordMap.get(id)).filter((r4) => r4 !== void 0);
|
|
30965
|
+
if (remainingFilters.length > 0) {
|
|
30966
|
+
items = items.filter((r4) => matchesAllFilters(r4, remainingFilters));
|
|
30967
|
+
}
|
|
30968
|
+
items = sortInMemory(items, sort);
|
|
30969
|
+
const page = items.slice(offset, offset + perPage);
|
|
30970
|
+
const hasNextPage = offset + perPage < items.length;
|
|
30971
|
+
const nextTokenValue = hasNextPage ? encodeOffsetToken(offset + perPage) : void 0;
|
|
30972
|
+
logger8.info("Filter-first query succeeded", {
|
|
30973
|
+
requestId,
|
|
30974
|
+
resource,
|
|
30975
|
+
filterField: filterCandidate.parsed.field,
|
|
30976
|
+
sortField: sort.field,
|
|
30977
|
+
totalMatched: items.length,
|
|
30978
|
+
offset,
|
|
30979
|
+
returned: page.length,
|
|
30980
|
+
hasNextPage
|
|
30981
|
+
});
|
|
30982
|
+
return {
|
|
30983
|
+
items: page,
|
|
30984
|
+
pageInfo: { hasNextPage, hasPreviousPage: offset > 0 },
|
|
30985
|
+
...nextTokenValue && { nextToken: nextTokenValue },
|
|
30986
|
+
consumedCapacity: costTracker.getAggregated()
|
|
30987
|
+
};
|
|
30988
|
+
}
|
|
30896
30989
|
function selectFilterFirstCandidate(parsedFilters, sortField, schema, perPage) {
|
|
30897
30990
|
const eqFilters = parsedFilters.filter(
|
|
30898
30991
|
(f4) => f4.parsed.operator === "$eq" && f4.parsed.field !== sortField
|
|
@@ -30900,9 +30993,10 @@ function selectFilterFirstCandidate(parsedFilters, sortField, schema, perPage) {
|
|
|
30900
30993
|
if (eqFilters.length === 0) return void 0;
|
|
30901
30994
|
const cardinality = schema?.cardinality;
|
|
30902
30995
|
if (!cardinality) {
|
|
30903
|
-
return
|
|
30996
|
+
return void 0;
|
|
30904
30997
|
}
|
|
30905
|
-
const
|
|
30998
|
+
const threshold = perPage / 2;
|
|
30999
|
+
const scored = eqFilters.map((f4) => ({ f: f4, score: cardinality[f4.parsed.field] ?? 0 })).filter(({ score }) => score > threshold).sort((a4, b4) => b4.score - a4.score);
|
|
30906
31000
|
return scored[0]?.f;
|
|
30907
31001
|
}
|
|
30908
31002
|
function sortInMemory(items, sort) {
|
|
@@ -31099,6 +31193,7 @@ var init_shadowQuery = __esm({
|
|
|
31099
31193
|
level: process.env.LOG_LEVEL || "info"
|
|
31100
31194
|
});
|
|
31101
31195
|
__name(executeShadowQuery, "executeShadowQuery");
|
|
31196
|
+
__name(executeFilterFirstQuery, "executeFilterFirstQuery");
|
|
31102
31197
|
__name(selectFilterFirstCandidate, "selectFilterFirstCandidate");
|
|
31103
31198
|
__name(sortInMemory, "sortInMemory");
|
|
31104
31199
|
__name(executeShadowRecordQuery, "executeShadowRecordQuery");
|
|
@@ -34400,7 +34495,7 @@ async function handler(event) {
|
|
|
34400
34495
|
return createCorsResponse(HTTP_STATUS.OK);
|
|
34401
34496
|
}
|
|
34402
34497
|
if (event.requestContext.http.method === "GET" && event.requestContext.http.path === "/version") {
|
|
34403
|
-
const version = "1.4.
|
|
34498
|
+
const version = "1.4.9";
|
|
34404
34499
|
return createSuccessResponse({ version, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, requestId);
|
|
34405
34500
|
}
|
|
34406
34501
|
if (event.requestContext.http.method !== "POST") {
|