@exabugs/dynamodb-client 1.27.0 → 1.27.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.
- package/CHANGELOG.md +18 -0
- package/dist/__generated__/models/findResultPageInfo.d.ts +2 -0
- package/dist/__generated__/models/findResultPageInfo.d.ts.map +1 -1
- package/dist/server/handler.cjs +318 -307
- package/dist/server/handler.cjs.map +4 -4
- package/dist/server/media-handler.cjs +2 -2
- package/dist/server/media-process-handler-dlq.cjs +2 -2
- package/dist/server/media-process-handler.cjs +2 -2
- package/dist/server/operations/find/handler.d.ts.map +1 -1
- package/dist/server/operations/find/handler.js +4 -1
- package/dist/server/operations/find/handler.js.map +1 -1
- package/dist/server/operations/find/nearQuery.d.ts +4 -1
- package/dist/server/operations/find/nearQuery.d.ts.map +1 -1
- package/dist/server/operations/find/nearQuery.js +30 -42
- package/dist/server/operations/find/nearQuery.js.map +1 -1
- package/dist/server/operations/updateMany.d.ts.map +1 -1
- package/dist/server/operations/updateMany.js +17 -15
- package/dist/server/operations/updateMany.js.map +1 -1
- package/dist/server/query/nearSearch.d.ts +37 -25
- package/dist/server/query/nearSearch.d.ts.map +1 -1
- package/dist/server/query/nearSearch.js +87 -125
- package/dist/server/query/nearSearch.js.map +1 -1
- package/dist/server/utils/updateOperators.d.ts +12 -1
- package/dist/server/utils/updateOperators.d.ts.map +1 -1
- package/dist/server/utils/updateOperators.js +53 -6
- package/dist/server/utils/updateOperators.js.map +1 -1
- package/package.json +1 -1
package/dist/server/handler.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// @exabugs/dynamodb-client v1.27.
|
|
2
|
-
// Built: 2026-11-
|
|
1
|
+
// @exabugs/dynamodb-client v1.27.1
|
|
2
|
+
// Built: 2026-11-15T11:40:11.703Z
|
|
3
3
|
"use strict";
|
|
4
4
|
var __create = Object.create;
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
@@ -38934,6 +38934,9 @@ function isGeoCoordinates(value) {
|
|
|
38934
38934
|
function encodeGeoHash(latitude, longitude, precision = 6) {
|
|
38935
38935
|
return import_ngeohash.default.encode(latitude, longitude, precision);
|
|
38936
38936
|
}
|
|
38937
|
+
function decodeGeoHash(geohash) {
|
|
38938
|
+
return import_ngeohash.default.decode(geohash);
|
|
38939
|
+
}
|
|
38937
38940
|
function getNeighborGeoHashes(geohash) {
|
|
38938
38941
|
const neighbors = [
|
|
38939
38942
|
geohash,
|
|
@@ -39004,6 +39007,7 @@ var init_utils5 = __esm({
|
|
|
39004
39007
|
import_ngeohash = __toESM(require_main(), 1);
|
|
39005
39008
|
__name(isGeoCoordinates, "isGeoCoordinates");
|
|
39006
39009
|
__name(encodeGeoHash, "encodeGeoHash");
|
|
39010
|
+
__name(decodeGeoHash, "decodeGeoHash");
|
|
39007
39011
|
__name(getNeighborGeoHashes, "getNeighborGeoHashes");
|
|
39008
39012
|
__name(calculateDistance, "calculateDistance");
|
|
39009
39013
|
__name(isNearQueryGeoJSON, "isNearQueryGeoJSON");
|
|
@@ -39808,6 +39812,37 @@ var init_utils6 = __esm({
|
|
|
39808
39812
|
}
|
|
39809
39813
|
});
|
|
39810
39814
|
|
|
39815
|
+
// src/server/utils/idFilter.ts
|
|
39816
|
+
function splitIdFilter(filter) {
|
|
39817
|
+
const { id, ...rest } = filter ?? {};
|
|
39818
|
+
if (typeof id === "string") {
|
|
39819
|
+
return { id, rest };
|
|
39820
|
+
}
|
|
39821
|
+
if (typeof id === "object" && id !== null && "$in" in id) {
|
|
39822
|
+
return { ids: (id.$in ?? []).slice(), rest };
|
|
39823
|
+
}
|
|
39824
|
+
return { rest: filter ?? {} };
|
|
39825
|
+
}
|
|
39826
|
+
function conditionOf(rest) {
|
|
39827
|
+
return Object.keys(rest).length > 0 ? rest : void 0;
|
|
39828
|
+
}
|
|
39829
|
+
function conditionMatcher(condition) {
|
|
39830
|
+
if (!condition || Object.keys(condition).length === 0) {
|
|
39831
|
+
return () => true;
|
|
39832
|
+
}
|
|
39833
|
+
const parsed = parseFilters(condition);
|
|
39834
|
+
return (record) => matchesAllFilters(record, parsed);
|
|
39835
|
+
}
|
|
39836
|
+
var init_idFilter = __esm({
|
|
39837
|
+
"src/server/utils/idFilter.ts"() {
|
|
39838
|
+
"use strict";
|
|
39839
|
+
init_utils6();
|
|
39840
|
+
__name(splitIdFilter, "splitIdFilter");
|
|
39841
|
+
__name(conditionOf, "conditionOf");
|
|
39842
|
+
__name(conditionMatcher, "conditionMatcher");
|
|
39843
|
+
}
|
|
39844
|
+
});
|
|
39845
|
+
|
|
39811
39846
|
// src/server/utils/batchGet.ts
|
|
39812
39847
|
function sleep2(ms) {
|
|
39813
39848
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -39929,80 +39964,68 @@ var init_converter = __esm({
|
|
|
39929
39964
|
});
|
|
39930
39965
|
|
|
39931
39966
|
// src/server/query/nearSearch.ts
|
|
39932
|
-
function
|
|
39933
|
-
const
|
|
39934
|
-
|
|
39935
|
-
|
|
39936
|
-
|
|
39937
|
-
|
|
39967
|
+
function cellSizeMeters(precision, cosLat) {
|
|
39968
|
+
const latBits = Math.floor(5 * precision / 2);
|
|
39969
|
+
const lonBits = Math.ceil(5 * precision / 2);
|
|
39970
|
+
const heightDeg = 180 / 2 ** latBits;
|
|
39971
|
+
return {
|
|
39972
|
+
height: heightDeg * METERS_PER_DEGREE,
|
|
39973
|
+
width: 360 / 2 ** lonBits * METERS_PER_DEGREE * cosLat,
|
|
39974
|
+
heightDeg
|
|
39975
|
+
};
|
|
39976
|
+
}
|
|
39977
|
+
function guaranteedRadius(precision, latitude) {
|
|
39978
|
+
const { heightDeg } = cellSizeMeters(precision, 1);
|
|
39979
|
+
const worstLatitude = Math.min(89.9, Math.abs(latitude) + 2 * heightDeg);
|
|
39980
|
+
const { height, width } = cellSizeMeters(precision, Math.cos(worstLatitude * Math.PI / 180));
|
|
39981
|
+
return Math.min(height, width);
|
|
39982
|
+
}
|
|
39983
|
+
function shadowPositionError(shadowPrecision) {
|
|
39984
|
+
const { height, width } = cellSizeMeters(shadowPrecision, 1);
|
|
39985
|
+
return Math.hypot(height, width) / 2;
|
|
39938
39986
|
}
|
|
39939
|
-
|
|
39987
|
+
function kthOf(sortedAscending, k5) {
|
|
39988
|
+
return sortedAscending.length >= k5 ? sortedAscending[k5 - 1] : void 0;
|
|
39989
|
+
}
|
|
39990
|
+
async function executeNearSearch(nearQuery, fieldName, limit, searchShadows, readBodies, config = DEFAULT_GEOHASH_CONFIG) {
|
|
39940
39991
|
const { latitude, longitude } = extractCoordinatesFromNearQuery(nearQuery);
|
|
39941
39992
|
const maxDistance = extractMaxDistanceFromNearQuery(nearQuery);
|
|
39942
39993
|
const minDistance = extractMinDistanceFromNearQuery(nearQuery);
|
|
39994
|
+
const epsilon = shadowPositionError(config.shadowPrecision);
|
|
39943
39995
|
let precision = config.searchPrecision;
|
|
39944
|
-
let allCandidates = [];
|
|
39945
39996
|
let iterations = 0;
|
|
39946
|
-
|
|
39997
|
+
let exhaustive = false;
|
|
39998
|
+
let approx = /* @__PURE__ */ new Map();
|
|
39999
|
+
let kth;
|
|
40000
|
+
while (precision >= config.minPrecision && iterations < config.maxIterations) {
|
|
39947
40001
|
iterations++;
|
|
39948
|
-
const
|
|
39949
|
-
const
|
|
39950
|
-
const
|
|
39951
|
-
|
|
39952
|
-
const
|
|
39953
|
-
|
|
39954
|
-
|
|
39955
|
-
|
|
39956
|
-
|
|
39957
|
-
|
|
39958
|
-
|
|
39959
|
-
|
|
39960
|
-
|
|
39961
|
-
|
|
39962
|
-
|
|
39963
|
-
|
|
39964
|
-
|
|
39965
|
-
longitude,
|
|
39966
|
-
location.latitude,
|
|
39967
|
-
location.longitude
|
|
39968
|
-
);
|
|
39969
|
-
if (distance <= maxDistance) {
|
|
39970
|
-
candidatesWithinDistance++;
|
|
39971
|
-
}
|
|
39972
|
-
}
|
|
39973
|
-
}
|
|
39974
|
-
if (candidatesWithinDistance >= limit) {
|
|
39975
|
-
console.log("[nearSearch] Early termination: found enough candidates within maxDistance", {
|
|
39976
|
-
candidatesWithinDistance,
|
|
39977
|
-
limit,
|
|
39978
|
-
maxDistance,
|
|
39979
|
-
precision,
|
|
39980
|
-
iterations
|
|
39981
|
-
});
|
|
39982
|
-
break;
|
|
39983
|
-
}
|
|
39984
|
-
if (coversMaxDistance(precision, maxDistance)) {
|
|
39985
|
-
console.log("[nearSearch] Early termination: current precision covers maxDistance", {
|
|
39986
|
-
precision,
|
|
39987
|
-
maxDistance,
|
|
39988
|
-
coverage: GEOHASH_COVERAGE[precision],
|
|
39989
|
-
candidatesWithinDistance,
|
|
39990
|
-
iterations
|
|
39991
|
-
});
|
|
39992
|
-
break;
|
|
39993
|
-
}
|
|
40002
|
+
const radius = guaranteedRadius(precision, latitude);
|
|
40003
|
+
const neighbors = getNeighborGeoHashes(encodeGeoHash(latitude, longitude, precision));
|
|
40004
|
+
const hits = (await Promise.all(neighbors.map((prefix) => searchShadows(prefix)))).flat();
|
|
40005
|
+
approx = /* @__PURE__ */ new Map();
|
|
40006
|
+
for (const hit of hits) {
|
|
40007
|
+
const center = decodeGeoHash(hit.geohash);
|
|
40008
|
+
approx.set(hit.id, calculateDistance(latitude, longitude, center.latitude, center.longitude));
|
|
40009
|
+
}
|
|
40010
|
+
const sure = [...approx.values()].filter(
|
|
40011
|
+
(d5) => (minDistance === void 0 || d5 - epsilon >= minDistance) && (maxDistance === void 0 || d5 + epsilon <= maxDistance)
|
|
40012
|
+
).sort((a5, b5) => a5 - b5);
|
|
40013
|
+
kth = kthOf(sure, limit);
|
|
40014
|
+
const topKConfirmed = kth !== void 0 && kth + epsilon <= radius;
|
|
40015
|
+
const circleCovered = maxDistance !== void 0 && maxDistance + epsilon <= radius;
|
|
40016
|
+
if (topKConfirmed || circleCovered) {
|
|
40017
|
+
exhaustive = true;
|
|
40018
|
+
break;
|
|
39994
40019
|
}
|
|
39995
40020
|
precision--;
|
|
39996
40021
|
}
|
|
39997
|
-
const
|
|
40022
|
+
const cutoff = kth !== void 0 ? kth + 2 * epsilon : void 0;
|
|
40023
|
+
const wanted = [...approx.entries()].filter(
|
|
40024
|
+
([, d5]) => (cutoff === void 0 || d5 <= cutoff) && (maxDistance === void 0 || d5 <= maxDistance + epsilon) && (minDistance === void 0 || d5 >= minDistance - epsilon)
|
|
40025
|
+
).map(([id]) => id);
|
|
40026
|
+
const bodies = wanted.length > 0 ? await readBodies(wanted) : [];
|
|
40027
|
+
const documents = bodies.map((doc) => {
|
|
39998
40028
|
const location = doc[fieldName];
|
|
39999
|
-
if (!location) {
|
|
40000
|
-
console.log("[nearSearch] Location field not found:", {
|
|
40001
|
-
fieldName,
|
|
40002
|
-
docKeys: Object.keys(doc),
|
|
40003
|
-
doc: JSON.stringify(doc).substring(0, 200)
|
|
40004
|
-
});
|
|
40005
|
-
}
|
|
40006
40029
|
if (!location || typeof location.latitude !== "number" || typeof location.longitude !== "number") {
|
|
40007
40030
|
return null;
|
|
40008
40031
|
}
|
|
@@ -40012,19 +40035,8 @@ async function executeNearSearch(nearQuery, fieldName, limit, searchFunction, co
|
|
|
40012
40035
|
location.latitude,
|
|
40013
40036
|
location.longitude
|
|
40014
40037
|
);
|
|
40015
|
-
|
|
40016
|
-
|
|
40017
|
-
distance,
|
|
40018
|
-
maxDistance,
|
|
40019
|
-
minDistance,
|
|
40020
|
-
willBeFiltered: maxDistance !== void 0 && distance > maxDistance || minDistance !== void 0 && distance < minDistance
|
|
40021
|
-
});
|
|
40022
|
-
if (maxDistance !== void 0 && distance > maxDistance) {
|
|
40023
|
-
return null;
|
|
40024
|
-
}
|
|
40025
|
-
if (minDistance !== void 0 && distance < minDistance) {
|
|
40026
|
-
return null;
|
|
40027
|
-
}
|
|
40038
|
+
if (maxDistance !== void 0 && distance > maxDistance) return null;
|
|
40039
|
+
if (minDistance !== void 0 && distance < minDistance) return null;
|
|
40028
40040
|
return {
|
|
40029
40041
|
...doc,
|
|
40030
40042
|
__distance: distance,
|
|
@@ -40032,36 +40044,26 @@ async function executeNearSearch(nearQuery, fieldName, limit, searchFunction, co
|
|
|
40032
40044
|
};
|
|
40033
40045
|
}).filter((doc) => doc !== null).sort((a5, b5) => (a5.__distance ?? 0) - (b5.__distance ?? 0)).slice(0, limit);
|
|
40034
40046
|
return {
|
|
40035
|
-
documents
|
|
40047
|
+
documents,
|
|
40036
40048
|
metadata: {
|
|
40037
40049
|
iterations,
|
|
40038
|
-
candidatesFound:
|
|
40039
|
-
|
|
40050
|
+
candidatesFound: approx.size,
|
|
40051
|
+
bodiesRead: wanted.length,
|
|
40052
|
+
requestedLimit: limit,
|
|
40053
|
+
exhaustive
|
|
40040
40054
|
}
|
|
40041
40055
|
};
|
|
40042
40056
|
}
|
|
40043
|
-
var
|
|
40057
|
+
var METERS_PER_DEGREE;
|
|
40044
40058
|
var init_nearSearch = __esm({
|
|
40045
40059
|
"src/server/query/nearSearch.ts"() {
|
|
40046
40060
|
"use strict";
|
|
40047
40061
|
init_geohash();
|
|
40048
|
-
|
|
40049
|
-
|
|
40050
|
-
|
|
40051
|
-
|
|
40052
|
-
|
|
40053
|
-
6: 610 * 3,
|
|
40054
|
-
// ±610m × 3 = 約1,830m (1.8km)
|
|
40055
|
-
5: 2400 * 3,
|
|
40056
|
-
// ±2.4km × 3 = 約7,200m (7.2km)
|
|
40057
|
-
4: 2e4 * 3,
|
|
40058
|
-
// ±20km × 3 = 約60,000m (60km)
|
|
40059
|
-
3: 78e3 * 3,
|
|
40060
|
-
// ±78km × 3 = 約234,000m (234km)
|
|
40061
|
-
2: 63e4 * 3
|
|
40062
|
-
// ±630km × 3 = 約1,890,000m (1,890km)
|
|
40063
|
-
};
|
|
40064
|
-
__name(coversMaxDistance, "coversMaxDistance");
|
|
40062
|
+
METERS_PER_DEGREE = 111320;
|
|
40063
|
+
__name(cellSizeMeters, "cellSizeMeters");
|
|
40064
|
+
__name(guaranteedRadius, "guaranteedRadius");
|
|
40065
|
+
__name(shadowPositionError, "shadowPositionError");
|
|
40066
|
+
__name(kthOf, "kthOf");
|
|
40065
40067
|
__name(executeNearSearch, "executeNearSearch");
|
|
40066
40068
|
}
|
|
40067
40069
|
});
|
|
@@ -40543,149 +40545,6 @@ var init_idQuery = __esm({
|
|
|
40543
40545
|
}
|
|
40544
40546
|
});
|
|
40545
40547
|
|
|
40546
|
-
// src/server/operations/find/nearQuery.ts
|
|
40547
|
-
async function executeNearQuery(resource, fieldName, nearQuery, limit, requestId) {
|
|
40548
|
-
logger7.debug("Executing $near query", {
|
|
40549
|
-
requestId,
|
|
40550
|
-
resource,
|
|
40551
|
-
fieldName,
|
|
40552
|
-
nearQuery,
|
|
40553
|
-
limit
|
|
40554
|
-
});
|
|
40555
|
-
const costTracker = new CostTracker();
|
|
40556
|
-
const searchFunction = /* @__PURE__ */ __name(async (geohashPrefix) => {
|
|
40557
|
-
const dbClient2 = getDBClient();
|
|
40558
|
-
const tableName = getTableName();
|
|
40559
|
-
logger7.debug("Searching shadow records", {
|
|
40560
|
-
requestId,
|
|
40561
|
-
resource,
|
|
40562
|
-
fieldName,
|
|
40563
|
-
geohashPrefix,
|
|
40564
|
-
skPrefix: `${fieldName}#${geohashPrefix}`
|
|
40565
|
-
});
|
|
40566
|
-
const shadowRecords = [];
|
|
40567
|
-
const watcher = new ScanWatcher({
|
|
40568
|
-
requestId,
|
|
40569
|
-
resource,
|
|
40570
|
-
path: "near-search",
|
|
40571
|
-
sortField: fieldName,
|
|
40572
|
-
filters: ["$near"]
|
|
40573
|
-
});
|
|
40574
|
-
let exclusiveStartKey;
|
|
40575
|
-
let previousKeySignature;
|
|
40576
|
-
do {
|
|
40577
|
-
const queryResult = await executeDynamoDBOperation(
|
|
40578
|
-
() => dbClient2.send(
|
|
40579
|
-
new import_lib_dynamodb4.QueryCommand({
|
|
40580
|
-
TableName: tableName,
|
|
40581
|
-
KeyConditionExpression: "PK = :pk AND begins_with(SK, :skPrefix)",
|
|
40582
|
-
ExpressionAttributeValues: {
|
|
40583
|
-
":pk": resource,
|
|
40584
|
-
":skPrefix": `${fieldName}#${geohashPrefix}`
|
|
40585
|
-
},
|
|
40586
|
-
ExclusiveStartKey: exclusiveStartKey,
|
|
40587
|
-
ConsistentRead: false,
|
|
40588
|
-
// シャドウレコードは結果整合性で十分
|
|
40589
|
-
ReturnConsumedCapacity: "TOTAL"
|
|
40590
|
-
})
|
|
40591
|
-
),
|
|
40592
|
-
"Query"
|
|
40593
|
-
);
|
|
40594
|
-
costTracker.add(queryResult.ConsumedCapacity);
|
|
40595
|
-
shadowRecords.push(...queryResult.Items || []);
|
|
40596
|
-
watcher.add((queryResult.Items || []).length);
|
|
40597
|
-
const nextKey = queryResult.LastEvaluatedKey;
|
|
40598
|
-
const nextKeySignature = nextKey ? `${nextKey.PK}#${nextKey.SK}` : void 0;
|
|
40599
|
-
if (nextKeySignature && nextKeySignature === previousKeySignature) {
|
|
40600
|
-
throw new AppError(
|
|
40601
|
-
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
40602
|
-
"Near search received the same LastEvaluatedKey repeatedly",
|
|
40603
|
-
500,
|
|
40604
|
-
{ resource, geohashPrefix }
|
|
40605
|
-
);
|
|
40606
|
-
}
|
|
40607
|
-
previousKeySignature = nextKeySignature;
|
|
40608
|
-
exclusiveStartKey = nextKey;
|
|
40609
|
-
} while (exclusiveStartKey);
|
|
40610
|
-
logger7.debug("Shadow records found", {
|
|
40611
|
-
requestId,
|
|
40612
|
-
resource,
|
|
40613
|
-
geohashPrefix,
|
|
40614
|
-
count: shadowRecords.length
|
|
40615
|
-
});
|
|
40616
|
-
const mainRecordIds = shadowRecords.map((item) => {
|
|
40617
|
-
const sk = item.SK;
|
|
40618
|
-
const parts = sk.split("#id#");
|
|
40619
|
-
return parts.length === 2 ? parts[1] : null;
|
|
40620
|
-
}).filter((id) => id !== null);
|
|
40621
|
-
logger7.debug("Main record IDs extracted", {
|
|
40622
|
-
requestId,
|
|
40623
|
-
resource,
|
|
40624
|
-
geohashPrefix,
|
|
40625
|
-
ids: mainRecordIds
|
|
40626
|
-
});
|
|
40627
|
-
const validRecords = await batchGetAll(
|
|
40628
|
-
mainRecordIds.map((id) => ({ PK: resource, SK: `id#${id}` })),
|
|
40629
|
-
{ consistentRead: false, costTracker, requestId }
|
|
40630
|
-
);
|
|
40631
|
-
logger7.debug("Main records retrieved", {
|
|
40632
|
-
requestId,
|
|
40633
|
-
resource,
|
|
40634
|
-
geohashPrefix,
|
|
40635
|
-
count: validRecords.length
|
|
40636
|
-
});
|
|
40637
|
-
const cleanRecords = validRecords.map((record) => extractCleanRecord(record));
|
|
40638
|
-
logger7.debug("Clean records extracted", {
|
|
40639
|
-
requestId,
|
|
40640
|
-
resource,
|
|
40641
|
-
geohashPrefix,
|
|
40642
|
-
count: cleanRecords.length,
|
|
40643
|
-
sampleKeys: cleanRecords[0] ? Object.keys(cleanRecords[0]) : []
|
|
40644
|
-
});
|
|
40645
|
-
return cleanRecords;
|
|
40646
|
-
}, "searchFunction");
|
|
40647
|
-
const minPrecisionOverride = "minPrecision" in nearQuery ? nearQuery.minPrecision : "$minPrecision" in nearQuery ? nearQuery.$minPrecision : void 0;
|
|
40648
|
-
const config = minPrecisionOverride !== void 0 ? { ...DEFAULT_GEOHASH_CONFIG, minPrecision: minPrecisionOverride } : DEFAULT_GEOHASH_CONFIG;
|
|
40649
|
-
const result = await executeNearSearch(nearQuery, fieldName, limit, searchFunction, config);
|
|
40650
|
-
const items = result.documents;
|
|
40651
|
-
logger7.info("$near query succeeded", {
|
|
40652
|
-
requestId,
|
|
40653
|
-
resource,
|
|
40654
|
-
fieldName,
|
|
40655
|
-
count: items.length,
|
|
40656
|
-
iterations: result.metadata.iterations,
|
|
40657
|
-
candidatesFound: result.metadata.candidatesFound
|
|
40658
|
-
});
|
|
40659
|
-
return {
|
|
40660
|
-
items,
|
|
40661
|
-
pageInfo: {
|
|
40662
|
-
hasNextPage: false,
|
|
40663
|
-
// $near検索はページネーション非対応
|
|
40664
|
-
hasPreviousPage: false
|
|
40665
|
-
},
|
|
40666
|
-
consumedCapacity: costTracker.getAggregated()
|
|
40667
|
-
};
|
|
40668
|
-
}
|
|
40669
|
-
var import_lib_dynamodb4, logger7;
|
|
40670
|
-
var init_nearQuery = __esm({
|
|
40671
|
-
"src/server/operations/find/nearQuery.ts"() {
|
|
40672
|
-
"use strict";
|
|
40673
|
-
import_lib_dynamodb4 = __toESM(require_dist_cjs22(), 1);
|
|
40674
|
-
init_geohash();
|
|
40675
|
-
init_shared();
|
|
40676
|
-
init_nearSearch();
|
|
40677
|
-
init_batchGet();
|
|
40678
|
-
init_cost_tracker();
|
|
40679
|
-
init_dynamodb3();
|
|
40680
|
-
init_scanWarning();
|
|
40681
|
-
logger7 = createLogger({
|
|
40682
|
-
service: "near-query",
|
|
40683
|
-
level: process.env.LOG_LEVEL || "info"
|
|
40684
|
-
});
|
|
40685
|
-
__name(executeNearQuery, "executeNearQuery");
|
|
40686
|
-
}
|
|
40687
|
-
});
|
|
40688
|
-
|
|
40689
40548
|
// src/server/operations/find/shadowQuery.ts
|
|
40690
40549
|
async function executeShadowQuery(resource, normalizedParams, requestId) {
|
|
40691
40550
|
const { sort, pagination, parsedFilters } = normalizedParams;
|
|
@@ -40714,7 +40573,7 @@ async function executeShadowQuery(resource, normalizedParams, requestId) {
|
|
|
40714
40573
|
(f5) => !(isKeyConditionOptimized && (f5 === optimizableFilter || f5 === upperFilter))
|
|
40715
40574
|
);
|
|
40716
40575
|
if (residualFilters.length > 0) {
|
|
40717
|
-
|
|
40576
|
+
logger7.debug("Residual filters detected, falling back to full scan", {
|
|
40718
40577
|
requestId,
|
|
40719
40578
|
resource,
|
|
40720
40579
|
sortField: sort.field,
|
|
@@ -40722,7 +40581,7 @@ async function executeShadowQuery(resource, normalizedParams, requestId) {
|
|
|
40722
40581
|
});
|
|
40723
40582
|
return executeFullScanQuery(resource, normalizedParams, costTracker, requestId);
|
|
40724
40583
|
}
|
|
40725
|
-
|
|
40584
|
+
logger7.debug("Executing shadow query", {
|
|
40726
40585
|
requestId,
|
|
40727
40586
|
resource,
|
|
40728
40587
|
sortField: sort.field,
|
|
@@ -40771,7 +40630,7 @@ async function executeShadowQuery(resource, normalizedParams, requestId) {
|
|
|
40771
40630
|
shadowRecords.LastEvaluatedKey.PK,
|
|
40772
40631
|
shadowRecords.LastEvaluatedKey.SK
|
|
40773
40632
|
) : void 0;
|
|
40774
|
-
|
|
40633
|
+
logger7.info("Shadow query succeeded", {
|
|
40775
40634
|
requestId,
|
|
40776
40635
|
resource,
|
|
40777
40636
|
sortField: sort.field,
|
|
@@ -40796,7 +40655,7 @@ async function executeFilterFirstQuery(resource, normalizedParams, filterCandida
|
|
|
40796
40655
|
const offset = nextToken ? decodeOffsetToken(nextToken) ?? 0 : 0;
|
|
40797
40656
|
const filterSort = { field: filterCandidate.parsed.field, order: "ASC" };
|
|
40798
40657
|
const remainingFilters = parsedFilters;
|
|
40799
|
-
|
|
40658
|
+
logger7.debug("Executing filter-first query", {
|
|
40800
40659
|
requestId,
|
|
40801
40660
|
resource,
|
|
40802
40661
|
filterField: filterCandidate.parsed.field,
|
|
@@ -40819,7 +40678,7 @@ async function executeFilterFirstQuery(resource, normalizedParams, filterCandida
|
|
|
40819
40678
|
const page = items.slice(offset, offset + perPage);
|
|
40820
40679
|
const hasNextPage = offset + perPage < items.length;
|
|
40821
40680
|
const nextTokenValue = hasNextPage ? encodeOffsetToken(offset + perPage) : void 0;
|
|
40822
|
-
|
|
40681
|
+
logger7.info("Filter-first query succeeded", {
|
|
40823
40682
|
requestId,
|
|
40824
40683
|
resource,
|
|
40825
40684
|
filterField: filterCandidate.parsed.field,
|
|
@@ -40840,7 +40699,7 @@ async function executeFullScanQuery(resource, normalizedParams, costTracker, req
|
|
|
40840
40699
|
const { sort, pagination, parsedFilters } = normalizedParams;
|
|
40841
40700
|
const { perPage, nextToken } = pagination;
|
|
40842
40701
|
const offset = nextToken ? decodeOffsetToken(nextToken) ?? 0 : 0;
|
|
40843
|
-
|
|
40702
|
+
logger7.debug("Executing full scan query", {
|
|
40844
40703
|
requestId,
|
|
40845
40704
|
resource,
|
|
40846
40705
|
sortField: sort.field,
|
|
@@ -40861,7 +40720,7 @@ async function executeFullScanQuery(resource, normalizedParams, costTracker, req
|
|
|
40861
40720
|
const page = items.slice(offset, offset + perPage);
|
|
40862
40721
|
const hasNextPage = offset + perPage < items.length;
|
|
40863
40722
|
const nextTokenValue = hasNextPage ? encodeOffsetToken(offset + perPage) : void 0;
|
|
40864
|
-
|
|
40723
|
+
logger7.info("Full scan query succeeded", {
|
|
40865
40724
|
requestId,
|
|
40866
40725
|
resource,
|
|
40867
40726
|
sortField: sort.field,
|
|
@@ -40892,7 +40751,7 @@ async function fetchAllRecordsViaShadowIndex(resource, indexSort, indexFilter, c
|
|
|
40892
40751
|
let iterations = 0;
|
|
40893
40752
|
do {
|
|
40894
40753
|
if (++iterations > MAX_ITERATIONS) {
|
|
40895
|
-
|
|
40754
|
+
logger7.error("fetchAllRecordsViaShadowIndex: \u6700\u5927\u53CD\u5FA9\u56DE\u6570\u3092\u8D85\u904E", {
|
|
40896
40755
|
requestId,
|
|
40897
40756
|
resource,
|
|
40898
40757
|
iterations
|
|
@@ -40922,7 +40781,7 @@ async function fetchAllRecordsViaShadowIndex(resource, indexSort, indexFilter, c
|
|
|
40922
40781
|
const nextKey = result.LastEvaluatedKey;
|
|
40923
40782
|
const nextKeySignature = nextKey ? `${nextKey.PK}#${nextKey.SK}` : void 0;
|
|
40924
40783
|
if (nextKeySignature && nextKeySignature === previousKeySignature) {
|
|
40925
|
-
|
|
40784
|
+
logger7.error("fetchAllRecordsViaShadowIndex: \u540C\u4E00\u306ELastEvaluatedKey\u304C\u8FD4\u5374\u3055\u308C\u305F", {
|
|
40926
40785
|
requestId,
|
|
40927
40786
|
resource,
|
|
40928
40787
|
iterations
|
|
@@ -40995,7 +40854,7 @@ async function executeShadowRecordQuery(resource, sort, perPage, nextToken, opti
|
|
|
40995
40854
|
);
|
|
40996
40855
|
const result = await executeDynamoDBOperation(
|
|
40997
40856
|
() => dbClient2.send(
|
|
40998
|
-
new
|
|
40857
|
+
new import_lib_dynamodb4.QueryCommand({
|
|
40999
40858
|
TableName: tableName,
|
|
41000
40859
|
KeyConditionExpression: keyConditionExpression,
|
|
41001
40860
|
ExpressionAttributeValues: expressionAttributeValues,
|
|
@@ -41023,7 +40882,7 @@ async function fetchMainRecords(resource, recordIds, costTracker, requestId) {
|
|
|
41023
40882
|
recordIds.map((id) => ({ PK: resource, SK: `id#${id}` })),
|
|
41024
40883
|
{ consistentRead: true, costTracker, requestId }
|
|
41025
40884
|
);
|
|
41026
|
-
|
|
40885
|
+
logger7.debug("Main records fetched", {
|
|
41027
40886
|
requestId,
|
|
41028
40887
|
resource,
|
|
41029
40888
|
requestedCount: new Set(recordIds).size,
|
|
@@ -41031,11 +40890,11 @@ async function fetchMainRecords(resource, recordIds, costTracker, requestId) {
|
|
|
41031
40890
|
});
|
|
41032
40891
|
return allRecords;
|
|
41033
40892
|
}
|
|
41034
|
-
var
|
|
40893
|
+
var import_lib_dynamodb4, logger7;
|
|
41035
40894
|
var init_shadowQuery = __esm({
|
|
41036
40895
|
"src/server/operations/find/shadowQuery.ts"() {
|
|
41037
40896
|
"use strict";
|
|
41038
|
-
|
|
40897
|
+
import_lib_dynamodb4 = __toESM(require_dist_cjs22(), 1);
|
|
41039
40898
|
init_shared();
|
|
41040
40899
|
init_batchGet();
|
|
41041
40900
|
init_cost_tracker();
|
|
@@ -41044,7 +40903,7 @@ var init_shadowQuery = __esm({
|
|
|
41044
40903
|
init_scanWarning();
|
|
41045
40904
|
init_keyCondition();
|
|
41046
40905
|
init_utils6();
|
|
41047
|
-
|
|
40906
|
+
logger7 = createLogger({
|
|
41048
40907
|
service: "shadow-query",
|
|
41049
40908
|
level: process.env.LOG_LEVEL || "info"
|
|
41050
40909
|
});
|
|
@@ -41060,6 +40919,148 @@ var init_shadowQuery = __esm({
|
|
|
41060
40919
|
}
|
|
41061
40920
|
});
|
|
41062
40921
|
|
|
40922
|
+
// src/server/operations/find/nearQuery.ts
|
|
40923
|
+
async function executeNearQuery(resource, fieldName, nearQuery, limit, requestId, condition) {
|
|
40924
|
+
logger8.debug("Executing $near query", {
|
|
40925
|
+
requestId,
|
|
40926
|
+
resource,
|
|
40927
|
+
fieldName,
|
|
40928
|
+
nearQuery,
|
|
40929
|
+
limit
|
|
40930
|
+
});
|
|
40931
|
+
const costTracker = new CostTracker();
|
|
40932
|
+
const searchShadows = /* @__PURE__ */ __name(async (geohashPrefix) => {
|
|
40933
|
+
const dbClient2 = getDBClient();
|
|
40934
|
+
const tableName = getTableName();
|
|
40935
|
+
logger8.debug("Searching shadow records", {
|
|
40936
|
+
requestId,
|
|
40937
|
+
resource,
|
|
40938
|
+
fieldName,
|
|
40939
|
+
geohashPrefix,
|
|
40940
|
+
skPrefix: `${fieldName}#${geohashPrefix}`
|
|
40941
|
+
});
|
|
40942
|
+
const shadowRecords = [];
|
|
40943
|
+
const watcher = new ScanWatcher({
|
|
40944
|
+
requestId,
|
|
40945
|
+
resource,
|
|
40946
|
+
path: "near-search",
|
|
40947
|
+
sortField: fieldName,
|
|
40948
|
+
filters: ["$near"]
|
|
40949
|
+
});
|
|
40950
|
+
let exclusiveStartKey;
|
|
40951
|
+
let previousKeySignature;
|
|
40952
|
+
do {
|
|
40953
|
+
const queryResult = await executeDynamoDBOperation(
|
|
40954
|
+
() => dbClient2.send(
|
|
40955
|
+
new import_lib_dynamodb5.QueryCommand({
|
|
40956
|
+
TableName: tableName,
|
|
40957
|
+
KeyConditionExpression: "PK = :pk AND begins_with(SK, :skPrefix)",
|
|
40958
|
+
ExpressionAttributeValues: {
|
|
40959
|
+
":pk": resource,
|
|
40960
|
+
":skPrefix": `${fieldName}#${geohashPrefix}`
|
|
40961
|
+
},
|
|
40962
|
+
ExclusiveStartKey: exclusiveStartKey,
|
|
40963
|
+
ConsistentRead: false,
|
|
40964
|
+
// シャドウレコードは結果整合性で十分
|
|
40965
|
+
ReturnConsumedCapacity: "TOTAL"
|
|
40966
|
+
})
|
|
40967
|
+
),
|
|
40968
|
+
"Query"
|
|
40969
|
+
);
|
|
40970
|
+
costTracker.add(queryResult.ConsumedCapacity);
|
|
40971
|
+
shadowRecords.push(...queryResult.Items || []);
|
|
40972
|
+
watcher.add((queryResult.Items || []).length);
|
|
40973
|
+
const nextKey = queryResult.LastEvaluatedKey;
|
|
40974
|
+
const nextKeySignature = nextKey ? `${nextKey.PK}#${nextKey.SK}` : void 0;
|
|
40975
|
+
if (nextKeySignature && nextKeySignature === previousKeySignature) {
|
|
40976
|
+
throw new AppError(
|
|
40977
|
+
"INTERNAL_ERROR" /* INTERNAL_ERROR */,
|
|
40978
|
+
"Near search received the same LastEvaluatedKey repeatedly",
|
|
40979
|
+
500,
|
|
40980
|
+
{ resource, geohashPrefix }
|
|
40981
|
+
);
|
|
40982
|
+
}
|
|
40983
|
+
previousKeySignature = nextKeySignature;
|
|
40984
|
+
exclusiveStartKey = nextKey;
|
|
40985
|
+
} while (exclusiveStartKey);
|
|
40986
|
+
logger8.debug("Shadow records found", {
|
|
40987
|
+
requestId,
|
|
40988
|
+
resource,
|
|
40989
|
+
geohashPrefix,
|
|
40990
|
+
count: shadowRecords.length
|
|
40991
|
+
});
|
|
40992
|
+
const hits = [];
|
|
40993
|
+
for (const record of shadowRecords) {
|
|
40994
|
+
const sk = String(record.SK);
|
|
40995
|
+
const afterField = sk.slice(fieldName.length + 1);
|
|
40996
|
+
const geohash = afterField.slice(0, afterField.indexOf("#"));
|
|
40997
|
+
const [id] = extractRecordIds([record]);
|
|
40998
|
+
if (id !== void 0 && geohash !== "") hits.push({ id, geohash });
|
|
40999
|
+
}
|
|
41000
|
+
return hits;
|
|
41001
|
+
}, "searchShadows");
|
|
41002
|
+
const matches = conditionMatcher(condition);
|
|
41003
|
+
const readBodies = /* @__PURE__ */ __name(async (ids) => {
|
|
41004
|
+
const bodies = await batchGetAll(
|
|
41005
|
+
ids.map((id) => ({ PK: resource, SK: `id#${id}` })),
|
|
41006
|
+
{ consistentRead: false, costTracker, requestId }
|
|
41007
|
+
);
|
|
41008
|
+
return bodies.map((record) => extractCleanRecord(record)).filter(matches);
|
|
41009
|
+
}, "readBodies");
|
|
41010
|
+
const minPrecisionOverride = "minPrecision" in nearQuery ? nearQuery.minPrecision : "$minPrecision" in nearQuery ? nearQuery.$minPrecision : void 0;
|
|
41011
|
+
const config = minPrecisionOverride !== void 0 ? { ...DEFAULT_GEOHASH_CONFIG, minPrecision: minPrecisionOverride } : DEFAULT_GEOHASH_CONFIG;
|
|
41012
|
+
const result = await executeNearSearch(
|
|
41013
|
+
nearQuery,
|
|
41014
|
+
fieldName,
|
|
41015
|
+
limit,
|
|
41016
|
+
searchShadows,
|
|
41017
|
+
readBodies,
|
|
41018
|
+
config
|
|
41019
|
+
);
|
|
41020
|
+
const items = result.documents;
|
|
41021
|
+
logger8.info("$near query succeeded", {
|
|
41022
|
+
requestId,
|
|
41023
|
+
resource,
|
|
41024
|
+
fieldName,
|
|
41025
|
+
count: items.length,
|
|
41026
|
+
iterations: result.metadata.iterations,
|
|
41027
|
+
candidatesFound: result.metadata.candidatesFound,
|
|
41028
|
+
bodiesRead: result.metadata.bodiesRead,
|
|
41029
|
+
exhaustive: result.metadata.exhaustive
|
|
41030
|
+
});
|
|
41031
|
+
return {
|
|
41032
|
+
items,
|
|
41033
|
+
pageInfo: {
|
|
41034
|
+
hasNextPage: false,
|
|
41035
|
+
// $near検索はページネーション非対応
|
|
41036
|
+
hasPreviousPage: false,
|
|
41037
|
+
exhaustive: result.metadata.exhaustive
|
|
41038
|
+
},
|
|
41039
|
+
consumedCapacity: costTracker.getAggregated()
|
|
41040
|
+
};
|
|
41041
|
+
}
|
|
41042
|
+
var import_lib_dynamodb5, logger8;
|
|
41043
|
+
var init_nearQuery = __esm({
|
|
41044
|
+
"src/server/operations/find/nearQuery.ts"() {
|
|
41045
|
+
"use strict";
|
|
41046
|
+
import_lib_dynamodb5 = __toESM(require_dist_cjs22(), 1);
|
|
41047
|
+
init_geohash();
|
|
41048
|
+
init_shared();
|
|
41049
|
+
init_nearSearch();
|
|
41050
|
+
init_batchGet();
|
|
41051
|
+
init_cost_tracker();
|
|
41052
|
+
init_dynamodb3();
|
|
41053
|
+
init_idFilter();
|
|
41054
|
+
init_scanWarning();
|
|
41055
|
+
init_shadowQuery();
|
|
41056
|
+
logger8 = createLogger({
|
|
41057
|
+
service: "near-query",
|
|
41058
|
+
level: process.env.LOG_LEVEL || "info"
|
|
41059
|
+
});
|
|
41060
|
+
__name(executeNearQuery, "executeNearQuery");
|
|
41061
|
+
}
|
|
41062
|
+
});
|
|
41063
|
+
|
|
41063
41064
|
// src/server/operations/find/handler.ts
|
|
41064
41065
|
async function handleFind(resource, params, requestId) {
|
|
41065
41066
|
logger9.debug("Executing find", {
|
|
@@ -41075,12 +41076,16 @@ async function handleFind(resource, params, requestId) {
|
|
|
41075
41076
|
fieldName: nearDetection.fieldName
|
|
41076
41077
|
});
|
|
41077
41078
|
const limit = params.pagination?.perPage || 10;
|
|
41079
|
+
const otherFilters = Object.fromEntries(
|
|
41080
|
+
Object.entries(params.filter ?? {}).filter(([field]) => field !== nearDetection.fieldName)
|
|
41081
|
+
);
|
|
41078
41082
|
return executeNearQuery(
|
|
41079
41083
|
resource,
|
|
41080
41084
|
nearDetection.fieldName,
|
|
41081
41085
|
nearDetection.nearQuery,
|
|
41082
41086
|
limit,
|
|
41083
|
-
requestId
|
|
41087
|
+
requestId,
|
|
41088
|
+
conditionOf(otherFilters)
|
|
41084
41089
|
);
|
|
41085
41090
|
}
|
|
41086
41091
|
const config = initializeFindConfig();
|
|
@@ -41106,6 +41111,7 @@ var init_handler = __esm({
|
|
|
41106
41111
|
"src/server/operations/find/handler.ts"() {
|
|
41107
41112
|
"use strict";
|
|
41108
41113
|
init_shared();
|
|
41114
|
+
init_idFilter();
|
|
41109
41115
|
init_validation2();
|
|
41110
41116
|
init_idQuery();
|
|
41111
41117
|
init_nearQuery();
|
|
@@ -41422,37 +41428,6 @@ var init_chunking = __esm({
|
|
|
41422
41428
|
}
|
|
41423
41429
|
});
|
|
41424
41430
|
|
|
41425
|
-
// src/server/utils/idFilter.ts
|
|
41426
|
-
function splitIdFilter(filter) {
|
|
41427
|
-
const { id, ...rest } = filter ?? {};
|
|
41428
|
-
if (typeof id === "string") {
|
|
41429
|
-
return { id, rest };
|
|
41430
|
-
}
|
|
41431
|
-
if (typeof id === "object" && id !== null && "$in" in id) {
|
|
41432
|
-
return { ids: (id.$in ?? []).slice(), rest };
|
|
41433
|
-
}
|
|
41434
|
-
return { rest: filter ?? {} };
|
|
41435
|
-
}
|
|
41436
|
-
function conditionOf(rest) {
|
|
41437
|
-
return Object.keys(rest).length > 0 ? rest : void 0;
|
|
41438
|
-
}
|
|
41439
|
-
function conditionMatcher(condition) {
|
|
41440
|
-
if (!condition || Object.keys(condition).length === 0) {
|
|
41441
|
-
return () => true;
|
|
41442
|
-
}
|
|
41443
|
-
const parsed = parseFilters(condition);
|
|
41444
|
-
return (record) => matchesAllFilters(record, parsed);
|
|
41445
|
-
}
|
|
41446
|
-
var init_idFilter = __esm({
|
|
41447
|
-
"src/server/utils/idFilter.ts"() {
|
|
41448
|
-
"use strict";
|
|
41449
|
-
init_utils6();
|
|
41450
|
-
__name(splitIdFilter, "splitIdFilter");
|
|
41451
|
-
__name(conditionOf, "conditionOf");
|
|
41452
|
-
__name(conditionMatcher, "conditionMatcher");
|
|
41453
|
-
}
|
|
41454
|
-
});
|
|
41455
|
-
|
|
41456
41431
|
// src/server/utils/revision.ts
|
|
41457
41432
|
function revisionOf(item) {
|
|
41458
41433
|
const rev = item[REVISION_ATTRIBUTE];
|
|
@@ -42362,10 +42337,39 @@ function unsetFields(value) {
|
|
|
42362
42337
|
}
|
|
42363
42338
|
return Object.keys(asObject(value, "$unset"));
|
|
42364
42339
|
}
|
|
42340
|
+
function incFields(value) {
|
|
42341
|
+
const inc = {};
|
|
42342
|
+
for (const [field, amount] of Object.entries(asObject(value, "$inc"))) {
|
|
42343
|
+
if (typeof amount !== "number" || !Number.isFinite(amount)) {
|
|
42344
|
+
throw invalid(`$inc value for "${field}" must be a finite number`);
|
|
42345
|
+
}
|
|
42346
|
+
inc[field] = amount;
|
|
42347
|
+
}
|
|
42348
|
+
return inc;
|
|
42349
|
+
}
|
|
42350
|
+
function readByPath(data, path) {
|
|
42351
|
+
let current = data;
|
|
42352
|
+
for (const key of path.split(".")) {
|
|
42353
|
+
if (typeof current !== "object" || current === null) return void 0;
|
|
42354
|
+
current = current[key];
|
|
42355
|
+
}
|
|
42356
|
+
return current;
|
|
42357
|
+
}
|
|
42358
|
+
function applyInc(data, inc) {
|
|
42359
|
+
const added = {};
|
|
42360
|
+
for (const [field, amount] of Object.entries(inc)) {
|
|
42361
|
+
const current = readByPath(data, field);
|
|
42362
|
+
if (current !== void 0 && current !== null && (typeof current !== "number" || !Number.isFinite(current))) {
|
|
42363
|
+
throw invalid(`Field "${field}" is not a number, $inc cannot be applied`);
|
|
42364
|
+
}
|
|
42365
|
+
added[field] = (current ?? 0) + amount;
|
|
42366
|
+
}
|
|
42367
|
+
return added;
|
|
42368
|
+
}
|
|
42365
42369
|
function resolveUpdateOperators(data) {
|
|
42366
42370
|
const operators = Object.keys(data).filter((key) => key.startsWith("$"));
|
|
42367
42371
|
if (operators.length === 0) {
|
|
42368
|
-
return { patch: data, setOnInsert: {}, returned: data };
|
|
42372
|
+
return { patch: data, setOnInsert: {}, inc: {}, returned: data };
|
|
42369
42373
|
}
|
|
42370
42374
|
const unsupported = operators.filter((op2) => !SUPPORTED_OPERATORS.includes(op2));
|
|
42371
42375
|
if (unsupported.length > 0) {
|
|
@@ -42381,7 +42385,12 @@ function resolveUpdateOperators(data) {
|
|
|
42381
42385
|
}
|
|
42382
42386
|
patch[field] = null;
|
|
42383
42387
|
}
|
|
42384
|
-
|
|
42388
|
+
const inc = incFields(data.$inc);
|
|
42389
|
+
for (const field of Object.keys(inc)) {
|
|
42390
|
+
if (field in set) throw invalid(`Field "${field}" is in both $set and $inc`);
|
|
42391
|
+
if (field in patch) throw invalid(`Field "${field}" is in both $unset and $inc`);
|
|
42392
|
+
}
|
|
42393
|
+
return { patch, setOnInsert: asObject(data.$setOnInsert, "$setOnInsert"), inc, returned: set };
|
|
42385
42394
|
}
|
|
42386
42395
|
function equalityFieldsOf(filter) {
|
|
42387
42396
|
const fields = {};
|
|
@@ -42397,10 +42406,13 @@ var init_updateOperators = __esm({
|
|
|
42397
42406
|
"src/server/utils/updateOperators.ts"() {
|
|
42398
42407
|
"use strict";
|
|
42399
42408
|
init_shared();
|
|
42400
|
-
SUPPORTED_OPERATORS = ["$set", "$setOnInsert", "$unset"];
|
|
42409
|
+
SUPPORTED_OPERATORS = ["$set", "$setOnInsert", "$unset", "$inc"];
|
|
42401
42410
|
__name(invalid, "invalid");
|
|
42402
42411
|
__name(asObject, "asObject");
|
|
42403
42412
|
__name(unsetFields, "unsetFields");
|
|
42413
|
+
__name(incFields, "incFields");
|
|
42414
|
+
__name(readByPath, "readByPath");
|
|
42415
|
+
__name(applyInc, "applyInc");
|
|
42404
42416
|
__name(resolveUpdateOperators, "resolveUpdateOperators");
|
|
42405
42417
|
__name(equalityFieldsOf, "equalityFieldsOf");
|
|
42406
42418
|
}
|
|
@@ -42532,7 +42544,11 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42532
42544
|
const oldShadowKeys = item.__shadowKeys ?? existingData.__shadowKeys ?? [];
|
|
42533
42545
|
const timestampedPatch = addUpdateTimestamp(update.patch);
|
|
42534
42546
|
const mergedData = applyJsonMergePatch(removeShadowKeys(existingData), timestampedPatch);
|
|
42535
|
-
const
|
|
42547
|
+
const added = applyInc(mergedData, update.inc);
|
|
42548
|
+
const updatedData = {
|
|
42549
|
+
...applyJsonMergePatch(mergedData, added),
|
|
42550
|
+
id
|
|
42551
|
+
};
|
|
42536
42552
|
const newShadowRecords = generateShadowRecords(updatedData, resource, shadowConfig);
|
|
42537
42553
|
const newShadowKeys = newShadowRecords.map((shadow) => shadow.SK);
|
|
42538
42554
|
const mainSK = generateMainRecordSK2(id);
|
|
@@ -42543,6 +42559,7 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42543
42559
|
newShadowKeys,
|
|
42544
42560
|
mainSK,
|
|
42545
42561
|
isNew: false,
|
|
42562
|
+
returned: { ...update.returned, ...added },
|
|
42546
42563
|
revision: revisionOf(item)
|
|
42547
42564
|
});
|
|
42548
42565
|
} catch (error2) {
|
|
@@ -42568,10 +42585,9 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42568
42585
|
const { addCreateTimestamps: addCreateTimestamps2 } = await Promise.resolve().then(() => (init_timestamps(), timestamps_exports));
|
|
42569
42586
|
for (const id of notFoundIds2) {
|
|
42570
42587
|
try {
|
|
42571
|
-
const
|
|
42572
|
-
|
|
42573
|
-
|
|
42574
|
-
};
|
|
42588
|
+
const baseData = applyJsonMergePatch({}, { ...update.setOnInsert, ...update.patch });
|
|
42589
|
+
const added = applyInc(baseData, update.inc);
|
|
42590
|
+
const mergedData = { ...applyJsonMergePatch(baseData, added), id };
|
|
42575
42591
|
const newData = addCreateTimestamps2(mergedData);
|
|
42576
42592
|
const newShadowRecords = generateShadowRecords(newData, resource, shadowConfig);
|
|
42577
42593
|
const newShadowKeys = newShadowRecords.map((shadow) => shadow.SK);
|
|
@@ -42583,7 +42599,8 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42583
42599
|
// 新規作成なので空
|
|
42584
42600
|
newShadowKeys,
|
|
42585
42601
|
mainSK,
|
|
42586
|
-
isNew: true
|
|
42602
|
+
isNew: true,
|
|
42603
|
+
returned: { ...update.setOnInsert, ...update.returned, ...added }
|
|
42587
42604
|
});
|
|
42588
42605
|
} catch (error2) {
|
|
42589
42606
|
const errorMessage = error2 instanceof Error ? error2.message : "Unknown preparation error";
|
|
@@ -42707,6 +42724,7 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42707
42724
|
const failedIdsMap = {};
|
|
42708
42725
|
const errorsMap = {};
|
|
42709
42726
|
const successIdSet = new Set(successRecords.map((r5) => r5.id));
|
|
42727
|
+
const returnedById = new Map(successRecords.map((r5) => [r5.id, r5.returned]));
|
|
42710
42728
|
const upsertedIds = [];
|
|
42711
42729
|
for (let i5 = 0; i5 < ids.length; i5++) {
|
|
42712
42730
|
const id = ids[i5];
|
|
@@ -42714,16 +42732,9 @@ async function handleUpdateMany(resource, params, requestId) {
|
|
|
42714
42732
|
successIds[i5] = id;
|
|
42715
42733
|
if (upsert && notFoundIds.includes(id)) {
|
|
42716
42734
|
upsertedIds.push(id);
|
|
42717
|
-
items.push({
|
|
42718
|
-
id,
|
|
42719
|
-
...update.setOnInsert,
|
|
42720
|
-
...update.returned
|
|
42721
|
-
});
|
|
42735
|
+
items.push({ id, ...returnedById.get(id) });
|
|
42722
42736
|
} else {
|
|
42723
|
-
items.push({
|
|
42724
|
-
id,
|
|
42725
|
-
...update.returned
|
|
42726
|
-
});
|
|
42737
|
+
items.push({ id, ...returnedById.get(id) });
|
|
42727
42738
|
}
|
|
42728
42739
|
}
|
|
42729
42740
|
}
|
|
@@ -44993,7 +45004,7 @@ async function handler(event) {
|
|
|
44993
45004
|
return createCorsResponse(HTTP_STATUS.OK);
|
|
44994
45005
|
}
|
|
44995
45006
|
if (event.requestContext.http.method === "GET" && event.requestContext.http.path === "/version") {
|
|
44996
|
-
const version = "1.27.
|
|
45007
|
+
const version = "1.27.1";
|
|
44997
45008
|
return createSuccessResponse({ version, timestamp: (/* @__PURE__ */ new Date()).toISOString() }, requestId);
|
|
44998
45009
|
}
|
|
44999
45010
|
if (event.requestContext.http.method !== "POST") {
|