@payloadcms/drizzle 3.91.0 → 3.92.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6,7 +6,9 @@ type BuildPolymorphicJoinQueryArgs = {
6
6
  currentTableName: string;
7
7
  field: FlattenedJoinField;
8
8
  limit: number;
9
+ locale?: string;
9
10
  page?: number;
11
+ pageSize?: number;
10
12
  path: string;
11
13
  shouldCount: boolean;
12
14
  sort?: string | string[];
@@ -25,13 +27,13 @@ type PolymorphicJoinQuery = {
25
27
  *
26
28
  * `field.collection` must contain at least one configured collection. Each mapped table must have
27
29
  * an `id` column and the column named by `field.on`. The supplied `limit` is used as-is; callers can
28
- * include an extra look-ahead row when they calculate pagination.
30
+ * include an extra look-ahead row and supply the original `pageSize` for offset calculation.
29
31
  *
30
32
  * @returns The stable projection name, the document projection, and the count projection when
31
33
  * `shouldCount` is true.
32
34
  * @throws If the join definition, target collection, mapped table, required columns, or sort shape
33
35
  * cannot be represented by the polymorphic query.
34
36
  */
35
- export declare const buildPolymorphicJoinQuery: ({ adapter, currentTableName, field, limit, page, path, shouldCount, sort, where, }: BuildPolymorphicJoinQueryArgs) => PolymorphicJoinQuery;
37
+ export declare const buildPolymorphicJoinQuery: ({ adapter, currentTableName, field, limit, locale, page, pageSize, path, shouldCount, sort, where, }: BuildPolymorphicJoinQueryArgs) => PolymorphicJoinQuery;
36
38
  export {};
37
39
  //# sourceMappingURL=buildPolymorphicJoinQuery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"buildPolymorphicJoinQuery.d.ts","sourceRoot":"","sources":["../../src/find/buildPolymorphicJoinQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAKtC,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AAG7D,OAAO,KAAK,EAAE,cAAc,EAAgB,MAAM,aAAa,CAAA;AAO/D,KAAK,6BAA6B,GAAG;IACnC,OAAO,EAAE,cAAc,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;IACxB,KAAK,EAAE,kBAAkB,CAAA;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACxB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd,CAAA;AAED,KAAK,oBAAoB,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACnB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAA;CACvB,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,yBAAyB,uFAUnC,6BAA6B,KAAG,oBA4HlC,CAAA"}
1
+ {"version":3,"file":"buildPolymorphicJoinQuery.d.ts","sourceRoot":"","sources":["../../src/find/buildPolymorphicJoinQuery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAKtC,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AAG7D,OAAO,KAAK,EAAE,cAAc,EAAgB,MAAM,aAAa,CAAA;AAO/D,KAAK,6BAA6B,GAAG;IACnC,OAAO,EAAE,cAAc,CAAA;IACvB,gBAAgB,EAAE,MAAM,CAAA;IACxB,KAAK,EAAE,kBAAkB,CAAA;IACzB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAA;IACxB,KAAK,CAAC,EAAE,KAAK,CAAA;CACd,CAAA;AAED,KAAK,oBAAoB,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC,OAAO,CAAA;IACnB,SAAS,EAAE,GAAG,CAAC,OAAO,CAAA;CACvB,CAAA;AAED;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,yBAAyB,yGAYnC,6BAA6B,KAAG,oBAkJlC,CAAA"}
@@ -1,4 +1,4 @@
1
- import { asc, count, desc, eq, sql } from 'drizzle-orm';
1
+ import { and, asc, count, desc, eq, getTableName, sql } from 'drizzle-orm';
2
2
  import toSnakeCase from 'to-snake-case';
3
3
  import { jsonAggBuildObject } from '../utilities/json.js';
4
4
  import { buildPolymorphicJoinWhere } from './buildPolymorphicJoinWhere.js';
@@ -11,13 +11,13 @@ import { createPolymorphicJoinWherePlan } from './createPolymorphicJoinWherePlan
11
11
  *
12
12
  * `field.collection` must contain at least one configured collection. Each mapped table must have
13
13
  * an `id` column and the column named by `field.on`. The supplied `limit` is used as-is; callers can
14
- * include an extra look-ahead row when they calculate pagination.
14
+ * include an extra look-ahead row and supply the original `pageSize` for offset calculation.
15
15
  *
16
16
  * @returns The stable projection name, the document projection, and the count projection when
17
17
  * `shouldCount` is true.
18
18
  * @throws If the join definition, target collection, mapped table, required columns, or sort shape
19
19
  * cannot be represented by the polymorphic query.
20
- */ export const buildPolymorphicJoinQuery = ({ adapter, currentTableName, field, limit, page, path, shouldCount, sort, where })=>{
20
+ */ export const buildPolymorphicJoinQuery = ({ adapter, currentTableName, field, limit, locale, page, pageSize = limit, path, shouldCount, sort, where })=>{
21
21
  if (!Array.isArray(field.collection)) {
22
22
  throw new Error('A polymorphic join requires a collection array');
23
23
  }
@@ -79,7 +79,18 @@ import { createPolymorphicJoinWherePlan } from './createPolymorphicJoinWherePlan
79
79
  where,
80
80
  wherePlan
81
81
  }) : undefined;
82
- let collectionQuery = db.select(selectFields).from(table).$dynamic();
82
+ const hasLocalizedWhere = [
83
+ ...wherePlan.values()
84
+ ].some((pathPlan)=>{
85
+ const collectionField = pathPlan.fieldsByCollection.get(collection);
86
+ return collectionField?.type === 'scalar' && collectionField.isLocalized;
87
+ });
88
+ const shouldDeduplicate = hasLocalizedWhere && (!locale || locale === 'all');
89
+ let collectionQuery = (shouldDeduplicate ? db.selectDistinct(selectFields) : db.select(selectFields)).from(table).$dynamic();
90
+ if (hasLocalizedWhere) {
91
+ const localesTable = adapter.tables[`${getTableName(table)}${adapter.localesSuffix}`];
92
+ collectionQuery = collectionQuery.leftJoin(localesTable, and(eq(table['id'], localesTable._parentID), locale && locale !== 'all' ? eq(localesTable._locale, locale) : undefined));
93
+ }
83
94
  if (collectionWhere) {
84
95
  collectionQuery = collectionQuery.where(collectionWhere);
85
96
  }
@@ -101,7 +112,7 @@ import { createPolymorphicJoinWherePlan } from './createPolymorphicJoinWherePlan
101
112
  limitOffsetSQL = sql` LIMIT ${limit}`;
102
113
  }
103
114
  if (page && limit !== 0) {
104
- const offset = (page - 1) * limit;
115
+ const offset = (page - 1) * pageSize;
105
116
  if (offset > 0) {
106
117
  limitOffsetSQL = sql`${limitOffsetSQL} OFFSET ${offset}`;
107
118
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/find/buildPolymorphicJoinQuery.ts"],"sourcesContent":["import type { SQL } from 'drizzle-orm'\nimport type { LibSQLDatabase } from 'drizzle-orm/libsql'\nimport type { SQLiteSelect } from 'drizzle-orm/sqlite-core'\n\nimport { asc, count, desc, eq, sql } from 'drizzle-orm'\nimport { type FlattenedJoinField, type Where } from 'payload'\nimport toSnakeCase from 'to-snake-case'\n\nimport type { DrizzleAdapter, GenericTable } from '../types.js'\nimport type { PolymorphicJoinWherePlan } from './createPolymorphicJoinWherePlan.js'\n\nimport { jsonAggBuildObject } from '../utilities/json.js'\nimport { buildPolymorphicJoinWhere } from './buildPolymorphicJoinWhere.js'\nimport { createPolymorphicJoinWherePlan } from './createPolymorphicJoinWherePlan.js'\n\ntype BuildPolymorphicJoinQueryArgs = {\n adapter: DrizzleAdapter\n currentTableName: string\n field: FlattenedJoinField\n limit: number\n page?: number\n path: string\n shouldCount: boolean\n sort?: string | string[]\n where?: Where\n}\n\ntype PolymorphicJoinQuery = {\n columnName: string\n count?: SQL.Aliased\n documents: SQL.Aliased\n}\n\n/**\n * Builds the correlated document and optional count projections for a join that targets multiple\n * collections. Every collection branch exposes the same `id`, parent, `relationTo`, and sort\n * columns before the branches are combined. A missing sort field resolves to SQL NULL so targets\n * with different schemas can still share one ordered union.\n *\n * `field.collection` must contain at least one configured collection. Each mapped table must have\n * an `id` column and the column named by `field.on`. The supplied `limit` is used as-is; callers can\n * include an extra look-ahead row when they calculate pagination.\n *\n * @returns The stable projection name, the document projection, and the count projection when\n * `shouldCount` is true.\n * @throws If the join definition, target collection, mapped table, required columns, or sort shape\n * cannot be represented by the polymorphic query.\n */\nexport const buildPolymorphicJoinQuery = ({\n adapter,\n currentTableName,\n field,\n limit,\n page,\n path,\n shouldCount,\n sort,\n where,\n}: BuildPolymorphicJoinQueryArgs): PolymorphicJoinQuery => {\n if (!Array.isArray(field.collection)) {\n throw new Error('A polymorphic join requires a collection array')\n }\n\n if (field.collection.length === 0) {\n throw new Error('A polymorphic join requires at least one collection')\n }\n\n if (Array.isArray(sort)) {\n throw new Error('Polymorphic joins do not support multiple sort fields')\n }\n\n const collections = field.collection\n const columnName = `${path.replaceAll('.', '_')}${field.name}`\n const db = adapter.drizzle as LibSQLDatabase\n const onPath = field.on.split('.').join('_')\n const collectionTables = collections.map((collection) => {\n if (!adapter.payload.collections[collection]) {\n throw new Error(`Unknown polymorphic join collection \"${collection}\"`)\n }\n\n const tableName = adapter.tableNameMap.get(toSnakeCase(collection))\n const table = tableName ? (adapter.tables[tableName] as GenericTable | undefined) : undefined\n\n if (!table) {\n throw new Error(`Polymorphic join collection \"${collection}\" has no database table`)\n }\n\n if (!table['id']) {\n throw new Error(`Polymorphic join collection \"${collection}\" has no \"id\" column`)\n }\n\n if (!table[onPath]) {\n throw new Error(`Polymorphic join collection \"${collection}\" has no \"${onPath}\" column`)\n }\n\n return { collection, table }\n })\n const sortField = getSortField({ adapter, collections, sort })\n const sortOrder = sortField.startsWith('-') ? desc : asc\n const sortPath = sortField.replace('-', '').split('.').join('_')\n const wherePlan: PolymorphicJoinWherePlan = where\n ? createPolymorphicJoinWherePlan({ adapter, collections, where })\n : new Map()\n let unionQuery: null | SQLiteSelect = null\n\n for (const { collection, table } of collectionTables) {\n const sortColumn = table[sortPath]\n const selectFields = {\n id: table['id'],\n parent: sql`${table[onPath]}`.as(onPath),\n relationTo: sql`${collection}`.as('relationTo'),\n sortPath: sql`${sortColumn ?? null}`.as('sortPath'),\n }\n const collectionWhere =\n where && Object.keys(where).length > 0\n ? buildPolymorphicJoinWhere({\n adapter,\n collection,\n table,\n where,\n wherePlan,\n })\n : undefined\n let collectionQuery = db.select(selectFields).from(table).$dynamic()\n\n if (collectionWhere) {\n collectionQuery = collectionQuery.where(collectionWhere)\n }\n\n if (unionQuery === null) {\n unionQuery = collectionQuery as unknown as SQLiteSelect\n } else {\n unionQuery = unionQuery.unionAll(collectionQuery)\n }\n }\n\n const subQueryAlias = `${columnName}_subquery`\n const parentConstraint = eq(\n sql.raw(`\"${currentTableName}\".\"id\"`),\n sql.raw(`\"${subQueryAlias}\".\"${onPath}\"`),\n )\n const countExpression = shouldCount\n ? sql`${db\n .select({ count: count() })\n .from(sql`${unionQuery.as(subQueryAlias)}`)\n .where(parentConstraint)}`.as(`${columnName}_count`)\n : undefined\n\n unionQuery = unionQuery.orderBy(sortOrder(sql`\"sortPath\"`))\n\n const sortedUnionAlias = `${columnName}_sorted`\n let limitOffsetSQL = sql.empty()\n\n if (limit) {\n limitOffsetSQL = sql` LIMIT ${limit}`\n }\n\n if (page && limit !== 0) {\n const offset = (page - 1) * limit\n\n if (offset > 0) {\n limitOffsetSQL = sql`${limitOffsetSQL} OFFSET ${offset}`\n }\n }\n\n const parentWhere = sql.raw(`\"${sortedUnionAlias}\".\"${onPath}\" = \"${currentTableName}\".\"id\"`)\n const documents = sql`(\n SELECT ${jsonAggBuildObject(adapter, {\n id: sql.raw(`\"${subQueryAlias}\".\"id\"`),\n relationTo: sql.raw(`\"${subQueryAlias}\".\"relationTo\"`),\n })}\n FROM (\n SELECT * FROM ${sql`${unionQuery.as(sortedUnionAlias)}`}\n WHERE ${parentWhere}${limitOffsetSQL}\n ) AS ${sql.raw(`\"${subQueryAlias}\"`)}\n )`.as(columnName)\n\n return {\n columnName,\n count: countExpression,\n documents,\n }\n}\n\nconst getSortField = ({\n adapter,\n collections,\n sort,\n}: {\n adapter: DrizzleAdapter\n collections: string[]\n sort?: string\n}): string => {\n if (sort) {\n return sort\n }\n\n const hasCreatedAt = collections.some((collection) =>\n adapter.payload.collections[collection].config.fields.some(\n (field) => field.type === 'date' && field.name === 'createdAt',\n ),\n )\n\n return hasCreatedAt ? '-createdAt' : 'id'\n}\n"],"names":["asc","count","desc","eq","sql","toSnakeCase","jsonAggBuildObject","buildPolymorphicJoinWhere","createPolymorphicJoinWherePlan","buildPolymorphicJoinQuery","adapter","currentTableName","field","limit","page","path","shouldCount","sort","where","Array","isArray","collection","Error","length","collections","columnName","replaceAll","name","db","drizzle","onPath","on","split","join","collectionTables","map","payload","tableName","tableNameMap","get","table","tables","undefined","sortField","getSortField","sortOrder","startsWith","sortPath","replace","wherePlan","Map","unionQuery","sortColumn","selectFields","id","parent","as","relationTo","collectionWhere","Object","keys","collectionQuery","select","from","$dynamic","unionAll","subQueryAlias","parentConstraint","raw","countExpression","orderBy","sortedUnionAlias","limitOffsetSQL","empty","offset","parentWhere","documents","hasCreatedAt","some","config","fields","type"],"mappings":"AAIA,SAASA,GAAG,EAAEC,KAAK,EAAEC,IAAI,EAAEC,EAAE,EAAEC,GAAG,QAAQ,cAAa;AAEvD,OAAOC,iBAAiB,gBAAe;AAKvC,SAASC,kBAAkB,QAAQ,uBAAsB;AACzD,SAASC,yBAAyB,QAAQ,iCAAgC;AAC1E,SAASC,8BAA8B,QAAQ,sCAAqC;AAoBpF;;;;;;;;;;;;;;CAcC,GACD,OAAO,MAAMC,4BAA4B,CAAC,EACxCC,OAAO,EACPC,gBAAgB,EAChBC,KAAK,EACLC,KAAK,EACLC,IAAI,EACJC,IAAI,EACJC,WAAW,EACXC,IAAI,EACJC,KAAK,EACyB;IAC9B,IAAI,CAACC,MAAMC,OAAO,CAACR,MAAMS,UAAU,GAAG;QACpC,MAAM,IAAIC,MAAM;IAClB;IAEA,IAAIV,MAAMS,UAAU,CAACE,MAAM,KAAK,GAAG;QACjC,MAAM,IAAID,MAAM;IAClB;IAEA,IAAIH,MAAMC,OAAO,CAACH,OAAO;QACvB,MAAM,IAAIK,MAAM;IAClB;IAEA,MAAME,cAAcZ,MAAMS,UAAU;IACpC,MAAMI,aAAa,GAAGV,KAAKW,UAAU,CAAC,KAAK,OAAOd,MAAMe,IAAI,EAAE;IAC9D,MAAMC,KAAKlB,QAAQmB,OAAO;IAC1B,MAAMC,SAASlB,MAAMmB,EAAE,CAACC,KAAK,CAAC,KAAKC,IAAI,CAAC;IACxC,MAAMC,mBAAmBV,YAAYW,GAAG,CAAC,CAACd;QACxC,IAAI,CAACX,QAAQ0B,OAAO,CAACZ,WAAW,CAACH,WAAW,EAAE;YAC5C,MAAM,IAAIC,MAAM,CAAC,qCAAqC,EAAED,WAAW,CAAC,CAAC;QACvE;QAEA,MAAMgB,YAAY3B,QAAQ4B,YAAY,CAACC,GAAG,CAAClC,YAAYgB;QACvD,MAAMmB,QAAQH,YAAa3B,QAAQ+B,MAAM,CAACJ,UAAU,GAAgCK;QAEpF,IAAI,CAACF,OAAO;YACV,MAAM,IAAIlB,MAAM,CAAC,6BAA6B,EAAED,WAAW,uBAAuB,CAAC;QACrF;QAEA,IAAI,CAACmB,KAAK,CAAC,KAAK,EAAE;YAChB,MAAM,IAAIlB,MAAM,CAAC,6BAA6B,EAAED,WAAW,oBAAoB,CAAC;QAClF;QAEA,IAAI,CAACmB,KAAK,CAACV,OAAO,EAAE;YAClB,MAAM,IAAIR,MAAM,CAAC,6BAA6B,EAAED,WAAW,UAAU,EAAES,OAAO,QAAQ,CAAC;QACzF;QAEA,OAAO;YAAET;YAAYmB;QAAM;IAC7B;IACA,MAAMG,YAAYC,aAAa;QAAElC;QAASc;QAAaP;IAAK;IAC5D,MAAM4B,YAAYF,UAAUG,UAAU,CAAC,OAAO5C,OAAOF;IACrD,MAAM+C,WAAWJ,UAAUK,OAAO,CAAC,KAAK,IAAIhB,KAAK,CAAC,KAAKC,IAAI,CAAC;IAC5D,MAAMgB,YAAsC/B,QACxCV,+BAA+B;QAAEE;QAASc;QAAaN;IAAM,KAC7D,IAAIgC;IACR,IAAIC,aAAkC;IAEtC,KAAK,MAAM,EAAE9B,UAAU,EAAEmB,KAAK,EAAE,IAAIN,iBAAkB;QACpD,MAAMkB,aAAaZ,KAAK,CAACO,SAAS;QAClC,MAAMM,eAAe;YACnBC,IAAId,KAAK,CAAC,KAAK;YACfe,QAAQnD,GAAG,CAAC,EAAEoC,KAAK,CAACV,OAAO,CAAC,CAAC,CAAC0B,EAAE,CAAC1B;YACjC2B,YAAYrD,GAAG,CAAC,EAAEiB,WAAW,CAAC,CAACmC,EAAE,CAAC;YAClCT,UAAU3C,GAAG,CAAC,EAAEgD,cAAc,KAAK,CAAC,CAACI,EAAE,CAAC;QAC1C;QACA,MAAME,kBACJxC,SAASyC,OAAOC,IAAI,CAAC1C,OAAOK,MAAM,GAAG,IACjChB,0BAA0B;YACxBG;YACAW;YACAmB;YACAtB;YACA+B;QACF,KACAP;QACN,IAAImB,kBAAkBjC,GAAGkC,MAAM,CAACT,cAAcU,IAAI,CAACvB,OAAOwB,QAAQ;QAElE,IAAIN,iBAAiB;YACnBG,kBAAkBA,gBAAgB3C,KAAK,CAACwC;QAC1C;QAEA,IAAIP,eAAe,MAAM;YACvBA,aAAaU;QACf,OAAO;YACLV,aAAaA,WAAWc,QAAQ,CAACJ;QACnC;IACF;IAEA,MAAMK,gBAAgB,GAAGzC,WAAW,SAAS,CAAC;IAC9C,MAAM0C,mBAAmBhE,GACvBC,IAAIgE,GAAG,CAAC,CAAC,CAAC,EAAEzD,iBAAiB,MAAM,CAAC,GACpCP,IAAIgE,GAAG,CAAC,CAAC,CAAC,EAAEF,cAAc,GAAG,EAAEpC,OAAO,CAAC,CAAC;IAE1C,MAAMuC,kBAAkBrD,cACpBZ,GAAG,CAAC,EAAEwB,GACHkC,MAAM,CAAC;QAAE7D,OAAOA;IAAQ,GACxB8D,IAAI,CAAC3D,GAAG,CAAC,EAAE+C,WAAWK,EAAE,CAACU,eAAe,CAAC,EACzChD,KAAK,CAACiD,kBAAkB,CAAC,CAACX,EAAE,CAAC,GAAG/B,WAAW,MAAM,CAAC,IACrDiB;IAEJS,aAAaA,WAAWmB,OAAO,CAACzB,UAAUzC,GAAG,CAAC,UAAU,CAAC;IAEzD,MAAMmE,mBAAmB,GAAG9C,WAAW,OAAO,CAAC;IAC/C,IAAI+C,iBAAiBpE,IAAIqE,KAAK;IAE9B,IAAI5D,OAAO;QACT2D,iBAAiBpE,GAAG,CAAC,OAAO,EAAES,MAAM,CAAC;IACvC;IAEA,IAAIC,QAAQD,UAAU,GAAG;QACvB,MAAM6D,SAAS,AAAC5D,CAAAA,OAAO,CAAA,IAAKD;QAE5B,IAAI6D,SAAS,GAAG;YACdF,iBAAiBpE,GAAG,CAAC,EAAEoE,eAAe,QAAQ,EAAEE,OAAO,CAAC;QAC1D;IACF;IAEA,MAAMC,cAAcvE,IAAIgE,GAAG,CAAC,CAAC,CAAC,EAAEG,iBAAiB,GAAG,EAAEzC,OAAO,KAAK,EAAEnB,iBAAiB,MAAM,CAAC;IAC5F,MAAMiE,YAAYxE,GAAG,CAAC;WACb,EAAEE,mBAAmBI,SAAS;QACnC4C,IAAIlD,IAAIgE,GAAG,CAAC,CAAC,CAAC,EAAEF,cAAc,MAAM,CAAC;QACrCT,YAAYrD,IAAIgE,GAAG,CAAC,CAAC,CAAC,EAAEF,cAAc,cAAc,CAAC;IACvD,GAAG;;oBAEa,EAAE9D,GAAG,CAAC,EAAE+C,WAAWK,EAAE,CAACe,kBAAkB,CAAC,CAAC;YAClD,EAAEI,YAAY,EAAEH,eAAe;SAClC,EAAEpE,IAAIgE,GAAG,CAAC,CAAC,CAAC,EAAEF,cAAc,CAAC,CAAC,EAAE;GACtC,CAAC,CAACV,EAAE,CAAC/B;IAEN,OAAO;QACLA;QACAxB,OAAOoE;QACPO;IACF;AACF,EAAC;AAED,MAAMhC,eAAe,CAAC,EACpBlC,OAAO,EACPc,WAAW,EACXP,IAAI,EAKL;IACC,IAAIA,MAAM;QACR,OAAOA;IACT;IAEA,MAAM4D,eAAerD,YAAYsD,IAAI,CAAC,CAACzD,aACrCX,QAAQ0B,OAAO,CAACZ,WAAW,CAACH,WAAW,CAAC0D,MAAM,CAACC,MAAM,CAACF,IAAI,CACxD,CAAClE,QAAUA,MAAMqE,IAAI,KAAK,UAAUrE,MAAMe,IAAI,KAAK;IAIvD,OAAOkD,eAAe,eAAe;AACvC"}
1
+ {"version":3,"sources":["../../src/find/buildPolymorphicJoinQuery.ts"],"sourcesContent":["import type { SQL } from 'drizzle-orm'\nimport type { LibSQLDatabase } from 'drizzle-orm/libsql'\nimport type { SQLiteSelect } from 'drizzle-orm/sqlite-core'\n\nimport { and, asc, count, desc, eq, getTableName, sql } from 'drizzle-orm'\nimport { type FlattenedJoinField, type Where } from 'payload'\nimport toSnakeCase from 'to-snake-case'\n\nimport type { DrizzleAdapter, GenericTable } from '../types.js'\nimport type { PolymorphicJoinWherePlan } from './createPolymorphicJoinWherePlan.js'\n\nimport { jsonAggBuildObject } from '../utilities/json.js'\nimport { buildPolymorphicJoinWhere } from './buildPolymorphicJoinWhere.js'\nimport { createPolymorphicJoinWherePlan } from './createPolymorphicJoinWherePlan.js'\n\ntype BuildPolymorphicJoinQueryArgs = {\n adapter: DrizzleAdapter\n currentTableName: string\n field: FlattenedJoinField\n limit: number\n locale?: string\n page?: number\n pageSize?: number\n path: string\n shouldCount: boolean\n sort?: string | string[]\n where?: Where\n}\n\ntype PolymorphicJoinQuery = {\n columnName: string\n count?: SQL.Aliased\n documents: SQL.Aliased\n}\n\n/**\n * Builds the correlated document and optional count projections for a join that targets multiple\n * collections. Every collection branch exposes the same `id`, parent, `relationTo`, and sort\n * columns before the branches are combined. A missing sort field resolves to SQL NULL so targets\n * with different schemas can still share one ordered union.\n *\n * `field.collection` must contain at least one configured collection. Each mapped table must have\n * an `id` column and the column named by `field.on`. The supplied `limit` is used as-is; callers can\n * include an extra look-ahead row and supply the original `pageSize` for offset calculation.\n *\n * @returns The stable projection name, the document projection, and the count projection when\n * `shouldCount` is true.\n * @throws If the join definition, target collection, mapped table, required columns, or sort shape\n * cannot be represented by the polymorphic query.\n */\nexport const buildPolymorphicJoinQuery = ({\n adapter,\n currentTableName,\n field,\n limit,\n locale,\n page,\n pageSize = limit,\n path,\n shouldCount,\n sort,\n where,\n}: BuildPolymorphicJoinQueryArgs): PolymorphicJoinQuery => {\n if (!Array.isArray(field.collection)) {\n throw new Error('A polymorphic join requires a collection array')\n }\n\n if (field.collection.length === 0) {\n throw new Error('A polymorphic join requires at least one collection')\n }\n\n if (Array.isArray(sort)) {\n throw new Error('Polymorphic joins do not support multiple sort fields')\n }\n\n const collections = field.collection\n const columnName = `${path.replaceAll('.', '_')}${field.name}`\n const db = adapter.drizzle as LibSQLDatabase\n const onPath = field.on.split('.').join('_')\n const collectionTables = collections.map((collection) => {\n if (!adapter.payload.collections[collection]) {\n throw new Error(`Unknown polymorphic join collection \"${collection}\"`)\n }\n\n const tableName = adapter.tableNameMap.get(toSnakeCase(collection))\n const table = tableName ? (adapter.tables[tableName] as GenericTable | undefined) : undefined\n\n if (!table) {\n throw new Error(`Polymorphic join collection \"${collection}\" has no database table`)\n }\n\n if (!table['id']) {\n throw new Error(`Polymorphic join collection \"${collection}\" has no \"id\" column`)\n }\n\n if (!table[onPath]) {\n throw new Error(`Polymorphic join collection \"${collection}\" has no \"${onPath}\" column`)\n }\n\n return { collection, table }\n })\n const sortField = getSortField({ adapter, collections, sort })\n const sortOrder = sortField.startsWith('-') ? desc : asc\n const sortPath = sortField.replace('-', '').split('.').join('_')\n const wherePlan: PolymorphicJoinWherePlan = where\n ? createPolymorphicJoinWherePlan({ adapter, collections, where })\n : new Map()\n let unionQuery: null | SQLiteSelect = null\n\n for (const { collection, table } of collectionTables) {\n const sortColumn = table[sortPath]\n const selectFields = {\n id: table['id'],\n parent: sql`${table[onPath]}`.as(onPath),\n relationTo: sql`${collection}`.as('relationTo'),\n sortPath: sql`${sortColumn ?? null}`.as('sortPath'),\n }\n const collectionWhere =\n where && Object.keys(where).length > 0\n ? buildPolymorphicJoinWhere({\n adapter,\n collection,\n table,\n where,\n wherePlan,\n })\n : undefined\n const hasLocalizedWhere = [...wherePlan.values()].some((pathPlan) => {\n const collectionField = pathPlan.fieldsByCollection.get(collection)\n\n return collectionField?.type === 'scalar' && collectionField.isLocalized\n })\n const shouldDeduplicate = hasLocalizedWhere && (!locale || locale === 'all')\n let collectionQuery = (\n shouldDeduplicate ? db.selectDistinct(selectFields) : db.select(selectFields)\n )\n .from(table)\n .$dynamic()\n\n if (hasLocalizedWhere) {\n const localesTable = adapter.tables[`${getTableName(table)}${adapter.localesSuffix}`]\n\n collectionQuery = collectionQuery.leftJoin(\n localesTable,\n and(\n eq(table['id'], localesTable._parentID),\n locale && locale !== 'all' ? eq(localesTable._locale, locale) : undefined,\n ),\n )\n }\n\n if (collectionWhere) {\n collectionQuery = collectionQuery.where(collectionWhere)\n }\n\n if (unionQuery === null) {\n unionQuery = collectionQuery as unknown as SQLiteSelect\n } else {\n unionQuery = unionQuery.unionAll(collectionQuery)\n }\n }\n\n const subQueryAlias = `${columnName}_subquery`\n const parentConstraint = eq(\n sql.raw(`\"${currentTableName}\".\"id\"`),\n sql.raw(`\"${subQueryAlias}\".\"${onPath}\"`),\n )\n const countExpression = shouldCount\n ? sql`${db\n .select({ count: count() })\n .from(sql`${unionQuery.as(subQueryAlias)}`)\n .where(parentConstraint)}`.as(`${columnName}_count`)\n : undefined\n\n unionQuery = unionQuery.orderBy(sortOrder(sql`\"sortPath\"`))\n\n const sortedUnionAlias = `${columnName}_sorted`\n let limitOffsetSQL = sql.empty()\n\n if (limit) {\n limitOffsetSQL = sql` LIMIT ${limit}`\n }\n\n if (page && limit !== 0) {\n const offset = (page - 1) * pageSize\n\n if (offset > 0) {\n limitOffsetSQL = sql`${limitOffsetSQL} OFFSET ${offset}`\n }\n }\n\n const parentWhere = sql.raw(`\"${sortedUnionAlias}\".\"${onPath}\" = \"${currentTableName}\".\"id\"`)\n const documents = sql`(\n SELECT ${jsonAggBuildObject(adapter, {\n id: sql.raw(`\"${subQueryAlias}\".\"id\"`),\n relationTo: sql.raw(`\"${subQueryAlias}\".\"relationTo\"`),\n })}\n FROM (\n SELECT * FROM ${sql`${unionQuery.as(sortedUnionAlias)}`}\n WHERE ${parentWhere}${limitOffsetSQL}\n ) AS ${sql.raw(`\"${subQueryAlias}\"`)}\n )`.as(columnName)\n\n return {\n columnName,\n count: countExpression,\n documents,\n }\n}\n\nconst getSortField = ({\n adapter,\n collections,\n sort,\n}: {\n adapter: DrizzleAdapter\n collections: string[]\n sort?: string\n}): string => {\n if (sort) {\n return sort\n }\n\n const hasCreatedAt = collections.some((collection) =>\n adapter.payload.collections[collection].config.fields.some(\n (field) => field.type === 'date' && field.name === 'createdAt',\n ),\n )\n\n return hasCreatedAt ? '-createdAt' : 'id'\n}\n"],"names":["and","asc","count","desc","eq","getTableName","sql","toSnakeCase","jsonAggBuildObject","buildPolymorphicJoinWhere","createPolymorphicJoinWherePlan","buildPolymorphicJoinQuery","adapter","currentTableName","field","limit","locale","page","pageSize","path","shouldCount","sort","where","Array","isArray","collection","Error","length","collections","columnName","replaceAll","name","db","drizzle","onPath","on","split","join","collectionTables","map","payload","tableName","tableNameMap","get","table","tables","undefined","sortField","getSortField","sortOrder","startsWith","sortPath","replace","wherePlan","Map","unionQuery","sortColumn","selectFields","id","parent","as","relationTo","collectionWhere","Object","keys","hasLocalizedWhere","values","some","pathPlan","collectionField","fieldsByCollection","type","isLocalized","shouldDeduplicate","collectionQuery","selectDistinct","select","from","$dynamic","localesTable","localesSuffix","leftJoin","_parentID","_locale","unionAll","subQueryAlias","parentConstraint","raw","countExpression","orderBy","sortedUnionAlias","limitOffsetSQL","empty","offset","parentWhere","documents","hasCreatedAt","config","fields"],"mappings":"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"}
@@ -4,7 +4,7 @@ import { drizzle } from 'drizzle-orm/libsql';
4
4
  import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
5
5
  import { flattenAllFields } from 'payload';
6
6
  import toSnakeCase from 'to-snake-case';
7
- import { afterAll, describe, expect, it } from 'vitest';
7
+ import { afterAll, beforeAll, describe, expect, it } from 'vitest';
8
8
  import { operatorMap } from '../queries/operatorMap.js';
9
9
  import { createJSONQuery } from '../sqlite/createJSONQuery/index.js';
10
10
  import { buildPolymorphicJoinQuery } from './buildPolymorphicJoinQuery.js';
@@ -19,6 +19,11 @@ const articlesTable = sqliteTable('join_articles', {
19
19
  score: integer('score'),
20
20
  title: text('title')
21
21
  });
22
+ const articlesLocalesTable = sqliteTable('join_articles_locales', {
23
+ _parentID: integer('_parent_id'),
24
+ _locale: text('_locale'),
25
+ _status: text('_status')
26
+ });
22
27
  const notesTable = sqliteTable('join_notes', {
23
28
  id: integer('id').primaryKey(),
24
29
  parent: integer('parent_id'),
@@ -135,12 +140,14 @@ const joinField = {
135
140
  on: 'parent',
136
141
  type: 'join'
137
142
  };
138
- const buildQuery = ({ adapter: adapterArg = adapter, field = joinField, limit = 0, page, path = '', shouldCount = false, sort, where } = {})=>buildPolymorphicJoinQuery({
143
+ const buildQuery = ({ adapter: adapterArg = adapter, field = joinField, limit = 0, locale, page, pageSize, path = '', shouldCount = false, sort, where } = {})=>buildPolymorphicJoinQuery({
139
144
  adapter: adapterArg,
140
145
  currentTableName: getTableName(parentsTable),
141
146
  field,
142
147
  limit,
148
+ locale,
143
149
  page,
150
+ pageSize,
144
151
  path,
145
152
  shouldCount,
146
153
  sort,
@@ -157,6 +164,162 @@ const renderQuery = (query)=>{
157
164
  };
158
165
  afterAll(()=>client.close());
159
166
  describe('buildPolymorphicJoinQuery', ()=>{
167
+ describe('localized filters', ()=>{
168
+ const localizedAdapter = createAdapter({
169
+ articles: {
170
+ fields: [
171
+ {
172
+ name: 'parent',
173
+ relationTo: 'join-parents',
174
+ type: 'relationship'
175
+ },
176
+ {
177
+ name: '_status',
178
+ type: 'select',
179
+ localized: true,
180
+ options: [
181
+ 'draft',
182
+ 'published'
183
+ ]
184
+ }
185
+ ],
186
+ table: articlesTable
187
+ },
188
+ notes: {
189
+ fields: [
190
+ {
191
+ name: 'parent',
192
+ relationTo: 'join-parents',
193
+ type: 'relationship'
194
+ }
195
+ ],
196
+ table: notesTable
197
+ }
198
+ });
199
+ localizedAdapter.localesSuffix = '_locales';
200
+ localizedAdapter.tables.join_articles_locales = articlesLocalesTable;
201
+ beforeAll(async ()=>{
202
+ await client.executeMultiple(`
203
+ CREATE TABLE join_parents (id INTEGER PRIMARY KEY);
204
+ CREATE TABLE join_articles (
205
+ id INTEGER PRIMARY KEY, parent_id INTEGER, created_at TEXT,
206
+ details_rank INTEGER, score INTEGER, title TEXT
207
+ );
208
+ CREATE TABLE join_notes (id INTEGER PRIMARY KEY, parent_id INTEGER, title TEXT);
209
+ CREATE TABLE join_articles_locales (_parent_id INTEGER, _locale TEXT, _status TEXT);
210
+ INSERT INTO join_parents VALUES (1);
211
+ INSERT INTO join_articles (id, parent_id) VALUES (1, 1), (2, 1), (3, 1);
212
+ INSERT INTO join_notes (id, parent_id) VALUES (4, 1);
213
+ INSERT INTO join_articles_locales VALUES
214
+ (1, 'en', 'published'), (1, 'fr', 'draft'),
215
+ (2, 'en', 'draft'), (2, 'fr', 'published'),
216
+ (3, 'en', 'published'), (3, 'fr', 'published');
217
+ `);
218
+ });
219
+ it.each([
220
+ {
221
+ locale: 'en',
222
+ ids: [
223
+ 1,
224
+ 3
225
+ ]
226
+ },
227
+ {
228
+ locale: 'fr',
229
+ ids: [
230
+ 2,
231
+ 3
232
+ ]
233
+ }
234
+ ])('should filter published documents in locale $locale', async ({ locale, ids })=>{
235
+ const query = buildQuery({
236
+ adapter: localizedAdapter,
237
+ locale,
238
+ shouldCount: true,
239
+ sort: 'id',
240
+ where: {
241
+ _status: {
242
+ equals: 'published'
243
+ }
244
+ }
245
+ });
246
+ const [result] = await db.select({
247
+ documents: query.documents,
248
+ count: query.count
249
+ }).from(parentsTable);
250
+ expect(JSON.parse(result.documents)).toEqual(ids.map((id)=>({
251
+ id,
252
+ relationTo: 'articles'
253
+ })));
254
+ expect(result.count).toBe(2);
255
+ });
256
+ it.each([
257
+ 'all',
258
+ undefined
259
+ ])('should count matching documents once across locales with locale %s', async (locale)=>{
260
+ const query = buildQuery({
261
+ adapter: localizedAdapter,
262
+ locale,
263
+ shouldCount: true,
264
+ sort: 'id',
265
+ where: {
266
+ _status: {
267
+ equals: 'published'
268
+ }
269
+ }
270
+ });
271
+ const [result] = await db.select({
272
+ documents: query.documents,
273
+ count: query.count
274
+ }).from(parentsTable);
275
+ expect(JSON.parse(result.documents)).toEqual([
276
+ {
277
+ id: 1,
278
+ relationTo: 'articles'
279
+ },
280
+ {
281
+ id: 2,
282
+ relationTo: 'articles'
283
+ },
284
+ {
285
+ id: 3,
286
+ relationTo: 'articles'
287
+ }
288
+ ]);
289
+ expect(result.count).toBe(3);
290
+ });
291
+ it('should paginate distinct documents using the page size before the look-ahead row', async ()=>{
292
+ const query = buildQuery({
293
+ adapter: localizedAdapter,
294
+ limit: 2,
295
+ locale: 'all',
296
+ page: 2,
297
+ pageSize: 1,
298
+ shouldCount: true,
299
+ sort: 'id',
300
+ where: {
301
+ _status: {
302
+ equals: 'published'
303
+ }
304
+ }
305
+ });
306
+ const [result] = await db.select({
307
+ documents: query.documents,
308
+ count: query.count
309
+ }).from(parentsTable);
310
+ expect(JSON.parse(result.documents)).toEqual([
311
+ {
312
+ id: 2,
313
+ relationTo: 'articles'
314
+ },
315
+ {
316
+ id: 3,
317
+ relationTo: 'articles'
318
+ }
319
+ ]);
320
+ expect(result.count).toBe(3);
321
+ });
322
+ });
160
323
  it('combines every target into one fixed polymorphic document projection', ()=>{
161
324
  const result = buildQuery({
162
325
  path: 'content.'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/find/buildPolymorphicJoinQuery.spec.ts"],"sourcesContent":["import type { Client } from '@libsql/client'\nimport type { SQL } from 'drizzle-orm'\nimport type { Field, FlattenedJoinField, Where } from 'payload'\n\nimport { createClient } from '@libsql/client'\nimport { getTableName, like, notLike } from 'drizzle-orm'\nimport { drizzle } from 'drizzle-orm/libsql'\nimport { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'\nimport { flattenAllFields } from 'payload'\nimport toSnakeCase from 'to-snake-case'\nimport { afterAll, describe, expect, it } from 'vitest'\n\nimport type { DrizzleAdapter, GenericTable } from '../types.js'\n\nimport { operatorMap } from '../queries/operatorMap.js'\nimport { createJSONQuery } from '../sqlite/createJSONQuery/index.js'\nimport { buildPolymorphicJoinQuery } from './buildPolymorphicJoinQuery.js'\n\nconst parentsTable = sqliteTable('join_parents', {\n id: integer('id').primaryKey(),\n})\n\nconst articlesTable = sqliteTable('join_articles', {\n id: integer('id').primaryKey(),\n createdAt: text('created_at'),\n details_rank: integer('details_rank'),\n parent: integer('parent_id'),\n score: integer('score'),\n title: text('title'),\n})\n\nconst notesTable = sqliteTable('join_notes', {\n id: integer('id').primaryKey(),\n parent: integer('parent_id'),\n title: text('title'),\n})\n\nconst tableWithoutID = sqliteTable('join_without_id', {\n parent: integer('parent_id'),\n})\n\nconst tableWithoutParent = sqliteTable('join_without_parent', {\n id: integer('id').primaryKey(),\n})\n\nconst client: Client = createClient({ url: 'file::memory:' })\nconst db = drizzle(client, {\n schema: { articlesTable, notesTable, parentsTable, tableWithoutID, tableWithoutParent },\n})\n\ntype CollectionFixture = {\n fields: Field[]\n table: GenericTable\n}\n\nconst createAdapter = (fixtures: Record<string, CollectionFixture>): DrizzleAdapter => {\n const collections: Record<\n string,\n { config: { fields: Field[]; flattenedFields: ReturnType<typeof flattenAllFields> } }\n > = {}\n const tableNameMap = new Map<string, string>()\n const tables: Record<string, GenericTable> = {}\n\n for (const [slug, fixture] of Object.entries(fixtures)) {\n const tableName = getTableName(fixture.table)\n\n collections[slug] = {\n config: {\n fields: fixture.fields,\n flattenedFields: flattenAllFields({ fields: fixture.fields }),\n },\n }\n tableNameMap.set(toSnakeCase(slug), tableName)\n tables[tableName] = fixture.table\n }\n\n return {\n createJSONQuery,\n drizzle: db,\n idType: 'serial',\n name: 'sqlite',\n operatorHandlers: [],\n operators: {\n ...operatorMap,\n contains: like,\n like,\n not_like: notLike,\n },\n payload: { collections },\n tableNameMap,\n tables,\n } as unknown as DrizzleAdapter\n}\n\nconst adapter = createAdapter({\n articles: {\n fields: [\n { name: 'createdAt', type: 'date' },\n {\n name: 'details',\n type: 'group',\n fields: [{ name: 'rank', type: 'number' }],\n },\n { name: 'parent', relationTo: 'join-parents', type: 'relationship' },\n { name: 'score', type: 'number' },\n { name: 'title', type: 'text' },\n ],\n table: articlesTable,\n },\n notes: {\n fields: [\n { name: 'parent', relationTo: 'join-parents', type: 'relationship' },\n { name: 'title', type: 'text' },\n ],\n table: notesTable,\n },\n})\n\nconst joinField = {\n collection: ['articles', 'notes'],\n name: 'children',\n on: 'parent',\n type: 'join',\n} as unknown as FlattenedJoinField\n\nconst buildQuery = ({\n adapter: adapterArg = adapter,\n field = joinField,\n limit = 0,\n page,\n path = '',\n shouldCount = false,\n sort,\n where,\n}: {\n adapter?: DrizzleAdapter\n field?: FlattenedJoinField\n limit?: number\n page?: number\n path?: string\n shouldCount?: boolean\n sort?: string | string[]\n where?: Where\n} = {}) =>\n buildPolymorphicJoinQuery({\n adapter: adapterArg,\n currentTableName: getTableName(parentsTable),\n field,\n limit,\n page,\n path,\n shouldCount,\n sort,\n where,\n })\n\nconst renderQuery = (query: ReturnType<typeof buildPolymorphicJoinQuery>) => {\n const selection: Record<string, SQL.Aliased> = { documents: query.documents }\n\n if (query.count) {\n selection.count = query.count\n }\n\n return db.select(selection).from(parentsTable).toSQL()\n}\n\nafterAll(() => client.close())\n\ndescribe('buildPolymorphicJoinQuery', () => {\n it('combines every target into one fixed polymorphic document projection', () => {\n const result = buildQuery({ path: 'content.' })\n const query = renderQuery(result)\n\n expect(result.columnName).toBe('content_children')\n expect(result.count).toBeUndefined()\n expect(query.sql).toContain('union all')\n expect(query.sql).toContain('select \"id\"')\n expect(query.sql).toContain('from \"join_articles\" union all')\n expect(query.sql).toContain('from \"join_notes\"')\n expect(query.sql).toContain('as \"parent\"')\n expect(query.sql).toContain('as \"relationTo\"')\n expect(query.sql).toContain(\"json_object('id',\")\n expect(query.sql).toContain(\"'relationTo',\")\n expect(query.params).toContain('articles')\n expect(query.params).toContain('notes')\n })\n\n it('sorts by createdAt descending by default when one target has timestamps', () => {\n const query = renderQuery(buildQuery())\n\n expect(query.sql).toContain('\"created_at\" as \"sortPath\" from \"join_articles\"')\n expect(query.sql).toContain('? as \"sortPath\" from \"join_notes\"')\n expect(query.sql).toContain('order by \"sortPath\" desc')\n expect(query.params).toContain(null)\n })\n\n it('uses id ascending by default when no target has a createdAt field', () => {\n const adapterWithoutTimestamps = createAdapter({\n articles: {\n fields: [{ name: 'parent', relationTo: 'join-parents', type: 'relationship' }],\n table: articlesTable,\n },\n notes: {\n fields: [{ name: 'parent', relationTo: 'join-parents', type: 'relationship' }],\n table: notesTable,\n },\n })\n const query = renderQuery(buildQuery({ adapter: adapterWithoutTimestamps }))\n\n expect(query.sql).toContain('\"id\" as \"sortPath\" from \"join_articles\"')\n expect(query.sql).toContain('\"id\" as \"sortPath\" from \"join_notes\"')\n expect(query.sql).toContain('order by \"sortPath\" asc')\n })\n\n it('supports an explicit ascending nested sort and substitutes null when it is absent', () => {\n const query = renderQuery(buildQuery({ sort: 'details.rank' }))\n\n expect(query.sql).toContain('\"details_rank\" as \"sortPath\" from \"join_articles\"')\n expect(query.sql).toContain('? as \"sortPath\" from \"join_notes\"')\n expect(query.sql).toContain('order by \"sortPath\" asc')\n expect(query.params).toContain(null)\n })\n\n it('applies the shared where clause independently to each target branch', () => {\n const query = renderQuery(\n buildQuery({\n where: {\n AND: [{ title: { equals: 'available' } }, { relationTo: { equals: 'articles' } }],\n },\n }),\n )\n\n expect(query.sql.match(/\"title\" = \\?/g)).toHaveLength(2)\n expect(query.sql).toContain('? = ?')\n expect(query.params.filter((value) => value === 'available')).toHaveLength(2)\n expect(query.params).toContain('articles')\n expect(query.params).toContain('notes')\n })\n\n it('adds a correlated count only when requested', () => {\n const result = buildQuery({ shouldCount: true })\n const query = renderQuery(result)\n\n expect(result.count).toBeDefined()\n expect(query.sql).toContain('select count(*) from')\n expect(query.sql).toContain('\"join_parents\".\"id\" = \"children_subquery\".\"parent\"')\n })\n\n it('adds limit and page offset to the document query', () => {\n const query = renderQuery(buildQuery({ limit: 11, page: 3 }))\n\n expect(query.sql).toContain('LIMIT ? OFFSET ?')\n expect(query.params.slice(-2)).toEqual([11, 22])\n })\n\n it('does not add limit or offset when limit is zero', () => {\n const query = renderQuery(buildQuery({ limit: 0, page: 3 }))\n const normalizedSQL = query.sql.toLowerCase()\n\n expect(normalizedSQL).not.toContain(' limit ')\n expect(normalizedSQL).not.toContain(' offset ')\n })\n\n it('rejects a join field with a non-polymorphic collection', () => {\n const scalarJoinField = {\n ...joinField,\n collection: 'articles',\n } as unknown as FlattenedJoinField\n\n expect(() => buildQuery({ field: scalarJoinField })).toThrow(\n 'A polymorphic join requires a collection array',\n )\n })\n\n it('rejects a polymorphic join with no target collections', () => {\n const emptyJoinField = { ...joinField, collection: [] } as unknown as FlattenedJoinField\n\n expect(() => buildQuery({ field: emptyJoinField })).toThrow(\n 'A polymorphic join requires at least one collection',\n )\n })\n\n it('rejects multiple sort fields with a descriptive error', () => {\n expect(() => buildQuery({ sort: ['title', '-createdAt'] })).toThrow(\n 'Polymorphic joins do not support multiple sort fields',\n )\n })\n\n it('throws a descriptive error when a target collection is not configured', () => {\n const missingCollectionField = {\n ...joinField,\n collection: ['articles', 'missing'],\n } as unknown as FlattenedJoinField\n\n expect(() => buildQuery({ field: missingCollectionField })).toThrow(\n 'Unknown polymorphic join collection \"missing\"',\n )\n })\n\n it('throws a descriptive error when a configured collection has no database table', () => {\n const adapterWithoutTable = createAdapter({\n articles: {\n fields: [{ name: 'parent', relationTo: 'join-parents', type: 'relationship' }],\n table: articlesTable,\n },\n })\n\n adapterWithoutTable.tables = {}\n\n const singleCollectionField = {\n ...joinField,\n collection: ['articles'],\n } as unknown as FlattenedJoinField\n\n expect(() =>\n buildQuery({ adapter: adapterWithoutTable, field: singleCollectionField }),\n ).toThrow('Polymorphic join collection \"articles\" has no database table')\n })\n\n it.each([\n [\n 'id',\n createAdapter({\n articles: {\n fields: [{ name: 'parent', relationTo: 'join-parents', type: 'relationship' }],\n table: tableWithoutID,\n },\n }),\n ],\n [\n 'parent',\n createAdapter({\n articles: {\n fields: [{ name: 'parent', relationTo: 'join-parents', type: 'relationship' }],\n table: tableWithoutParent,\n },\n }),\n ],\n ] as const)('rejects a target whose table has no %s column', (column, adapterArg) => {\n const singleCollectionField = {\n ...joinField,\n collection: ['articles'],\n } as unknown as FlattenedJoinField\n\n expect(() => buildQuery({ adapter: adapterArg, field: singleCollectionField })).toThrow(\n `Polymorphic join collection \"articles\" has no \"${column}\" column`,\n )\n })\n})\n"],"names":["createClient","getTableName","like","notLike","drizzle","integer","sqliteTable","text","flattenAllFields","toSnakeCase","afterAll","describe","expect","it","operatorMap","createJSONQuery","buildPolymorphicJoinQuery","parentsTable","id","primaryKey","articlesTable","createdAt","details_rank","parent","score","title","notesTable","tableWithoutID","tableWithoutParent","client","url","db","schema","createAdapter","fixtures","collections","tableNameMap","Map","tables","slug","fixture","Object","entries","tableName","table","config","fields","flattenedFields","set","idType","name","operatorHandlers","operators","contains","not_like","payload","adapter","articles","type","relationTo","notes","joinField","collection","on","buildQuery","adapterArg","field","limit","page","path","shouldCount","sort","where","currentTableName","renderQuery","query","selection","documents","count","select","from","toSQL","close","result","columnName","toBe","toBeUndefined","sql","toContain","params","adapterWithoutTimestamps","AND","equals","match","toHaveLength","filter","value","toBeDefined","slice","toEqual","normalizedSQL","toLowerCase","not","scalarJoinField","toThrow","emptyJoinField","missingCollectionField","adapterWithoutTable","singleCollectionField","each","column"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/find/buildPolymorphicJoinQuery.spec.ts"],"sourcesContent":["import type { Client } from '@libsql/client'\nimport type { SQL } from 'drizzle-orm'\nimport type { Field, FlattenedJoinField, Where } from 'payload'\n\nimport { createClient } from '@libsql/client'\nimport { getTableName, like, notLike } from 'drizzle-orm'\nimport { drizzle } from 'drizzle-orm/libsql'\nimport { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'\nimport { flattenAllFields } from 'payload'\nimport toSnakeCase from 'to-snake-case'\nimport { afterAll, beforeAll, describe, expect, it } from 'vitest'\n\nimport type { DrizzleAdapter, GenericTable } from '../types.js'\n\nimport { operatorMap } from '../queries/operatorMap.js'\nimport { createJSONQuery } from '../sqlite/createJSONQuery/index.js'\nimport { buildPolymorphicJoinQuery } from './buildPolymorphicJoinQuery.js'\n\nconst parentsTable = sqliteTable('join_parents', {\n id: integer('id').primaryKey(),\n})\n\nconst articlesTable = sqliteTable('join_articles', {\n id: integer('id').primaryKey(),\n createdAt: text('created_at'),\n details_rank: integer('details_rank'),\n parent: integer('parent_id'),\n score: integer('score'),\n title: text('title'),\n})\n\nconst articlesLocalesTable = sqliteTable('join_articles_locales', {\n _parentID: integer('_parent_id'),\n _locale: text('_locale'),\n _status: text('_status'),\n})\n\nconst notesTable = sqliteTable('join_notes', {\n id: integer('id').primaryKey(),\n parent: integer('parent_id'),\n title: text('title'),\n})\n\nconst tableWithoutID = sqliteTable('join_without_id', {\n parent: integer('parent_id'),\n})\n\nconst tableWithoutParent = sqliteTable('join_without_parent', {\n id: integer('id').primaryKey(),\n})\n\nconst client: Client = createClient({ url: 'file::memory:' })\nconst db = drizzle(client, {\n schema: { articlesTable, notesTable, parentsTable, tableWithoutID, tableWithoutParent },\n})\n\ntype CollectionFixture = {\n fields: Field[]\n table: GenericTable\n}\n\nconst createAdapter = (fixtures: Record<string, CollectionFixture>): DrizzleAdapter => {\n const collections: Record<\n string,\n { config: { fields: Field[]; flattenedFields: ReturnType<typeof flattenAllFields> } }\n > = {}\n const tableNameMap = new Map<string, string>()\n const tables: Record<string, GenericTable> = {}\n\n for (const [slug, fixture] of Object.entries(fixtures)) {\n const tableName = getTableName(fixture.table)\n\n collections[slug] = {\n config: {\n fields: fixture.fields,\n flattenedFields: flattenAllFields({ fields: fixture.fields }),\n },\n }\n tableNameMap.set(toSnakeCase(slug), tableName)\n tables[tableName] = fixture.table\n }\n\n return {\n createJSONQuery,\n drizzle: db,\n idType: 'serial',\n name: 'sqlite',\n operatorHandlers: [],\n operators: {\n ...operatorMap,\n contains: like,\n like,\n not_like: notLike,\n },\n payload: { collections },\n tableNameMap,\n tables,\n } as unknown as DrizzleAdapter\n}\n\nconst adapter = createAdapter({\n articles: {\n fields: [\n { name: 'createdAt', type: 'date' },\n {\n name: 'details',\n type: 'group',\n fields: [{ name: 'rank', type: 'number' }],\n },\n { name: 'parent', relationTo: 'join-parents', type: 'relationship' },\n { name: 'score', type: 'number' },\n { name: 'title', type: 'text' },\n ],\n table: articlesTable,\n },\n notes: {\n fields: [\n { name: 'parent', relationTo: 'join-parents', type: 'relationship' },\n { name: 'title', type: 'text' },\n ],\n table: notesTable,\n },\n})\n\nconst joinField = {\n collection: ['articles', 'notes'],\n name: 'children',\n on: 'parent',\n type: 'join',\n} as unknown as FlattenedJoinField\n\nconst buildQuery = ({\n adapter: adapterArg = adapter,\n field = joinField,\n limit = 0,\n locale,\n page,\n pageSize,\n path = '',\n shouldCount = false,\n sort,\n where,\n}: {\n adapter?: DrizzleAdapter\n field?: FlattenedJoinField\n limit?: number\n locale?: string\n page?: number\n pageSize?: number\n path?: string\n shouldCount?: boolean\n sort?: string | string[]\n where?: Where\n} = {}) =>\n buildPolymorphicJoinQuery({\n adapter: adapterArg,\n currentTableName: getTableName(parentsTable),\n field,\n limit,\n locale,\n page,\n pageSize,\n path,\n shouldCount,\n sort,\n where,\n })\n\nconst renderQuery = (query: ReturnType<typeof buildPolymorphicJoinQuery>) => {\n const selection: Record<string, SQL.Aliased> = { documents: query.documents }\n\n if (query.count) {\n selection.count = query.count\n }\n\n return db.select(selection).from(parentsTable).toSQL()\n}\n\nafterAll(() => client.close())\n\ndescribe('buildPolymorphicJoinQuery', () => {\n describe('localized filters', () => {\n const localizedAdapter = createAdapter({\n articles: {\n fields: [\n { name: 'parent', relationTo: 'join-parents', type: 'relationship' },\n { name: '_status', type: 'select', localized: true, options: ['draft', 'published'] },\n ],\n table: articlesTable,\n },\n notes: {\n fields: [{ name: 'parent', relationTo: 'join-parents', type: 'relationship' }],\n table: notesTable,\n },\n })\n\n localizedAdapter.localesSuffix = '_locales'\n localizedAdapter.tables.join_articles_locales = articlesLocalesTable\n\n beforeAll(async () => {\n await client.executeMultiple(`\n CREATE TABLE join_parents (id INTEGER PRIMARY KEY);\n CREATE TABLE join_articles (\n id INTEGER PRIMARY KEY, parent_id INTEGER, created_at TEXT,\n details_rank INTEGER, score INTEGER, title TEXT\n );\n CREATE TABLE join_notes (id INTEGER PRIMARY KEY, parent_id INTEGER, title TEXT);\n CREATE TABLE join_articles_locales (_parent_id INTEGER, _locale TEXT, _status TEXT);\n INSERT INTO join_parents VALUES (1);\n INSERT INTO join_articles (id, parent_id) VALUES (1, 1), (2, 1), (3, 1);\n INSERT INTO join_notes (id, parent_id) VALUES (4, 1);\n INSERT INTO join_articles_locales VALUES\n (1, 'en', 'published'), (1, 'fr', 'draft'),\n (2, 'en', 'draft'), (2, 'fr', 'published'),\n (3, 'en', 'published'), (3, 'fr', 'published');\n `)\n })\n\n it.each([\n { locale: 'en', ids: [1, 3] },\n { locale: 'fr', ids: [2, 3] },\n ])('should filter published documents in locale $locale', async ({ locale, ids }) => {\n const query = buildQuery({\n adapter: localizedAdapter,\n locale,\n shouldCount: true,\n sort: 'id',\n where: { _status: { equals: 'published' } },\n })\n const [result] = await db\n .select({ documents: query.documents, count: query.count! })\n .from(parentsTable)\n\n expect(JSON.parse(result.documents as string)).toEqual(\n ids.map((id) => ({ id, relationTo: 'articles' })),\n )\n expect(result.count).toBe(2)\n })\n\n it.each(['all', undefined])(\n 'should count matching documents once across locales with locale %s',\n async (locale) => {\n const query = buildQuery({\n adapter: localizedAdapter,\n locale,\n shouldCount: true,\n sort: 'id',\n where: { _status: { equals: 'published' } },\n })\n const [result] = await db\n .select({ documents: query.documents, count: query.count! })\n .from(parentsTable)\n\n expect(JSON.parse(result.documents as string)).toEqual([\n { id: 1, relationTo: 'articles' },\n { id: 2, relationTo: 'articles' },\n { id: 3, relationTo: 'articles' },\n ])\n expect(result.count).toBe(3)\n },\n )\n\n it('should paginate distinct documents using the page size before the look-ahead row', async () => {\n const query = buildQuery({\n adapter: localizedAdapter,\n limit: 2,\n locale: 'all',\n page: 2,\n pageSize: 1,\n shouldCount: true,\n sort: 'id',\n where: { _status: { equals: 'published' } },\n })\n const [result] = await db\n .select({ documents: query.documents, count: query.count! })\n .from(parentsTable)\n\n expect(JSON.parse(result.documents as string)).toEqual([\n { id: 2, relationTo: 'articles' },\n { id: 3, relationTo: 'articles' },\n ])\n expect(result.count).toBe(3)\n })\n })\n\n it('combines every target into one fixed polymorphic document projection', () => {\n const result = buildQuery({ path: 'content.' })\n const query = renderQuery(result)\n\n expect(result.columnName).toBe('content_children')\n expect(result.count).toBeUndefined()\n expect(query.sql).toContain('union all')\n expect(query.sql).toContain('select \"id\"')\n expect(query.sql).toContain('from \"join_articles\" union all')\n expect(query.sql).toContain('from \"join_notes\"')\n expect(query.sql).toContain('as \"parent\"')\n expect(query.sql).toContain('as \"relationTo\"')\n expect(query.sql).toContain(\"json_object('id',\")\n expect(query.sql).toContain(\"'relationTo',\")\n expect(query.params).toContain('articles')\n expect(query.params).toContain('notes')\n })\n\n it('sorts by createdAt descending by default when one target has timestamps', () => {\n const query = renderQuery(buildQuery())\n\n expect(query.sql).toContain('\"created_at\" as \"sortPath\" from \"join_articles\"')\n expect(query.sql).toContain('? as \"sortPath\" from \"join_notes\"')\n expect(query.sql).toContain('order by \"sortPath\" desc')\n expect(query.params).toContain(null)\n })\n\n it('uses id ascending by default when no target has a createdAt field', () => {\n const adapterWithoutTimestamps = createAdapter({\n articles: {\n fields: [{ name: 'parent', relationTo: 'join-parents', type: 'relationship' }],\n table: articlesTable,\n },\n notes: {\n fields: [{ name: 'parent', relationTo: 'join-parents', type: 'relationship' }],\n table: notesTable,\n },\n })\n const query = renderQuery(buildQuery({ adapter: adapterWithoutTimestamps }))\n\n expect(query.sql).toContain('\"id\" as \"sortPath\" from \"join_articles\"')\n expect(query.sql).toContain('\"id\" as \"sortPath\" from \"join_notes\"')\n expect(query.sql).toContain('order by \"sortPath\" asc')\n })\n\n it('supports an explicit ascending nested sort and substitutes null when it is absent', () => {\n const query = renderQuery(buildQuery({ sort: 'details.rank' }))\n\n expect(query.sql).toContain('\"details_rank\" as \"sortPath\" from \"join_articles\"')\n expect(query.sql).toContain('? as \"sortPath\" from \"join_notes\"')\n expect(query.sql).toContain('order by \"sortPath\" asc')\n expect(query.params).toContain(null)\n })\n\n it('applies the shared where clause independently to each target branch', () => {\n const query = renderQuery(\n buildQuery({\n where: {\n AND: [{ title: { equals: 'available' } }, { relationTo: { equals: 'articles' } }],\n },\n }),\n )\n\n expect(query.sql.match(/\"title\" = \\?/g)).toHaveLength(2)\n expect(query.sql).toContain('? = ?')\n expect(query.params.filter((value) => value === 'available')).toHaveLength(2)\n expect(query.params).toContain('articles')\n expect(query.params).toContain('notes')\n })\n\n it('adds a correlated count only when requested', () => {\n const result = buildQuery({ shouldCount: true })\n const query = renderQuery(result)\n\n expect(result.count).toBeDefined()\n expect(query.sql).toContain('select count(*) from')\n expect(query.sql).toContain('\"join_parents\".\"id\" = \"children_subquery\".\"parent\"')\n })\n\n it('adds limit and page offset to the document query', () => {\n const query = renderQuery(buildQuery({ limit: 11, page: 3 }))\n\n expect(query.sql).toContain('LIMIT ? OFFSET ?')\n expect(query.params.slice(-2)).toEqual([11, 22])\n })\n\n it('does not add limit or offset when limit is zero', () => {\n const query = renderQuery(buildQuery({ limit: 0, page: 3 }))\n const normalizedSQL = query.sql.toLowerCase()\n\n expect(normalizedSQL).not.toContain(' limit ')\n expect(normalizedSQL).not.toContain(' offset ')\n })\n\n it('rejects a join field with a non-polymorphic collection', () => {\n const scalarJoinField = {\n ...joinField,\n collection: 'articles',\n } as unknown as FlattenedJoinField\n\n expect(() => buildQuery({ field: scalarJoinField })).toThrow(\n 'A polymorphic join requires a collection array',\n )\n })\n\n it('rejects a polymorphic join with no target collections', () => {\n const emptyJoinField = { ...joinField, collection: [] } as unknown as FlattenedJoinField\n\n expect(() => buildQuery({ field: emptyJoinField })).toThrow(\n 'A polymorphic join requires at least one collection',\n )\n })\n\n it('rejects multiple sort fields with a descriptive error', () => {\n expect(() => buildQuery({ sort: ['title', '-createdAt'] })).toThrow(\n 'Polymorphic joins do not support multiple sort fields',\n )\n })\n\n it('throws a descriptive error when a target collection is not configured', () => {\n const missingCollectionField = {\n ...joinField,\n collection: ['articles', 'missing'],\n } as unknown as FlattenedJoinField\n\n expect(() => buildQuery({ field: missingCollectionField })).toThrow(\n 'Unknown polymorphic join collection \"missing\"',\n )\n })\n\n it('throws a descriptive error when a configured collection has no database table', () => {\n const adapterWithoutTable = createAdapter({\n articles: {\n fields: [{ name: 'parent', relationTo: 'join-parents', type: 'relationship' }],\n table: articlesTable,\n },\n })\n\n adapterWithoutTable.tables = {}\n\n const singleCollectionField = {\n ...joinField,\n collection: ['articles'],\n } as unknown as FlattenedJoinField\n\n expect(() =>\n buildQuery({ adapter: adapterWithoutTable, field: singleCollectionField }),\n ).toThrow('Polymorphic join collection \"articles\" has no database table')\n })\n\n it.each([\n [\n 'id',\n createAdapter({\n articles: {\n fields: [{ name: 'parent', relationTo: 'join-parents', type: 'relationship' }],\n table: tableWithoutID,\n },\n }),\n ],\n [\n 'parent',\n createAdapter({\n articles: {\n fields: [{ name: 'parent', relationTo: 'join-parents', type: 'relationship' }],\n table: tableWithoutParent,\n },\n }),\n ],\n ] as const)('rejects a target whose table has no %s column', (column, adapterArg) => {\n const singleCollectionField = {\n ...joinField,\n collection: ['articles'],\n } as unknown as FlattenedJoinField\n\n expect(() => buildQuery({ adapter: adapterArg, field: singleCollectionField })).toThrow(\n `Polymorphic join collection \"articles\" has no \"${column}\" column`,\n )\n })\n})\n"],"names":["createClient","getTableName","like","notLike","drizzle","integer","sqliteTable","text","flattenAllFields","toSnakeCase","afterAll","beforeAll","describe","expect","it","operatorMap","createJSONQuery","buildPolymorphicJoinQuery","parentsTable","id","primaryKey","articlesTable","createdAt","details_rank","parent","score","title","articlesLocalesTable","_parentID","_locale","_status","notesTable","tableWithoutID","tableWithoutParent","client","url","db","schema","createAdapter","fixtures","collections","tableNameMap","Map","tables","slug","fixture","Object","entries","tableName","table","config","fields","flattenedFields","set","idType","name","operatorHandlers","operators","contains","not_like","payload","adapter","articles","type","relationTo","notes","joinField","collection","on","buildQuery","adapterArg","field","limit","locale","page","pageSize","path","shouldCount","sort","where","currentTableName","renderQuery","query","selection","documents","count","select","from","toSQL","close","localizedAdapter","localized","options","localesSuffix","join_articles_locales","executeMultiple","each","ids","equals","result","JSON","parse","toEqual","map","toBe","undefined","columnName","toBeUndefined","sql","toContain","params","adapterWithoutTimestamps","AND","match","toHaveLength","filter","value","toBeDefined","slice","normalizedSQL","toLowerCase","not","scalarJoinField","toThrow","emptyJoinField","missingCollectionField","adapterWithoutTable","singleCollectionField","column"],"mappings":"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"}
@@ -237,9 +237,14 @@ const resolveWherePath = ({ adapter, collection, schemaPath, table, wherePlan })
237
237
  pathPlan
238
238
  };
239
239
  }
240
+ let column = sql`null`;
241
+ if (fieldContext) {
242
+ const fieldTable = fieldContext.isLocalized ? adapter.tables[`${getTableName(table)}${adapter.localesSuffix}`] : table;
243
+ column = fieldTable[pathPlan.columnPath];
244
+ }
240
245
  return {
241
246
  type: 'scalar',
242
- column: fieldContext ? table[pathPlan.columnPath] : sql`null`,
247
+ column,
243
248
  pathPlan,
244
249
  queryValueContext
245
250
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/find/buildPolymorphicJoinWhere.ts"],"sourcesContent":["import type { Column, SQL } from 'drizzle-orm'\n\nimport { and, getTableName, isNotNull, isNull, or, sql } from 'drizzle-orm'\nimport { type FlattenedField, QueryError, type Where } from 'payload'\nimport toSnakeCase from 'to-snake-case'\n\nimport type { DrizzleAdapter, GenericTable } from '../types.js'\nimport type {\n PolymorphicJoinWherePlan,\n ScalarWhereField,\n WherePathPlan,\n} from './createPolymorphicJoinWherePlan.js'\n\nimport { sanitizeQueryValue } from '../queries/sanitizeQueryValue.js'\n\nconst supportedJSONQueryOperators = new Set(['contains', 'equals', 'exists', 'in', 'like'])\n\ntype BuildPolymorphicJoinWhereArgs = {\n adapter: DrizzleAdapter\n collection: string\n table: GenericTable\n where: Where\n wherePlan: PolymorphicJoinWherePlan\n}\n\ntype ResolvedWherePath =\n | {\n column: Column\n pathPlan: WherePathPlan\n queryValueContext: ScalarWhereField\n type: 'scalar'\n }\n | {\n fieldContext: FlattenedField\n jsonExpression: string\n pathPlan: WherePathPlan\n type: 'hasManySelect'\n }\n | {\n pathPlan: WherePathPlan\n type: 'invalid'\n }\n\n/**\n * Builds a where clause for one collection before the polymorphic branches are combined. A field\n * that is absent from this collection resolves to SQL NULL, and relationTo resolves to the current\n * collection slug.\n */\nexport const buildPolymorphicJoinWhere = ({\n adapter,\n collection,\n table,\n where,\n wherePlan,\n}: BuildPolymorphicJoinWhereArgs): SQL | undefined => {\n const constraints: SQL[] = []\n\n for (const key in where) {\n if (['AND', 'OR'].includes(key.toUpperCase())) {\n if (!Array.isArray(where[key])) {\n throw new QueryError([{ path: key }])\n }\n\n const combine = key.toUpperCase() === 'AND' ? and : or\n const nestedConstraints = where[key].map((nestedWhere) =>\n buildPolymorphicJoinWhere({\n adapter,\n collection,\n table,\n where: nestedWhere,\n wherePlan,\n }),\n )\n const nestedCondition = combine(...nestedConstraints)\n\n if (nestedCondition) {\n constraints.push(nestedCondition)\n }\n\n continue\n }\n\n const resolvedPath = resolveWherePath({\n adapter,\n collection,\n schemaPath: key,\n table,\n wherePlan,\n })\n\n for (let payloadOperator of Object.keys(where[key])) {\n const originalOperator = payloadOperator\n let value = where[key][payloadOperator]\n\n if (resolvedPath.type === 'invalid') {\n throw new QueryError([{ path: `${key}.${payloadOperator}` }])\n }\n\n if (resolvedPath.type === 'hasManySelect') {\n if (!supportedJSONQueryOperators.has(payloadOperator)) {\n throw new QueryError([{ path: `${key}.${payloadOperator}` }])\n }\n\n const sanitizedQueryValue = sanitizeQueryValue({\n adapter,\n field: resolvedPath.fieldContext,\n isUUID: false,\n operator: payloadOperator,\n relationOrPath: key,\n val: value,\n })\n\n if (sanitizedQueryValue === null || sanitizedQueryValue.columns) {\n throw new QueryError([{ path: `${key}.${originalOperator}` }])\n }\n\n value = sanitizedQueryValue.value\n\n if (payloadOperator === 'in' && Array.isArray(value) && value.length === 0) {\n constraints.push(sql.raw('false'))\n continue\n }\n\n const jsonQueryOperator =\n payloadOperator === 'exists' ? 'exists' : sanitizedQueryValue.operator\n\n constraints.push(\n sql.raw(\n adapter.createJSONQuery({\n column: resolvedPath.jsonExpression,\n operator: jsonQueryOperator,\n pathSegments: [resolvedPath.pathPlan.columnPath],\n value,\n }),\n ),\n )\n continue\n }\n\n if (payloadOperator === '$raw') {\n if (typeof value !== 'string') {\n throw new QueryError([{ path: `${key}.${payloadOperator}` }])\n }\n\n constraints.push(sql.raw(value))\n continue\n }\n\n const { column, queryValueContext } = resolvedPath\n\n if (\n payloadOperator === 'like' &&\n (queryValueContext.field.type === 'number' ||\n queryValueContext.field.type === 'relationship' ||\n queryValueContext.field.type === 'upload' ||\n queryValueContext.isUUID)\n ) {\n payloadOperator = 'equals'\n }\n\n const sanitizedQueryValue = sanitizeQueryValue({\n adapter,\n field: queryValueContext.field,\n isUUID: queryValueContext.isUUID,\n operator: payloadOperator,\n relationOrPath: key,\n val: value,\n })\n\n if (sanitizedQueryValue === null || sanitizedQueryValue.columns) {\n throw new QueryError([{ path: `${key}.${originalOperator}` }])\n }\n\n payloadOperator = sanitizedQueryValue.operator\n value = sanitizedQueryValue.value\n\n if (!(payloadOperator in adapter.operators)) {\n throw new QueryError([{ path: `${key}.${originalOperator}` }])\n }\n\n const operator = adapter.operators[payloadOperator as keyof typeof adapter.operators]\n\n if (originalOperator === 'equals' && value === null) {\n constraints.push(isNull(column))\n continue\n }\n\n if (originalOperator === 'not_equals') {\n if (value === null) {\n constraints.push(isNotNull(column))\n } else {\n const notEqualsConstraint = or(isNull(column), operator(column, value))\n\n if (notEqualsConstraint) {\n constraints.push(notEqualsConstraint)\n }\n }\n continue\n }\n\n if (originalOperator === 'in' && Array.isArray(value) && value.includes(null)) {\n const nonNullValues = value.filter((item) => item !== null)\n const inConstraint = nonNullValues.length ? operator(column, nonNullValues) : undefined\n const nullAwareInConstraint = inConstraint\n ? or(isNull(column), inConstraint)\n : isNull(column)\n\n if (nullAwareInConstraint) {\n constraints.push(nullAwareInConstraint)\n }\n continue\n }\n\n if (payloadOperator === 'like' && typeof value === 'string') {\n const wordConstraints = value.split(' ').map((word) => operator(column, `%${word}%`))\n const wordCondition = and(...wordConstraints)\n\n if (wordCondition) {\n constraints.push(wordCondition)\n }\n continue\n }\n\n constraints.push(operator(column, value))\n }\n }\n\n return and(...constraints)\n}\n\nconst resolveWherePath = ({\n adapter,\n collection,\n schemaPath,\n table,\n wherePlan,\n}: {\n schemaPath: string\n} & Omit<BuildPolymorphicJoinWhereArgs, 'where'>): ResolvedWherePath => {\n const pathPlan = wherePlan.get(schemaPath)\n\n if (!pathPlan) {\n throw new QueryError([{ path: schemaPath }])\n }\n\n if (pathPlan.type === 'invalid') {\n return { type: 'invalid', pathPlan }\n }\n\n if (schemaPath === 'relationTo') {\n return {\n type: 'scalar',\n column: sql`${collection}` as unknown as Column,\n pathPlan,\n queryValueContext: {\n type: 'scalar',\n field: { name: 'relationTo', type: 'text' },\n isUUID: false,\n },\n }\n }\n\n if (pathPlan.type === 'hasManySelect') {\n const fieldContext = [...pathPlan.fieldsByCollection.values()].find(\n (field) => field.type === 'hasManySelect',\n )?.field\n\n if (!fieldContext) {\n return { type: 'invalid', pathPlan }\n }\n\n return {\n type: 'hasManySelect',\n fieldContext,\n jsonExpression: getHasManySelectExpression({\n adapter,\n collection,\n pathPlan,\n table,\n }),\n pathPlan,\n }\n }\n\n const collectionField = pathPlan.fieldsByCollection.get(collection)\n const fieldContext = collectionField?.type === 'scalar' ? collectionField : undefined\n const queryValueContext =\n fieldContext ??\n [...pathPlan.fieldsByCollection.values()].find(\n (field): field is ScalarWhereField => field.type === 'scalar',\n )\n\n if (!queryValueContext) {\n return { type: 'invalid', pathPlan }\n }\n\n return {\n type: 'scalar',\n column: fieldContext ? table[pathPlan.columnPath] : (sql`null` as unknown as Column),\n pathPlan,\n queryValueContext,\n }\n}\n\nconst getHasManySelectExpression = ({\n adapter,\n collection,\n pathPlan,\n table,\n}: {\n adapter: DrizzleAdapter\n collection: string\n pathPlan: WherePathPlan\n table: GenericTable\n}): string => {\n if (pathPlan.fieldsByCollection.get(collection)?.type !== 'hasManySelect') {\n return adapter.name === 'postgres' ? `'[]'::jsonb` : `'[]'`\n }\n\n const selectTablePath = pathPlan.schemaPath\n .split('.')\n .map((pathSegment) => toSnakeCase(pathSegment))\n .join('_')\n const valuesTableName = adapter.tableNameMap.get(`${toSnakeCase(collection)}_${selectTablePath}`)\n\n if (!valuesTableName) {\n throw new Error(\n `Polymorphic join collection \"${collection}\" has no value table for \"${pathPlan.schemaPath}\"`,\n )\n }\n\n let qualifiedValuesTableName = valuesTableName\n let parentTableName = getTableName(table)\n\n if (adapter.schemaName) {\n qualifiedValuesTableName = `\"${adapter.schemaName}\".\"${valuesTableName}\"`\n parentTableName = `\"${adapter.schemaName}\".\"${parentTableName}\"`\n }\n\n if (adapter.name === 'postgres') {\n return `(select coalesce(jsonb_agg(${qualifiedValuesTableName}.value), '[]'::jsonb) from ${qualifiedValuesTableName} where ${qualifiedValuesTableName}.parent_id = ${parentTableName}.id)`\n }\n\n return `(select json_group_array(${qualifiedValuesTableName}.value) from ${qualifiedValuesTableName} where ${qualifiedValuesTableName}.parent_id = ${parentTableName}.id)`\n}\n"],"names":["and","getTableName","isNotNull","isNull","or","sql","QueryError","toSnakeCase","sanitizeQueryValue","supportedJSONQueryOperators","Set","buildPolymorphicJoinWhere","adapter","collection","table","where","wherePlan","constraints","key","includes","toUpperCase","Array","isArray","path","combine","nestedConstraints","map","nestedWhere","nestedCondition","push","resolvedPath","resolveWherePath","schemaPath","payloadOperator","Object","keys","originalOperator","value","type","has","sanitizedQueryValue","field","fieldContext","isUUID","operator","relationOrPath","val","columns","length","raw","jsonQueryOperator","createJSONQuery","column","jsonExpression","pathSegments","pathPlan","columnPath","queryValueContext","operators","notEqualsConstraint","nonNullValues","filter","item","inConstraint","undefined","nullAwareInConstraint","wordConstraints","split","word","wordCondition","get","name","fieldsByCollection","values","find","getHasManySelectExpression","collectionField","selectTablePath","pathSegment","join","valuesTableName","tableNameMap","Error","qualifiedValuesTableName","parentTableName","schemaName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../src/find/buildPolymorphicJoinWhere.ts"],"sourcesContent":["import type { Column, SQL } from 'drizzle-orm'\n\nimport { and, getTableName, isNotNull, isNull, or, sql } from 'drizzle-orm'\nimport { type FlattenedField, QueryError, type Where } from 'payload'\nimport toSnakeCase from 'to-snake-case'\n\nimport type { DrizzleAdapter, GenericTable } from '../types.js'\nimport type {\n PolymorphicJoinWherePlan,\n ScalarWhereField,\n WherePathPlan,\n} from './createPolymorphicJoinWherePlan.js'\n\nimport { sanitizeQueryValue } from '../queries/sanitizeQueryValue.js'\n\nconst supportedJSONQueryOperators = new Set(['contains', 'equals', 'exists', 'in', 'like'])\n\ntype BuildPolymorphicJoinWhereArgs = {\n adapter: DrizzleAdapter\n collection: string\n table: GenericTable\n where: Where\n wherePlan: PolymorphicJoinWherePlan\n}\n\ntype ResolvedWherePath =\n | {\n column: Column\n pathPlan: WherePathPlan\n queryValueContext: ScalarWhereField\n type: 'scalar'\n }\n | {\n fieldContext: FlattenedField\n jsonExpression: string\n pathPlan: WherePathPlan\n type: 'hasManySelect'\n }\n | {\n pathPlan: WherePathPlan\n type: 'invalid'\n }\n\n/**\n * Builds a where clause for one collection before the polymorphic branches are combined. A field\n * that is absent from this collection resolves to SQL NULL, and relationTo resolves to the current\n * collection slug.\n */\nexport const buildPolymorphicJoinWhere = ({\n adapter,\n collection,\n table,\n where,\n wherePlan,\n}: BuildPolymorphicJoinWhereArgs): SQL | undefined => {\n const constraints: SQL[] = []\n\n for (const key in where) {\n if (['AND', 'OR'].includes(key.toUpperCase())) {\n if (!Array.isArray(where[key])) {\n throw new QueryError([{ path: key }])\n }\n\n const combine = key.toUpperCase() === 'AND' ? and : or\n const nestedConstraints = where[key].map((nestedWhere) =>\n buildPolymorphicJoinWhere({\n adapter,\n collection,\n table,\n where: nestedWhere,\n wherePlan,\n }),\n )\n const nestedCondition = combine(...nestedConstraints)\n\n if (nestedCondition) {\n constraints.push(nestedCondition)\n }\n\n continue\n }\n\n const resolvedPath = resolveWherePath({\n adapter,\n collection,\n schemaPath: key,\n table,\n wherePlan,\n })\n\n for (let payloadOperator of Object.keys(where[key])) {\n const originalOperator = payloadOperator\n let value = where[key][payloadOperator]\n\n if (resolvedPath.type === 'invalid') {\n throw new QueryError([{ path: `${key}.${payloadOperator}` }])\n }\n\n if (resolvedPath.type === 'hasManySelect') {\n if (!supportedJSONQueryOperators.has(payloadOperator)) {\n throw new QueryError([{ path: `${key}.${payloadOperator}` }])\n }\n\n const sanitizedQueryValue = sanitizeQueryValue({\n adapter,\n field: resolvedPath.fieldContext,\n isUUID: false,\n operator: payloadOperator,\n relationOrPath: key,\n val: value,\n })\n\n if (sanitizedQueryValue === null || sanitizedQueryValue.columns) {\n throw new QueryError([{ path: `${key}.${originalOperator}` }])\n }\n\n value = sanitizedQueryValue.value\n\n if (payloadOperator === 'in' && Array.isArray(value) && value.length === 0) {\n constraints.push(sql.raw('false'))\n continue\n }\n\n const jsonQueryOperator =\n payloadOperator === 'exists' ? 'exists' : sanitizedQueryValue.operator\n\n constraints.push(\n sql.raw(\n adapter.createJSONQuery({\n column: resolvedPath.jsonExpression,\n operator: jsonQueryOperator,\n pathSegments: [resolvedPath.pathPlan.columnPath],\n value,\n }),\n ),\n )\n continue\n }\n\n if (payloadOperator === '$raw') {\n if (typeof value !== 'string') {\n throw new QueryError([{ path: `${key}.${payloadOperator}` }])\n }\n\n constraints.push(sql.raw(value))\n continue\n }\n\n const { column, queryValueContext } = resolvedPath\n\n if (\n payloadOperator === 'like' &&\n (queryValueContext.field.type === 'number' ||\n queryValueContext.field.type === 'relationship' ||\n queryValueContext.field.type === 'upload' ||\n queryValueContext.isUUID)\n ) {\n payloadOperator = 'equals'\n }\n\n const sanitizedQueryValue = sanitizeQueryValue({\n adapter,\n field: queryValueContext.field,\n isUUID: queryValueContext.isUUID,\n operator: payloadOperator,\n relationOrPath: key,\n val: value,\n })\n\n if (sanitizedQueryValue === null || sanitizedQueryValue.columns) {\n throw new QueryError([{ path: `${key}.${originalOperator}` }])\n }\n\n payloadOperator = sanitizedQueryValue.operator\n value = sanitizedQueryValue.value\n\n if (!(payloadOperator in adapter.operators)) {\n throw new QueryError([{ path: `${key}.${originalOperator}` }])\n }\n\n const operator = adapter.operators[payloadOperator as keyof typeof adapter.operators]\n\n if (originalOperator === 'equals' && value === null) {\n constraints.push(isNull(column))\n continue\n }\n\n if (originalOperator === 'not_equals') {\n if (value === null) {\n constraints.push(isNotNull(column))\n } else {\n const notEqualsConstraint = or(isNull(column), operator(column, value))\n\n if (notEqualsConstraint) {\n constraints.push(notEqualsConstraint)\n }\n }\n continue\n }\n\n if (originalOperator === 'in' && Array.isArray(value) && value.includes(null)) {\n const nonNullValues = value.filter((item) => item !== null)\n const inConstraint = nonNullValues.length ? operator(column, nonNullValues) : undefined\n const nullAwareInConstraint = inConstraint\n ? or(isNull(column), inConstraint)\n : isNull(column)\n\n if (nullAwareInConstraint) {\n constraints.push(nullAwareInConstraint)\n }\n continue\n }\n\n if (payloadOperator === 'like' && typeof value === 'string') {\n const wordConstraints = value.split(' ').map((word) => operator(column, `%${word}%`))\n const wordCondition = and(...wordConstraints)\n\n if (wordCondition) {\n constraints.push(wordCondition)\n }\n continue\n }\n\n constraints.push(operator(column, value))\n }\n }\n\n return and(...constraints)\n}\n\nconst resolveWherePath = ({\n adapter,\n collection,\n schemaPath,\n table,\n wherePlan,\n}: {\n schemaPath: string\n} & Omit<BuildPolymorphicJoinWhereArgs, 'where'>): ResolvedWherePath => {\n const pathPlan = wherePlan.get(schemaPath)\n\n if (!pathPlan) {\n throw new QueryError([{ path: schemaPath }])\n }\n\n if (pathPlan.type === 'invalid') {\n return { type: 'invalid', pathPlan }\n }\n\n if (schemaPath === 'relationTo') {\n return {\n type: 'scalar',\n column: sql`${collection}` as unknown as Column,\n pathPlan,\n queryValueContext: {\n type: 'scalar',\n field: { name: 'relationTo', type: 'text' },\n isUUID: false,\n },\n }\n }\n\n if (pathPlan.type === 'hasManySelect') {\n const fieldContext = [...pathPlan.fieldsByCollection.values()].find(\n (field) => field.type === 'hasManySelect',\n )?.field\n\n if (!fieldContext) {\n return { type: 'invalid', pathPlan }\n }\n\n return {\n type: 'hasManySelect',\n fieldContext,\n jsonExpression: getHasManySelectExpression({\n adapter,\n collection,\n pathPlan,\n table,\n }),\n pathPlan,\n }\n }\n\n const collectionField = pathPlan.fieldsByCollection.get(collection)\n const fieldContext = collectionField?.type === 'scalar' ? collectionField : undefined\n const queryValueContext =\n fieldContext ??\n [...pathPlan.fieldsByCollection.values()].find(\n (field): field is ScalarWhereField => field.type === 'scalar',\n )\n\n if (!queryValueContext) {\n return { type: 'invalid', pathPlan }\n }\n\n let column = sql`null` as unknown as Column\n\n if (fieldContext) {\n const fieldTable = fieldContext.isLocalized\n ? adapter.tables[`${getTableName(table)}${adapter.localesSuffix}`]\n : table\n\n column = fieldTable[pathPlan.columnPath]\n }\n\n return {\n type: 'scalar',\n column,\n pathPlan,\n queryValueContext,\n }\n}\n\nconst getHasManySelectExpression = ({\n adapter,\n collection,\n pathPlan,\n table,\n}: {\n adapter: DrizzleAdapter\n collection: string\n pathPlan: WherePathPlan\n table: GenericTable\n}): string => {\n if (pathPlan.fieldsByCollection.get(collection)?.type !== 'hasManySelect') {\n return adapter.name === 'postgres' ? `'[]'::jsonb` : `'[]'`\n }\n\n const selectTablePath = pathPlan.schemaPath\n .split('.')\n .map((pathSegment) => toSnakeCase(pathSegment))\n .join('_')\n const valuesTableName = adapter.tableNameMap.get(`${toSnakeCase(collection)}_${selectTablePath}`)\n\n if (!valuesTableName) {\n throw new Error(\n `Polymorphic join collection \"${collection}\" has no value table for \"${pathPlan.schemaPath}\"`,\n )\n }\n\n let qualifiedValuesTableName = valuesTableName\n let parentTableName = getTableName(table)\n\n if (adapter.schemaName) {\n qualifiedValuesTableName = `\"${adapter.schemaName}\".\"${valuesTableName}\"`\n parentTableName = `\"${adapter.schemaName}\".\"${parentTableName}\"`\n }\n\n if (adapter.name === 'postgres') {\n return `(select coalesce(jsonb_agg(${qualifiedValuesTableName}.value), '[]'::jsonb) from ${qualifiedValuesTableName} where ${qualifiedValuesTableName}.parent_id = ${parentTableName}.id)`\n }\n\n return `(select json_group_array(${qualifiedValuesTableName}.value) from ${qualifiedValuesTableName} where ${qualifiedValuesTableName}.parent_id = ${parentTableName}.id)`\n}\n"],"names":["and","getTableName","isNotNull","isNull","or","sql","QueryError","toSnakeCase","sanitizeQueryValue","supportedJSONQueryOperators","Set","buildPolymorphicJoinWhere","adapter","collection","table","where","wherePlan","constraints","key","includes","toUpperCase","Array","isArray","path","combine","nestedConstraints","map","nestedWhere","nestedCondition","push","resolvedPath","resolveWherePath","schemaPath","payloadOperator","Object","keys","originalOperator","value","type","has","sanitizedQueryValue","field","fieldContext","isUUID","operator","relationOrPath","val","columns","length","raw","jsonQueryOperator","createJSONQuery","column","jsonExpression","pathSegments","pathPlan","columnPath","queryValueContext","operators","notEqualsConstraint","nonNullValues","filter","item","inConstraint","undefined","nullAwareInConstraint","wordConstraints","split","word","wordCondition","get","name","fieldsByCollection","values","find","getHasManySelectExpression","collectionField","fieldTable","isLocalized","tables","localesSuffix","selectTablePath","pathSegment","join","valuesTableName","tableNameMap","Error","qualifiedValuesTableName","parentTableName","schemaName"],"mappings":"AAEA,SAASA,GAAG,EAAEC,YAAY,EAAEC,SAAS,EAAEC,MAAM,EAAEC,EAAE,EAAEC,GAAG,QAAQ,cAAa;AAC3E,SAA8BC,UAAU,QAAoB,UAAS;AACrE,OAAOC,iBAAiB,gBAAe;AASvC,SAASC,kBAAkB,QAAQ,mCAAkC;AAErE,MAAMC,8BAA8B,IAAIC,IAAI;IAAC;IAAY;IAAU;IAAU;IAAM;CAAO;AA4B1F;;;;CAIC,GACD,OAAO,MAAMC,4BAA4B,CAAC,EACxCC,OAAO,EACPC,UAAU,EACVC,KAAK,EACLC,KAAK,EACLC,SAAS,EACqB;IAC9B,MAAMC,cAAqB,EAAE;IAE7B,IAAK,MAAMC,OAAOH,MAAO;QACvB,IAAI;YAAC;YAAO;SAAK,CAACI,QAAQ,CAACD,IAAIE,WAAW,KAAK;YAC7C,IAAI,CAACC,MAAMC,OAAO,CAACP,KAAK,CAACG,IAAI,GAAG;gBAC9B,MAAM,IAAIZ,WAAW;oBAAC;wBAAEiB,MAAML;oBAAI;iBAAE;YACtC;YAEA,MAAMM,UAAUN,IAAIE,WAAW,OAAO,QAAQpB,MAAMI;YACpD,MAAMqB,oBAAoBV,KAAK,CAACG,IAAI,CAACQ,GAAG,CAAC,CAACC,cACxChB,0BAA0B;oBACxBC;oBACAC;oBACAC;oBACAC,OAAOY;oBACPX;gBACF;YAEF,MAAMY,kBAAkBJ,WAAWC;YAEnC,IAAIG,iBAAiB;gBACnBX,YAAYY,IAAI,CAACD;YACnB;YAEA;QACF;QAEA,MAAME,eAAeC,iBAAiB;YACpCnB;YACAC;YACAmB,YAAYd;YACZJ;YACAE;QACF;QAEA,KAAK,IAAIiB,mBAAmBC,OAAOC,IAAI,CAACpB,KAAK,CAACG,IAAI,EAAG;YACnD,MAAMkB,mBAAmBH;YACzB,IAAII,QAAQtB,KAAK,CAACG,IAAI,CAACe,gBAAgB;YAEvC,IAAIH,aAAaQ,IAAI,KAAK,WAAW;gBACnC,MAAM,IAAIhC,WAAW;oBAAC;wBAAEiB,MAAM,GAAGL,IAAI,CAAC,EAAEe,iBAAiB;oBAAC;iBAAE;YAC9D;YAEA,IAAIH,aAAaQ,IAAI,KAAK,iBAAiB;gBACzC,IAAI,CAAC7B,4BAA4B8B,GAAG,CAACN,kBAAkB;oBACrD,MAAM,IAAI3B,WAAW;wBAAC;4BAAEiB,MAAM,GAAGL,IAAI,CAAC,EAAEe,iBAAiB;wBAAC;qBAAE;gBAC9D;gBAEA,MAAMO,sBAAsBhC,mBAAmB;oBAC7CI;oBACA6B,OAAOX,aAAaY,YAAY;oBAChCC,QAAQ;oBACRC,UAAUX;oBACVY,gBAAgB3B;oBAChB4B,KAAKT;gBACP;gBAEA,IAAIG,wBAAwB,QAAQA,oBAAoBO,OAAO,EAAE;oBAC/D,MAAM,IAAIzC,WAAW;wBAAC;4BAAEiB,MAAM,GAAGL,IAAI,CAAC,EAAEkB,kBAAkB;wBAAC;qBAAE;gBAC/D;gBAEAC,QAAQG,oBAAoBH,KAAK;gBAEjC,IAAIJ,oBAAoB,QAAQZ,MAAMC,OAAO,CAACe,UAAUA,MAAMW,MAAM,KAAK,GAAG;oBAC1E/B,YAAYY,IAAI,CAACxB,IAAI4C,GAAG,CAAC;oBACzB;gBACF;gBAEA,MAAMC,oBACJjB,oBAAoB,WAAW,WAAWO,oBAAoBI,QAAQ;gBAExE3B,YAAYY,IAAI,CACdxB,IAAI4C,GAAG,CACLrC,QAAQuC,eAAe,CAAC;oBACtBC,QAAQtB,aAAauB,cAAc;oBACnCT,UAAUM;oBACVI,cAAc;wBAACxB,aAAayB,QAAQ,CAACC,UAAU;qBAAC;oBAChDnB;gBACF;gBAGJ;YACF;YAEA,IAAIJ,oBAAoB,QAAQ;gBAC9B,IAAI,OAAOI,UAAU,UAAU;oBAC7B,MAAM,IAAI/B,WAAW;wBAAC;4BAAEiB,MAAM,GAAGL,IAAI,CAAC,EAAEe,iBAAiB;wBAAC;qBAAE;gBAC9D;gBAEAhB,YAAYY,IAAI,CAACxB,IAAI4C,GAAG,CAACZ;gBACzB;YACF;YAEA,MAAM,EAAEe,MAAM,EAAEK,iBAAiB,EAAE,GAAG3B;YAEtC,IACEG,oBAAoB,UACnBwB,CAAAA,kBAAkBhB,KAAK,CAACH,IAAI,KAAK,YAChCmB,kBAAkBhB,KAAK,CAACH,IAAI,KAAK,kBACjCmB,kBAAkBhB,KAAK,CAACH,IAAI,KAAK,YACjCmB,kBAAkBd,MAAM,AAAD,GACzB;gBACAV,kBAAkB;YACpB;YAEA,MAAMO,sBAAsBhC,mBAAmB;gBAC7CI;gBACA6B,OAAOgB,kBAAkBhB,KAAK;gBAC9BE,QAAQc,kBAAkBd,MAAM;gBAChCC,UAAUX;gBACVY,gBAAgB3B;gBAChB4B,KAAKT;YACP;YAEA,IAAIG,wBAAwB,QAAQA,oBAAoBO,OAAO,EAAE;gBAC/D,MAAM,IAAIzC,WAAW;oBAAC;wBAAEiB,MAAM,GAAGL,IAAI,CAAC,EAAEkB,kBAAkB;oBAAC;iBAAE;YAC/D;YAEAH,kBAAkBO,oBAAoBI,QAAQ;YAC9CP,QAAQG,oBAAoBH,KAAK;YAEjC,IAAI,CAAEJ,CAAAA,mBAAmBrB,QAAQ8C,SAAS,AAAD,GAAI;gBAC3C,MAAM,IAAIpD,WAAW;oBAAC;wBAAEiB,MAAM,GAAGL,IAAI,CAAC,EAAEkB,kBAAkB;oBAAC;iBAAE;YAC/D;YAEA,MAAMQ,WAAWhC,QAAQ8C,SAAS,CAACzB,gBAAkD;YAErF,IAAIG,qBAAqB,YAAYC,UAAU,MAAM;gBACnDpB,YAAYY,IAAI,CAAC1B,OAAOiD;gBACxB;YACF;YAEA,IAAIhB,qBAAqB,cAAc;gBACrC,IAAIC,UAAU,MAAM;oBAClBpB,YAAYY,IAAI,CAAC3B,UAAUkD;gBAC7B,OAAO;oBACL,MAAMO,sBAAsBvD,GAAGD,OAAOiD,SAASR,SAASQ,QAAQf;oBAEhE,IAAIsB,qBAAqB;wBACvB1C,YAAYY,IAAI,CAAC8B;oBACnB;gBACF;gBACA;YACF;YAEA,IAAIvB,qBAAqB,QAAQf,MAAMC,OAAO,CAACe,UAAUA,MAAMlB,QAAQ,CAAC,OAAO;gBAC7E,MAAMyC,gBAAgBvB,MAAMwB,MAAM,CAAC,CAACC,OAASA,SAAS;gBACtD,MAAMC,eAAeH,cAAcZ,MAAM,GAAGJ,SAASQ,QAAQQ,iBAAiBI;gBAC9E,MAAMC,wBAAwBF,eAC1B3D,GAAGD,OAAOiD,SAASW,gBACnB5D,OAAOiD;gBAEX,IAAIa,uBAAuB;oBACzBhD,YAAYY,IAAI,CAACoC;gBACnB;gBACA;YACF;YAEA,IAAIhC,oBAAoB,UAAU,OAAOI,UAAU,UAAU;gBAC3D,MAAM6B,kBAAkB7B,MAAM8B,KAAK,CAAC,KAAKzC,GAAG,CAAC,CAAC0C,OAASxB,SAASQ,QAAQ,CAAC,CAAC,EAAEgB,KAAK,CAAC,CAAC;gBACnF,MAAMC,gBAAgBrE,OAAOkE;gBAE7B,IAAIG,eAAe;oBACjBpD,YAAYY,IAAI,CAACwC;gBACnB;gBACA;YACF;YAEApD,YAAYY,IAAI,CAACe,SAASQ,QAAQf;QACpC;IACF;IAEA,OAAOrC,OAAOiB;AAChB,EAAC;AAED,MAAMc,mBAAmB,CAAC,EACxBnB,OAAO,EACPC,UAAU,EACVmB,UAAU,EACVlB,KAAK,EACLE,SAAS,EAGqC;IAC9C,MAAMuC,WAAWvC,UAAUsD,GAAG,CAACtC;IAE/B,IAAI,CAACuB,UAAU;QACb,MAAM,IAAIjD,WAAW;YAAC;gBAAEiB,MAAMS;YAAW;SAAE;IAC7C;IAEA,IAAIuB,SAASjB,IAAI,KAAK,WAAW;QAC/B,OAAO;YAAEA,MAAM;YAAWiB;QAAS;IACrC;IAEA,IAAIvB,eAAe,cAAc;QAC/B,OAAO;YACLM,MAAM;YACNc,QAAQ/C,GAAG,CAAC,EAAEQ,WAAW,CAAC;YAC1B0C;YACAE,mBAAmB;gBACjBnB,MAAM;gBACNG,OAAO;oBAAE8B,MAAM;oBAAcjC,MAAM;gBAAO;gBAC1CK,QAAQ;YACV;QACF;IACF;IAEA,IAAIY,SAASjB,IAAI,KAAK,iBAAiB;QACrC,MAAMI,eAAe;eAAIa,SAASiB,kBAAkB,CAACC,MAAM;SAAG,CAACC,IAAI,CACjE,CAACjC,QAAUA,MAAMH,IAAI,KAAK,kBACzBG;QAEH,IAAI,CAACC,cAAc;YACjB,OAAO;gBAAEJ,MAAM;gBAAWiB;YAAS;QACrC;QAEA,OAAO;YACLjB,MAAM;YACNI;YACAW,gBAAgBsB,2BAA2B;gBACzC/D;gBACAC;gBACA0C;gBACAzC;YACF;YACAyC;QACF;IACF;IAEA,MAAMqB,kBAAkBrB,SAASiB,kBAAkB,CAACF,GAAG,CAACzD;IACxD,MAAM6B,eAAekC,iBAAiBtC,SAAS,WAAWsC,kBAAkBZ;IAC5E,MAAMP,oBACJf,gBACA;WAAIa,SAASiB,kBAAkB,CAACC,MAAM;KAAG,CAACC,IAAI,CAC5C,CAACjC,QAAqCA,MAAMH,IAAI,KAAK;IAGzD,IAAI,CAACmB,mBAAmB;QACtB,OAAO;YAAEnB,MAAM;YAAWiB;QAAS;IACrC;IAEA,IAAIH,SAAS/C,GAAG,CAAC,IAAI,CAAC;IAEtB,IAAIqC,cAAc;QAChB,MAAMmC,aAAanC,aAAaoC,WAAW,GACvClE,QAAQmE,MAAM,CAAC,GAAG9E,aAAaa,SAASF,QAAQoE,aAAa,EAAE,CAAC,GAChElE;QAEJsC,SAASyB,UAAU,CAACtB,SAASC,UAAU,CAAC;IAC1C;IAEA,OAAO;QACLlB,MAAM;QACNc;QACAG;QACAE;IACF;AACF;AAEA,MAAMkB,6BAA6B,CAAC,EAClC/D,OAAO,EACPC,UAAU,EACV0C,QAAQ,EACRzC,KAAK,EAMN;IACC,IAAIyC,SAASiB,kBAAkB,CAACF,GAAG,CAACzD,aAAayB,SAAS,iBAAiB;QACzE,OAAO1B,QAAQ2D,IAAI,KAAK,aAAa,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;IAC7D;IAEA,MAAMU,kBAAkB1B,SAASvB,UAAU,CACxCmC,KAAK,CAAC,KACNzC,GAAG,CAAC,CAACwD,cAAgB3E,YAAY2E,cACjCC,IAAI,CAAC;IACR,MAAMC,kBAAkBxE,QAAQyE,YAAY,CAACf,GAAG,CAAC,GAAG/D,YAAYM,YAAY,CAAC,EAAEoE,iBAAiB;IAEhG,IAAI,CAACG,iBAAiB;QACpB,MAAM,IAAIE,MACR,CAAC,6BAA6B,EAAEzE,WAAW,0BAA0B,EAAE0C,SAASvB,UAAU,CAAC,CAAC,CAAC;IAEjG;IAEA,IAAIuD,2BAA2BH;IAC/B,IAAII,kBAAkBvF,aAAaa;IAEnC,IAAIF,QAAQ6E,UAAU,EAAE;QACtBF,2BAA2B,CAAC,CAAC,EAAE3E,QAAQ6E,UAAU,CAAC,GAAG,EAAEL,gBAAgB,CAAC,CAAC;QACzEI,kBAAkB,CAAC,CAAC,EAAE5E,QAAQ6E,UAAU,CAAC,GAAG,EAAED,gBAAgB,CAAC,CAAC;IAClE;IAEA,IAAI5E,QAAQ2D,IAAI,KAAK,YAAY;QAC/B,OAAO,CAAC,2BAA2B,EAAEgB,yBAAyB,2BAA2B,EAAEA,yBAAyB,OAAO,EAAEA,yBAAyB,aAAa,EAAEC,gBAAgB,IAAI,CAAC;IAC5L;IAEA,OAAO,CAAC,yBAAyB,EAAED,yBAAyB,aAAa,EAAEA,yBAAyB,OAAO,EAAEA,yBAAyB,aAAa,EAAEC,gBAAgB,IAAI,CAAC;AAC5K"}
@@ -2,6 +2,7 @@ import { type FlattenedField, type Where } from 'payload';
2
2
  import type { DrizzleAdapter } from '../types.js';
3
3
  export type ScalarWhereField = {
4
4
  field: FlattenedField;
5
+ isLocalized?: boolean;
5
6
  isUUID: boolean;
6
7
  type: 'scalar';
7
8
  };
@@ -22,7 +23,7 @@ export type PolymorphicJoinWherePlan = Map<string, WherePathPlan>;
22
23
  * whether the path uses a scalar column or a has-many select value table. A field may be absent
23
24
  * from some target collections; those branches compare against SQL NULL or an empty JSON array.
24
25
  *
25
- * Paths are marked as invalid when their storage shapes conflict, require localized or separate-row
26
+ * Paths are marked as invalid when their storage shapes conflict, require separate-row
26
27
  * traversal, have no matching field, lack a required column, or collide after path flattening.
27
28
  *
28
29
  * @returns A plan keyed by each unique schema path in `where`.
@@ -1 +1 @@
1
- {"version":3,"file":"createPolymorphicJoinWherePlan.d.ts","sourceRoot":"","sources":["../../src/find/createPolymorphicJoinWherePlan.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAAkB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AAGzE,OAAO,KAAK,EAAE,cAAc,EAAgB,MAAM,aAAa,CAAA;AAK/D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,cAAc,CAAA;IACrB,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,QAAQ,CAAA;CACf,CAAA;AAED,KAAK,oBAAoB,GAAG;IAAE,KAAK,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GAAG,gBAAgB,CAAA;AAE/F,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;IACrD,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,eAAe,GAAG,SAAS,GAAG,QAAQ,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;AAEjE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,8BAA8B,qCAIxC;IACD,OAAO,EAAE,cAAc,CAAA;IACvB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,KAAK,EAAE,KAAK,CAAA;CACb,KAAG,wBAoIH,CAAA"}
1
+ {"version":3,"file":"createPolymorphicJoinWherePlan.d.ts","sourceRoot":"","sources":["../../src/find/createPolymorphicJoinWherePlan.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,cAAc,EAAkB,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AAGzE,OAAO,KAAK,EAAE,cAAc,EAAgB,MAAM,aAAa,CAAA;AAK/D,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,cAAc,CAAA;IACrB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,EAAE,OAAO,CAAA;IACf,IAAI,EAAE,QAAQ,CAAA;CACf,CAAA;AAED,KAAK,oBAAoB,GAAG;IAAE,KAAK,EAAE,cAAc,CAAC;IAAC,IAAI,EAAE,eAAe,CAAA;CAAE,GAAG,gBAAgB,CAAA;AAE/F,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,MAAM,CAAA;IAClB,kBAAkB,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;IACrD,UAAU,EAAE,MAAM,CAAA;IAClB,IAAI,EAAE,eAAe,GAAG,SAAS,GAAG,QAAQ,CAAA;CAC7C,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;AAEjE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,8BAA8B,qCAIxC;IACD,OAAO,EAAE,cAAc,CAAA;IACvB,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,KAAK,EAAE,KAAK,CAAA;CACb,KAAG,wBA0IH,CAAA"}