@payloadcms/drizzle 4.0.0-internal.f05c47f → 4.0.0-internal.f15737c

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.
Files changed (205) hide show
  1. package/dist/count.d.ts.map +1 -1
  2. package/dist/count.js +2 -8
  3. package/dist/count.js.map +1 -1
  4. package/dist/createGlobalVersion.d.ts.map +1 -1
  5. package/dist/createGlobalVersion.js +2 -15
  6. package/dist/createGlobalVersion.js.map +1 -1
  7. package/dist/createVersion.d.ts.map +1 -1
  8. package/dist/createVersion.js +1 -12
  9. package/dist/createVersion.js.map +1 -1
  10. package/dist/deleteOne.d.ts.map +1 -1
  11. package/dist/deleteOne.js +1 -18
  12. package/dist/deleteOne.js.map +1 -1
  13. package/dist/exports/postgres.d.ts +3 -0
  14. package/dist/exports/postgres.d.ts.map +1 -1
  15. package/dist/exports/postgres.js +3 -0
  16. package/dist/exports/postgres.js.map +1 -1
  17. package/dist/exports/sqlite.d.ts +1 -0
  18. package/dist/exports/sqlite.d.ts.map +1 -1
  19. package/dist/exports/sqlite.js +1 -0
  20. package/dist/exports/sqlite.js.map +1 -1
  21. package/dist/find/buildFindManyArgs.d.ts +2 -3
  22. package/dist/find/buildFindManyArgs.d.ts.map +1 -1
  23. package/dist/find/buildFindManyArgs.js +1 -2
  24. package/dist/find/buildFindManyArgs.js.map +1 -1
  25. package/dist/find/buildPolymorphicJoinQuery.d.ts +38 -0
  26. package/dist/find/buildPolymorphicJoinQuery.d.ts.map +1 -0
  27. package/dist/find/buildPolymorphicJoinQuery.js +135 -0
  28. package/dist/find/buildPolymorphicJoinQuery.js.map +1 -0
  29. package/dist/find/buildPolymorphicJoinWhere.d.ts +20 -0
  30. package/dist/find/buildPolymorphicJoinWhere.d.ts.map +1 -0
  31. package/dist/find/buildPolymorphicJoinWhere.js +301 -0
  32. package/dist/find/buildPolymorphicJoinWhere.js.map +1 -0
  33. package/dist/find/createPolymorphicJoinWherePlan.d.ts +37 -0
  34. package/dist/find/createPolymorphicJoinWherePlan.d.ts.map +1 -0
  35. package/dist/find/createPolymorphicJoinWherePlan.js +191 -0
  36. package/dist/find/createPolymorphicJoinWherePlan.js.map +1 -0
  37. package/dist/find/findMany.d.ts.map +1 -1
  38. package/dist/find/findMany.js +0 -1
  39. package/dist/find/findMany.js.map +1 -1
  40. package/dist/find/traverseFields.d.ts +2 -3
  41. package/dist/find/traverseFields.d.ts.map +1 -1
  42. package/dist/find/traverseFields.js +20 -215
  43. package/dist/find/traverseFields.js.map +1 -1
  44. package/dist/find.d.ts.map +1 -1
  45. package/dist/find.js +3 -17
  46. package/dist/find.js.map +1 -1
  47. package/dist/findGlobal.d.ts.map +1 -1
  48. package/dist/findGlobal.js +4 -16
  49. package/dist/findGlobal.js.map +1 -1
  50. package/dist/findGlobalVersions.js +3 -8
  51. package/dist/findGlobalVersions.js.map +1 -1
  52. package/dist/findOne.d.ts +1 -1
  53. package/dist/findOne.d.ts.map +1 -1
  54. package/dist/findOne.js +2 -15
  55. package/dist/findOne.js.map +1 -1
  56. package/dist/index.d.ts +4 -2
  57. package/dist/index.d.ts.map +1 -1
  58. package/dist/index.js +2 -0
  59. package/dist/index.js.map +1 -1
  60. package/dist/migrate.d.ts.map +1 -1
  61. package/dist/migrate.js +41 -15
  62. package/dist/migrate.js.map +1 -1
  63. package/dist/migrateDown.d.ts +2 -1
  64. package/dist/migrateDown.d.ts.map +1 -1
  65. package/dist/migrateDown.js +17 -4
  66. package/dist/migrateDown.js.map +1 -1
  67. package/dist/migrateFresh.d.ts +4 -2
  68. package/dist/migrateFresh.d.ts.map +1 -1
  69. package/dist/migrateFresh.js +26 -9
  70. package/dist/migrateFresh.js.map +1 -1
  71. package/dist/migrateRefresh.d.ts +2 -1
  72. package/dist/migrateRefresh.d.ts.map +1 -1
  73. package/dist/migrateRefresh.js +20 -5
  74. package/dist/migrateRefresh.js.map +1 -1
  75. package/dist/migrateReset.d.ts +2 -1
  76. package/dist/migrateReset.d.ts.map +1 -1
  77. package/dist/migrateReset.js +18 -4
  78. package/dist/migrateReset.js.map +1 -1
  79. package/dist/migrateStatus.d.ts +2 -1
  80. package/dist/migrateStatus.d.ts.map +1 -1
  81. package/dist/migrateStatus.js +11 -6
  82. package/dist/migrateStatus.js.map +1 -1
  83. package/dist/postgres/createJSONQuery/index.js +3 -3
  84. package/dist/postgres/createJSONQuery/index.js.map +1 -1
  85. package/dist/postgres/init.d.ts.map +1 -1
  86. package/dist/postgres/init.js +6 -0
  87. package/dist/postgres/init.js.map +1 -1
  88. package/dist/postgres/predefinedMigrations/sizes-to-variants/index.d.ts +35 -0
  89. package/dist/postgres/predefinedMigrations/sizes-to-variants/index.d.ts.map +1 -0
  90. package/dist/postgres/predefinedMigrations/sizes-to-variants/index.js +185 -0
  91. package/dist/postgres/predefinedMigrations/sizes-to-variants/index.js.map +1 -0
  92. package/dist/postgres/predefinedMigrations/v2-v3/fetchAndResave/index.d.ts.map +1 -1
  93. package/dist/postgres/predefinedMigrations/v2-v3/fetchAndResave/index.js +8 -4
  94. package/dist/postgres/predefinedMigrations/v2-v3/fetchAndResave/index.js.map +1 -1
  95. package/dist/postgres/predefinedMigrations/v2-v3/index.js +1 -1
  96. package/dist/postgres/predefinedMigrations/v2-v3/index.js.map +1 -1
  97. package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.d.ts +15 -0
  98. package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.d.ts.map +1 -0
  99. package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.js +25 -0
  100. package/dist/postgres/query/assertOperatorHandlerExtensionsInstalled.js.map +1 -0
  101. package/dist/postgres/query/postgresUnaccent.d.ts +13 -0
  102. package/dist/postgres/query/postgresUnaccent.d.ts.map +1 -0
  103. package/dist/postgres/query/postgresUnaccent.js +40 -0
  104. package/dist/postgres/query/postgresUnaccent.js.map +1 -0
  105. package/dist/postgres/types.d.ts +13 -2
  106. package/dist/postgres/types.d.ts.map +1 -1
  107. package/dist/postgres/types.js.map +1 -1
  108. package/dist/queries/buildOperatorConstraint.d.ts +22 -0
  109. package/dist/queries/buildOperatorConstraint.d.ts.map +1 -0
  110. package/dist/queries/buildOperatorConstraint.js +63 -0
  111. package/dist/queries/buildOperatorConstraint.js.map +1 -0
  112. package/dist/queries/getTableColumnFromPath.d.ts +12 -3
  113. package/dist/queries/getTableColumnFromPath.d.ts.map +1 -1
  114. package/dist/queries/getTableColumnFromPath.js +59 -27
  115. package/dist/queries/getTableColumnFromPath.js.map +1 -1
  116. package/dist/queries/operatorMap.d.ts +7 -3
  117. package/dist/queries/operatorMap.d.ts.map +1 -1
  118. package/dist/queries/operatorMap.js.map +1 -1
  119. package/dist/queries/parseParams.d.ts.map +1 -1
  120. package/dist/queries/parseParams.js +262 -10
  121. package/dist/queries/parseParams.js.map +1 -1
  122. package/dist/queries/resolveRelationshipPath.d.ts +36 -0
  123. package/dist/queries/resolveRelationshipPath.d.ts.map +1 -0
  124. package/dist/queries/resolveRelationshipPath.js +66 -0
  125. package/dist/queries/resolveRelationshipPath.js.map +1 -0
  126. package/dist/queries/validateOperatorHandlers.d.ts +8 -0
  127. package/dist/queries/validateOperatorHandlers.d.ts.map +1 -0
  128. package/dist/queries/validateOperatorHandlers.js +30 -0
  129. package/dist/queries/validateOperatorHandlers.js.map +1 -0
  130. package/dist/queryDrafts.d.ts.map +1 -1
  131. package/dist/queryDrafts.js +3 -10
  132. package/dist/queryDrafts.js.map +1 -1
  133. package/dist/schema/build.d.ts.map +1 -1
  134. package/dist/schema/build.js +4 -5
  135. package/dist/schema/build.js.map +1 -1
  136. package/dist/sqlite/createJSONQuery/convertPathToJSONTraversal.js +3 -2
  137. package/dist/sqlite/createJSONQuery/convertPathToJSONTraversal.js.map +1 -1
  138. package/dist/sqlite/createJSONQuery/index.d.ts.map +1 -1
  139. package/dist/sqlite/createJSONQuery/index.js +6 -5
  140. package/dist/sqlite/createJSONQuery/index.js.map +1 -1
  141. package/dist/sqlite/insert.d.ts.map +1 -1
  142. package/dist/sqlite/insert.js +4 -1
  143. package/dist/sqlite/insert.js.map +1 -1
  144. package/dist/sqlite/predefinedMigrations/sizes-to-variants/index.d.ts +15 -0
  145. package/dist/sqlite/predefinedMigrations/sizes-to-variants/index.d.ts.map +1 -0
  146. package/dist/sqlite/predefinedMigrations/sizes-to-variants/index.js +114 -0
  147. package/dist/sqlite/predefinedMigrations/sizes-to-variants/index.js.map +1 -0
  148. package/dist/transform/write/traverseFields.d.ts.map +1 -1
  149. package/dist/transform/write/traverseFields.js +8 -14
  150. package/dist/transform/write/traverseFields.js.map +1 -1
  151. package/dist/types.d.ts +50 -2
  152. package/dist/types.d.ts.map +1 -1
  153. package/dist/types.js.map +1 -1
  154. package/dist/updateGlobal.d.ts +1 -1
  155. package/dist/updateGlobal.d.ts.map +1 -1
  156. package/dist/updateGlobal.js +3 -30
  157. package/dist/updateGlobal.js.map +1 -1
  158. package/dist/updateOne.d.ts.map +1 -1
  159. package/dist/updateOne.js +43 -9
  160. package/dist/updateOne.js.map +1 -1
  161. package/dist/upsertRow/index.d.ts +1 -1
  162. package/dist/upsertRow/index.d.ts.map +1 -1
  163. package/dist/upsertRow/index.js +25 -5
  164. package/dist/upsertRow/index.js.map +1 -1
  165. package/dist/utilities/buildCreateMigration.d.ts.map +1 -1
  166. package/dist/utilities/buildCreateMigration.js +12 -8
  167. package/dist/utilities/buildCreateMigration.js.map +1 -1
  168. package/dist/utilities/buildDynamicPredefinedSizesToVariantsMigration.d.ts +15 -0
  169. package/dist/utilities/buildDynamicPredefinedSizesToVariantsMigration.d.ts.map +1 -0
  170. package/dist/utilities/buildDynamicPredefinedSizesToVariantsMigration.js +110 -0
  171. package/dist/utilities/buildDynamicPredefinedSizesToVariantsMigration.js.map +1 -0
  172. package/dist/utilities/buildForeignKeyName.d.ts.map +1 -1
  173. package/dist/utilities/buildForeignKeyName.js +3 -2
  174. package/dist/utilities/buildForeignKeyName.js.map +1 -1
  175. package/dist/utilities/buildIndexName.d.ts.map +1 -1
  176. package/dist/utilities/buildIndexName.js +3 -2
  177. package/dist/utilities/buildIndexName.js.map +1 -1
  178. package/dist/utilities/checkTruncatedIdentifiers.d.ts +13 -0
  179. package/dist/utilities/checkTruncatedIdentifiers.d.ts.map +1 -0
  180. package/dist/utilities/checkTruncatedIdentifiers.js +56 -0
  181. package/dist/utilities/checkTruncatedIdentifiers.js.map +1 -0
  182. package/dist/utilities/createSchemaGenerator.d.ts.map +1 -1
  183. package/dist/utilities/createSchemaGenerator.js +3 -0
  184. package/dist/utilities/createSchemaGenerator.js.map +1 -1
  185. package/dist/utilities/getSizesToVariantsRenames.d.ts +54 -0
  186. package/dist/utilities/getSizesToVariantsRenames.d.ts.map +1 -0
  187. package/dist/utilities/getSizesToVariantsRenames.js +249 -0
  188. package/dist/utilities/getSizesToVariantsRenames.js.map +1 -0
  189. package/dist/utilities/parseJSONPathSegment.d.ts +9 -0
  190. package/dist/utilities/parseJSONPathSegment.d.ts.map +1 -0
  191. package/dist/utilities/parseJSONPathSegment.js +17 -0
  192. package/dist/utilities/parseJSONPathSegment.js.map +1 -0
  193. package/dist/utilities/validateIdentifierLength.d.ts +5 -0
  194. package/dist/utilities/validateIdentifierLength.d.ts.map +1 -1
  195. package/dist/utilities/validateIdentifierLength.js +4 -0
  196. package/dist/utilities/validateIdentifierLength.js.map +1 -1
  197. package/package.json +3 -3
  198. package/dist/schema/buildRawSchema.spec.js +0 -230
  199. package/dist/schema/buildRawSchema.spec.js.map +0 -1
  200. package/dist/upsertRow/handleUpsertError.spec.js +0 -42
  201. package/dist/upsertRow/handleUpsertError.spec.js.map +0 -1
  202. package/dist/utilities/isValidStringID.spec.js +0 -15
  203. package/dist/utilities/isValidStringID.spec.js.map +0 -1
  204. package/dist/utilities/validateIdentifierLength.spec.js +0 -19
  205. package/dist/utilities/validateIdentifierLength.spec.js.map +0 -1
@@ -0,0 +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 locale?: string\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 locale,\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 locale,\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","locale","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;AAqBpF;;;;;;;;;;;;;;CAcC,GACD,OAAO,MAAMC,4BAA4B,CAAC,EACxCC,OAAO,EACPC,gBAAgB,EAChBC,KAAK,EACLC,KAAK,EACLC,MAAM,EACNC,IAAI,EACJC,IAAI,EACJC,WAAW,EACXC,IAAI,EACJC,KAAK,EACyB;IAC9B,IAAI,CAACC,MAAMC,OAAO,CAACT,MAAMU,UAAU,GAAG;QACpC,MAAM,IAAIC,MAAM;IAClB;IAEA,IAAIX,MAAMU,UAAU,CAACE,MAAM,KAAK,GAAG;QACjC,MAAM,IAAID,MAAM;IAClB;IAEA,IAAIH,MAAMC,OAAO,CAACH,OAAO;QACvB,MAAM,IAAIK,MAAM;IAClB;IAEA,MAAME,cAAcb,MAAMU,UAAU;IACpC,MAAMI,aAAa,GAAGV,KAAKW,UAAU,CAAC,KAAK,OAAOf,MAAMgB,IAAI,EAAE;IAC9D,MAAMC,KAAKnB,QAAQoB,OAAO;IAC1B,MAAMC,SAASnB,MAAMoB,EAAE,CAACC,KAAK,CAAC,KAAKC,IAAI,CAAC;IACxC,MAAMC,mBAAmBV,YAAYW,GAAG,CAAC,CAACd;QACxC,IAAI,CAACZ,QAAQ2B,OAAO,CAACZ,WAAW,CAACH,WAAW,EAAE;YAC5C,MAAM,IAAIC,MAAM,CAAC,qCAAqC,EAAED,WAAW,CAAC,CAAC;QACvE;QAEA,MAAMgB,YAAY5B,QAAQ6B,YAAY,CAACC,GAAG,CAACnC,YAAYiB;QACvD,MAAMmB,QAAQH,YAAa5B,QAAQgC,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;QAAEnC;QAASe;QAAaP;IAAK;IAC5D,MAAM4B,YAAYF,UAAUG,UAAU,CAAC,OAAO7C,OAAOF;IACrD,MAAMgD,WAAWJ,UAAUK,OAAO,CAAC,KAAK,IAAIhB,KAAK,CAAC,KAAKC,IAAI,CAAC;IAC5D,MAAMgB,YAAsC/B,QACxCX,+BAA+B;QAAEE;QAASe;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,QAAQpD,GAAG,CAAC,EAAEqC,KAAK,CAACV,OAAO,CAAC,CAAC,CAAC0B,EAAE,CAAC1B;YACjC2B,YAAYtD,GAAG,CAAC,EAAEkB,WAAW,CAAC,CAACmC,EAAE,CAAC;YAClCT,UAAU5C,GAAG,CAAC,EAAEiD,cAAc,KAAK,CAAC,CAACI,EAAE,CAAC;QAC1C;QACA,MAAME,kBACJxC,SAASyC,OAAOC,IAAI,CAAC1C,OAAOK,MAAM,GAAG,IACjCjB,0BAA0B;YACxBG;YACAY;YACAR;YACA2B;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,mBAAmBjE,GACvBC,IAAIiE,GAAG,CAAC,CAAC,CAAC,EAAE1D,iBAAiB,MAAM,CAAC,GACpCP,IAAIiE,GAAG,CAAC,CAAC,CAAC,EAAEF,cAAc,GAAG,EAAEpC,OAAO,CAAC,CAAC;IAE1C,MAAMuC,kBAAkBrD,cACpBb,GAAG,CAAC,EAAEyB,GACHkC,MAAM,CAAC;QAAE9D,OAAOA;IAAQ,GACxB+D,IAAI,CAAC5D,GAAG,CAAC,EAAEgD,WAAWK,EAAE,CAACU,eAAe,CAAC,EACzChD,KAAK,CAACiD,kBAAkB,CAAC,CAACX,EAAE,CAAC,GAAG/B,WAAW,MAAM,CAAC,IACrDiB;IAEJS,aAAaA,WAAWmB,OAAO,CAACzB,UAAU1C,GAAG,CAAC,UAAU,CAAC;IAEzD,MAAMoE,mBAAmB,GAAG9C,WAAW,OAAO,CAAC;IAC/C,IAAI+C,iBAAiBrE,IAAIsE,KAAK;IAE9B,IAAI7D,OAAO;QACT4D,iBAAiBrE,GAAG,CAAC,OAAO,EAAES,MAAM,CAAC;IACvC;IAEA,IAAIE,QAAQF,UAAU,GAAG;QACvB,MAAM8D,SAAS,AAAC5D,CAAAA,OAAO,CAAA,IAAKF;QAE5B,IAAI8D,SAAS,GAAG;YACdF,iBAAiBrE,GAAG,CAAC,EAAEqE,eAAe,QAAQ,EAAEE,OAAO,CAAC;QAC1D;IACF;IAEA,MAAMC,cAAcxE,IAAIiE,GAAG,CAAC,CAAC,CAAC,EAAEG,iBAAiB,GAAG,EAAEzC,OAAO,KAAK,EAAEpB,iBAAiB,MAAM,CAAC;IAC5F,MAAMkE,YAAYzE,GAAG,CAAC;WACb,EAAEE,mBAAmBI,SAAS;QACnC6C,IAAInD,IAAIiE,GAAG,CAAC,CAAC,CAAC,EAAEF,cAAc,MAAM,CAAC;QACrCT,YAAYtD,IAAIiE,GAAG,CAAC,CAAC,CAAC,EAAEF,cAAc,cAAc,CAAC;IACvD,GAAG;;oBAEa,EAAE/D,GAAG,CAAC,EAAEgD,WAAWK,EAAE,CAACe,kBAAkB,CAAC,CAAC;YAClD,EAAEI,YAAY,EAAEH,eAAe;SAClC,EAAErE,IAAIiE,GAAG,CAAC,CAAC,CAAC,EAAEF,cAAc,CAAC,CAAC,EAAE;GACtC,CAAC,CAACV,EAAE,CAAC/B;IAEN,OAAO;QACLA;QACAzB,OAAOqE;QACPO;IACF;AACF,EAAC;AAED,MAAMhC,eAAe,CAAC,EACpBnC,OAAO,EACPe,WAAW,EACXP,IAAI,EAKL;IACC,IAAIA,MAAM;QACR,OAAOA;IACT;IAEA,MAAM4D,eAAerD,YAAYsD,IAAI,CAAC,CAACzD,aACrCZ,QAAQ2B,OAAO,CAACZ,WAAW,CAACH,WAAW,CAAC0D,MAAM,CAACC,MAAM,CAACF,IAAI,CACxD,CAACnE,QAAUA,MAAMsE,IAAI,KAAK,UAAUtE,MAAMgB,IAAI,KAAK;IAIvD,OAAOkD,eAAe,eAAe;AACvC"}
@@ -0,0 +1,20 @@
1
+ import type { SQL } from 'drizzle-orm';
2
+ import { type Where } from 'payload';
3
+ import type { DrizzleAdapter, GenericTable } from '../types.js';
4
+ import type { PolymorphicJoinWherePlan } from './createPolymorphicJoinWherePlan.js';
5
+ type BuildPolymorphicJoinWhereArgs = {
6
+ adapter: DrizzleAdapter;
7
+ collection: string;
8
+ locale?: string;
9
+ table: GenericTable;
10
+ where: Where;
11
+ wherePlan: PolymorphicJoinWherePlan;
12
+ };
13
+ /**
14
+ * Builds a where clause for one collection before the polymorphic branches are combined. A field
15
+ * that is absent from this collection resolves to SQL NULL, and relationTo resolves to the current
16
+ * collection slug.
17
+ */
18
+ export declare const buildPolymorphicJoinWhere: ({ adapter, collection, locale, table, where, wherePlan, }: BuildPolymorphicJoinWhereArgs) => SQL | undefined;
19
+ export {};
20
+ //# sourceMappingURL=buildPolymorphicJoinWhere.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildPolymorphicJoinWhere.d.ts","sourceRoot":"","sources":["../../src/find/buildPolymorphicJoinWhere.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAU,GAAG,EAAE,MAAM,aAAa,CAAA;AAG9C,OAAO,EAAkD,KAAK,KAAK,EAAE,MAAM,SAAS,CAAA;AAIpF,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/D,OAAO,KAAK,EACV,wBAAwB,EAGzB,MAAM,qCAAqC,CAAA;AAO5C,KAAK,6BAA6B,GAAG;IACnC,OAAO,EAAE,cAAc,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,YAAY,CAAA;IACnB,KAAK,EAAE,KAAK,CAAA;IACZ,SAAS,EAAE,wBAAwB,CAAA;CACpC,CAAA;AAqBD;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,8DAOnC,6BAA6B,KAAG,GAAG,GAAG,SAsMxC,CAAA"}
@@ -0,0 +1,301 @@
1
+ import { and, getTableName, isNotNull, isNull, or, sql } from 'drizzle-orm';
2
+ import { QueryError } from 'payload';
3
+ import toSnakeCase from 'to-snake-case';
4
+ import { buildOperatorConstraint } from '../queries/buildOperatorConstraint.js';
5
+ import { sanitizeQueryValue } from '../queries/sanitizeQueryValue.js';
6
+ const supportedJSONQueryOperators = new Set([
7
+ 'contains',
8
+ 'equals',
9
+ 'exists',
10
+ 'in',
11
+ 'like'
12
+ ]);
13
+ /**
14
+ * Builds a where clause for one collection before the polymorphic branches are combined. A field
15
+ * that is absent from this collection resolves to SQL NULL, and relationTo resolves to the current
16
+ * collection slug.
17
+ */ export const buildPolymorphicJoinWhere = ({ adapter, collection, locale, table, where, wherePlan })=>{
18
+ const constraints = [];
19
+ for(const key in where){
20
+ if ([
21
+ 'AND',
22
+ 'OR'
23
+ ].includes(key.toUpperCase())) {
24
+ if (!Array.isArray(where[key])) {
25
+ throw new QueryError([
26
+ {
27
+ path: key
28
+ }
29
+ ]);
30
+ }
31
+ const combine = key.toUpperCase() === 'AND' ? and : or;
32
+ const nestedConstraints = where[key].map((nestedWhere)=>buildPolymorphicJoinWhere({
33
+ adapter,
34
+ collection,
35
+ locale,
36
+ table,
37
+ where: nestedWhere,
38
+ wherePlan
39
+ }));
40
+ const nestedCondition = combine(...nestedConstraints);
41
+ if (nestedCondition) {
42
+ constraints.push(nestedCondition);
43
+ }
44
+ continue;
45
+ }
46
+ const resolvedPath = resolveWherePath({
47
+ adapter,
48
+ collection,
49
+ schemaPath: key,
50
+ table,
51
+ wherePlan
52
+ });
53
+ for (let payloadOperator of Object.keys(where[key])){
54
+ const originalOperator = payloadOperator;
55
+ let value = where[key][payloadOperator];
56
+ if (resolvedPath.type === 'invalid') {
57
+ throw new QueryError([
58
+ {
59
+ path: `${key}.${payloadOperator}`
60
+ }
61
+ ]);
62
+ }
63
+ if (resolvedPath.type === 'hasManySelect') {
64
+ if (!supportedJSONQueryOperators.has(payloadOperator)) {
65
+ throw new QueryError([
66
+ {
67
+ path: `${key}.${payloadOperator}`
68
+ }
69
+ ]);
70
+ }
71
+ const sanitizedQueryValue = sanitizeQueryValue({
72
+ adapter,
73
+ field: resolvedPath.fieldContext,
74
+ isUUID: false,
75
+ operator: payloadOperator,
76
+ relationOrPath: key,
77
+ val: value
78
+ });
79
+ if (sanitizedQueryValue === null) {
80
+ throw new QueryError([
81
+ {
82
+ path: `${key}.${originalOperator}`
83
+ }
84
+ ]);
85
+ }
86
+ if (sanitizedQueryValue.columns) {
87
+ throw new QueryError([
88
+ {
89
+ path: `${key}.${originalOperator}`
90
+ }
91
+ ]);
92
+ }
93
+ value = sanitizedQueryValue.value;
94
+ if (payloadOperator === 'in' && Array.isArray(value) && value.length === 0) {
95
+ constraints.push(sql.raw('false'));
96
+ continue;
97
+ }
98
+ const jsonQueryOperator = payloadOperator === 'exists' ? 'exists' : sanitizedQueryValue.operator;
99
+ constraints.push(sql.raw(adapter.createJSONQuery({
100
+ column: resolvedPath.jsonExpression,
101
+ operator: jsonQueryOperator,
102
+ pathSegments: [
103
+ resolvedPath.pathPlan.columnPath
104
+ ],
105
+ value
106
+ })));
107
+ continue;
108
+ }
109
+ if (payloadOperator === '$raw') {
110
+ if (typeof value !== 'string') {
111
+ throw new QueryError([
112
+ {
113
+ path: `${key}.${payloadOperator}`
114
+ }
115
+ ]);
116
+ }
117
+ constraints.push(sql.raw(value));
118
+ continue;
119
+ }
120
+ const { column, fieldContext, queryValueContext } = resolvedPath;
121
+ if (payloadOperator === 'like' && (queryValueContext.field.type === 'number' || queryValueContext.field.type === 'relationship' || queryValueContext.field.type === 'upload' || queryValueContext.isUUID)) {
122
+ payloadOperator = 'equals';
123
+ }
124
+ const sanitizedQueryValue = sanitizeQueryValue({
125
+ adapter,
126
+ field: queryValueContext.field,
127
+ isUUID: queryValueContext.isUUID,
128
+ operator: payloadOperator,
129
+ relationOrPath: key,
130
+ val: value
131
+ });
132
+ if (sanitizedQueryValue === null) {
133
+ throw new QueryError([
134
+ {
135
+ path: `${key}.${originalOperator}`
136
+ }
137
+ ]);
138
+ }
139
+ if (sanitizedQueryValue.columns) {
140
+ throw new QueryError([
141
+ {
142
+ path: `${key}.${originalOperator}`
143
+ }
144
+ ]);
145
+ }
146
+ payloadOperator = sanitizedQueryValue.operator;
147
+ value = sanitizedQueryValue.value;
148
+ if (!(payloadOperator in adapter.operators)) {
149
+ throw new QueryError([
150
+ {
151
+ path: `${key}.${originalOperator}`
152
+ }
153
+ ]);
154
+ }
155
+ const resolvedOperator = payloadOperator;
156
+ const operator = adapter.operators[resolvedOperator];
157
+ const buildColumnConstraint = (constraintValue)=>{
158
+ if (!fieldContext) {
159
+ return operator(column, constraintValue);
160
+ }
161
+ return buildOperatorConstraint({
162
+ adapter,
163
+ column,
164
+ field: fieldContext.field,
165
+ locale,
166
+ originalOperator,
167
+ path: key,
168
+ resolvedOperator,
169
+ value: constraintValue
170
+ });
171
+ };
172
+ if (originalOperator === 'equals' && value === null) {
173
+ constraints.push(isNull(column));
174
+ continue;
175
+ }
176
+ if (originalOperator === 'not_equals') {
177
+ if (value === null) {
178
+ constraints.push(isNotNull(column));
179
+ } else {
180
+ const notEqualsConstraint = or(isNull(column), buildColumnConstraint(value));
181
+ if (notEqualsConstraint) {
182
+ constraints.push(notEqualsConstraint);
183
+ }
184
+ }
185
+ continue;
186
+ }
187
+ if (originalOperator === 'in' && Array.isArray(value) && value.includes(null)) {
188
+ const nonNullValues = value.filter((item)=>item !== null);
189
+ const inConstraint = buildColumnConstraint(nonNullValues);
190
+ const nullAwareInConstraint = or(isNull(column), inConstraint);
191
+ if (nullAwareInConstraint) {
192
+ constraints.push(nullAwareInConstraint);
193
+ }
194
+ continue;
195
+ }
196
+ if (payloadOperator === 'like' && typeof value === 'string') {
197
+ const wordConstraints = value.split(' ').map((word)=>buildColumnConstraint(`%${word}%`));
198
+ const wordCondition = and(...wordConstraints);
199
+ if (wordCondition) {
200
+ constraints.push(wordCondition);
201
+ }
202
+ continue;
203
+ }
204
+ constraints.push(buildColumnConstraint(value));
205
+ }
206
+ }
207
+ return and(...constraints);
208
+ };
209
+ const resolveWherePath = ({ adapter, collection, schemaPath, table, wherePlan })=>{
210
+ const pathPlan = wherePlan.get(schemaPath);
211
+ if (!pathPlan) {
212
+ throw new QueryError([
213
+ {
214
+ path: schemaPath
215
+ }
216
+ ]);
217
+ }
218
+ if (pathPlan.type === 'invalid') {
219
+ return {
220
+ type: 'invalid',
221
+ pathPlan
222
+ };
223
+ }
224
+ if (schemaPath === 'relationTo') {
225
+ return {
226
+ type: 'scalar',
227
+ column: sql`${collection}`,
228
+ pathPlan,
229
+ queryValueContext: {
230
+ type: 'scalar',
231
+ field: {
232
+ name: 'relationTo',
233
+ type: 'text'
234
+ },
235
+ isUUID: false
236
+ }
237
+ };
238
+ }
239
+ if (pathPlan.type === 'hasManySelect') {
240
+ const fieldContext = [
241
+ ...pathPlan.fieldsByCollection.values()
242
+ ].find((field)=>field.type === 'hasManySelect')?.field;
243
+ if (!fieldContext) {
244
+ return {
245
+ type: 'invalid',
246
+ pathPlan
247
+ };
248
+ }
249
+ return {
250
+ type: 'hasManySelect',
251
+ fieldContext,
252
+ jsonExpression: getHasManySelectExpression({
253
+ adapter,
254
+ collection,
255
+ pathPlan,
256
+ table
257
+ }),
258
+ pathPlan
259
+ };
260
+ }
261
+ const collectionField = pathPlan.fieldsByCollection.get(collection);
262
+ const fieldContext = collectionField?.type === 'scalar' ? collectionField : undefined;
263
+ const queryValueContext = fieldContext ?? [
264
+ ...pathPlan.fieldsByCollection.values()
265
+ ].find((field)=>field.type === 'scalar');
266
+ if (!queryValueContext) {
267
+ return {
268
+ type: 'invalid',
269
+ pathPlan
270
+ };
271
+ }
272
+ return {
273
+ type: 'scalar',
274
+ column: fieldContext ? table[pathPlan.columnPath] : sql`null`,
275
+ fieldContext,
276
+ pathPlan,
277
+ queryValueContext
278
+ };
279
+ };
280
+ const getHasManySelectExpression = ({ adapter, collection, pathPlan, table })=>{
281
+ if (pathPlan.fieldsByCollection.get(collection)?.type !== 'hasManySelect') {
282
+ return adapter.name === 'postgres' ? `'[]'::jsonb` : `'[]'`;
283
+ }
284
+ const selectTablePath = pathPlan.schemaPath.split('.').map((pathSegment)=>toSnakeCase(pathSegment)).join('_');
285
+ const valuesTableName = adapter.tableNameMap.get(`${toSnakeCase(collection)}_${selectTablePath}`);
286
+ if (!valuesTableName) {
287
+ throw new Error(`Polymorphic join collection "${collection}" has no value table for "${pathPlan.schemaPath}"`);
288
+ }
289
+ let qualifiedValuesTableName = valuesTableName;
290
+ let parentTableName = getTableName(table);
291
+ if (adapter.schemaName) {
292
+ qualifiedValuesTableName = `"${adapter.schemaName}"."${valuesTableName}"`;
293
+ parentTableName = `"${adapter.schemaName}"."${parentTableName}"`;
294
+ }
295
+ if (adapter.name === 'postgres') {
296
+ return `(select coalesce(jsonb_agg(${qualifiedValuesTableName}.value), '[]'::jsonb) from ${qualifiedValuesTableName} where ${qualifiedValuesTableName}.parent_id = ${parentTableName}.id)`;
297
+ }
298
+ return `(select json_group_array(${qualifiedValuesTableName}.value) from ${qualifiedValuesTableName} where ${qualifiedValuesTableName}.parent_id = ${parentTableName}.id)`;
299
+ };
300
+
301
+ //# sourceMappingURL=buildPolymorphicJoinWhere.js.map
@@ -0,0 +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, type Operator, QueryError, type Where } from 'payload'\nimport toSnakeCase from 'to-snake-case'\n\nimport type { DrizzleResolvedOperator } from '../queries/operatorMap.js'\nimport type { DrizzleAdapter, GenericTable } from '../types.js'\nimport type {\n PolymorphicJoinWherePlan,\n ScalarWhereField,\n WherePathPlan,\n} from './createPolymorphicJoinWherePlan.js'\n\nimport { buildOperatorConstraint } from '../queries/buildOperatorConstraint.js'\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 locale?: string\n table: GenericTable\n where: Where\n wherePlan: PolymorphicJoinWherePlan\n}\n\ntype ResolvedWherePath =\n | {\n column: Column | SQL\n fieldContext?: ScalarWhereField\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 locale,\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 locale,\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 as Operator\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) {\n throw new QueryError([{ path: `${key}.${originalOperator}` }])\n }\n\n if (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, fieldContext, 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) {\n throw new QueryError([{ path: `${key}.${originalOperator}` }])\n }\n\n if (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 resolvedOperator = payloadOperator as DrizzleResolvedOperator\n const operator = adapter.operators[resolvedOperator]\n const buildColumnConstraint = (constraintValue: unknown) => {\n if (!fieldContext) {\n return operator(column, constraintValue)\n }\n\n return buildOperatorConstraint({\n adapter,\n column,\n field: fieldContext.field,\n locale,\n originalOperator,\n path: key,\n resolvedOperator,\n value: constraintValue,\n })\n }\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), buildColumnConstraint(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 = buildColumnConstraint(nonNullValues)\n const nullAwareInConstraint = or(isNull(column), inConstraint)\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) => buildColumnConstraint(`%${word}%`))\n const wordCondition = and(...wordConstraints)\n\n if (wordCondition) {\n constraints.push(wordCondition)\n }\n continue\n }\n\n constraints.push(buildColumnConstraint(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, 'locale' | '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}`,\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`,\n fieldContext,\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","buildOperatorConstraint","sanitizeQueryValue","supportedJSONQueryOperators","Set","buildPolymorphicJoinWhere","adapter","collection","locale","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","resolvedOperator","buildColumnConstraint","constraintValue","notEqualsConstraint","nonNullValues","filter","item","inConstraint","nullAwareInConstraint","wordConstraints","split","word","wordCondition","get","name","fieldsByCollection","values","find","getHasManySelectExpression","collectionField","undefined","selectTablePath","pathSegment","join","valuesTableName","tableNameMap","Error","qualifiedValuesTableName","parentTableName","schemaName"],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ import { type FlattenedField, type Where } from 'payload';
2
+ import type { DrizzleAdapter } from '../types.js';
3
+ export type ScalarWhereField = {
4
+ field: FlattenedField;
5
+ isUUID: boolean;
6
+ type: 'scalar';
7
+ };
8
+ type CollectionWhereField = {
9
+ field: FlattenedField;
10
+ type: 'hasManySelect';
11
+ } | ScalarWhereField;
12
+ export type WherePathPlan = {
13
+ columnPath: string;
14
+ fieldsByCollection: Map<string, CollectionWhereField>;
15
+ schemaPath: string;
16
+ type: 'hasManySelect' | 'invalid' | 'scalar';
17
+ };
18
+ export type PolymorphicJoinWherePlan = Map<string, WherePathPlan>;
19
+ /**
20
+ * Analyzes every leaf path in a polymorphic join where clause before SQL is built. Each plan entry
21
+ * records the flattened column path, the compatible field shape for each target collection, and
22
+ * whether the path uses a scalar column or a has-many select value table. A field may be absent
23
+ * from some target collections; those branches compare against SQL NULL or an empty JSON array.
24
+ *
25
+ * Paths are marked as invalid when their storage shapes conflict, require localized or separate-row
26
+ * traversal, have no matching field, lack a required column, or collide after path flattening.
27
+ *
28
+ * @returns A plan keyed by each unique schema path in `where`.
29
+ * @throws If a target collection or its mapped database table is not available in the adapter.
30
+ */
31
+ export declare const createPolymorphicJoinWherePlan: ({ adapter, collections, where, }: {
32
+ adapter: DrizzleAdapter;
33
+ collections: string[];
34
+ where: Where;
35
+ }) => PolymorphicJoinWherePlan;
36
+ export {};
37
+ //# sourceMappingURL=createPolymorphicJoinWherePlan.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,191 @@
1
+ import { getFieldByPath } from 'payload';
2
+ import toSnakeCase from 'to-snake-case';
3
+ import { isUUIDType } from '../utilities/isUUIDType.js';
4
+ import { sanitizePathSegment } from '../utilities/sanitizePathSegment.js';
5
+ /**
6
+ * Analyzes every leaf path in a polymorphic join where clause before SQL is built. Each plan entry
7
+ * records the flattened column path, the compatible field shape for each target collection, and
8
+ * whether the path uses a scalar column or a has-many select value table. A field may be absent
9
+ * from some target collections; those branches compare against SQL NULL or an empty JSON array.
10
+ *
11
+ * Paths are marked as invalid when their storage shapes conflict, require localized or separate-row
12
+ * traversal, have no matching field, lack a required column, or collide after path flattening.
13
+ *
14
+ * @returns A plan keyed by each unique schema path in `where`.
15
+ * @throws If a target collection or its mapped database table is not available in the adapter.
16
+ */ export const createPolymorphicJoinWherePlan = ({ adapter, collections, where })=>{
17
+ const collectionContexts = collections.map((collection)=>{
18
+ const collectionConfig = adapter.payload.collections[collection]?.config;
19
+ if (!collectionConfig) {
20
+ throw new Error(`Unknown polymorphic join collection "${collection}"`);
21
+ }
22
+ const tableName = adapter.tableNameMap.get(toSnakeCase(collection));
23
+ const table = tableName ? adapter.tables[tableName] : undefined;
24
+ if (!table) {
25
+ throw new Error(`Polymorphic join collection "${collection}" has no database table`);
26
+ }
27
+ return {
28
+ collection,
29
+ collectionConfig,
30
+ table
31
+ };
32
+ });
33
+ const schemaPathsByColumnPath = new Map();
34
+ const schemaPaths = new Set(getWhereSchemaPaths(where));
35
+ for (const schemaPath of schemaPaths){
36
+ const columnPath = getColumnPath(schemaPath);
37
+ const paths = schemaPathsByColumnPath.get(columnPath) ?? new Set();
38
+ paths.add(schemaPath);
39
+ schemaPathsByColumnPath.set(columnPath, paths);
40
+ }
41
+ const plan = new Map();
42
+ for (const schemaPath of schemaPaths){
43
+ const columnPath = getColumnPath(schemaPath);
44
+ const fieldsByCollection = new Map();
45
+ let isFieldPresent = schemaPath === 'id' || schemaPath === 'relationTo';
46
+ let hasManySelect = false;
47
+ let hasUnsupportedFieldShape = false;
48
+ const scalarQueryValueSignatures = new Set();
49
+ for (const { collection, collectionConfig, table } of collectionContexts){
50
+ const fieldAtPath = getFieldByPath({
51
+ fields: collectionConfig.flattenedFields,
52
+ path: schemaPath
53
+ });
54
+ if (schemaPath === 'id') {
55
+ const idColumn = table['id'];
56
+ if (!idColumn) {
57
+ hasUnsupportedFieldShape = true;
58
+ } else {
59
+ scalarQueryValueSignatures.add(`id:${idColumn.getSQLType()}`);
60
+ fieldsByCollection.set(collection, {
61
+ type: 'scalar',
62
+ field: fieldAtPath?.field ?? {
63
+ name: 'id',
64
+ type: isUUIDType(adapter.idType) ? 'text' : 'number'
65
+ },
66
+ isUUID: !fieldAtPath && isUUIDType(adapter.idType)
67
+ });
68
+ }
69
+ continue;
70
+ }
71
+ if (!fieldAtPath) {
72
+ if (pathHasUnsupportedNestedContainer({
73
+ fields: collectionConfig.flattenedFields,
74
+ path: schemaPath
75
+ })) {
76
+ hasUnsupportedFieldShape = true;
77
+ }
78
+ continue;
79
+ }
80
+ isFieldPresent = true;
81
+ if (fieldAtPath.pathHasLocalized || pathHasSeparateRows({
82
+ fields: collectionConfig.flattenedFields,
83
+ path: schemaPath
84
+ })) {
85
+ hasUnsupportedFieldShape = true;
86
+ continue;
87
+ }
88
+ if (fieldAtPath.field.type === 'select' && fieldAtPath.field.hasMany) {
89
+ hasManySelect = true;
90
+ fieldsByCollection.set(collection, {
91
+ type: 'hasManySelect',
92
+ field: fieldAtPath.field
93
+ });
94
+ continue;
95
+ }
96
+ const fieldColumn = table[columnPath];
97
+ if (!fieldColumn) {
98
+ hasUnsupportedFieldShape = true;
99
+ continue;
100
+ }
101
+ fieldsByCollection.set(collection, {
102
+ type: 'scalar',
103
+ field: fieldAtPath.field,
104
+ isUUID: fieldColumn.columnType === 'PgUUID'
105
+ });
106
+ scalarQueryValueSignatures.add(getScalarQueryValueSignature({
107
+ column: fieldColumn,
108
+ field: fieldAtPath.field
109
+ }));
110
+ }
111
+ const hasColumnPathCollision = (schemaPathsByColumnPath.get(columnPath)?.size ?? 0) > 1;
112
+ const isInvalid = hasColumnPathCollision || !isFieldPresent || hasUnsupportedFieldShape || hasManySelect && scalarQueryValueSignatures.size > 0 || scalarQueryValueSignatures.size > 1;
113
+ plan.set(schemaPath, {
114
+ type: isInvalid ? 'invalid' : hasManySelect ? 'hasManySelect' : 'scalar',
115
+ columnPath,
116
+ fieldsByCollection,
117
+ schemaPath
118
+ });
119
+ }
120
+ return plan;
121
+ };
122
+ const textQueryFieldTypes = new Set([
123
+ 'code',
124
+ 'email',
125
+ 'slug',
126
+ 'text',
127
+ 'textarea'
128
+ ]);
129
+ const getScalarQueryValueSignature = ({ column, field })=>{
130
+ if (field.type === 'select' || field.type === 'radio') {
131
+ const optionValues = field.options.map((option)=>typeof option === 'string' ? option : option.value);
132
+ return `${field.type}:${JSON.stringify(optionValues)}`;
133
+ }
134
+ if (textQueryFieldTypes.has(field.type)) {
135
+ return 'text';
136
+ }
137
+ return `${field.type}:${column.getSQLType()}`;
138
+ };
139
+ const getWhereSchemaPaths = (where)=>{
140
+ const paths = [];
141
+ for(const key in where){
142
+ if ([
143
+ 'AND',
144
+ 'OR'
145
+ ].includes(key.toUpperCase())) {
146
+ if (Array.isArray(where[key])) {
147
+ for (const nestedWhere of where[key]){
148
+ paths.push(...getWhereSchemaPaths(nestedWhere));
149
+ }
150
+ }
151
+ } else {
152
+ paths.push(key);
153
+ }
154
+ }
155
+ return paths;
156
+ };
157
+ const getColumnPath = (schemaPath)=>schemaPath.split('.').map((segment)=>sanitizePathSegment(segment)).join('_');
158
+ const pathHasSeparateRows = ({ fields, path })=>{
159
+ const pathSegments = path.split('.');
160
+ for(let segmentIndex = 1; segmentIndex < pathSegments.length; segmentIndex++){
161
+ const fieldAtParentPath = getFieldByPath({
162
+ fields,
163
+ path: pathSegments.slice(0, segmentIndex).join('.')
164
+ });
165
+ if (fieldAtParentPath?.field.type === 'array' || fieldAtParentPath?.field.type === 'blocks') {
166
+ return true;
167
+ }
168
+ }
169
+ return false;
170
+ };
171
+ const pathHasUnsupportedNestedContainer = ({ fields, path })=>{
172
+ const pathSegments = path.split('.');
173
+ for(let segmentIndex = 1; segmentIndex < pathSegments.length; segmentIndex++){
174
+ const fieldAtParentPath = getFieldByPath({
175
+ fields,
176
+ path: pathSegments.slice(0, segmentIndex).join('.')
177
+ });
178
+ if (!fieldAtParentPath) {
179
+ return false;
180
+ }
181
+ if (![
182
+ 'group',
183
+ 'tab'
184
+ ].includes(fieldAtParentPath.field.type)) {
185
+ return true;
186
+ }
187
+ }
188
+ return false;
189
+ };
190
+
191
+ //# sourceMappingURL=createPolymorphicJoinWherePlan.js.map