@payloadcms/drizzle 4.0.0-internal.a7ca468 → 4.0.0-internal.af6aad0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/exports/postgres.d.ts +2 -0
- package/dist/exports/postgres.d.ts.map +1 -1
- package/dist/exports/postgres.js +2 -0
- package/dist/exports/postgres.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/postgres/init.d.ts.map +1 -1
- package/dist/postgres/init.js +6 -0
- package/dist/postgres/init.js.map +1 -1
- package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.d.ts +15 -0
- package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.d.ts.map +1 -0
- package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.js +25 -0
- package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.js.map +1 -0
- package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.spec.js +91 -0
- package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.spec.js.map +1 -0
- package/dist/postgres/query/postgresUnaccent.d.ts +13 -0
- package/dist/postgres/query/postgresUnaccent.d.ts.map +1 -0
- package/dist/postgres/query/postgresUnaccent.js +40 -0
- package/dist/postgres/query/postgresUnaccent.js.map +1 -0
- package/dist/postgres/query/postgresUnaccent.spec.js +71 -0
- package/dist/postgres/query/postgresUnaccent.spec.js.map +1 -0
- package/dist/postgres/types.d.ts +13 -2
- package/dist/postgres/types.d.ts.map +1 -1
- package/dist/postgres/types.js.map +1 -1
- package/dist/queries/buildOperatorConstraint.d.ts +22 -0
- package/dist/queries/buildOperatorConstraint.d.ts.map +1 -0
- package/dist/queries/buildOperatorConstraint.js +63 -0
- package/dist/queries/buildOperatorConstraint.js.map +1 -0
- package/dist/queries/buildOperatorConstraint.spec.js +348 -0
- package/dist/queries/buildOperatorConstraint.spec.js.map +1 -0
- package/dist/queries/operatorMap.d.ts +7 -3
- package/dist/queries/operatorMap.d.ts.map +1 -1
- package/dist/queries/operatorMap.js.map +1 -1
- package/dist/queries/parseParams.d.ts.map +1 -1
- package/dist/queries/parseParams.js +53 -6
- package/dist/queries/parseParams.js.map +1 -1
- package/dist/queries/validateOperatorHandlers.d.ts +8 -0
- package/dist/queries/validateOperatorHandlers.d.ts.map +1 -0
- package/dist/queries/validateOperatorHandlers.js +30 -0
- package/dist/queries/validateOperatorHandlers.js.map +1 -0
- package/dist/queries/validateOperatorHandlers.spec.js +142 -0
- package/dist/queries/validateOperatorHandlers.spec.js.map +1 -0
- package/dist/schema/build.d.ts.map +1 -1
- package/dist/schema/build.js +4 -5
- package/dist/schema/build.js.map +1 -1
- package/dist/schema/buildRawSchema.spec.js +70 -10
- package/dist/schema/buildRawSchema.spec.js.map +1 -1
- package/dist/types.d.ts +50 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/buildForeignKeyName.d.ts.map +1 -1
- package/dist/utilities/buildForeignKeyName.js +3 -2
- package/dist/utilities/buildForeignKeyName.js.map +1 -1
- package/dist/utilities/buildIndexName.d.ts.map +1 -1
- package/dist/utilities/buildIndexName.js +3 -2
- package/dist/utilities/buildIndexName.js.map +1 -1
- package/dist/utilities/checkTruncatedIdentifiers.d.ts +13 -0
- package/dist/utilities/checkTruncatedIdentifiers.d.ts.map +1 -0
- package/dist/utilities/checkTruncatedIdentifiers.js +56 -0
- package/dist/utilities/checkTruncatedIdentifiers.js.map +1 -0
- package/dist/utilities/checkTruncatedIdentifiers.spec.js +301 -0
- package/dist/utilities/checkTruncatedIdentifiers.spec.js.map +1 -0
- package/dist/utilities/validateIdentifierLength.d.ts +5 -0
- package/dist/utilities/validateIdentifierLength.d.ts.map +1 -1
- package/dist/utilities/validateIdentifierLength.js +4 -0
- package/dist/utilities/validateIdentifierLength.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Column, SQL } from 'drizzle-orm';
|
|
2
|
+
import type { FlattenedField, Operator } from 'payload';
|
|
3
|
+
import type { DrizzleAdapter } from '../types.js';
|
|
4
|
+
import type { DrizzleResolvedOperator } from './operatorMap.js';
|
|
5
|
+
type Args = {
|
|
6
|
+
adapter: DrizzleAdapter;
|
|
7
|
+
column: Column | SQL;
|
|
8
|
+
field: FlattenedField;
|
|
9
|
+
locale?: string;
|
|
10
|
+
originalOperator: Operator;
|
|
11
|
+
path: string;
|
|
12
|
+
resolvedOperator: DrizzleResolvedOperator;
|
|
13
|
+
value: unknown;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Builds the final, user-facing SQL comparison for one query leaf: applies every matching
|
|
17
|
+
* operand-transform handler in configuration order, then either calls the single matching
|
|
18
|
+
* replacement handler or falls back to `adapter.operators[resolvedOperator]`.
|
|
19
|
+
*/
|
|
20
|
+
export declare const buildOperatorConstraint: (args: Args) => SQL;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=buildOperatorConstraint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildOperatorConstraint.d.ts","sourceRoot":"","sources":["../../src/queries/buildOperatorConstraint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAIvD,OAAO,KAAK,EACV,cAAc,EAKf,MAAM,aAAa,CAAA;AACpB,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kBAAkB,CAAA;AAE/D,KAAK,IAAI,GAAG;IACV,OAAO,EAAE,cAAc,CAAA;IACvB,MAAM,EAAE,MAAM,GAAG,GAAG,CAAA;IACpB,KAAK,EAAE,cAAc,CAAA;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,gBAAgB,EAAE,QAAQ,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB,EAAE,uBAAuB,CAAA;IACzC,KAAK,EAAE,OAAO,CAAA;CACf,CAAA;AAsBD;;;;GAIG;AACH,eAAO,MAAM,uBAAuB,SAAU,IAAI,KAAG,GAuDpD,CAAA"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { APIError } from 'payload';
|
|
2
|
+
const isTransformHandler = (handler)=>typeof handler.transformOperands === 'function';
|
|
3
|
+
const isReplacementHandler = (handler)=>typeof handler.build === 'function';
|
|
4
|
+
const handlerMatches = (handler, args)=>{
|
|
5
|
+
if (!handler.operators.includes(args.resolvedOperator)) {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
if (handler.fieldTypes && !handler.fieldTypes.includes(args.field.type)) {
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
return true;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Builds the final, user-facing SQL comparison for one query leaf: applies every matching
|
|
15
|
+
* operand-transform handler in configuration order, then either calls the single matching
|
|
16
|
+
* replacement handler or falls back to `adapter.operators[resolvedOperator]`.
|
|
17
|
+
*/ export const buildOperatorConstraint = (args)=>{
|
|
18
|
+
const { adapter, field, locale, originalOperator, path, resolvedOperator } = args;
|
|
19
|
+
const matchingHandlers = (adapter.operatorHandlers ?? []).filter((handler)=>handlerMatches(handler, args));
|
|
20
|
+
const context = {
|
|
21
|
+
adapter,
|
|
22
|
+
column: args.column,
|
|
23
|
+
field,
|
|
24
|
+
locale,
|
|
25
|
+
originalOperator,
|
|
26
|
+
path,
|
|
27
|
+
resolvedOperator,
|
|
28
|
+
storage: 'column',
|
|
29
|
+
value: args.value
|
|
30
|
+
};
|
|
31
|
+
for (const handler of matchingHandlers.filter(isTransformHandler)){
|
|
32
|
+
let result;
|
|
33
|
+
try {
|
|
34
|
+
result = handler.transformOperands({
|
|
35
|
+
...context
|
|
36
|
+
});
|
|
37
|
+
} catch (error) {
|
|
38
|
+
throw new Error(`Operator handler "${handler.name}" threw while transforming operands for the "${resolvedOperator}" operator at path "${path}".`, {
|
|
39
|
+
cause: error
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (!result || typeof result !== 'object' || !('column' in result) || !('value' in result)) {
|
|
43
|
+
throw new APIError(`Operator handler "${handler.name}" returned an invalid operand transform for the "${resolvedOperator}" operator at path "${path}". Expected an object with "column" and "value" properties.`);
|
|
44
|
+
}
|
|
45
|
+
context.column = result.column;
|
|
46
|
+
context.value = result.value;
|
|
47
|
+
}
|
|
48
|
+
const replacementHandler = matchingHandlers.find(isReplacementHandler);
|
|
49
|
+
if (replacementHandler) {
|
|
50
|
+
try {
|
|
51
|
+
return replacementHandler.build({
|
|
52
|
+
...context
|
|
53
|
+
});
|
|
54
|
+
} catch (error) {
|
|
55
|
+
throw new Error(`Operator handler "${replacementHandler.name}" threw while building the "${resolvedOperator}" comparison at path "${path}".`, {
|
|
56
|
+
cause: error
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return adapter.operators[resolvedOperator](context.column, context.value);
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
//# sourceMappingURL=buildOperatorConstraint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/queries/buildOperatorConstraint.ts"],"sourcesContent":["import type { Column, SQL } from 'drizzle-orm'\nimport type { FlattenedField, Operator } from 'payload'\n\nimport { APIError } from 'payload'\n\nimport type {\n DrizzleAdapter,\n DrizzleOperandTransformHandler,\n DrizzleOperatorHandler,\n DrizzleOperatorHandlerContext,\n DrizzleOperatorReplacementHandler,\n} from '../types.js'\nimport type { DrizzleResolvedOperator } from './operatorMap.js'\n\ntype Args = {\n adapter: DrizzleAdapter\n column: Column | SQL\n field: FlattenedField\n locale?: string\n originalOperator: Operator\n path: string\n resolvedOperator: DrizzleResolvedOperator\n value: unknown\n}\n\nconst isTransformHandler = (\n handler: DrizzleOperatorHandler,\n): handler is DrizzleOperandTransformHandler => typeof handler.transformOperands === 'function'\n\nconst isReplacementHandler = (\n handler: DrizzleOperatorHandler,\n): handler is DrizzleOperatorReplacementHandler => typeof handler.build === 'function'\n\nconst handlerMatches = (handler: DrizzleOperatorHandler, args: Args): boolean => {\n if (!handler.operators.includes(args.resolvedOperator)) {\n return false\n }\n\n if (handler.fieldTypes && !handler.fieldTypes.includes(args.field.type)) {\n return false\n }\n\n return true\n}\n\n/**\n * Builds the final, user-facing SQL comparison for one query leaf: applies every matching\n * operand-transform handler in configuration order, then either calls the single matching\n * replacement handler or falls back to `adapter.operators[resolvedOperator]`.\n */\nexport const buildOperatorConstraint = (args: Args): SQL => {\n const { adapter, field, locale, originalOperator, path, resolvedOperator } = args\n\n const matchingHandlers = (adapter.operatorHandlers ?? []).filter((handler) =>\n handlerMatches(handler, args),\n )\n\n const context: DrizzleOperatorHandlerContext = {\n adapter,\n column: args.column,\n field,\n locale,\n originalOperator,\n path,\n resolvedOperator,\n storage: 'column',\n value: args.value,\n }\n\n for (const handler of matchingHandlers.filter(isTransformHandler)) {\n let result: { column: Column | SQL; value: unknown }\n\n try {\n result = handler.transformOperands({ ...context })\n } catch (error) {\n throw new Error(\n `Operator handler \"${handler.name}\" threw while transforming operands for the \"${resolvedOperator}\" operator at path \"${path}\".`,\n { cause: error },\n )\n }\n\n if (!result || typeof result !== 'object' || !('column' in result) || !('value' in result)) {\n throw new APIError(\n `Operator handler \"${handler.name}\" returned an invalid operand transform for the \"${resolvedOperator}\" operator at path \"${path}\". Expected an object with \"column\" and \"value\" properties.`,\n )\n }\n\n context.column = result.column\n context.value = result.value\n }\n\n const replacementHandler = matchingHandlers.find(isReplacementHandler)\n\n if (replacementHandler) {\n try {\n return replacementHandler.build({ ...context })\n } catch (error) {\n throw new Error(\n `Operator handler \"${replacementHandler.name}\" threw while building the \"${resolvedOperator}\" comparison at path \"${path}\".`,\n { cause: error },\n )\n }\n }\n\n return adapter.operators[resolvedOperator](context.column, context.value)\n}\n"],"names":["APIError","isTransformHandler","handler","transformOperands","isReplacementHandler","build","handlerMatches","args","operators","includes","resolvedOperator","fieldTypes","field","type","buildOperatorConstraint","adapter","locale","originalOperator","path","matchingHandlers","operatorHandlers","filter","context","column","storage","value","result","error","Error","name","cause","replacementHandler","find"],"mappings":"AAGA,SAASA,QAAQ,QAAQ,UAAS;AAsBlC,MAAMC,qBAAqB,CACzBC,UAC8C,OAAOA,QAAQC,iBAAiB,KAAK;AAErF,MAAMC,uBAAuB,CAC3BF,UACiD,OAAOA,QAAQG,KAAK,KAAK;AAE5E,MAAMC,iBAAiB,CAACJ,SAAiCK;IACvD,IAAI,CAACL,QAAQM,SAAS,CAACC,QAAQ,CAACF,KAAKG,gBAAgB,GAAG;QACtD,OAAO;IACT;IAEA,IAAIR,QAAQS,UAAU,IAAI,CAACT,QAAQS,UAAU,CAACF,QAAQ,CAACF,KAAKK,KAAK,CAACC,IAAI,GAAG;QACvE,OAAO;IACT;IAEA,OAAO;AACT;AAEA;;;;CAIC,GACD,OAAO,MAAMC,0BAA0B,CAACP;IACtC,MAAM,EAAEQ,OAAO,EAAEH,KAAK,EAAEI,MAAM,EAAEC,gBAAgB,EAAEC,IAAI,EAAER,gBAAgB,EAAE,GAAGH;IAE7E,MAAMY,mBAAmB,AAACJ,CAAAA,QAAQK,gBAAgB,IAAI,EAAE,AAAD,EAAGC,MAAM,CAAC,CAACnB,UAChEI,eAAeJ,SAASK;IAG1B,MAAMe,UAAyC;QAC7CP;QACAQ,QAAQhB,KAAKgB,MAAM;QACnBX;QACAI;QACAC;QACAC;QACAR;QACAc,SAAS;QACTC,OAAOlB,KAAKkB,KAAK;IACnB;IAEA,KAAK,MAAMvB,WAAWiB,iBAAiBE,MAAM,CAACpB,oBAAqB;QACjE,IAAIyB;QAEJ,IAAI;YACFA,SAASxB,QAAQC,iBAAiB,CAAC;gBAAE,GAAGmB,OAAO;YAAC;QAClD,EAAE,OAAOK,OAAO;YACd,MAAM,IAAIC,MACR,CAAC,kBAAkB,EAAE1B,QAAQ2B,IAAI,CAAC,6CAA6C,EAAEnB,iBAAiB,oBAAoB,EAAEQ,KAAK,EAAE,CAAC,EAChI;gBAAEY,OAAOH;YAAM;QAEnB;QAEA,IAAI,CAACD,UAAU,OAAOA,WAAW,YAAY,CAAE,CAAA,YAAYA,MAAK,KAAM,CAAE,CAAA,WAAWA,MAAK,GAAI;YAC1F,MAAM,IAAI1B,SACR,CAAC,kBAAkB,EAAEE,QAAQ2B,IAAI,CAAC,iDAAiD,EAAEnB,iBAAiB,oBAAoB,EAAEQ,KAAK,2DAA2D,CAAC;QAEjM;QAEAI,QAAQC,MAAM,GAAGG,OAAOH,MAAM;QAC9BD,QAAQG,KAAK,GAAGC,OAAOD,KAAK;IAC9B;IAEA,MAAMM,qBAAqBZ,iBAAiBa,IAAI,CAAC5B;IAEjD,IAAI2B,oBAAoB;QACtB,IAAI;YACF,OAAOA,mBAAmB1B,KAAK,CAAC;gBAAE,GAAGiB,OAAO;YAAC;QAC/C,EAAE,OAAOK,OAAO;YACd,MAAM,IAAIC,MACR,CAAC,kBAAkB,EAAEG,mBAAmBF,IAAI,CAAC,4BAA4B,EAAEnB,iBAAiB,sBAAsB,EAAEQ,KAAK,EAAE,CAAC,EAC5H;gBAAEY,OAAOH;YAAM;QAEnB;IACF;IAEA,OAAOZ,QAAQP,SAAS,CAACE,iBAAiB,CAACY,QAAQC,MAAM,EAAED,QAAQG,KAAK;AAC1E,EAAC"}
|
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
import { sql } from 'drizzle-orm';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { buildOperatorConstraint } from './buildOperatorConstraint.js';
|
|
4
|
+
const textField = {
|
|
5
|
+
name: 'title',
|
|
6
|
+
type: 'text'
|
|
7
|
+
};
|
|
8
|
+
const numberField = {
|
|
9
|
+
name: 'age',
|
|
10
|
+
type: 'number'
|
|
11
|
+
};
|
|
12
|
+
describe('buildOperatorConstraint', ()=>{
|
|
13
|
+
it('calls the default operator unchanged when no handlers are configured', ()=>{
|
|
14
|
+
const sentinel = sql`sentinel`;
|
|
15
|
+
const containsOperator = vi.fn().mockReturnValue(sentinel);
|
|
16
|
+
const adapter = {
|
|
17
|
+
operatorHandlers: [],
|
|
18
|
+
operators: {
|
|
19
|
+
contains: containsOperator
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
const column = 'col';
|
|
23
|
+
const result = buildOperatorConstraint({
|
|
24
|
+
adapter,
|
|
25
|
+
column,
|
|
26
|
+
field: textField,
|
|
27
|
+
originalOperator: 'contains',
|
|
28
|
+
path: 'title',
|
|
29
|
+
resolvedOperator: 'contains',
|
|
30
|
+
value: 'acido'
|
|
31
|
+
});
|
|
32
|
+
expect(containsOperator).toHaveBeenCalledWith(column, 'acido');
|
|
33
|
+
expect(result).toBe(sentinel);
|
|
34
|
+
});
|
|
35
|
+
it('applies operand-transform handlers in configuration order before the default operator runs', ()=>{
|
|
36
|
+
const calls = [];
|
|
37
|
+
const containsOperator = vi.fn(()=>sql`result`);
|
|
38
|
+
const handlerA = {
|
|
39
|
+
name: 'handler-a',
|
|
40
|
+
operators: [
|
|
41
|
+
'contains'
|
|
42
|
+
],
|
|
43
|
+
transformOperands: ({ column, value })=>{
|
|
44
|
+
calls.push('a');
|
|
45
|
+
return {
|
|
46
|
+
column: `${column}-a`,
|
|
47
|
+
value: `${value}-a`
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const handlerB = {
|
|
52
|
+
name: 'handler-b',
|
|
53
|
+
operators: [
|
|
54
|
+
'contains'
|
|
55
|
+
],
|
|
56
|
+
transformOperands: ({ column, value })=>{
|
|
57
|
+
calls.push('b');
|
|
58
|
+
return {
|
|
59
|
+
column: `${column}-b`,
|
|
60
|
+
value: `${value}-b`
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
const adapter = {
|
|
65
|
+
operatorHandlers: [
|
|
66
|
+
handlerA,
|
|
67
|
+
handlerB
|
|
68
|
+
],
|
|
69
|
+
operators: {
|
|
70
|
+
contains: containsOperator
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
buildOperatorConstraint({
|
|
74
|
+
adapter,
|
|
75
|
+
column: 'base-column',
|
|
76
|
+
field: textField,
|
|
77
|
+
originalOperator: 'contains',
|
|
78
|
+
path: 'title',
|
|
79
|
+
resolvedOperator: 'contains',
|
|
80
|
+
value: 'acido'
|
|
81
|
+
});
|
|
82
|
+
expect(calls).toEqual([
|
|
83
|
+
'a',
|
|
84
|
+
'b'
|
|
85
|
+
]);
|
|
86
|
+
expect(containsOperator).toHaveBeenCalledWith('base-column-a-b', 'acido-a-b');
|
|
87
|
+
});
|
|
88
|
+
it('skips a handler whose operators list excludes the resolved operator', ()=>{
|
|
89
|
+
const transformOperands = vi.fn(({ column, value })=>({
|
|
90
|
+
column,
|
|
91
|
+
value
|
|
92
|
+
}));
|
|
93
|
+
const adapter = {
|
|
94
|
+
operatorHandlers: [
|
|
95
|
+
{
|
|
96
|
+
name: 'like-only',
|
|
97
|
+
operators: [
|
|
98
|
+
'like'
|
|
99
|
+
],
|
|
100
|
+
transformOperands
|
|
101
|
+
}
|
|
102
|
+
],
|
|
103
|
+
operators: {
|
|
104
|
+
contains: vi.fn(()=>sql`result`)
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
buildOperatorConstraint({
|
|
108
|
+
adapter,
|
|
109
|
+
column: 'col',
|
|
110
|
+
field: textField,
|
|
111
|
+
originalOperator: 'contains',
|
|
112
|
+
path: 'title',
|
|
113
|
+
resolvedOperator: 'contains',
|
|
114
|
+
value: 'acido'
|
|
115
|
+
});
|
|
116
|
+
expect(transformOperands).not.toHaveBeenCalled();
|
|
117
|
+
});
|
|
118
|
+
it("skips a handler whose fieldTypes excludes the field's type even when operators matches", ()=>{
|
|
119
|
+
const transformOperands = vi.fn(({ column, value })=>({
|
|
120
|
+
column,
|
|
121
|
+
value
|
|
122
|
+
}));
|
|
123
|
+
const adapter = {
|
|
124
|
+
operatorHandlers: [
|
|
125
|
+
{
|
|
126
|
+
name: 'text-only',
|
|
127
|
+
operators: [
|
|
128
|
+
'contains'
|
|
129
|
+
],
|
|
130
|
+
fieldTypes: [
|
|
131
|
+
'text'
|
|
132
|
+
],
|
|
133
|
+
transformOperands
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
operators: {
|
|
137
|
+
contains: vi.fn(()=>sql`result`)
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
buildOperatorConstraint({
|
|
141
|
+
adapter,
|
|
142
|
+
column: 'col',
|
|
143
|
+
field: numberField,
|
|
144
|
+
originalOperator: 'contains',
|
|
145
|
+
path: 'age',
|
|
146
|
+
resolvedOperator: 'contains',
|
|
147
|
+
value: 5
|
|
148
|
+
});
|
|
149
|
+
expect(transformOperands).not.toHaveBeenCalled();
|
|
150
|
+
});
|
|
151
|
+
it('runs a handler with no fieldTypes for every field type', ()=>{
|
|
152
|
+
const transformOperands = vi.fn(({ column, value })=>({
|
|
153
|
+
column,
|
|
154
|
+
value
|
|
155
|
+
}));
|
|
156
|
+
const adapter = {
|
|
157
|
+
operatorHandlers: [
|
|
158
|
+
{
|
|
159
|
+
name: 'universal',
|
|
160
|
+
operators: [
|
|
161
|
+
'contains'
|
|
162
|
+
],
|
|
163
|
+
transformOperands
|
|
164
|
+
}
|
|
165
|
+
],
|
|
166
|
+
operators: {
|
|
167
|
+
contains: vi.fn(()=>sql`result`)
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
buildOperatorConstraint({
|
|
171
|
+
adapter,
|
|
172
|
+
column: 'col',
|
|
173
|
+
field: numberField,
|
|
174
|
+
originalOperator: 'contains',
|
|
175
|
+
path: 'age',
|
|
176
|
+
resolvedOperator: 'contains',
|
|
177
|
+
value: 5
|
|
178
|
+
});
|
|
179
|
+
expect(transformOperands).toHaveBeenCalled();
|
|
180
|
+
});
|
|
181
|
+
it('gives a single matching replacement handler the operands after every transform has run, and uses its result instead of the default operator', ()=>{
|
|
182
|
+
const containsOperator = vi.fn();
|
|
183
|
+
const sentinel = sql`replacement`;
|
|
184
|
+
const build = vi.fn().mockReturnValue(sentinel);
|
|
185
|
+
const transformOperands = vi.fn(({ column, value })=>({
|
|
186
|
+
column: `${column}-t`,
|
|
187
|
+
value: `${value}-t`
|
|
188
|
+
}));
|
|
189
|
+
const adapter = {
|
|
190
|
+
operatorHandlers: [
|
|
191
|
+
{
|
|
192
|
+
name: 'transform',
|
|
193
|
+
operators: [
|
|
194
|
+
'contains'
|
|
195
|
+
],
|
|
196
|
+
transformOperands
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: 'replace',
|
|
200
|
+
operators: [
|
|
201
|
+
'contains'
|
|
202
|
+
],
|
|
203
|
+
build
|
|
204
|
+
}
|
|
205
|
+
],
|
|
206
|
+
operators: {
|
|
207
|
+
contains: containsOperator
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
const result = buildOperatorConstraint({
|
|
211
|
+
adapter,
|
|
212
|
+
column: 'col',
|
|
213
|
+
field: textField,
|
|
214
|
+
originalOperator: 'contains',
|
|
215
|
+
path: 'title',
|
|
216
|
+
resolvedOperator: 'contains',
|
|
217
|
+
value: 'acido'
|
|
218
|
+
});
|
|
219
|
+
expect(build).toHaveBeenCalledWith(expect.objectContaining({
|
|
220
|
+
column: 'col-t',
|
|
221
|
+
value: 'acido-t'
|
|
222
|
+
}));
|
|
223
|
+
expect(containsOperator).not.toHaveBeenCalled();
|
|
224
|
+
expect(result).toBe(sentinel);
|
|
225
|
+
});
|
|
226
|
+
it('passes originalOperator, resolvedOperator, field, path, and locale to handlers', ()=>{
|
|
227
|
+
let capturedContext;
|
|
228
|
+
const transformOperands = vi.fn((context)=>{
|
|
229
|
+
capturedContext = context;
|
|
230
|
+
return {
|
|
231
|
+
column: context.column,
|
|
232
|
+
value: context.value
|
|
233
|
+
};
|
|
234
|
+
});
|
|
235
|
+
const adapter = {
|
|
236
|
+
operatorHandlers: [
|
|
237
|
+
{
|
|
238
|
+
name: 'observe',
|
|
239
|
+
operators: [
|
|
240
|
+
'like'
|
|
241
|
+
],
|
|
242
|
+
transformOperands
|
|
243
|
+
}
|
|
244
|
+
],
|
|
245
|
+
operators: {
|
|
246
|
+
like: vi.fn(()=>sql`result`)
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
buildOperatorConstraint({
|
|
250
|
+
adapter,
|
|
251
|
+
column: 'col',
|
|
252
|
+
field: textField,
|
|
253
|
+
locale: 'es',
|
|
254
|
+
originalOperator: 'like',
|
|
255
|
+
path: 'title',
|
|
256
|
+
resolvedOperator: 'like',
|
|
257
|
+
value: '%nino%'
|
|
258
|
+
});
|
|
259
|
+
expect(capturedContext).toMatchObject({
|
|
260
|
+
field: textField,
|
|
261
|
+
locale: 'es',
|
|
262
|
+
originalOperator: 'like',
|
|
263
|
+
path: 'title',
|
|
264
|
+
resolvedOperator: 'like'
|
|
265
|
+
});
|
|
266
|
+
});
|
|
267
|
+
it('wraps a handler error with the handler name, path, and resolved operator, retaining the original error as the cause', ()=>{
|
|
268
|
+
const originalError = new Error('boom');
|
|
269
|
+
const transformOperands = vi.fn(()=>{
|
|
270
|
+
throw originalError;
|
|
271
|
+
});
|
|
272
|
+
const adapter = {
|
|
273
|
+
operatorHandlers: [
|
|
274
|
+
{
|
|
275
|
+
name: 'explode',
|
|
276
|
+
operators: [
|
|
277
|
+
'contains'
|
|
278
|
+
],
|
|
279
|
+
transformOperands
|
|
280
|
+
}
|
|
281
|
+
],
|
|
282
|
+
operators: {
|
|
283
|
+
contains: vi.fn()
|
|
284
|
+
}
|
|
285
|
+
};
|
|
286
|
+
let thrown;
|
|
287
|
+
try {
|
|
288
|
+
buildOperatorConstraint({
|
|
289
|
+
adapter,
|
|
290
|
+
column: 'col',
|
|
291
|
+
field: textField,
|
|
292
|
+
originalOperator: 'contains',
|
|
293
|
+
path: 'title',
|
|
294
|
+
resolvedOperator: 'contains',
|
|
295
|
+
value: 'acido'
|
|
296
|
+
});
|
|
297
|
+
} catch (error) {
|
|
298
|
+
thrown = error;
|
|
299
|
+
}
|
|
300
|
+
expect(thrown).toBeInstanceOf(Error);
|
|
301
|
+
const error = thrown;
|
|
302
|
+
expect(error.message).toContain('explode');
|
|
303
|
+
expect(error.message).toContain('title');
|
|
304
|
+
expect(error.message).toContain('contains');
|
|
305
|
+
expect(error.cause).toBe(originalError);
|
|
306
|
+
});
|
|
307
|
+
it('throws a configuration error when a transform handler returns operands missing column or value, before any default operator or replacement runs', ()=>{
|
|
308
|
+
const transformOperands = vi.fn().mockReturnValue({
|
|
309
|
+
column: 'only-column'
|
|
310
|
+
});
|
|
311
|
+
const containsOperator = vi.fn();
|
|
312
|
+
const build = vi.fn();
|
|
313
|
+
const adapter = {
|
|
314
|
+
operatorHandlers: [
|
|
315
|
+
{
|
|
316
|
+
name: 'broken',
|
|
317
|
+
operators: [
|
|
318
|
+
'contains'
|
|
319
|
+
],
|
|
320
|
+
transformOperands
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
name: 'replace',
|
|
324
|
+
operators: [
|
|
325
|
+
'contains'
|
|
326
|
+
],
|
|
327
|
+
build
|
|
328
|
+
}
|
|
329
|
+
],
|
|
330
|
+
operators: {
|
|
331
|
+
contains: containsOperator
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
expect(()=>buildOperatorConstraint({
|
|
335
|
+
adapter,
|
|
336
|
+
column: 'col',
|
|
337
|
+
field: textField,
|
|
338
|
+
originalOperator: 'contains',
|
|
339
|
+
path: 'title',
|
|
340
|
+
resolvedOperator: 'contains',
|
|
341
|
+
value: 'acido'
|
|
342
|
+
})).toThrow(/broken/);
|
|
343
|
+
expect(containsOperator).not.toHaveBeenCalled();
|
|
344
|
+
expect(build).not.toHaveBeenCalled();
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
//# sourceMappingURL=buildOperatorConstraint.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/queries/buildOperatorConstraint.spec.ts"],"sourcesContent":["import type { Column } from 'drizzle-orm'\nimport type { FlattenedField } from 'payload'\n\nimport { sql } from 'drizzle-orm'\nimport { describe, expect, it, vi } from 'vitest'\n\nimport type { DrizzleAdapter, DrizzleOperandTransformHandler } from '../types.js'\n\nimport { buildOperatorConstraint } from './buildOperatorConstraint.js'\n\nconst textField = { name: 'title', type: 'text' } as unknown as FlattenedField\nconst numberField = { name: 'age', type: 'number' } as unknown as FlattenedField\n\ndescribe('buildOperatorConstraint', () => {\n it('calls the default operator unchanged when no handlers are configured', () => {\n const sentinel = sql`sentinel`\n const containsOperator = vi.fn().mockReturnValue(sentinel)\n const adapter = {\n operatorHandlers: [],\n operators: { contains: containsOperator },\n } as unknown as DrizzleAdapter\n const column = 'col' as unknown as Column\n\n const result = buildOperatorConstraint({\n adapter,\n column,\n field: textField,\n originalOperator: 'contains',\n path: 'title',\n resolvedOperator: 'contains',\n value: 'acido',\n })\n\n expect(containsOperator).toHaveBeenCalledWith(column, 'acido')\n expect(result).toBe(sentinel)\n })\n\n it('applies operand-transform handlers in configuration order before the default operator runs', () => {\n const calls: string[] = []\n const containsOperator = vi.fn(() => sql`result`)\n\n const handlerA: DrizzleOperandTransformHandler = {\n name: 'handler-a',\n operators: ['contains'],\n transformOperands: ({ column, value }) => {\n calls.push('a')\n return { column: `${column}-a` as unknown as Column, value: `${value}-a` }\n },\n }\n const handlerB: DrizzleOperandTransformHandler = {\n name: 'handler-b',\n operators: ['contains'],\n transformOperands: ({ column, value }) => {\n calls.push('b')\n return { column: `${column}-b` as unknown as Column, value: `${value}-b` }\n },\n }\n\n const adapter = {\n operatorHandlers: [handlerA, handlerB],\n operators: { contains: containsOperator },\n } as unknown as DrizzleAdapter\n\n buildOperatorConstraint({\n adapter,\n column: 'base-column' as unknown as Column,\n field: textField,\n originalOperator: 'contains',\n path: 'title',\n resolvedOperator: 'contains',\n value: 'acido',\n })\n\n expect(calls).toEqual(['a', 'b'])\n expect(containsOperator).toHaveBeenCalledWith('base-column-a-b', 'acido-a-b')\n })\n\n it('skips a handler whose operators list excludes the resolved operator', () => {\n const transformOperands = vi.fn(({ column, value }) => ({ column, value }))\n const adapter = {\n operatorHandlers: [{ name: 'like-only', operators: ['like'], transformOperands }],\n operators: { contains: vi.fn(() => sql`result`) },\n } as unknown as DrizzleAdapter\n\n buildOperatorConstraint({\n adapter,\n column: 'col' as unknown as Column,\n field: textField,\n originalOperator: 'contains',\n path: 'title',\n resolvedOperator: 'contains',\n value: 'acido',\n })\n\n expect(transformOperands).not.toHaveBeenCalled()\n })\n\n it(\"skips a handler whose fieldTypes excludes the field's type even when operators matches\", () => {\n const transformOperands = vi.fn(({ column, value }) => ({ column, value }))\n const adapter = {\n operatorHandlers: [\n { name: 'text-only', operators: ['contains'], fieldTypes: ['text'], transformOperands },\n ],\n operators: { contains: vi.fn(() => sql`result`) },\n } as unknown as DrizzleAdapter\n\n buildOperatorConstraint({\n adapter,\n column: 'col' as unknown as Column,\n field: numberField,\n originalOperator: 'contains',\n path: 'age',\n resolvedOperator: 'contains',\n value: 5,\n })\n\n expect(transformOperands).not.toHaveBeenCalled()\n })\n\n it('runs a handler with no fieldTypes for every field type', () => {\n const transformOperands = vi.fn(({ column, value }) => ({ column, value }))\n const adapter = {\n operatorHandlers: [{ name: 'universal', operators: ['contains'], transformOperands }],\n operators: { contains: vi.fn(() => sql`result`) },\n } as unknown as DrizzleAdapter\n\n buildOperatorConstraint({\n adapter,\n column: 'col' as unknown as Column,\n field: numberField,\n originalOperator: 'contains',\n path: 'age',\n resolvedOperator: 'contains',\n value: 5,\n })\n\n expect(transformOperands).toHaveBeenCalled()\n })\n\n it('gives a single matching replacement handler the operands after every transform has run, and uses its result instead of the default operator', () => {\n const containsOperator = vi.fn()\n const sentinel = sql`replacement`\n const build = vi.fn().mockReturnValue(sentinel)\n const transformOperands = vi.fn(({ column, value }) => ({\n column: `${column}-t` as unknown as Column,\n value: `${value}-t`,\n }))\n\n const adapter = {\n operatorHandlers: [\n { name: 'transform', operators: ['contains'], transformOperands },\n { name: 'replace', operators: ['contains'], build },\n ],\n operators: { contains: containsOperator },\n } as unknown as DrizzleAdapter\n\n const result = buildOperatorConstraint({\n adapter,\n column: 'col' as unknown as Column,\n field: textField,\n originalOperator: 'contains',\n path: 'title',\n resolvedOperator: 'contains',\n value: 'acido',\n })\n\n expect(build).toHaveBeenCalledWith(\n expect.objectContaining({ column: 'col-t', value: 'acido-t' }),\n )\n expect(containsOperator).not.toHaveBeenCalled()\n expect(result).toBe(sentinel)\n })\n\n it('passes originalOperator, resolvedOperator, field, path, and locale to handlers', () => {\n let capturedContext: any\n const transformOperands = vi.fn((context) => {\n capturedContext = context\n return { column: context.column, value: context.value }\n })\n\n const adapter = {\n operatorHandlers: [{ name: 'observe', operators: ['like'], transformOperands }],\n operators: { like: vi.fn(() => sql`result`) },\n } as unknown as DrizzleAdapter\n\n buildOperatorConstraint({\n adapter,\n column: 'col' as unknown as Column,\n field: textField,\n locale: 'es',\n originalOperator: 'like',\n path: 'title',\n resolvedOperator: 'like',\n value: '%nino%',\n })\n\n expect(capturedContext).toMatchObject({\n field: textField,\n locale: 'es',\n originalOperator: 'like',\n path: 'title',\n resolvedOperator: 'like',\n })\n })\n\n it('wraps a handler error with the handler name, path, and resolved operator, retaining the original error as the cause', () => {\n const originalError = new Error('boom')\n const transformOperands = vi.fn(() => {\n throw originalError\n })\n\n const adapter = {\n operatorHandlers: [{ name: 'explode', operators: ['contains'], transformOperands }],\n operators: { contains: vi.fn() },\n } as unknown as DrizzleAdapter\n\n let thrown: unknown\n try {\n buildOperatorConstraint({\n adapter,\n column: 'col' as unknown as Column,\n field: textField,\n originalOperator: 'contains',\n path: 'title',\n resolvedOperator: 'contains',\n value: 'acido',\n })\n } catch (error) {\n thrown = error\n }\n\n expect(thrown).toBeInstanceOf(Error)\n const error = thrown as Error\n expect(error.message).toContain('explode')\n expect(error.message).toContain('title')\n expect(error.message).toContain('contains')\n expect(error.cause).toBe(originalError)\n })\n\n it('throws a configuration error when a transform handler returns operands missing column or value, before any default operator or replacement runs', () => {\n const transformOperands = vi.fn().mockReturnValue({ column: 'only-column' })\n const containsOperator = vi.fn()\n const build = vi.fn()\n\n const adapter = {\n operatorHandlers: [\n { name: 'broken', operators: ['contains'], transformOperands },\n { name: 'replace', operators: ['contains'], build },\n ],\n operators: { contains: containsOperator },\n } as unknown as DrizzleAdapter\n\n expect(() =>\n buildOperatorConstraint({\n adapter,\n column: 'col' as unknown as Column,\n field: textField,\n originalOperator: 'contains',\n path: 'title',\n resolvedOperator: 'contains',\n value: 'acido',\n }),\n ).toThrow(/broken/)\n\n expect(containsOperator).not.toHaveBeenCalled()\n expect(build).not.toHaveBeenCalled()\n })\n})\n"],"names":["sql","describe","expect","it","vi","buildOperatorConstraint","textField","name","type","numberField","sentinel","containsOperator","fn","mockReturnValue","adapter","operatorHandlers","operators","contains","column","result","field","originalOperator","path","resolvedOperator","value","toHaveBeenCalledWith","toBe","calls","handlerA","transformOperands","push","handlerB","toEqual","not","toHaveBeenCalled","fieldTypes","build","objectContaining","capturedContext","context","like","locale","toMatchObject","originalError","Error","thrown","error","toBeInstanceOf","message","toContain","cause","toThrow"],"mappings":"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"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { type Column, type SQL } from 'drizzle-orm';
|
|
2
|
-
type OperatorKeys = 'and' | 'contains' | 'equals' | 'exists' | 'greater_than' | 'greater_than_equal' | 'in' | 'isNull' | 'less_than' | 'less_than_equal' | 'like' | 'not_equals' | 'not_in' | 'not_like' | 'or';
|
|
3
|
-
|
|
2
|
+
export type OperatorKeys = 'and' | 'contains' | 'equals' | 'exists' | 'greater_than' | 'greater_than_equal' | 'in' | 'isNull' | 'less_than' | 'less_than_equal' | 'like' | 'not_equals' | 'not_in' | 'not_like' | 'or';
|
|
3
|
+
/**
|
|
4
|
+
* The subset of operator keys that represent an actual user-facing comparison operator,
|
|
5
|
+
* excluding the `and`/`or` boolean combinators.
|
|
6
|
+
*/
|
|
7
|
+
export type DrizzleResolvedOperator = Exclude<OperatorKeys, 'and' | 'or'>;
|
|
8
|
+
export type Operators = Record<OperatorKeys, (column: Column | SQL, value: unknown) => SQL>;
|
|
4
9
|
export declare const operatorMap: Operators;
|
|
5
|
-
export {};
|
|
6
10
|
//# sourceMappingURL=operatorMap.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"operatorMap.d.ts","sourceRoot":"","sources":["../../src/queries/operatorMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAcX,KAAK,GAAG,EACT,MAAM,aAAa,CAAA;AAEpB,
|
|
1
|
+
{"version":3,"file":"operatorMap.d.ts","sourceRoot":"","sources":["../../src/queries/operatorMap.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAcX,KAAK,GAAG,EACT,MAAM,aAAa,CAAA;AAEpB,MAAM,MAAM,YAAY,GACpB,KAAK,GACL,UAAU,GACV,QAAQ,GACR,QAAQ,GACR,cAAc,GACd,oBAAoB,GACpB,IAAI,GACJ,QAAQ,GACR,WAAW,GACX,iBAAiB,GACjB,MAAM,GACN,YAAY,GACZ,QAAQ,GACR,UAAU,GACV,IAAI,CAAA;AAER;;;GAGG;AACH,MAAM,MAAM,uBAAuB,GAAG,OAAO,CAAC,YAAY,EAAE,KAAK,GAAG,IAAI,CAAC,CAAA;AAEzE,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,EAAE,KAAK,EAAE,OAAO,KAAK,GAAG,CAAC,CAAA;AAE3F,eAAO,MAAM,WAAW,EAAE,SAkBzB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/queries/operatorMap.ts"],"sourcesContent":["import {\n and,\n type Column,\n eq,\n gt,\n gte,\n ilike,\n inArray,\n isNotNull,\n isNull,\n lt,\n lte,\n ne,\n notIlike,\n notInArray,\n or,\n type SQL,\n} from 'drizzle-orm'\n\
|
|
1
|
+
{"version":3,"sources":["../../src/queries/operatorMap.ts"],"sourcesContent":["import {\n and,\n type Column,\n eq,\n gt,\n gte,\n ilike,\n inArray,\n isNotNull,\n isNull,\n lt,\n lte,\n ne,\n notIlike,\n notInArray,\n or,\n type SQL,\n} from 'drizzle-orm'\n\nexport type OperatorKeys =\n | 'and'\n | 'contains'\n | 'equals'\n | 'exists'\n | 'greater_than'\n | 'greater_than_equal'\n | 'in'\n | 'isNull'\n | 'less_than'\n | 'less_than_equal'\n | 'like'\n | 'not_equals'\n | 'not_in'\n | 'not_like'\n | 'or'\n\n/**\n * The subset of operator keys that represent an actual user-facing comparison operator,\n * excluding the `and`/`or` boolean combinators.\n */\nexport type DrizzleResolvedOperator = Exclude<OperatorKeys, 'and' | 'or'>\n\nexport type Operators = Record<OperatorKeys, (column: Column | SQL, value: unknown) => SQL>\n\nexport const operatorMap: Operators = {\n and,\n contains: ilike,\n equals: eq,\n exists: isNotNull,\n greater_than: gt,\n greater_than_equal: gte,\n in: inArray,\n isNull, // handles exists: false\n less_than: lt,\n less_than_equal: lte,\n like: ilike,\n not_equals: ne,\n not_like: notIlike,\n // TODO: support this\n // all: all,\n not_in: notInArray,\n or,\n}\n"],"names":["and","eq","gt","gte","ilike","inArray","isNotNull","isNull","lt","lte","ne","notIlike","notInArray","or","operatorMap","contains","equals","exists","greater_than","greater_than_equal","in","less_than","less_than_equal","like","not_equals","not_like","not_in"],"mappings":"AAAA,SACEA,GAAG,EAEHC,EAAE,EACFC,EAAE,EACFC,GAAG,EACHC,KAAK,EACLC,OAAO,EACPC,SAAS,EACTC,MAAM,EACNC,EAAE,EACFC,GAAG,EACHC,EAAE,EACFC,QAAQ,EACRC,UAAU,EACVC,EAAE,QAEG,cAAa;AA2BpB,OAAO,MAAMC,cAAyB;IACpCd;IACAe,UAAUX;IACVY,QAAQf;IACRgB,QAAQX;IACRY,cAAchB;IACdiB,oBAAoBhB;IACpBiB,IAAIf;IACJE;IACAc,WAAWb;IACXc,iBAAiBb;IACjBc,MAAMnB;IACNoB,YAAYd;IACZe,UAAUd;IACV,qBAAqB;IACrB,YAAY;IACZe,QAAQd;IACRC;AACF,EAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseParams.d.ts","sourceRoot":"","sources":["../../src/queries/parseParams.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAY,IAAI,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAOpE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;
|
|
1
|
+
{"version":3,"file":"parseParams.d.ts","sourceRoot":"","sources":["../../src/queries/parseParams.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAY,IAAI,EAAE,KAAK,EAAE,MAAM,SAAS,CAAA;AAOpE,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAA;AAY5D,MAAM,MAAM,YAAY,GAAG;IAAE,OAAO,CAAC,EAAE,GAAG,CAAC;IAAC,IAAI,EAAE,IAAI,CAAA;CAAE,CAAA;AAExD,KAAK,IAAI,GAAG;IACV,OAAO,EAAE,cAAc,CAAA;IACvB,UAAU,CAAC,EAAE,KAAK,CAAA;IAClB,OAAO,EAAE,YAAY,CAAA;IACrB,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,KAAK,EAAE,qBAAqB,CAAA;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,iBAAiB,EAAE,OAAO,CAAA;IAC1B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAC3C,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,KAAK,CAAA;CACb,CAAA;AAED,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,UAAU,EACV,OAAO,EACP,MAAM,EACN,KAAK,EACL,MAAM,EACN,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,KAAK,GACN,EAAE,IAAI,GAAG,GAAG,CAweZ"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { and, getTableName, isNotNull, isNull,
|
|
1
|
+
import { and, getTableName, isNotNull, isNull, notInArray, or, sql } from 'drizzle-orm';
|
|
2
2
|
import { PgUUID } from 'drizzle-orm/pg-core';
|
|
3
3
|
import { APIError, QueryError } from 'payload';
|
|
4
4
|
import { validOperatorSet } from 'payload/shared';
|
|
@@ -7,6 +7,7 @@ import { getNameFromDrizzleTable } from '../utilities/getNameFromDrizzleTable.js
|
|
|
7
7
|
import { isValidStringID } from '../utilities/isValidStringID.js';
|
|
8
8
|
import { DistinctSymbol } from '../utilities/rawConstraint.js';
|
|
9
9
|
import { buildAndOrConditions } from './buildAndOrConditions.js';
|
|
10
|
+
import { buildOperatorConstraint } from './buildOperatorConstraint.js';
|
|
10
11
|
import { getTableColumnFromPath } from './getTableColumnFromPath.js';
|
|
11
12
|
import { sanitizeQueryValue } from './sanitizeQueryValue.js';
|
|
12
13
|
export function parseParams({ adapter, aliasTable, context, fields, joins, locale, parentIsLocalized, selectFields, selectLocale, tableName, where }) {
|
|
@@ -49,6 +50,7 @@ export function parseParams({ adapter, aliasTable, context, fields, joins, local
|
|
|
49
50
|
for (let operator of Object.keys(pathOperators)){
|
|
50
51
|
if (validOperatorSet.has(operator)) {
|
|
51
52
|
const val = where[relationOrPath][operator];
|
|
53
|
+
const originalOperator = operator;
|
|
52
54
|
const { columnName, columns, constraints: queryConstraints, field, getNotNullColumnByValue, pathSegments, rawColumn, table } = getTableColumnFromPath({
|
|
53
55
|
adapter,
|
|
54
56
|
aliasTable,
|
|
@@ -181,7 +183,16 @@ export function parseParams({ adapter, aliasTable, context, fields, joins, local
|
|
|
181
183
|
operator = 'equals';
|
|
182
184
|
}
|
|
183
185
|
if (operator === 'like') {
|
|
184
|
-
constraints.push(and(...val.split(' ').map((word)=>
|
|
186
|
+
constraints.push(and(...val.split(' ').map((word)=>buildOperatorConstraint({
|
|
187
|
+
adapter,
|
|
188
|
+
column: table[columnName],
|
|
189
|
+
field,
|
|
190
|
+
locale,
|
|
191
|
+
originalOperator,
|
|
192
|
+
path: relationOrPath,
|
|
193
|
+
resolvedOperator: 'like',
|
|
194
|
+
value: `%${word}%`
|
|
195
|
+
}))));
|
|
185
196
|
break;
|
|
186
197
|
}
|
|
187
198
|
const sanitizedQueryValue = sanitizeQueryValue({
|
|
@@ -219,11 +230,29 @@ export function parseParams({ adapter, aliasTable, context, fields, joins, local
|
|
|
219
230
|
].includes(operator)) {
|
|
220
231
|
wrapOperator = and;
|
|
221
232
|
}
|
|
222
|
-
constraints.push(wrapOperator(...queryColumns.map(({ rawColumn, value })=>
|
|
233
|
+
constraints.push(wrapOperator(...queryColumns.map(({ rawColumn, value })=>buildOperatorConstraint({
|
|
234
|
+
adapter,
|
|
235
|
+
column: rawColumn,
|
|
236
|
+
field,
|
|
237
|
+
locale,
|
|
238
|
+
originalOperator,
|
|
239
|
+
path: relationOrPath,
|
|
240
|
+
resolvedOperator: queryOperator,
|
|
241
|
+
value
|
|
242
|
+
}))));
|
|
223
243
|
break;
|
|
224
244
|
}
|
|
225
245
|
if (queryOperator === 'not_equals' && queryValue !== null) {
|
|
226
|
-
constraints.push(or(isNull(resolvedColumn),
|
|
246
|
+
constraints.push(or(isNull(resolvedColumn), buildOperatorConstraint({
|
|
247
|
+
adapter,
|
|
248
|
+
column: resolvedColumn,
|
|
249
|
+
field,
|
|
250
|
+
locale,
|
|
251
|
+
originalOperator,
|
|
252
|
+
path: relationOrPath,
|
|
253
|
+
resolvedOperator: 'not_equals',
|
|
254
|
+
value: queryValue
|
|
255
|
+
})));
|
|
227
256
|
break;
|
|
228
257
|
}
|
|
229
258
|
if ((field.type === 'relationship' || field.type === 'upload') && Array.isArray(queryValue) && queryOperator === 'not_in') {
|
|
@@ -287,7 +316,16 @@ export function parseParams({ adapter, aliasTable, context, fields, joins, local
|
|
|
287
316
|
'text'
|
|
288
317
|
].includes(field.type)) {
|
|
289
318
|
// Create OR conditions for each value in the array
|
|
290
|
-
orConditions.push(...queryValue.map((val)=>
|
|
319
|
+
orConditions.push(...queryValue.map((val)=>buildOperatorConstraint({
|
|
320
|
+
adapter,
|
|
321
|
+
column: resolvedColumn,
|
|
322
|
+
field,
|
|
323
|
+
locale,
|
|
324
|
+
originalOperator,
|
|
325
|
+
path: relationOrPath,
|
|
326
|
+
resolvedOperator: queryOperator,
|
|
327
|
+
value: val
|
|
328
|
+
})));
|
|
291
329
|
// Set constraint to combine all OR conditions
|
|
292
330
|
const constraint = orConditions.length > 0 ? or(...orConditions) : undefined;
|
|
293
331
|
if (constraint) {
|
|
@@ -295,7 +333,16 @@ export function parseParams({ adapter, aliasTable, context, fields, joins, local
|
|
|
295
333
|
}
|
|
296
334
|
break;
|
|
297
335
|
}
|
|
298
|
-
let constraint =
|
|
336
|
+
let constraint = buildOperatorConstraint({
|
|
337
|
+
adapter,
|
|
338
|
+
column: resolvedColumn,
|
|
339
|
+
field,
|
|
340
|
+
locale,
|
|
341
|
+
originalOperator,
|
|
342
|
+
path: relationOrPath,
|
|
343
|
+
resolvedOperator: queryOperator,
|
|
344
|
+
value: resolvedQueryValue
|
|
345
|
+
});
|
|
299
346
|
if (adapter.limitedBoundParameters && (operator === 'in' || operator === 'not_in') && relationOrPath === 'id' && Array.isArray(queryValue)) {
|
|
300
347
|
let isInvalid = false;
|
|
301
348
|
for (const val of queryValue){
|