@open-aih/payload-ddb 3.1.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -18
- package/dist/count.d.ts.map +1 -1
- package/dist/count.js +4 -2
- package/dist/count.js.map +1 -1
- package/dist/countGlobalVersions.d.ts.map +1 -1
- package/dist/countGlobalVersions.js +6 -1
- package/dist/countGlobalVersions.js.map +1 -1
- package/dist/countVersions.d.ts.map +1 -1
- package/dist/countVersions.js +6 -1
- package/dist/countVersions.js.map +1 -1
- package/dist/create.d.ts.map +1 -1
- package/dist/create.js +31 -15
- package/dist/create.js.map +1 -1
- package/dist/createGlobal.d.ts.map +1 -1
- package/dist/createGlobal.js +2 -14
- package/dist/createGlobal.js.map +1 -1
- package/dist/createGlobalVersion.d.ts +1 -1
- package/dist/createGlobalVersion.d.ts.map +1 -1
- package/dist/createGlobalVersion.js +3 -41
- package/dist/createGlobalVersion.js.map +1 -1
- package/dist/createVersion.d.ts +6 -5
- package/dist/createVersion.d.ts.map +1 -1
- package/dist/createVersion.js +8 -48
- package/dist/createVersion.js.map +1 -1
- package/dist/deleteMany.d.ts +1 -6
- package/dist/deleteMany.d.ts.map +1 -1
- package/dist/deleteMany.js +8 -19
- package/dist/deleteMany.js.map +1 -1
- package/dist/deleteOne.d.ts.map +1 -1
- package/dist/deleteOne.js +20 -24
- package/dist/deleteOne.js.map +1 -1
- package/dist/deleteVersions.d.ts.map +1 -1
- package/dist/deleteVersions.js +8 -14
- package/dist/deleteVersions.js.map +1 -1
- package/dist/find.d.ts.map +1 -1
- package/dist/find.js +15 -2
- package/dist/find.js.map +1 -1
- package/dist/findDistinct.d.ts.map +1 -1
- package/dist/findDistinct.js +3 -1
- package/dist/findDistinct.js.map +1 -1
- package/dist/findGlobal.d.ts.map +1 -1
- package/dist/findGlobal.js +3 -2
- package/dist/findGlobal.js.map +1 -1
- package/dist/findGlobalVersions.d.ts.map +1 -1
- package/dist/findGlobalVersions.js +10 -2
- package/dist/findGlobalVersions.js.map +1 -1
- package/dist/findOne.d.ts.map +1 -1
- package/dist/findOne.js +17 -6
- package/dist/findOne.js.map +1 -1
- package/dist/findVersions.d.ts.map +1 -1
- package/dist/findVersions.js +10 -2
- package/dist/findVersions.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/queryDrafts.d.ts.map +1 -1
- package/dist/queryDrafts.js +24 -4
- package/dist/queryDrafts.js.map +1 -1
- package/dist/updateGlobal.d.ts +5 -4
- package/dist/updateGlobal.d.ts.map +1 -1
- package/dist/updateGlobal.js +22 -36
- package/dist/updateGlobal.js.map +1 -1
- package/dist/updateGlobalVersion.d.ts.map +1 -1
- package/dist/updateGlobalVersion.js +3 -49
- package/dist/updateGlobalVersion.js.map +1 -1
- package/dist/updateJobs.d.ts +21 -0
- package/dist/updateJobs.d.ts.map +1 -0
- package/dist/updateJobs.js +83 -0
- package/dist/updateJobs.js.map +1 -0
- package/dist/updateMany.d.ts +9 -3
- package/dist/updateMany.d.ts.map +1 -1
- package/dist/updateMany.js +47 -30
- package/dist/updateMany.js.map +1 -1
- package/dist/updateOne.d.ts +6 -1
- package/dist/updateOne.d.ts.map +1 -1
- package/dist/updateOne.js +49 -49
- package/dist/updateOne.js.map +1 -1
- package/dist/updateVersion.d.ts.map +1 -1
- package/dist/updateVersion.js +3 -52
- package/dist/updateVersion.js.map +1 -1
- package/dist/upsert.d.ts +6 -0
- package/dist/upsert.d.ts.map +1 -1
- package/dist/upsert.js +57 -41
- package/dist/upsert.js.map +1 -1
- package/dist/utilities/backfillUniqueGuards.d.ts +42 -0
- package/dist/utilities/backfillUniqueGuards.d.ts.map +1 -0
- package/dist/utilities/backfillUniqueGuards.js +39 -0
- package/dist/utilities/backfillUniqueGuards.js.map +1 -0
- package/dist/utilities/buildFilterExpression.d.ts +29 -14
- package/dist/utilities/buildFilterExpression.d.ts.map +1 -1
- package/dist/utilities/buildFilterExpression.js +55 -14
- package/dist/utilities/buildFilterExpression.js.map +1 -1
- package/dist/utilities/castWhere.d.ts +84 -0
- package/dist/utilities/castWhere.d.ts.map +1 -0
- package/dist/utilities/castWhere.js +254 -0
- package/dist/utilities/castWhere.js.map +1 -0
- package/dist/utilities/findFirst.d.ts +3 -2
- package/dist/utilities/findFirst.d.ts.map +1 -1
- package/dist/utilities/findFirst.js +14 -46
- package/dist/utilities/findFirst.js.map +1 -1
- package/dist/utilities/geo.d.ts +36 -0
- package/dist/utilities/geo.d.ts.map +1 -0
- package/dist/utilities/geo.js +108 -0
- package/dist/utilities/geo.js.map +1 -0
- package/dist/utilities/mapWithConcurrency.d.ts +12 -0
- package/dist/utilities/mapWithConcurrency.d.ts.map +1 -0
- package/dist/utilities/mapWithConcurrency.js +32 -0
- package/dist/utilities/mapWithConcurrency.js.map +1 -0
- package/dist/utilities/matchesWhere.d.ts +25 -5
- package/dist/utilities/matchesWhere.d.ts.map +1 -1
- package/dist/utilities/matchesWhere.js +150 -38
- package/dist/utilities/matchesWhere.js.map +1 -1
- package/dist/utilities/operators.d.ts +22 -12
- package/dist/utilities/operators.d.ts.map +1 -1
- package/dist/utilities/operators.js +36 -31
- package/dist/utilities/operators.js.map +1 -1
- package/dist/utilities/optimistic.d.ts +29 -0
- package/dist/utilities/optimistic.d.ts.map +1 -0
- package/dist/utilities/optimistic.js +58 -0
- package/dist/utilities/optimistic.js.map +1 -0
- package/dist/utilities/prepareWhere.d.ts +63 -0
- package/dist/utilities/prepareWhere.d.ts.map +1 -0
- package/dist/utilities/prepareWhere.js +198 -0
- package/dist/utilities/prepareWhere.js.map +1 -0
- package/dist/utilities/queryCount.d.ts +6 -3
- package/dist/utilities/queryCount.d.ts.map +1 -1
- package/dist/utilities/queryCount.js +16 -45
- package/dist/utilities/queryCount.js.map +1 -1
- package/dist/utilities/queryMatching.d.ts +8 -7
- package/dist/utilities/queryMatching.d.ts.map +1 -1
- package/dist/utilities/queryMatching.js +17 -54
- package/dist/utilities/queryMatching.js.map +1 -1
- package/dist/utilities/queryPartition.d.ts +26 -0
- package/dist/utilities/queryPartition.d.ts.map +1 -0
- package/dist/utilities/queryPartition.js +55 -0
- package/dist/utilities/queryPartition.js.map +1 -0
- package/dist/utilities/resolveJoins.d.ts +37 -0
- package/dist/utilities/resolveJoins.d.ts.map +1 -0
- package/dist/utilities/resolveJoins.js +195 -0
- package/dist/utilities/resolveJoins.js.map +1 -0
- package/dist/utilities/stripInternalKeys.d.ts +17 -3
- package/dist/utilities/stripInternalKeys.d.ts.map +1 -1
- package/dist/utilities/stripInternalKeys.js +25 -4
- package/dist/utilities/stripInternalKeys.js.map +1 -1
- package/dist/utilities/uniqueGuards.d.ts +39 -0
- package/dist/utilities/uniqueGuards.d.ts.map +1 -0
- package/dist/utilities/uniqueGuards.js +106 -0
- package/dist/utilities/uniqueGuards.js.map +1 -0
- package/dist/utilities/updateVersionRow.d.ts +19 -0
- package/dist/utilities/updateVersionRow.d.ts.map +1 -0
- package/dist/utilities/updateVersionRow.js +40 -0
- package/dist/utilities/updateVersionRow.js.map +1 -0
- package/dist/utilities/writeErrors.d.ts +11 -0
- package/dist/utilities/writeErrors.d.ts.map +1 -0
- package/dist/utilities/writeErrors.js +27 -0
- package/dist/utilities/writeErrors.js.map +1 -0
- package/dist/utilities/writeItems.d.ts +124 -0
- package/dist/utilities/writeItems.d.ts.map +1 -0
- package/dist/utilities/writeItems.js +383 -0
- package/dist/utilities/writeItems.js.map +1 -0
- package/package.json +21 -14
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `Promise.all(items.map(fn))`, but with at most `limit` calls in flight.
|
|
3
|
+
* Results come back in input order.
|
|
4
|
+
*
|
|
5
|
+
* Bulk writes need this: firing one request per row all at once means a
|
|
6
|
+
* `deleteMany` over a few thousand rows opens a few thousand concurrent
|
|
7
|
+
* requests, which exhausts the SDK's socket pool and invites throttling.
|
|
8
|
+
* A rejection stops new work from starting and rejects the whole call, same
|
|
9
|
+
* as `Promise.all`.
|
|
10
|
+
*/ export async function mapWithConcurrency(items, limit, fn) {
|
|
11
|
+
const results = new Array(items.length);
|
|
12
|
+
let next = 0;
|
|
13
|
+
let failed = false;
|
|
14
|
+
const worker = async ()=>{
|
|
15
|
+
while(!failed && next < items.length){
|
|
16
|
+
const index = next++;
|
|
17
|
+
try {
|
|
18
|
+
results[index] = await fn(items[index], index);
|
|
19
|
+
} catch (err) {
|
|
20
|
+
failed = true;
|
|
21
|
+
throw err;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
const workers = Math.max(1, Math.min(limit, items.length));
|
|
26
|
+
await Promise.all(Array.from({
|
|
27
|
+
length: workers
|
|
28
|
+
}, worker));
|
|
29
|
+
return results;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//# sourceMappingURL=mapWithConcurrency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/mapWithConcurrency.ts"],"sourcesContent":["/**\n * `Promise.all(items.map(fn))`, but with at most `limit` calls in flight.\n * Results come back in input order.\n *\n * Bulk writes need this: firing one request per row all at once means a\n * `deleteMany` over a few thousand rows opens a few thousand concurrent\n * requests, which exhausts the SDK's socket pool and invites throttling.\n * A rejection stops new work from starting and rejects the whole call, same\n * as `Promise.all`.\n */\nexport async function mapWithConcurrency<T, R>(\n items: readonly T[],\n limit: number,\n fn: (item: T, index: number) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length)\n let next = 0\n let failed = false\n\n const worker = async (): Promise<void> => {\n while (!failed && next < items.length) {\n const index = next++\n try {\n results[index] = await fn(items[index] as T, index)\n } catch (err) {\n failed = true\n throw err\n }\n }\n }\n\n const workers = Math.max(1, Math.min(limit, items.length))\n await Promise.all(Array.from({ length: workers }, worker))\n return results\n}\n"],"names":["mapWithConcurrency","items","limit","fn","results","Array","length","next","failed","worker","index","err","workers","Math","max","min","Promise","all","from"],"mappings":"AAAA;;;;;;;;;CASC,GACD,OAAO,eAAeA,mBACpBC,KAAmB,EACnBC,KAAa,EACbC,EAA0C;IAE1C,MAAMC,UAAU,IAAIC,MAASJ,MAAMK,MAAM;IACzC,IAAIC,OAAO;IACX,IAAIC,SAAS;IAEb,MAAMC,SAAS;QACb,MAAO,CAACD,UAAUD,OAAON,MAAMK,MAAM,CAAE;YACrC,MAAMI,QAAQH;YACd,IAAI;gBACFH,OAAO,CAACM,MAAM,GAAG,MAAMP,GAAGF,KAAK,CAACS,MAAM,EAAOA;YAC/C,EAAE,OAAOC,KAAK;gBACZH,SAAS;gBACT,MAAMG;YACR;QACF;IACF;IAEA,MAAMC,UAAUC,KAAKC,GAAG,CAAC,GAAGD,KAAKE,GAAG,CAACb,OAAOD,MAAMK,MAAM;IACxD,MAAMU,QAAQC,GAAG,CAACZ,MAAMa,IAAI,CAAC;QAAEZ,QAAQM;IAAQ,GAAGH;IAClD,OAAOL;AACT"}
|
|
@@ -1,12 +1,32 @@
|
|
|
1
1
|
import type { Where } from 'payload';
|
|
2
2
|
/**
|
|
3
3
|
* In-memory predicate that evaluates a Payload `Where` against a fetched item.
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* This is the adapter's reference evaluator: `buildFilterExpression` pushes
|
|
5
|
+
* down whatever part of a `where` DynamoDB can express, and every row that
|
|
6
|
+
* comes back from an inexact pushdown is re-checked here. It also runs alone
|
|
7
|
+
* for rows that only take their doc shape after projection (drafts
|
|
8
|
+
* supplements, `queryDrafts`).
|
|
6
9
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
10
|
+
* Where a clause can be evaluated by both, the two must return the same rows
|
|
11
|
+
* — `test/parity` pins that.
|
|
12
|
+
*
|
|
13
|
+
* Paths follow MongoDB's array semantics, which is what Payload's query
|
|
14
|
+
* language assumes: an array anywhere along a path is transparent, so
|
|
15
|
+
* `tags equals 'x'` matches a `hasMany` value containing `'x'` and
|
|
16
|
+
* `items.label equals 'x'` matches when any item has that label. A negative
|
|
17
|
+
* operator (`not_equals`, `not_in`, `not_like`) holds only when *no* element
|
|
18
|
+
* matches its positive form.
|
|
19
|
+
*
|
|
20
|
+
* Throws on any unsupported operator so we surface coverage gaps instead of
|
|
9
21
|
* silently returning wrong results.
|
|
10
22
|
*/
|
|
11
|
-
export declare function matchesWhere(item: Record<string, unknown>, where:
|
|
23
|
+
export declare function matchesWhere(item: Record<string, unknown>, where: undefined | Where): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Every value a dotted path can reach in `source`, treating arrays as
|
|
26
|
+
* transparent. A path that ends on an array yields the array itself (so an
|
|
27
|
+
* array operand can match it whole, and `exists` sees an empty list as a
|
|
28
|
+
* value) followed by each of its elements. A path that reaches nothing
|
|
29
|
+
* yields no candidates.
|
|
30
|
+
*/
|
|
31
|
+
export declare function candidatesAt(source: unknown, path: string): unknown[];
|
|
12
32
|
//# sourceMappingURL=matchesWhere.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"matchesWhere.d.ts","sourceRoot":"","sources":["../../src/utilities/matchesWhere.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"matchesWhere.d.ts","sourceRoot":"","sources":["../../src/utilities/matchesWhere.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAOpC;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,GAAG,KAAK,GAAG,OAAO,CAuD7F;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,EAAE,CAIrE"}
|
|
@@ -1,12 +1,26 @@
|
|
|
1
|
+
import { matchesIntersects, matchesNear, matchesWithin } from './geo.js';
|
|
1
2
|
import { getByPath } from './getByPath.js';
|
|
2
|
-
import {
|
|
3
|
+
import { normalizeForDynamo } from './normalizeForDynamo.js';
|
|
4
|
+
import { JS_ONLY_MARKER, SUPPORTED_OPERATORS, unsupportedOperatorError } from './operators.js';
|
|
3
5
|
/**
|
|
4
6
|
* In-memory predicate that evaluates a Payload `Where` against a fetched item.
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
+
* This is the adapter's reference evaluator: `buildFilterExpression` pushes
|
|
8
|
+
* down whatever part of a `where` DynamoDB can express, and every row that
|
|
9
|
+
* comes back from an inexact pushdown is re-checked here. It also runs alone
|
|
10
|
+
* for rows that only take their doc shape after projection (drafts
|
|
11
|
+
* supplements, `queryDrafts`).
|
|
7
12
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
13
|
+
* Where a clause can be evaluated by both, the two must return the same rows
|
|
14
|
+
* — `test/parity` pins that.
|
|
15
|
+
*
|
|
16
|
+
* Paths follow MongoDB's array semantics, which is what Payload's query
|
|
17
|
+
* language assumes: an array anywhere along a path is transparent, so
|
|
18
|
+
* `tags equals 'x'` matches a `hasMany` value containing `'x'` and
|
|
19
|
+
* `items.label equals 'x'` matches when any item has that label. A negative
|
|
20
|
+
* operator (`not_equals`, `not_in`, `not_like`) holds only when *no* element
|
|
21
|
+
* matches its positive form.
|
|
22
|
+
*
|
|
23
|
+
* Throws on any unsupported operator so we surface coverage gaps instead of
|
|
10
24
|
* silently returning wrong results.
|
|
11
25
|
*/ export function matchesWhere(item, where) {
|
|
12
26
|
if (!where) {
|
|
@@ -35,64 +49,162 @@ import { SUPPORTED_OPERATORS, unsupportedOperatorError } from './operators.js';
|
|
|
35
49
|
if (!raw || typeof raw !== 'object') {
|
|
36
50
|
continue;
|
|
37
51
|
}
|
|
38
|
-
const fieldValue = getByPath(item, key);
|
|
39
52
|
const operators = raw;
|
|
53
|
+
let candidates;
|
|
40
54
|
for (const [operator, expected] of Object.entries(operators)){
|
|
55
|
+
if (operator === JS_ONLY_MARKER) continue;
|
|
41
56
|
if (!SUPPORTED_OPERATORS.has(operator)) {
|
|
42
57
|
throw unsupportedOperatorError(operator, key);
|
|
43
58
|
}
|
|
44
|
-
|
|
59
|
+
// Geometry reads the stored point whole — `[lng, lat]` is a value, not
|
|
60
|
+
// a list of candidates.
|
|
61
|
+
if (operator === 'near' || operator === 'within' || operator === 'intersects') {
|
|
62
|
+
if (!evaluateGeo(getByPath(item, key), operator, expected)) return false;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
candidates ??= candidatesAt(item, key);
|
|
66
|
+
if (!evaluate(candidates, operator, expected)) {
|
|
45
67
|
return false;
|
|
46
68
|
}
|
|
47
69
|
}
|
|
48
70
|
}
|
|
49
71
|
return true;
|
|
50
72
|
}
|
|
51
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Every value a dotted path can reach in `source`, treating arrays as
|
|
75
|
+
* transparent. A path that ends on an array yields the array itself (so an
|
|
76
|
+
* array operand can match it whole, and `exists` sees an empty list as a
|
|
77
|
+
* value) followed by each of its elements. A path that reaches nothing
|
|
78
|
+
* yields no candidates.
|
|
79
|
+
*/ export function candidatesAt(source, path) {
|
|
80
|
+
const out = [];
|
|
81
|
+
collect(source, path.split('.'), 0, out);
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
function collect(value, segments, index, out) {
|
|
85
|
+
if (index === segments.length) {
|
|
86
|
+
if (value === undefined) return;
|
|
87
|
+
out.push(value);
|
|
88
|
+
if (Array.isArray(value)) {
|
|
89
|
+
for (const member of value){
|
|
90
|
+
if (member !== undefined) out.push(member);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (Array.isArray(value)) {
|
|
96
|
+
for (const member of value)collect(member, segments, index, out);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
if (value === null || typeof value !== 'object') return;
|
|
100
|
+
collect(value[segments[index]], segments, index + 1, out);
|
|
101
|
+
}
|
|
102
|
+
function evaluateGeo(value, operator, expected) {
|
|
103
|
+
switch(operator){
|
|
104
|
+
case 'intersects':
|
|
105
|
+
return matchesIntersects(value, expected);
|
|
106
|
+
case 'near':
|
|
107
|
+
return matchesNear(value, expected);
|
|
108
|
+
default:
|
|
109
|
+
return matchesWithin(value, expected);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function evaluate(candidates, operator, rawExpected) {
|
|
113
|
+
// Coerce the operand exactly as `buildFilterExpression` coerces its
|
|
114
|
+
// expression values (today: `Date` → ISO string, including inside `in` /
|
|
115
|
+
// `not_in` lists). Rows hold ISO strings, so comparing them against a raw
|
|
116
|
+
// `Date` would never be equal and would order by `Date#toString()` text.
|
|
117
|
+
const expected = normalizeForDynamo(rawExpected);
|
|
118
|
+
const some = (test)=>candidates.some(test);
|
|
119
|
+
const hasValue = (candidate)=>candidate !== undefined && candidate !== null;
|
|
52
120
|
switch(operator){
|
|
121
|
+
case 'all':
|
|
122
|
+
return Array.isArray(expected) && expected.every((member)=>some((candidate)=>valuesEqual(candidate, member)));
|
|
123
|
+
case 'contains':
|
|
124
|
+
return asList(expected).some((needle)=>some((candidate)=>containsText(candidate, needle)));
|
|
53
125
|
case 'equals':
|
|
54
|
-
return
|
|
55
|
-
case '
|
|
56
|
-
return
|
|
126
|
+
return some((candidate)=>valuesEqual(candidate, expected));
|
|
127
|
+
case 'exists':
|
|
128
|
+
return expected ? some(hasValue) : !some(hasValue);
|
|
57
129
|
case 'greater_than':
|
|
58
|
-
return compareLoose(
|
|
130
|
+
return some((candidate)=>compareLoose(candidate, expected) > 0);
|
|
59
131
|
case 'greater_than_equal':
|
|
60
|
-
return compareLoose(
|
|
132
|
+
return some((candidate)=>compareLoose(candidate, expected) >= 0);
|
|
133
|
+
case 'in':
|
|
134
|
+
return Array.isArray(expected) && expected.some((member)=>some((candidate)=>valuesEqual(candidate, member)));
|
|
61
135
|
case 'less_than':
|
|
62
|
-
return compareLoose(
|
|
136
|
+
return some((candidate)=>compareLoose(candidate, expected) < 0);
|
|
63
137
|
case 'less_than_equal':
|
|
64
|
-
return compareLoose(
|
|
65
|
-
case 'exists':
|
|
66
|
-
return expected ? actual !== undefined && actual !== null : actual === undefined || actual === null;
|
|
67
|
-
case 'in':
|
|
68
|
-
return Array.isArray(expected) && expected.includes(actual);
|
|
69
|
-
case 'not_in':
|
|
70
|
-
return Array.isArray(expected) && !expected.includes(actual);
|
|
138
|
+
return some((candidate)=>compareLoose(candidate, expected) <= 0);
|
|
71
139
|
case 'like':
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
140
|
+
return isLike(candidates, expected);
|
|
141
|
+
case 'not_equals':
|
|
142
|
+
return !some((candidate)=>valuesEqual(candidate, expected));
|
|
143
|
+
case 'not_in':
|
|
144
|
+
return Array.isArray(expected) && !expected.some((member)=>some((candidate)=>valuesEqual(candidate, member)));
|
|
145
|
+
case 'not_like':
|
|
146
|
+
return !isLike(candidates, expected);
|
|
79
147
|
default:
|
|
80
148
|
return false;
|
|
81
149
|
}
|
|
82
150
|
}
|
|
151
|
+
const asList = (value)=>Array.isArray(value) ? value : [
|
|
152
|
+
value
|
|
153
|
+
];
|
|
154
|
+
function isLike(candidates, expected) {
|
|
155
|
+
// Empty needle means "no constraint" — mirrors SQL `LIKE '%%'` and what
|
|
156
|
+
// Payload's admin search produces when the search input is cleared.
|
|
157
|
+
if (typeof expected !== 'string' || expected === '') return true;
|
|
158
|
+
const needle = expected.toLowerCase();
|
|
159
|
+
return candidates.some((candidate)=>typeof candidate === 'string' && candidate.toLowerCase().includes(needle));
|
|
160
|
+
}
|
|
83
161
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
|
|
87
|
-
|
|
162
|
+
* `contains`: case-insensitive substring, over text and numbers (a `hasMany`
|
|
163
|
+
* number field is searched by its digits, as the Mongo adapter does).
|
|
164
|
+
*/ function containsText(candidate, needle) {
|
|
165
|
+
if (typeof needle !== 'string' && typeof needle !== 'number') return false;
|
|
166
|
+
if (typeof candidate !== 'string' && typeof candidate !== 'number') return false;
|
|
167
|
+
return String(candidate).toLowerCase().includes(String(needle).toLowerCase());
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Equality as DynamoDB's `=` defines it: scalars by value and type, lists
|
|
171
|
+
* element-by-element in order, maps key-by-key regardless of key order. A
|
|
172
|
+
* plain `===` would compare objects by reference and never match — which
|
|
173
|
+
* breaks object operands such as a polymorphic relationship's
|
|
174
|
+
* `{ relationTo, value }`.
|
|
175
|
+
*
|
|
176
|
+
* Keys holding `undefined` are ignored on both sides, since the marshaller
|
|
177
|
+
* drops them before anything reaches DynamoDB (`removeUndefinedValues`).
|
|
178
|
+
*/ function valuesEqual(a, b) {
|
|
179
|
+
if (a === b) return true;
|
|
180
|
+
if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object') return false;
|
|
181
|
+
if (Array.isArray(a) || Array.isArray(b)) {
|
|
182
|
+
if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
|
|
183
|
+
return a.every((member, index)=>valuesEqual(member, b[index]));
|
|
184
|
+
}
|
|
185
|
+
const left = a;
|
|
186
|
+
const right = b;
|
|
187
|
+
const definedKeys = (record)=>Object.keys(record).filter((key)=>record[key] !== undefined);
|
|
188
|
+
const leftKeys = definedKeys(left);
|
|
189
|
+
if (leftKeys.length !== definedKeys(right).length) return false;
|
|
190
|
+
return leftKeys.every((key)=>right[key] !== undefined && valuesEqual(left[key], right[key]));
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Ordered comparison matching DynamoDB's `<`/`>` semantics: two numbers or
|
|
194
|
+
* two strings (including ISO date strings) compare naturally; anything else
|
|
195
|
+
* — a missing side, or operands of different types — yields a non-match by
|
|
196
|
+
* returning `NaN`. DynamoDB never orders a number against a string, so
|
|
197
|
+
* falling back to string comparison here would match rows the pushdown
|
|
198
|
+
* rejects. `castWhere` is what turns a string operand into the field's real
|
|
199
|
+
* type before it gets this far.
|
|
88
200
|
*/ function compareLoose(a, b) {
|
|
89
|
-
if (a === undefined || a === null || b === undefined || b === null) return NaN;
|
|
90
201
|
if (typeof a === 'number' && typeof b === 'number') return a - b;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
202
|
+
if (typeof a === 'string' && typeof b === 'string') {
|
|
203
|
+
if (a < b) return -1;
|
|
204
|
+
if (a > b) return 1;
|
|
205
|
+
return 0;
|
|
206
|
+
}
|
|
207
|
+
return NaN;
|
|
96
208
|
}
|
|
97
209
|
|
|
98
210
|
//# sourceMappingURL=matchesWhere.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/matchesWhere.ts"],"sourcesContent":["import type { Where } from 'payload'\n\nimport { getByPath } from './getByPath.js'\nimport { SUPPORTED_OPERATORS, unsupportedOperatorError } from './operators.js'\n\n/**\n * In-memory predicate that evaluates a Payload `Where` against a fetched item.\n * Used as a fallback when the query cannot be reduced to a `GetItem` and we\n * have to `Scan` the table.\n *\n * Supports: `equals`, `not_equals`, `exists`, `in`, `not_in`, `and`, `or`.\n * Throws on any other operator so we surface coverage gaps instead of\n * silently returning wrong results.\n */\nexport function matchesWhere(item: Record<string, unknown>, where: Where | undefined): boolean {\n if (!where) {\n return true\n }\n\n for (const [key, raw] of Object.entries(where)) {\n if (key === 'and') {\n if (!Array.isArray(raw)) continue\n for (const sub of raw) {\n if (!matchesWhere(item, sub)) return false\n }\n continue\n }\n\n if (key === 'or') {\n if (!Array.isArray(raw)) continue\n let any = false\n for (const sub of raw) {\n if (matchesWhere(item, sub)) {\n any = true\n break\n }\n }\n if (!any) return false\n continue\n }\n\n if (!raw || typeof raw !== 'object') {\n continue\n }\n\n const fieldValue = getByPath(item, key)\n const operators = raw as Record<string, unknown>\n\n for (const [operator, expected] of Object.entries(operators)) {\n if (!SUPPORTED_OPERATORS.has(operator)) {\n throw unsupportedOperatorError(operator, key)\n }\n\n if (!evaluate(fieldValue, operator, expected)) {\n return false\n }\n }\n }\n\n return true\n}\n\nfunction evaluate(actual: unknown, operator: string, expected: unknown): boolean {\n switch (operator) {\n case 'equals':\n return actual === expected\n case 'not_equals':\n return actual !== expected\n case 'greater_than':\n return compareLoose(actual, expected) > 0\n case 'greater_than_equal':\n return compareLoose(actual, expected) >= 0\n case 'less_than':\n return compareLoose(actual, expected) < 0\n case 'less_than_equal':\n return compareLoose(actual, expected) <= 0\n case 'exists':\n return expected ? actual !== undefined && actual !== null : actual === undefined || actual === null\n case 'in':\n return Array.isArray(expected) && expected.includes(actual)\n case 'not_in':\n return Array.isArray(expected) && !expected.includes(actual)\n case 'like': {\n // Empty needle means \"no constraint\" — mirrors SQL `LIKE '%%'` and what\n // Payload's admin search produces when the search input is cleared.\n if (typeof expected !== 'string' || expected === '') return true\n if (typeof actual !== 'string') return false\n return actual.toLowerCase().includes(expected.toLowerCase())\n }\n default:\n return false\n }\n}\n\n/**\n * Loose ordered comparison matching DynamoDB's `<`/`>` semantics: numbers and\n * strings (including ISO date strings) compare naturally; nullish on either\n * side yields a non-match by returning `NaN`. Lets `greater_than`/`less_than`\n * mirror the server-side filter evaluator behavior.\n */\nfunction compareLoose(a: unknown, b: unknown): number {\n if (a === undefined || a === null || b === undefined || b === null) return NaN\n if (typeof a === 'number' && typeof b === 'number') return a - b\n const as = String(a)\n const bs = String(b)\n if (as < bs) return -1\n if (as > bs) return 1\n return 0\n}\n"],"names":["getByPath","SUPPORTED_OPERATORS","unsupportedOperatorError","matchesWhere","item","where","key","raw","Object","entries","Array","isArray","sub","any","fieldValue","operators","operator","expected","has","evaluate","actual","compareLoose","undefined","includes","toLowerCase","a","b","NaN","as","String","bs"],"mappings":"AAEA,SAASA,SAAS,QAAQ,iBAAgB;AAC1C,SAASC,mBAAmB,EAAEC,wBAAwB,QAAQ,iBAAgB;AAE9E;;;;;;;;CAQC,GACD,OAAO,SAASC,aAAaC,IAA6B,EAAEC,KAAwB;IAClF,IAAI,CAACA,OAAO;QACV,OAAO;IACT;IAEA,KAAK,MAAM,CAACC,KAAKC,IAAI,IAAIC,OAAOC,OAAO,CAACJ,OAAQ;QAC9C,IAAIC,QAAQ,OAAO;YACjB,IAAI,CAACI,MAAMC,OAAO,CAACJ,MAAM;YACzB,KAAK,MAAMK,OAAOL,IAAK;gBACrB,IAAI,CAACJ,aAAaC,MAAMQ,MAAM,OAAO;YACvC;YACA;QACF;QAEA,IAAIN,QAAQ,MAAM;YAChB,IAAI,CAACI,MAAMC,OAAO,CAACJ,MAAM;YACzB,IAAIM,MAAM;YACV,KAAK,MAAMD,OAAOL,IAAK;gBACrB,IAAIJ,aAAaC,MAAMQ,MAAM;oBAC3BC,MAAM;oBACN;gBACF;YACF;YACA,IAAI,CAACA,KAAK,OAAO;YACjB;QACF;QAEA,IAAI,CAACN,OAAO,OAAOA,QAAQ,UAAU;YACnC;QACF;QAEA,MAAMO,aAAad,UAAUI,MAAME;QACnC,MAAMS,YAAYR;QAElB,KAAK,MAAM,CAACS,UAAUC,SAAS,IAAIT,OAAOC,OAAO,CAACM,WAAY;YAC5D,IAAI,CAACd,oBAAoBiB,GAAG,CAACF,WAAW;gBACtC,MAAMd,yBAAyBc,UAAUV;YAC3C;YAEA,IAAI,CAACa,SAASL,YAAYE,UAAUC,WAAW;gBAC7C,OAAO;YACT;QACF;IACF;IAEA,OAAO;AACT;AAEA,SAASE,SAASC,MAAe,EAAEJ,QAAgB,EAAEC,QAAiB;IACpE,OAAQD;QACN,KAAK;YACH,OAAOI,WAAWH;QACpB,KAAK;YACH,OAAOG,WAAWH;QACpB,KAAK;YACH,OAAOI,aAAaD,QAAQH,YAAY;QAC1C,KAAK;YACH,OAAOI,aAAaD,QAAQH,aAAa;QAC3C,KAAK;YACH,OAAOI,aAAaD,QAAQH,YAAY;QAC1C,KAAK;YACH,OAAOI,aAAaD,QAAQH,aAAa;QAC3C,KAAK;YACH,OAAOA,WAAWG,WAAWE,aAAaF,WAAW,OAAOA,WAAWE,aAAaF,WAAW;QACjG,KAAK;YACH,OAAOV,MAAMC,OAAO,CAACM,aAAaA,SAASM,QAAQ,CAACH;QACtD,KAAK;YACH,OAAOV,MAAMC,OAAO,CAACM,aAAa,CAACA,SAASM,QAAQ,CAACH;QACvD,KAAK;YAAQ;gBACX,wEAAwE;gBACxE,oEAAoE;gBACpE,IAAI,OAAOH,aAAa,YAAYA,aAAa,IAAI,OAAO;gBAC5D,IAAI,OAAOG,WAAW,UAAU,OAAO;gBACvC,OAAOA,OAAOI,WAAW,GAAGD,QAAQ,CAACN,SAASO,WAAW;YAC3D;QACA;YACE,OAAO;IACX;AACF;AAEA;;;;;CAKC,GACD,SAASH,aAAaI,CAAU,EAAEC,CAAU;IAC1C,IAAID,MAAMH,aAAaG,MAAM,QAAQC,MAAMJ,aAAaI,MAAM,MAAM,OAAOC;IAC3E,IAAI,OAAOF,MAAM,YAAY,OAAOC,MAAM,UAAU,OAAOD,IAAIC;IAC/D,MAAME,KAAKC,OAAOJ;IAClB,MAAMK,KAAKD,OAAOH;IAClB,IAAIE,KAAKE,IAAI,OAAO,CAAC;IACrB,IAAIF,KAAKE,IAAI,OAAO;IACpB,OAAO;AACT"}
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/matchesWhere.ts"],"sourcesContent":["import type { Where } from 'payload'\n\nimport { matchesIntersects, matchesNear, matchesWithin } from './geo.js'\nimport { getByPath } from './getByPath.js'\nimport { normalizeForDynamo } from './normalizeForDynamo.js'\nimport { JS_ONLY_MARKER, SUPPORTED_OPERATORS, unsupportedOperatorError } from './operators.js'\n\n/**\n * In-memory predicate that evaluates a Payload `Where` against a fetched item.\n * This is the adapter's reference evaluator: `buildFilterExpression` pushes\n * down whatever part of a `where` DynamoDB can express, and every row that\n * comes back from an inexact pushdown is re-checked here. It also runs alone\n * for rows that only take their doc shape after projection (drafts\n * supplements, `queryDrafts`).\n *\n * Where a clause can be evaluated by both, the two must return the same rows\n * — `test/parity` pins that.\n *\n * Paths follow MongoDB's array semantics, which is what Payload's query\n * language assumes: an array anywhere along a path is transparent, so\n * `tags equals 'x'` matches a `hasMany` value containing `'x'` and\n * `items.label equals 'x'` matches when any item has that label. A negative\n * operator (`not_equals`, `not_in`, `not_like`) holds only when *no* element\n * matches its positive form.\n *\n * Throws on any unsupported operator so we surface coverage gaps instead of\n * silently returning wrong results.\n */\nexport function matchesWhere(item: Record<string, unknown>, where: undefined | Where): boolean {\n if (!where) {\n return true\n }\n\n for (const [key, raw] of Object.entries(where)) {\n if (key === 'and') {\n if (!Array.isArray(raw)) continue\n for (const sub of raw) {\n if (!matchesWhere(item, sub)) return false\n }\n continue\n }\n\n if (key === 'or') {\n if (!Array.isArray(raw)) continue\n let any = false\n for (const sub of raw) {\n if (matchesWhere(item, sub)) {\n any = true\n break\n }\n }\n if (!any) return false\n continue\n }\n\n if (!raw || typeof raw !== 'object') {\n continue\n }\n\n const operators = raw as Record<string, unknown>\n let candidates: undefined | unknown[]\n\n for (const [operator, expected] of Object.entries(operators)) {\n if (operator === JS_ONLY_MARKER) continue\n if (!SUPPORTED_OPERATORS.has(operator)) {\n throw unsupportedOperatorError(operator, key)\n }\n\n // Geometry reads the stored point whole — `[lng, lat]` is a value, not\n // a list of candidates.\n if (operator === 'near' || operator === 'within' || operator === 'intersects') {\n if (!evaluateGeo(getByPath(item, key), operator, expected)) return false\n continue\n }\n\n candidates ??= candidatesAt(item, key)\n if (!evaluate(candidates, operator, expected)) {\n return false\n }\n }\n }\n\n return true\n}\n\n/**\n * Every value a dotted path can reach in `source`, treating arrays as\n * transparent. A path that ends on an array yields the array itself (so an\n * array operand can match it whole, and `exists` sees an empty list as a\n * value) followed by each of its elements. A path that reaches nothing\n * yields no candidates.\n */\nexport function candidatesAt(source: unknown, path: string): unknown[] {\n const out: unknown[] = []\n collect(source, path.split('.'), 0, out)\n return out\n}\n\nfunction collect(value: unknown, segments: string[], index: number, out: unknown[]): void {\n if (index === segments.length) {\n if (value === undefined) return\n out.push(value)\n if (Array.isArray(value)) {\n for (const member of value) {\n if (member !== undefined) out.push(member)\n }\n }\n return\n }\n if (Array.isArray(value)) {\n for (const member of value) collect(member, segments, index, out)\n return\n }\n if (value === null || typeof value !== 'object') return\n collect((value as Record<string, unknown>)[segments[index]!], segments, index + 1, out)\n}\n\nfunction evaluateGeo(value: unknown, operator: string, expected: unknown): boolean {\n switch (operator) {\n case 'intersects':\n return matchesIntersects(value, expected)\n case 'near':\n return matchesNear(value, expected)\n default:\n return matchesWithin(value, expected)\n }\n}\n\nfunction evaluate(candidates: unknown[], operator: string, rawExpected: unknown): boolean {\n // Coerce the operand exactly as `buildFilterExpression` coerces its\n // expression values (today: `Date` → ISO string, including inside `in` /\n // `not_in` lists). Rows hold ISO strings, so comparing them against a raw\n // `Date` would never be equal and would order by `Date#toString()` text.\n const expected = normalizeForDynamo(rawExpected)\n const some = (test: (candidate: unknown) => boolean) => candidates.some(test)\n const hasValue = (candidate: unknown) => candidate !== undefined && candidate !== null\n\n switch (operator) {\n case 'all':\n return (\n Array.isArray(expected) &&\n expected.every((member) => some((candidate) => valuesEqual(candidate, member)))\n )\n case 'contains':\n return asList(expected).some((needle) => some((candidate) => containsText(candidate, needle)))\n case 'equals':\n return some((candidate) => valuesEqual(candidate, expected))\n case 'exists':\n return expected ? some(hasValue) : !some(hasValue)\n case 'greater_than':\n return some((candidate) => compareLoose(candidate, expected) > 0)\n case 'greater_than_equal':\n return some((candidate) => compareLoose(candidate, expected) >= 0)\n case 'in':\n return (\n Array.isArray(expected) &&\n expected.some((member) => some((candidate) => valuesEqual(candidate, member)))\n )\n case 'less_than':\n return some((candidate) => compareLoose(candidate, expected) < 0)\n case 'less_than_equal':\n return some((candidate) => compareLoose(candidate, expected) <= 0)\n case 'like':\n return isLike(candidates, expected)\n case 'not_equals':\n return !some((candidate) => valuesEqual(candidate, expected))\n case 'not_in':\n return (\n Array.isArray(expected) &&\n !expected.some((member) => some((candidate) => valuesEqual(candidate, member)))\n )\n case 'not_like':\n return !isLike(candidates, expected)\n default:\n return false\n }\n}\n\nconst asList = (value: unknown): unknown[] => (Array.isArray(value) ? value : [value])\n\nfunction isLike(candidates: unknown[], expected: unknown): boolean {\n // Empty needle means \"no constraint\" — mirrors SQL `LIKE '%%'` and what\n // Payload's admin search produces when the search input is cleared.\n if (typeof expected !== 'string' || expected === '') return true\n const needle = expected.toLowerCase()\n return candidates.some(\n (candidate) => typeof candidate === 'string' && candidate.toLowerCase().includes(needle),\n )\n}\n\n/**\n * `contains`: case-insensitive substring, over text and numbers (a `hasMany`\n * number field is searched by its digits, as the Mongo adapter does).\n */\nfunction containsText(candidate: unknown, needle: unknown): boolean {\n if (typeof needle !== 'string' && typeof needle !== 'number') return false\n if (typeof candidate !== 'string' && typeof candidate !== 'number') return false\n return String(candidate).toLowerCase().includes(String(needle).toLowerCase())\n}\n\n/**\n * Equality as DynamoDB's `=` defines it: scalars by value and type, lists\n * element-by-element in order, maps key-by-key regardless of key order. A\n * plain `===` would compare objects by reference and never match — which\n * breaks object operands such as a polymorphic relationship's\n * `{ relationTo, value }`.\n *\n * Keys holding `undefined` are ignored on both sides, since the marshaller\n * drops them before anything reaches DynamoDB (`removeUndefinedValues`).\n */\nfunction valuesEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true\n if (a === null || b === null || typeof a !== 'object' || typeof b !== 'object') return false\n\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false\n return a.every((member, index) => valuesEqual(member, b[index]))\n }\n\n const left = a as Record<string, unknown>\n const right = b as Record<string, unknown>\n const definedKeys = (record: Record<string, unknown>) =>\n Object.keys(record).filter((key) => record[key] !== undefined)\n const leftKeys = definedKeys(left)\n if (leftKeys.length !== definedKeys(right).length) return false\n return leftKeys.every((key) => right[key] !== undefined && valuesEqual(left[key], right[key]))\n}\n\n/**\n * Ordered comparison matching DynamoDB's `<`/`>` semantics: two numbers or\n * two strings (including ISO date strings) compare naturally; anything else\n * — a missing side, or operands of different types — yields a non-match by\n * returning `NaN`. DynamoDB never orders a number against a string, so\n * falling back to string comparison here would match rows the pushdown\n * rejects. `castWhere` is what turns a string operand into the field's real\n * type before it gets this far.\n */\nfunction compareLoose(a: unknown, b: unknown): number {\n if (typeof a === 'number' && typeof b === 'number') return a - b\n if (typeof a === 'string' && typeof b === 'string') {\n if (a < b) return -1\n if (a > b) return 1\n return 0\n }\n return NaN\n}\n"],"names":["matchesIntersects","matchesNear","matchesWithin","getByPath","normalizeForDynamo","JS_ONLY_MARKER","SUPPORTED_OPERATORS","unsupportedOperatorError","matchesWhere","item","where","key","raw","Object","entries","Array","isArray","sub","any","operators","candidates","operator","expected","has","evaluateGeo","candidatesAt","evaluate","source","path","out","collect","split","value","segments","index","length","undefined","push","member","rawExpected","some","test","hasValue","candidate","every","valuesEqual","asList","needle","containsText","compareLoose","isLike","toLowerCase","includes","String","a","b","left","right","definedKeys","record","keys","filter","leftKeys","NaN"],"mappings":"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"}
|
|
@@ -1,26 +1,36 @@
|
|
|
1
|
-
import type { Where } from 'payload';
|
|
2
1
|
/**
|
|
3
2
|
* The where-operator coverage shared by `matchesWhere` (in-JS evaluator) and
|
|
4
3
|
* `buildFilterExpression` (DynamoDB pushdown). Keeping the set in one place
|
|
5
4
|
* keeps the two paths honest — if an operator is supported in one, it should
|
|
6
5
|
* be supported in the other, since callers can't know which path runs.
|
|
6
|
+
*
|
|
7
|
+
* This is Payload's full operator list (`validOperators` in core).
|
|
7
8
|
*/
|
|
8
9
|
export declare const SUPPORTED_OPERATORS: Set<string>;
|
|
9
10
|
/**
|
|
10
11
|
* Operators we can't faithfully express in a DynamoDB `FilterExpression` and
|
|
11
|
-
* therefore evaluate in JS after fetching candidate rows
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* `
|
|
12
|
+
* therefore evaluate in JS after fetching candidate rows:
|
|
13
|
+
*
|
|
14
|
+
* - `like` / `not_like` / `contains`: Payload's contract is case-insensitive
|
|
15
|
+
* matching, while DynamoDB's `contains()` is case-sensitive — pushing it
|
|
16
|
+
* down would silently change semantics.
|
|
17
|
+
* - `all`: needs "every operand is a member" over a list; no equivalent.
|
|
18
|
+
* - `near` / `within` / `intersects`: geometry.
|
|
19
|
+
*
|
|
20
|
+
* A clause using one of these is simply left out of the pushed-down filter
|
|
21
|
+
* (see `buildFilterExpression`); the rest of the `where` still narrows the
|
|
22
|
+
* read server-side, and `matchesWhere` re-checks every returned row.
|
|
17
23
|
*/
|
|
18
24
|
export declare const JS_ONLY_OPERATORS: Set<string>;
|
|
19
|
-
export declare const SUPPORTED_OPERATORS_DESCRIPTION: string;
|
|
20
|
-
export declare function unsupportedOperatorError(operator: string, field: string): Error;
|
|
21
25
|
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
26
|
+
* Pseudo-operator `castWhere` adds to a clause whose *path* can't be pushed
|
|
27
|
+
* down, whatever its operators: one that runs through an array or a
|
|
28
|
+
* `hasMany` value (DynamoDB document paths can't mean "any element"), or
|
|
29
|
+
* into a field whose inner shape the schema doesn't describe. The pushdown
|
|
30
|
+
* skips the whole clause; `matchesWhere` ignores the marker and evaluates the
|
|
31
|
+
* real operators with any-element semantics.
|
|
24
32
|
*/
|
|
25
|
-
export declare
|
|
33
|
+
export declare const JS_ONLY_MARKER = "$js";
|
|
34
|
+
export declare const SUPPORTED_OPERATORS_DESCRIPTION: string;
|
|
35
|
+
export declare function unsupportedOperatorError(operator: string, field: string): Error;
|
|
26
36
|
//# sourceMappingURL=operators.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operators.d.ts","sourceRoot":"","sources":["../../src/utilities/operators.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"operators.d.ts","sourceRoot":"","sources":["../../src/utilities/operators.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,aAiB9B,CAAA;AAEF;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,aAQ5B,CAAA;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,cAAc,QAAQ,CAAA;AAEnC,eAAO,MAAM,+BAA+B,QAAoD,CAAA;AAEhG,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAK/E"}
|
|
@@ -3,56 +3,61 @@
|
|
|
3
3
|
* `buildFilterExpression` (DynamoDB pushdown). Keeping the set in one place
|
|
4
4
|
* keeps the two paths honest — if an operator is supported in one, it should
|
|
5
5
|
* be supported in the other, since callers can't know which path runs.
|
|
6
|
+
*
|
|
7
|
+
* This is Payload's full operator list (`validOperators` in core).
|
|
6
8
|
*/ export const SUPPORTED_OPERATORS = new Set([
|
|
9
|
+
'all',
|
|
10
|
+
'contains',
|
|
7
11
|
'equals',
|
|
8
12
|
'exists',
|
|
9
13
|
'greater_than',
|
|
10
14
|
'greater_than_equal',
|
|
11
15
|
'in',
|
|
16
|
+
'intersects',
|
|
12
17
|
'less_than',
|
|
13
18
|
'less_than_equal',
|
|
14
19
|
'like',
|
|
20
|
+
'near',
|
|
15
21
|
'not_equals',
|
|
16
|
-
'not_in'
|
|
22
|
+
'not_in',
|
|
23
|
+
'not_like',
|
|
24
|
+
'within'
|
|
17
25
|
]);
|
|
18
26
|
/**
|
|
19
27
|
* Operators we can't faithfully express in a DynamoDB `FilterExpression` and
|
|
20
|
-
* therefore evaluate in JS after fetching candidate rows
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* `
|
|
28
|
+
* therefore evaluate in JS after fetching candidate rows:
|
|
29
|
+
*
|
|
30
|
+
* - `like` / `not_like` / `contains`: Payload's contract is case-insensitive
|
|
31
|
+
* matching, while DynamoDB's `contains()` is case-sensitive — pushing it
|
|
32
|
+
* down would silently change semantics.
|
|
33
|
+
* - `all`: needs "every operand is a member" over a list; no equivalent.
|
|
34
|
+
* - `near` / `within` / `intersects`: geometry.
|
|
35
|
+
*
|
|
36
|
+
* A clause using one of these is simply left out of the pushed-down filter
|
|
37
|
+
* (see `buildFilterExpression`); the rest of the `where` still narrows the
|
|
38
|
+
* read server-side, and `matchesWhere` re-checks every returned row.
|
|
26
39
|
*/ export const JS_ONLY_OPERATORS = new Set([
|
|
27
|
-
'
|
|
40
|
+
'all',
|
|
41
|
+
'contains',
|
|
42
|
+
'intersects',
|
|
43
|
+
'like',
|
|
44
|
+
'near',
|
|
45
|
+
'not_like',
|
|
46
|
+
'within'
|
|
28
47
|
]);
|
|
48
|
+
/**
|
|
49
|
+
* Pseudo-operator `castWhere` adds to a clause whose *path* can't be pushed
|
|
50
|
+
* down, whatever its operators: one that runs through an array or a
|
|
51
|
+
* `hasMany` value (DynamoDB document paths can't mean "any element"), or
|
|
52
|
+
* into a field whose inner shape the schema doesn't describe. The pushdown
|
|
53
|
+
* skips the whole clause; `matchesWhere` ignores the marker and evaluates the
|
|
54
|
+
* real operators with any-element semantics.
|
|
55
|
+
*/ export const JS_ONLY_MARKER = '$js';
|
|
29
56
|
export const SUPPORTED_OPERATORS_DESCRIPTION = `${[
|
|
30
57
|
...SUPPORTED_OPERATORS
|
|
31
58
|
].join(', ')}, and, or`;
|
|
32
59
|
export function unsupportedOperatorError(operator, field) {
|
|
33
|
-
return new Error(`payload-ddb: operator \`${operator}\` is not supported
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Walk a `Where` and return true if any leaf clause uses an operator that
|
|
37
|
-
* forces JS-side evaluation. Recurses into `and`/`or` groups.
|
|
38
|
-
*/ export function whereHasJsOnlyOperator(where) {
|
|
39
|
-
if (!where) return false;
|
|
40
|
-
for (const [key, raw] of Object.entries(where)){
|
|
41
|
-
if (key === 'and' || key === 'or') {
|
|
42
|
-
if (!Array.isArray(raw)) continue;
|
|
43
|
-
for (const sub of raw){
|
|
44
|
-
if (sub && typeof sub === 'object' && whereHasJsOnlyOperator(sub)) {
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
if (!raw || typeof raw !== 'object') continue;
|
|
51
|
-
for (const op of Object.keys(raw)){
|
|
52
|
-
if (JS_ONLY_OPERATORS.has(op)) return true;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
return false;
|
|
60
|
+
return new Error(`payload-ddb: operator \`${operator}\` is not supported on field \`${field}\`. ` + `Supported: ${SUPPORTED_OPERATORS_DESCRIPTION}.`);
|
|
56
61
|
}
|
|
57
62
|
|
|
58
63
|
//# sourceMappingURL=operators.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/operators.ts"],"sourcesContent":["
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/operators.ts"],"sourcesContent":["/**\n * The where-operator coverage shared by `matchesWhere` (in-JS evaluator) and\n * `buildFilterExpression` (DynamoDB pushdown). Keeping the set in one place\n * keeps the two paths honest — if an operator is supported in one, it should\n * be supported in the other, since callers can't know which path runs.\n *\n * This is Payload's full operator list (`validOperators` in core).\n */\nexport const SUPPORTED_OPERATORS = new Set([\n 'all',\n 'contains',\n 'equals',\n 'exists',\n 'greater_than',\n 'greater_than_equal',\n 'in',\n 'intersects',\n 'less_than',\n 'less_than_equal',\n 'like',\n 'near',\n 'not_equals',\n 'not_in',\n 'not_like',\n 'within',\n])\n\n/**\n * Operators we can't faithfully express in a DynamoDB `FilterExpression` and\n * therefore evaluate in JS after fetching candidate rows:\n *\n * - `like` / `not_like` / `contains`: Payload's contract is case-insensitive\n * matching, while DynamoDB's `contains()` is case-sensitive — pushing it\n * down would silently change semantics.\n * - `all`: needs \"every operand is a member\" over a list; no equivalent.\n * - `near` / `within` / `intersects`: geometry.\n *\n * A clause using one of these is simply left out of the pushed-down filter\n * (see `buildFilterExpression`); the rest of the `where` still narrows the\n * read server-side, and `matchesWhere` re-checks every returned row.\n */\nexport const JS_ONLY_OPERATORS = new Set([\n 'all',\n 'contains',\n 'intersects',\n 'like',\n 'near',\n 'not_like',\n 'within',\n])\n\n/**\n * Pseudo-operator `castWhere` adds to a clause whose *path* can't be pushed\n * down, whatever its operators: one that runs through an array or a\n * `hasMany` value (DynamoDB document paths can't mean \"any element\"), or\n * into a field whose inner shape the schema doesn't describe. The pushdown\n * skips the whole clause; `matchesWhere` ignores the marker and evaluates the\n * real operators with any-element semantics.\n */\nexport const JS_ONLY_MARKER = '$js'\n\nexport const SUPPORTED_OPERATORS_DESCRIPTION = `${[...SUPPORTED_OPERATORS].join(', ')}, and, or`\n\nexport function unsupportedOperatorError(operator: string, field: string): Error {\n return new Error(\n `payload-ddb: operator \\`${operator}\\` is not supported on field \\`${field}\\`. ` +\n `Supported: ${SUPPORTED_OPERATORS_DESCRIPTION}.`,\n )\n}\n"],"names":["SUPPORTED_OPERATORS","Set","JS_ONLY_OPERATORS","JS_ONLY_MARKER","SUPPORTED_OPERATORS_DESCRIPTION","join","unsupportedOperatorError","operator","field","Error"],"mappings":"AAAA;;;;;;;CAOC,GACD,OAAO,MAAMA,sBAAsB,IAAIC,IAAI;IACzC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD,EAAC;AAEF;;;;;;;;;;;;;CAaC,GACD,OAAO,MAAMC,oBAAoB,IAAID,IAAI;IACvC;IACA;IACA;IACA;IACA;IACA;IACA;CACD,EAAC;AAEF;;;;;;;CAOC,GACD,OAAO,MAAME,iBAAiB,MAAK;AAEnC,OAAO,MAAMC,kCAAkC,GAAG;OAAIJ;CAAoB,CAACK,IAAI,CAAC,MAAM,SAAS,CAAC,CAAA;AAEhG,OAAO,SAASC,yBAAyBC,QAAgB,EAAEC,KAAa;IACtE,OAAO,IAAIC,MACT,CAAC,wBAAwB,EAAEF,SAAS,+BAA+B,EAAEC,MAAM,IAAI,CAAC,GAC9E,CAAC,WAAW,EAAEJ,gCAAgC,CAAC,CAAC;AAEtD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { APIError } from 'payload';
|
|
2
|
+
import type { DynamoAdapter } from '../types.js';
|
|
3
|
+
type Row = Record<string, unknown>;
|
|
4
|
+
/**
|
|
5
|
+
* Read one row by id with a strongly consistent `GetItem`. The returned
|
|
6
|
+
* object carries its revision (see `stripInternalKeys`), so it can be handed
|
|
7
|
+
* to `putItem` as `replaces`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getById(adapter: DynamoAdapter, partition: string, id: unknown): Promise<null | Row>;
|
|
10
|
+
/** Enough to ride out a burst of writers on one row; beyond it something is wrong. */
|
|
11
|
+
export declare const MAX_WRITE_ATTEMPTS = 10;
|
|
12
|
+
/**
|
|
13
|
+
* Run a read-merge-write until it lands.
|
|
14
|
+
*
|
|
15
|
+
* `write` merges onto the row it's given and puts the result with
|
|
16
|
+
* `replaces: current`. If another writer got in first, the put's revision
|
|
17
|
+
* check fails; `reread` then fetches the row as it is now and the merge is
|
|
18
|
+
* redone on top of it — so two concurrent patches to different fields both
|
|
19
|
+
* survive, instead of the second silently overwriting the first.
|
|
20
|
+
*
|
|
21
|
+
* `reread` returning `null` means the row is gone or no longer qualifies;
|
|
22
|
+
* the result is then `null` and nothing is written.
|
|
23
|
+
*/
|
|
24
|
+
export declare function writeWithRetry<T>(first: null | Row, reread: () => Promise<null | Row>, write: (current: Row) => Promise<T>): Promise<null | T>;
|
|
25
|
+
export declare function conflictError(): APIError;
|
|
26
|
+
/** A short random pause so writers that collided don't collide again in step. */
|
|
27
|
+
export declare function backoff(attempt: number): Promise<void>;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=optimistic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"optimistic.d.ts","sourceRoot":"","sources":["../../src/utilities/optimistic.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAElC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAKhD,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAElC;;;;GAIG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,OAAO,GACV,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC,CAerB;AAED,sFAAsF;AACtF,eAAO,MAAM,kBAAkB,KAAK,CAAA;AAEpC;;;;;;;;;;;GAWG;AACH,wBAAsB,cAAc,CAAC,CAAC,EACpC,KAAK,EAAE,IAAI,GAAG,GAAG,EACjB,MAAM,EAAE,MAAM,OAAO,CAAC,IAAI,GAAG,GAAG,CAAC,EACjC,KAAK,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,CAAC,GAClC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAenB;AAED,wBAAgB,aAAa,IAAI,QAAQ,CAOxC;AAED,iFAAiF;AACjF,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAEtD"}
|