@payloadcms/drizzle 4.0.0-canary.33 → 4.0.0-canary.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/find/buildPolymorphicJoinQuery.d.ts +38 -0
- package/dist/find/buildPolymorphicJoinQuery.d.ts.map +1 -0
- package/dist/find/buildPolymorphicJoinQuery.js +135 -0
- package/dist/find/buildPolymorphicJoinQuery.js.map +1 -0
- package/dist/find/buildPolymorphicJoinQuery.spec.js +384 -0
- package/dist/find/buildPolymorphicJoinQuery.spec.js.map +1 -0
- package/dist/find/buildPolymorphicJoinWhere.d.ts +20 -0
- package/dist/find/buildPolymorphicJoinWhere.d.ts.map +1 -0
- package/dist/find/buildPolymorphicJoinWhere.js +301 -0
- package/dist/find/buildPolymorphicJoinWhere.js.map +1 -0
- package/dist/find/buildPolymorphicJoinWhere.spec.js +805 -0
- package/dist/find/buildPolymorphicJoinWhere.spec.js.map +1 -0
- package/dist/find/createPolymorphicJoinWherePlan.d.ts +37 -0
- package/dist/find/createPolymorphicJoinWherePlan.d.ts.map +1 -0
- package/dist/find/createPolymorphicJoinWherePlan.js +191 -0
- package/dist/find/createPolymorphicJoinWherePlan.js.map +1 -0
- package/dist/find/createPolymorphicJoinWherePlan.spec.js +778 -0
- package/dist/find/createPolymorphicJoinWherePlan.spec.js.map +1 -0
- package/dist/find/traverseFields.d.ts.map +1 -1
- package/dist/find/traverseFields.js +19 -191
- package/dist/find/traverseFields.js.map +1 -1
- package/dist/postgres/createJSONQuery/index.js +3 -3
- package/dist/postgres/createJSONQuery/index.js.map +1 -1
- package/dist/queries/getTableColumnFromPath.d.ts.map +1 -1
- package/dist/queries/getTableColumnFromPath.js +9 -0
- package/dist/queries/getTableColumnFromPath.js.map +1 -1
- package/dist/queries/parseParams.d.ts.map +1 -1
- package/dist/queries/parseParams.js +59 -2
- package/dist/queries/parseParams.js.map +1 -1
- package/dist/sqlite/createJSONQuery/convertPathToJSONTraversal.js +3 -2
- package/dist/sqlite/createJSONQuery/convertPathToJSONTraversal.js.map +1 -1
- package/dist/sqlite/createJSONQuery/index.d.ts.map +1 -1
- package/dist/sqlite/createJSONQuery/index.js +6 -5
- package/dist/sqlite/createJSONQuery/index.js.map +1 -1
- package/dist/transform/write/traverseFields.d.ts.map +1 -1
- package/dist/transform/write/traverseFields.js +5 -14
- package/dist/transform/write/traverseFields.js.map +1 -1
- package/dist/updateOne.d.ts.map +1 -1
- package/dist/updateOne.js +41 -1
- package/dist/updateOne.js.map +1 -1
- package/dist/updateOne.spec.js +84 -0
- package/dist/updateOne.spec.js.map +1 -0
- package/dist/upsertRow/conditionalUpdate.spec.js +61 -0
- package/dist/upsertRow/conditionalUpdate.spec.js.map +1 -0
- package/dist/upsertRow/index.d.ts +1 -1
- package/dist/upsertRow/index.d.ts.map +1 -1
- package/dist/upsertRow/index.js +25 -5
- package/dist/upsertRow/index.js.map +1 -1
- package/dist/utilities/parseJSONPathSegment.d.ts +9 -0
- package/dist/utilities/parseJSONPathSegment.d.ts.map +1 -0
- package/dist/utilities/parseJSONPathSegment.js +17 -0
- package/dist/utilities/parseJSONPathSegment.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { SQL } from 'drizzle-orm';
|
|
2
|
+
import { type FlattenedJoinField, type Where } from 'payload';
|
|
3
|
+
import type { DrizzleAdapter } from '../types.js';
|
|
4
|
+
type BuildPolymorphicJoinQueryArgs = {
|
|
5
|
+
adapter: DrizzleAdapter;
|
|
6
|
+
currentTableName: string;
|
|
7
|
+
field: FlattenedJoinField;
|
|
8
|
+
limit: number;
|
|
9
|
+
locale?: string;
|
|
10
|
+
page?: number;
|
|
11
|
+
path: string;
|
|
12
|
+
shouldCount: boolean;
|
|
13
|
+
sort?: string | string[];
|
|
14
|
+
where?: Where;
|
|
15
|
+
};
|
|
16
|
+
type PolymorphicJoinQuery = {
|
|
17
|
+
columnName: string;
|
|
18
|
+
count?: SQL.Aliased;
|
|
19
|
+
documents: SQL.Aliased;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Builds the correlated document and optional count projections for a join that targets multiple
|
|
23
|
+
* collections. Every collection branch exposes the same `id`, parent, `relationTo`, and sort
|
|
24
|
+
* columns before the branches are combined. A missing sort field resolves to SQL NULL so targets
|
|
25
|
+
* with different schemas can still share one ordered union.
|
|
26
|
+
*
|
|
27
|
+
* `field.collection` must contain at least one configured collection. Each mapped table must have
|
|
28
|
+
* an `id` column and the column named by `field.on`. The supplied `limit` is used as-is; callers can
|
|
29
|
+
* include an extra look-ahead row when they calculate pagination.
|
|
30
|
+
*
|
|
31
|
+
* @returns The stable projection name, the document projection, and the count projection when
|
|
32
|
+
* `shouldCount` is true.
|
|
33
|
+
* @throws If the join definition, target collection, mapped table, required columns, or sort shape
|
|
34
|
+
* cannot be represented by the polymorphic query.
|
|
35
|
+
*/
|
|
36
|
+
export declare const buildPolymorphicJoinQuery: ({ adapter, currentTableName, field, limit, locale, page, path, shouldCount, sort, where, }: BuildPolymorphicJoinQueryArgs) => PolymorphicJoinQuery;
|
|
37
|
+
export {};
|
|
38
|
+
//# sourceMappingURL=buildPolymorphicJoinQuery.d.ts.map
|
|
@@ -0,0 +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,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,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,+FAWnC,6BAA6B,KAAG,oBA6HlC,CAAA"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { asc, count, desc, eq, sql } from 'drizzle-orm';
|
|
2
|
+
import toSnakeCase from 'to-snake-case';
|
|
3
|
+
import { jsonAggBuildObject } from '../utilities/json.js';
|
|
4
|
+
import { buildPolymorphicJoinWhere } from './buildPolymorphicJoinWhere.js';
|
|
5
|
+
import { createPolymorphicJoinWherePlan } from './createPolymorphicJoinWherePlan.js';
|
|
6
|
+
/**
|
|
7
|
+
* Builds the correlated document and optional count projections for a join that targets multiple
|
|
8
|
+
* collections. Every collection branch exposes the same `id`, parent, `relationTo`, and sort
|
|
9
|
+
* columns before the branches are combined. A missing sort field resolves to SQL NULL so targets
|
|
10
|
+
* with different schemas can still share one ordered union.
|
|
11
|
+
*
|
|
12
|
+
* `field.collection` must contain at least one configured collection. Each mapped table must have
|
|
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.
|
|
15
|
+
*
|
|
16
|
+
* @returns The stable projection name, the document projection, and the count projection when
|
|
17
|
+
* `shouldCount` is true.
|
|
18
|
+
* @throws If the join definition, target collection, mapped table, required columns, or sort shape
|
|
19
|
+
* cannot be represented by the polymorphic query.
|
|
20
|
+
*/ export const buildPolymorphicJoinQuery = ({ adapter, currentTableName, field, limit, locale, page, path, shouldCount, sort, where })=>{
|
|
21
|
+
if (!Array.isArray(field.collection)) {
|
|
22
|
+
throw new Error('A polymorphic join requires a collection array');
|
|
23
|
+
}
|
|
24
|
+
if (field.collection.length === 0) {
|
|
25
|
+
throw new Error('A polymorphic join requires at least one collection');
|
|
26
|
+
}
|
|
27
|
+
if (Array.isArray(sort)) {
|
|
28
|
+
throw new Error('Polymorphic joins do not support multiple sort fields');
|
|
29
|
+
}
|
|
30
|
+
const collections = field.collection;
|
|
31
|
+
const columnName = `${path.replaceAll('.', '_')}${field.name}`;
|
|
32
|
+
const db = adapter.drizzle;
|
|
33
|
+
const onPath = field.on.split('.').join('_');
|
|
34
|
+
const collectionTables = collections.map((collection)=>{
|
|
35
|
+
if (!adapter.payload.collections[collection]) {
|
|
36
|
+
throw new Error(`Unknown polymorphic join collection "${collection}"`);
|
|
37
|
+
}
|
|
38
|
+
const tableName = adapter.tableNameMap.get(toSnakeCase(collection));
|
|
39
|
+
const table = tableName ? adapter.tables[tableName] : undefined;
|
|
40
|
+
if (!table) {
|
|
41
|
+
throw new Error(`Polymorphic join collection "${collection}" has no database table`);
|
|
42
|
+
}
|
|
43
|
+
if (!table['id']) {
|
|
44
|
+
throw new Error(`Polymorphic join collection "${collection}" has no "id" column`);
|
|
45
|
+
}
|
|
46
|
+
if (!table[onPath]) {
|
|
47
|
+
throw new Error(`Polymorphic join collection "${collection}" has no "${onPath}" column`);
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
collection,
|
|
51
|
+
table
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
const sortField = getSortField({
|
|
55
|
+
adapter,
|
|
56
|
+
collections,
|
|
57
|
+
sort
|
|
58
|
+
});
|
|
59
|
+
const sortOrder = sortField.startsWith('-') ? desc : asc;
|
|
60
|
+
const sortPath = sortField.replace('-', '').split('.').join('_');
|
|
61
|
+
const wherePlan = where ? createPolymorphicJoinWherePlan({
|
|
62
|
+
adapter,
|
|
63
|
+
collections,
|
|
64
|
+
where
|
|
65
|
+
}) : new Map();
|
|
66
|
+
let unionQuery = null;
|
|
67
|
+
for (const { collection, table } of collectionTables){
|
|
68
|
+
const sortColumn = table[sortPath];
|
|
69
|
+
const selectFields = {
|
|
70
|
+
id: table['id'],
|
|
71
|
+
parent: sql`${table[onPath]}`.as(onPath),
|
|
72
|
+
relationTo: sql`${collection}`.as('relationTo'),
|
|
73
|
+
sortPath: sql`${sortColumn ?? null}`.as('sortPath')
|
|
74
|
+
};
|
|
75
|
+
const collectionWhere = where && Object.keys(where).length > 0 ? buildPolymorphicJoinWhere({
|
|
76
|
+
adapter,
|
|
77
|
+
collection,
|
|
78
|
+
locale,
|
|
79
|
+
table,
|
|
80
|
+
where,
|
|
81
|
+
wherePlan
|
|
82
|
+
}) : undefined;
|
|
83
|
+
let collectionQuery = db.select(selectFields).from(table).$dynamic();
|
|
84
|
+
if (collectionWhere) {
|
|
85
|
+
collectionQuery = collectionQuery.where(collectionWhere);
|
|
86
|
+
}
|
|
87
|
+
if (unionQuery === null) {
|
|
88
|
+
unionQuery = collectionQuery;
|
|
89
|
+
} else {
|
|
90
|
+
unionQuery = unionQuery.unionAll(collectionQuery);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const subQueryAlias = `${columnName}_subquery`;
|
|
94
|
+
const parentConstraint = eq(sql.raw(`"${currentTableName}"."id"`), sql.raw(`"${subQueryAlias}"."${onPath}"`));
|
|
95
|
+
const countExpression = shouldCount ? sql`${db.select({
|
|
96
|
+
count: count()
|
|
97
|
+
}).from(sql`${unionQuery.as(subQueryAlias)}`).where(parentConstraint)}`.as(`${columnName}_count`) : undefined;
|
|
98
|
+
unionQuery = unionQuery.orderBy(sortOrder(sql`"sortPath"`));
|
|
99
|
+
const sortedUnionAlias = `${columnName}_sorted`;
|
|
100
|
+
let limitOffsetSQL = sql.empty();
|
|
101
|
+
if (limit) {
|
|
102
|
+
limitOffsetSQL = sql` LIMIT ${limit}`;
|
|
103
|
+
}
|
|
104
|
+
if (page && limit !== 0) {
|
|
105
|
+
const offset = (page - 1) * limit;
|
|
106
|
+
if (offset > 0) {
|
|
107
|
+
limitOffsetSQL = sql`${limitOffsetSQL} OFFSET ${offset}`;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
const parentWhere = sql.raw(`"${sortedUnionAlias}"."${onPath}" = "${currentTableName}"."id"`);
|
|
111
|
+
const documents = sql`(
|
|
112
|
+
SELECT ${jsonAggBuildObject(adapter, {
|
|
113
|
+
id: sql.raw(`"${subQueryAlias}"."id"`),
|
|
114
|
+
relationTo: sql.raw(`"${subQueryAlias}"."relationTo"`)
|
|
115
|
+
})}
|
|
116
|
+
FROM (
|
|
117
|
+
SELECT * FROM ${sql`${unionQuery.as(sortedUnionAlias)}`}
|
|
118
|
+
WHERE ${parentWhere}${limitOffsetSQL}
|
|
119
|
+
) AS ${sql.raw(`"${subQueryAlias}"`)}
|
|
120
|
+
)`.as(columnName);
|
|
121
|
+
return {
|
|
122
|
+
columnName,
|
|
123
|
+
count: countExpression,
|
|
124
|
+
documents
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
const getSortField = ({ adapter, collections, sort })=>{
|
|
128
|
+
if (sort) {
|
|
129
|
+
return sort;
|
|
130
|
+
}
|
|
131
|
+
const hasCreatedAt = collections.some((collection)=>adapter.payload.collections[collection].config.fields.some((field)=>field.type === 'date' && field.name === 'createdAt'));
|
|
132
|
+
return hasCreatedAt ? '-createdAt' : 'id';
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
//# sourceMappingURL=buildPolymorphicJoinQuery.js.map
|
|
@@ -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":"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"}
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { createClient } from '@libsql/client';
|
|
2
|
+
import { getTableName, like, notLike } from 'drizzle-orm';
|
|
3
|
+
import { drizzle } from 'drizzle-orm/libsql';
|
|
4
|
+
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
|
|
5
|
+
import { flattenAllFields } from 'payload';
|
|
6
|
+
import toSnakeCase from 'to-snake-case';
|
|
7
|
+
import { afterAll, describe, expect, it } from 'vitest';
|
|
8
|
+
import { operatorMap } from '../queries/operatorMap.js';
|
|
9
|
+
import { createJSONQuery } from '../sqlite/createJSONQuery/index.js';
|
|
10
|
+
import { buildPolymorphicJoinQuery } from './buildPolymorphicJoinQuery.js';
|
|
11
|
+
const parentsTable = sqliteTable('join_parents', {
|
|
12
|
+
id: integer('id').primaryKey()
|
|
13
|
+
});
|
|
14
|
+
const articlesTable = sqliteTable('join_articles', {
|
|
15
|
+
id: integer('id').primaryKey(),
|
|
16
|
+
createdAt: text('created_at'),
|
|
17
|
+
details_rank: integer('details_rank'),
|
|
18
|
+
parent: integer('parent_id'),
|
|
19
|
+
score: integer('score'),
|
|
20
|
+
title: text('title')
|
|
21
|
+
});
|
|
22
|
+
const notesTable = sqliteTable('join_notes', {
|
|
23
|
+
id: integer('id').primaryKey(),
|
|
24
|
+
parent: integer('parent_id'),
|
|
25
|
+
title: text('title')
|
|
26
|
+
});
|
|
27
|
+
const tableWithoutID = sqliteTable('join_without_id', {
|
|
28
|
+
parent: integer('parent_id')
|
|
29
|
+
});
|
|
30
|
+
const tableWithoutParent = sqliteTable('join_without_parent', {
|
|
31
|
+
id: integer('id').primaryKey()
|
|
32
|
+
});
|
|
33
|
+
const client = createClient({
|
|
34
|
+
url: 'file::memory:'
|
|
35
|
+
});
|
|
36
|
+
const db = drizzle(client, {
|
|
37
|
+
schema: {
|
|
38
|
+
articlesTable,
|
|
39
|
+
notesTable,
|
|
40
|
+
parentsTable,
|
|
41
|
+
tableWithoutID,
|
|
42
|
+
tableWithoutParent
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
const createAdapter = (fixtures)=>{
|
|
46
|
+
const collections = {};
|
|
47
|
+
const tableNameMap = new Map();
|
|
48
|
+
const tables = {};
|
|
49
|
+
for (const [slug, fixture] of Object.entries(fixtures)){
|
|
50
|
+
const tableName = getTableName(fixture.table);
|
|
51
|
+
collections[slug] = {
|
|
52
|
+
config: {
|
|
53
|
+
fields: fixture.fields,
|
|
54
|
+
flattenedFields: flattenAllFields({
|
|
55
|
+
fields: fixture.fields
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
tableNameMap.set(toSnakeCase(slug), tableName);
|
|
60
|
+
tables[tableName] = fixture.table;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
createJSONQuery,
|
|
64
|
+
drizzle: db,
|
|
65
|
+
idType: 'serial',
|
|
66
|
+
name: 'sqlite',
|
|
67
|
+
operatorHandlers: [],
|
|
68
|
+
operators: {
|
|
69
|
+
...operatorMap,
|
|
70
|
+
contains: like,
|
|
71
|
+
like,
|
|
72
|
+
not_like: notLike
|
|
73
|
+
},
|
|
74
|
+
payload: {
|
|
75
|
+
collections
|
|
76
|
+
},
|
|
77
|
+
tableNameMap,
|
|
78
|
+
tables
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
const adapter = createAdapter({
|
|
82
|
+
articles: {
|
|
83
|
+
fields: [
|
|
84
|
+
{
|
|
85
|
+
name: 'createdAt',
|
|
86
|
+
type: 'date'
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
name: 'details',
|
|
90
|
+
type: 'group',
|
|
91
|
+
fields: [
|
|
92
|
+
{
|
|
93
|
+
name: 'rank',
|
|
94
|
+
type: 'number'
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'parent',
|
|
100
|
+
relationTo: 'join-parents',
|
|
101
|
+
type: 'relationship'
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: 'score',
|
|
105
|
+
type: 'number'
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
name: 'title',
|
|
109
|
+
type: 'text'
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
table: articlesTable
|
|
113
|
+
},
|
|
114
|
+
notes: {
|
|
115
|
+
fields: [
|
|
116
|
+
{
|
|
117
|
+
name: 'parent',
|
|
118
|
+
relationTo: 'join-parents',
|
|
119
|
+
type: 'relationship'
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
name: 'title',
|
|
123
|
+
type: 'text'
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
table: notesTable
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
const joinField = {
|
|
130
|
+
collection: [
|
|
131
|
+
'articles',
|
|
132
|
+
'notes'
|
|
133
|
+
],
|
|
134
|
+
name: 'children',
|
|
135
|
+
on: 'parent',
|
|
136
|
+
type: 'join'
|
|
137
|
+
};
|
|
138
|
+
const buildQuery = ({ adapter: adapterArg = adapter, field = joinField, limit = 0, page, path = '', shouldCount = false, sort, where } = {})=>buildPolymorphicJoinQuery({
|
|
139
|
+
adapter: adapterArg,
|
|
140
|
+
currentTableName: getTableName(parentsTable),
|
|
141
|
+
field,
|
|
142
|
+
limit,
|
|
143
|
+
page,
|
|
144
|
+
path,
|
|
145
|
+
shouldCount,
|
|
146
|
+
sort,
|
|
147
|
+
where
|
|
148
|
+
});
|
|
149
|
+
const renderQuery = (query)=>{
|
|
150
|
+
const selection = {
|
|
151
|
+
documents: query.documents
|
|
152
|
+
};
|
|
153
|
+
if (query.count) {
|
|
154
|
+
selection.count = query.count;
|
|
155
|
+
}
|
|
156
|
+
return db.select(selection).from(parentsTable).toSQL();
|
|
157
|
+
};
|
|
158
|
+
afterAll(()=>client.close());
|
|
159
|
+
describe('buildPolymorphicJoinQuery', ()=>{
|
|
160
|
+
it('combines every target into one fixed polymorphic document projection', ()=>{
|
|
161
|
+
const result = buildQuery({
|
|
162
|
+
path: 'content.'
|
|
163
|
+
});
|
|
164
|
+
const query = renderQuery(result);
|
|
165
|
+
expect(result.columnName).toBe('content_children');
|
|
166
|
+
expect(result.count).toBeUndefined();
|
|
167
|
+
expect(query.sql).toContain('union all');
|
|
168
|
+
expect(query.sql).toContain('select "id"');
|
|
169
|
+
expect(query.sql).toContain('from "join_articles" union all');
|
|
170
|
+
expect(query.sql).toContain('from "join_notes"');
|
|
171
|
+
expect(query.sql).toContain('as "parent"');
|
|
172
|
+
expect(query.sql).toContain('as "relationTo"');
|
|
173
|
+
expect(query.sql).toContain("json_object('id',");
|
|
174
|
+
expect(query.sql).toContain("'relationTo',");
|
|
175
|
+
expect(query.params).toContain('articles');
|
|
176
|
+
expect(query.params).toContain('notes');
|
|
177
|
+
});
|
|
178
|
+
it('sorts by createdAt descending by default when one target has timestamps', ()=>{
|
|
179
|
+
const query = renderQuery(buildQuery());
|
|
180
|
+
expect(query.sql).toContain('"created_at" as "sortPath" from "join_articles"');
|
|
181
|
+
expect(query.sql).toContain('? as "sortPath" from "join_notes"');
|
|
182
|
+
expect(query.sql).toContain('order by "sortPath" desc');
|
|
183
|
+
expect(query.params).toContain(null);
|
|
184
|
+
});
|
|
185
|
+
it('uses id ascending by default when no target has a createdAt field', ()=>{
|
|
186
|
+
const adapterWithoutTimestamps = createAdapter({
|
|
187
|
+
articles: {
|
|
188
|
+
fields: [
|
|
189
|
+
{
|
|
190
|
+
name: 'parent',
|
|
191
|
+
relationTo: 'join-parents',
|
|
192
|
+
type: 'relationship'
|
|
193
|
+
}
|
|
194
|
+
],
|
|
195
|
+
table: articlesTable
|
|
196
|
+
},
|
|
197
|
+
notes: {
|
|
198
|
+
fields: [
|
|
199
|
+
{
|
|
200
|
+
name: 'parent',
|
|
201
|
+
relationTo: 'join-parents',
|
|
202
|
+
type: 'relationship'
|
|
203
|
+
}
|
|
204
|
+
],
|
|
205
|
+
table: notesTable
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
const query = renderQuery(buildQuery({
|
|
209
|
+
adapter: adapterWithoutTimestamps
|
|
210
|
+
}));
|
|
211
|
+
expect(query.sql).toContain('"id" as "sortPath" from "join_articles"');
|
|
212
|
+
expect(query.sql).toContain('"id" as "sortPath" from "join_notes"');
|
|
213
|
+
expect(query.sql).toContain('order by "sortPath" asc');
|
|
214
|
+
});
|
|
215
|
+
it('supports an explicit ascending nested sort and substitutes null when it is absent', ()=>{
|
|
216
|
+
const query = renderQuery(buildQuery({
|
|
217
|
+
sort: 'details.rank'
|
|
218
|
+
}));
|
|
219
|
+
expect(query.sql).toContain('"details_rank" as "sortPath" from "join_articles"');
|
|
220
|
+
expect(query.sql).toContain('? as "sortPath" from "join_notes"');
|
|
221
|
+
expect(query.sql).toContain('order by "sortPath" asc');
|
|
222
|
+
expect(query.params).toContain(null);
|
|
223
|
+
});
|
|
224
|
+
it('applies the shared where clause independently to each target branch', ()=>{
|
|
225
|
+
const query = renderQuery(buildQuery({
|
|
226
|
+
where: {
|
|
227
|
+
AND: [
|
|
228
|
+
{
|
|
229
|
+
title: {
|
|
230
|
+
equals: 'available'
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
relationTo: {
|
|
235
|
+
equals: 'articles'
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
}));
|
|
241
|
+
expect(query.sql.match(/"title" = \?/g)).toHaveLength(2);
|
|
242
|
+
expect(query.sql).toContain('? = ?');
|
|
243
|
+
expect(query.params.filter((value)=>value === 'available')).toHaveLength(2);
|
|
244
|
+
expect(query.params).toContain('articles');
|
|
245
|
+
expect(query.params).toContain('notes');
|
|
246
|
+
});
|
|
247
|
+
it('adds a correlated count only when requested', ()=>{
|
|
248
|
+
const result = buildQuery({
|
|
249
|
+
shouldCount: true
|
|
250
|
+
});
|
|
251
|
+
const query = renderQuery(result);
|
|
252
|
+
expect(result.count).toBeDefined();
|
|
253
|
+
expect(query.sql).toContain('select count(*) from');
|
|
254
|
+
expect(query.sql).toContain('"join_parents"."id" = "children_subquery"."parent"');
|
|
255
|
+
});
|
|
256
|
+
it('adds limit and page offset to the document query', ()=>{
|
|
257
|
+
const query = renderQuery(buildQuery({
|
|
258
|
+
limit: 11,
|
|
259
|
+
page: 3
|
|
260
|
+
}));
|
|
261
|
+
expect(query.sql).toContain('LIMIT ? OFFSET ?');
|
|
262
|
+
expect(query.params.slice(-2)).toEqual([
|
|
263
|
+
11,
|
|
264
|
+
22
|
|
265
|
+
]);
|
|
266
|
+
});
|
|
267
|
+
it('does not add limit or offset when limit is zero', ()=>{
|
|
268
|
+
const query = renderQuery(buildQuery({
|
|
269
|
+
limit: 0,
|
|
270
|
+
page: 3
|
|
271
|
+
}));
|
|
272
|
+
const normalizedSQL = query.sql.toLowerCase();
|
|
273
|
+
expect(normalizedSQL).not.toContain(' limit ');
|
|
274
|
+
expect(normalizedSQL).not.toContain(' offset ');
|
|
275
|
+
});
|
|
276
|
+
it('rejects a join field with a non-polymorphic collection', ()=>{
|
|
277
|
+
const scalarJoinField = {
|
|
278
|
+
...joinField,
|
|
279
|
+
collection: 'articles'
|
|
280
|
+
};
|
|
281
|
+
expect(()=>buildQuery({
|
|
282
|
+
field: scalarJoinField
|
|
283
|
+
})).toThrow('A polymorphic join requires a collection array');
|
|
284
|
+
});
|
|
285
|
+
it('rejects a polymorphic join with no target collections', ()=>{
|
|
286
|
+
const emptyJoinField = {
|
|
287
|
+
...joinField,
|
|
288
|
+
collection: []
|
|
289
|
+
};
|
|
290
|
+
expect(()=>buildQuery({
|
|
291
|
+
field: emptyJoinField
|
|
292
|
+
})).toThrow('A polymorphic join requires at least one collection');
|
|
293
|
+
});
|
|
294
|
+
it('rejects multiple sort fields with a descriptive error', ()=>{
|
|
295
|
+
expect(()=>buildQuery({
|
|
296
|
+
sort: [
|
|
297
|
+
'title',
|
|
298
|
+
'-createdAt'
|
|
299
|
+
]
|
|
300
|
+
})).toThrow('Polymorphic joins do not support multiple sort fields');
|
|
301
|
+
});
|
|
302
|
+
it('throws a descriptive error when a target collection is not configured', ()=>{
|
|
303
|
+
const missingCollectionField = {
|
|
304
|
+
...joinField,
|
|
305
|
+
collection: [
|
|
306
|
+
'articles',
|
|
307
|
+
'missing'
|
|
308
|
+
]
|
|
309
|
+
};
|
|
310
|
+
expect(()=>buildQuery({
|
|
311
|
+
field: missingCollectionField
|
|
312
|
+
})).toThrow('Unknown polymorphic join collection "missing"');
|
|
313
|
+
});
|
|
314
|
+
it('throws a descriptive error when a configured collection has no database table', ()=>{
|
|
315
|
+
const adapterWithoutTable = createAdapter({
|
|
316
|
+
articles: {
|
|
317
|
+
fields: [
|
|
318
|
+
{
|
|
319
|
+
name: 'parent',
|
|
320
|
+
relationTo: 'join-parents',
|
|
321
|
+
type: 'relationship'
|
|
322
|
+
}
|
|
323
|
+
],
|
|
324
|
+
table: articlesTable
|
|
325
|
+
}
|
|
326
|
+
});
|
|
327
|
+
adapterWithoutTable.tables = {};
|
|
328
|
+
const singleCollectionField = {
|
|
329
|
+
...joinField,
|
|
330
|
+
collection: [
|
|
331
|
+
'articles'
|
|
332
|
+
]
|
|
333
|
+
};
|
|
334
|
+
expect(()=>buildQuery({
|
|
335
|
+
adapter: adapterWithoutTable,
|
|
336
|
+
field: singleCollectionField
|
|
337
|
+
})).toThrow('Polymorphic join collection "articles" has no database table');
|
|
338
|
+
});
|
|
339
|
+
it.each([
|
|
340
|
+
[
|
|
341
|
+
'id',
|
|
342
|
+
createAdapter({
|
|
343
|
+
articles: {
|
|
344
|
+
fields: [
|
|
345
|
+
{
|
|
346
|
+
name: 'parent',
|
|
347
|
+
relationTo: 'join-parents',
|
|
348
|
+
type: 'relationship'
|
|
349
|
+
}
|
|
350
|
+
],
|
|
351
|
+
table: tableWithoutID
|
|
352
|
+
}
|
|
353
|
+
})
|
|
354
|
+
],
|
|
355
|
+
[
|
|
356
|
+
'parent',
|
|
357
|
+
createAdapter({
|
|
358
|
+
articles: {
|
|
359
|
+
fields: [
|
|
360
|
+
{
|
|
361
|
+
name: 'parent',
|
|
362
|
+
relationTo: 'join-parents',
|
|
363
|
+
type: 'relationship'
|
|
364
|
+
}
|
|
365
|
+
],
|
|
366
|
+
table: tableWithoutParent
|
|
367
|
+
}
|
|
368
|
+
})
|
|
369
|
+
]
|
|
370
|
+
])('rejects a target whose table has no %s column', (column, adapterArg)=>{
|
|
371
|
+
const singleCollectionField = {
|
|
372
|
+
...joinField,
|
|
373
|
+
collection: [
|
|
374
|
+
'articles'
|
|
375
|
+
]
|
|
376
|
+
};
|
|
377
|
+
expect(()=>buildQuery({
|
|
378
|
+
adapter: adapterArg,
|
|
379
|
+
field: singleCollectionField
|
|
380
|
+
})).toThrow(`Polymorphic join collection "articles" has no "${column}" column`);
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
|
|
384
|
+
//# sourceMappingURL=buildPolymorphicJoinQuery.spec.js.map
|
|
@@ -0,0 +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":"AAIA,SAASA,YAAY,QAAQ,iBAAgB;AAC7C,SAASC,YAAY,EAAEC,IAAI,EAAEC,OAAO,QAAQ,cAAa;AACzD,SAASC,OAAO,QAAQ,qBAAoB;AAC5C,SAASC,OAAO,EAAEC,WAAW,EAAEC,IAAI,QAAQ,0BAAyB;AACpE,SAASC,gBAAgB,QAAQ,UAAS;AAC1C,OAAOC,iBAAiB,gBAAe;AACvC,SAASC,QAAQ,EAAEC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAIvD,SAASC,WAAW,QAAQ,4BAA2B;AACvD,SAASC,eAAe,QAAQ,qCAAoC;AACpE,SAASC,yBAAyB,QAAQ,iCAAgC;AAE1E,MAAMC,eAAeX,YAAY,gBAAgB;IAC/CY,IAAIb,QAAQ,MAAMc,UAAU;AAC9B;AAEA,MAAMC,gBAAgBd,YAAY,iBAAiB;IACjDY,IAAIb,QAAQ,MAAMc,UAAU;IAC5BE,WAAWd,KAAK;IAChBe,cAAcjB,QAAQ;IACtBkB,QAAQlB,QAAQ;IAChBmB,OAAOnB,QAAQ;IACfoB,OAAOlB,KAAK;AACd;AAEA,MAAMmB,aAAapB,YAAY,cAAc;IAC3CY,IAAIb,QAAQ,MAAMc,UAAU;IAC5BI,QAAQlB,QAAQ;IAChBoB,OAAOlB,KAAK;AACd;AAEA,MAAMoB,iBAAiBrB,YAAY,mBAAmB;IACpDiB,QAAQlB,QAAQ;AAClB;AAEA,MAAMuB,qBAAqBtB,YAAY,uBAAuB;IAC5DY,IAAIb,QAAQ,MAAMc,UAAU;AAC9B;AAEA,MAAMU,SAAiB7B,aAAa;IAAE8B,KAAK;AAAgB;AAC3D,MAAMC,KAAK3B,QAAQyB,QAAQ;IACzBG,QAAQ;QAAEZ;QAAeM;QAAYT;QAAcU;QAAgBC;IAAmB;AACxF;AAOA,MAAMK,gBAAgB,CAACC;IACrB,MAAMC,cAGF,CAAC;IACL,MAAMC,eAAe,IAAIC;IACzB,MAAMC,SAAuC,CAAC;IAE9C,KAAK,MAAM,CAACC,MAAMC,QAAQ,IAAIC,OAAOC,OAAO,CAACR,UAAW;QACtD,MAAMS,YAAY1C,aAAauC,QAAQI,KAAK;QAE5CT,WAAW,CAACI,KAAK,GAAG;YAClBM,QAAQ;gBACNC,QAAQN,QAAQM,MAAM;gBACtBC,iBAAiBvC,iBAAiB;oBAAEsC,QAAQN,QAAQM,MAAM;gBAAC;YAC7D;QACF;QACAV,aAAaY,GAAG,CAACvC,YAAY8B,OAAOI;QACpCL,MAAM,CAACK,UAAU,GAAGH,QAAQI,KAAK;IACnC;IAEA,OAAO;QACL7B;QACAX,SAAS2B;QACTkB,QAAQ;QACRC,MAAM;QACNC,kBAAkB,EAAE;QACpBC,WAAW;YACT,GAAGtC,WAAW;YACduC,UAAUnD;YACVA;YACAoD,UAAUnD;QACZ;QACAoD,SAAS;YAAEpB;QAAY;QACvBC;QACAE;IACF;AACF;AAEA,MAAMkB,UAAUvB,cAAc;IAC5BwB,UAAU;QACRX,QAAQ;YACN;gBAAEI,MAAM;gBAAaQ,MAAM;YAAO;YAClC;gBACER,MAAM;gBACNQ,MAAM;gBACNZ,QAAQ;oBAAC;wBAAEI,MAAM;wBAAQQ,MAAM;oBAAS;iBAAE;YAC5C;YACA;gBAAER,MAAM;gBAAUS,YAAY;gBAAgBD,MAAM;YAAe;YACnE;gBAAER,MAAM;gBAASQ,MAAM;YAAS;YAChC;gBAAER,MAAM;gBAASQ,MAAM;YAAO;SAC/B;QACDd,OAAOxB;IACT;IACAwC,OAAO;QACLd,QAAQ;YACN;gBAAEI,MAAM;gBAAUS,YAAY;gBAAgBD,MAAM;YAAe;YACnE;gBAAER,MAAM;gBAASQ,MAAM;YAAO;SAC/B;QACDd,OAAOlB;IACT;AACF;AAEA,MAAMmC,YAAY;IAChBC,YAAY;QAAC;QAAY;KAAQ;IACjCZ,MAAM;IACNa,IAAI;IACJL,MAAM;AACR;AAEA,MAAMM,aAAa,CAAC,EAClBR,SAASS,aAAaT,OAAO,EAC7BU,QAAQL,SAAS,EACjBM,QAAQ,CAAC,EACTC,IAAI,EACJC,OAAO,EAAE,EACTC,cAAc,KAAK,EACnBC,IAAI,EACJC,KAAK,EAUN,GAAG,CAAC,CAAC,GACJxD,0BAA0B;QACxBwC,SAASS;QACTQ,kBAAkBxE,aAAagB;QAC/BiD;QACAC;QACAC;QACAC;QACAC;QACAC;QACAC;IACF;AAEF,MAAME,cAAc,CAACC;IACnB,MAAMC,YAAyC;QAAEC,WAAWF,MAAME,SAAS;IAAC;IAE5E,IAAIF,MAAMG,KAAK,EAAE;QACfF,UAAUE,KAAK,GAAGH,MAAMG,KAAK;IAC/B;IAEA,OAAO/C,GAAGgD,MAAM,CAACH,WAAWI,IAAI,CAAC/D,cAAcgE,KAAK;AACtD;AAEAvE,SAAS,IAAMmB,OAAOqD,KAAK;AAE3BvE,SAAS,6BAA6B;IACpCE,GAAG,wEAAwE;QACzE,MAAMsE,SAASnB,WAAW;YAAEK,MAAM;QAAW;QAC7C,MAAMM,QAAQD,YAAYS;QAE1BvE,OAAOuE,OAAOC,UAAU,EAAEC,IAAI,CAAC;QAC/BzE,OAAOuE,OAAOL,KAAK,EAAEQ,aAAa;QAClC1E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMc,MAAM,EAAED,SAAS,CAAC;QAC/B5E,OAAO+D,MAAMc,MAAM,EAAED,SAAS,CAAC;IACjC;IAEA3E,GAAG,2EAA2E;QAC5E,MAAM8D,QAAQD,YAAYV;QAE1BpD,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMc,MAAM,EAAED,SAAS,CAAC;IACjC;IAEA3E,GAAG,qEAAqE;QACtE,MAAM6E,2BAA2BzD,cAAc;YAC7CwB,UAAU;gBACRX,QAAQ;oBAAC;wBAAEI,MAAM;wBAAUS,YAAY;wBAAgBD,MAAM;oBAAe;iBAAE;gBAC9Ed,OAAOxB;YACT;YACAwC,OAAO;gBACLd,QAAQ;oBAAC;wBAAEI,MAAM;wBAAUS,YAAY;wBAAgBD,MAAM;oBAAe;iBAAE;gBAC9Ed,OAAOlB;YACT;QACF;QACA,MAAMiD,QAAQD,YAAYV,WAAW;YAAER,SAASkC;QAAyB;QAEzE9E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;IAC9B;IAEA3E,GAAG,qFAAqF;QACtF,MAAM8D,QAAQD,YAAYV,WAAW;YAAEO,MAAM;QAAe;QAE5D3D,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMc,MAAM,EAAED,SAAS,CAAC;IACjC;IAEA3E,GAAG,uEAAuE;QACxE,MAAM8D,QAAQD,YACZV,WAAW;YACTQ,OAAO;gBACLmB,KAAK;oBAAC;wBAAElE,OAAO;4BAAEmE,QAAQ;wBAAY;oBAAE;oBAAG;wBAAEjC,YAAY;4BAAEiC,QAAQ;wBAAW;oBAAE;iBAAE;YACnF;QACF;QAGFhF,OAAO+D,MAAMY,GAAG,CAACM,KAAK,CAAC,kBAAkBC,YAAY,CAAC;QACtDlF,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMc,MAAM,CAACM,MAAM,CAAC,CAACC,QAAUA,UAAU,cAAcF,YAAY,CAAC;QAC3ElF,OAAO+D,MAAMc,MAAM,EAAED,SAAS,CAAC;QAC/B5E,OAAO+D,MAAMc,MAAM,EAAED,SAAS,CAAC;IACjC;IAEA3E,GAAG,+CAA+C;QAChD,MAAMsE,SAASnB,WAAW;YAAEM,aAAa;QAAK;QAC9C,MAAMK,QAAQD,YAAYS;QAE1BvE,OAAOuE,OAAOL,KAAK,EAAEmB,WAAW;QAChCrF,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;IAC9B;IAEA3E,GAAG,oDAAoD;QACrD,MAAM8D,QAAQD,YAAYV,WAAW;YAAEG,OAAO;YAAIC,MAAM;QAAE;QAE1DxD,OAAO+D,MAAMY,GAAG,EAAEC,SAAS,CAAC;QAC5B5E,OAAO+D,MAAMc,MAAM,CAACS,KAAK,CAAC,CAAC,IAAIC,OAAO,CAAC;YAAC;YAAI;SAAG;IACjD;IAEAtF,GAAG,mDAAmD;QACpD,MAAM8D,QAAQD,YAAYV,WAAW;YAAEG,OAAO;YAAGC,MAAM;QAAE;QACzD,MAAMgC,gBAAgBzB,MAAMY,GAAG,CAACc,WAAW;QAE3CzF,OAAOwF,eAAeE,GAAG,CAACd,SAAS,CAAC;QACpC5E,OAAOwF,eAAeE,GAAG,CAACd,SAAS,CAAC;IACtC;IAEA3E,GAAG,0DAA0D;QAC3D,MAAM0F,kBAAkB;YACtB,GAAG1C,SAAS;YACZC,YAAY;QACd;QAEAlD,OAAO,IAAMoD,WAAW;gBAAEE,OAAOqC;YAAgB,IAAIC,OAAO,CAC1D;IAEJ;IAEA3F,GAAG,yDAAyD;QAC1D,MAAM4F,iBAAiB;YAAE,GAAG5C,SAAS;YAAEC,YAAY,EAAE;QAAC;QAEtDlD,OAAO,IAAMoD,WAAW;gBAAEE,OAAOuC;YAAe,IAAID,OAAO,CACzD;IAEJ;IAEA3F,GAAG,yDAAyD;QAC1DD,OAAO,IAAMoD,WAAW;gBAAEO,MAAM;oBAAC;oBAAS;iBAAa;YAAC,IAAIiC,OAAO,CACjE;IAEJ;IAEA3F,GAAG,yEAAyE;QAC1E,MAAM6F,yBAAyB;YAC7B,GAAG7C,SAAS;YACZC,YAAY;gBAAC;gBAAY;aAAU;QACrC;QAEAlD,OAAO,IAAMoD,WAAW;gBAAEE,OAAOwC;YAAuB,IAAIF,OAAO,CACjE;IAEJ;IAEA3F,GAAG,iFAAiF;QAClF,MAAM8F,sBAAsB1E,cAAc;YACxCwB,UAAU;gBACRX,QAAQ;oBAAC;wBAAEI,MAAM;wBAAUS,YAAY;wBAAgBD,MAAM;oBAAe;iBAAE;gBAC9Ed,OAAOxB;YACT;QACF;QAEAuF,oBAAoBrE,MAAM,GAAG,CAAC;QAE9B,MAAMsE,wBAAwB;YAC5B,GAAG/C,SAAS;YACZC,YAAY;gBAAC;aAAW;QAC1B;QAEAlD,OAAO,IACLoD,WAAW;gBAAER,SAASmD;gBAAqBzC,OAAO0C;YAAsB,IACxEJ,OAAO,CAAC;IACZ;IAEA3F,GAAGgG,IAAI,CAAC;QACN;YACE;YACA5E,cAAc;gBACZwB,UAAU;oBACRX,QAAQ;wBAAC;4BAAEI,MAAM;4BAAUS,YAAY;4BAAgBD,MAAM;wBAAe;qBAAE;oBAC9Ed,OAAOjB;gBACT;YACF;SACD;QACD;YACE;YACAM,cAAc;gBACZwB,UAAU;oBACRX,QAAQ;wBAAC;4BAAEI,MAAM;4BAAUS,YAAY;4BAAgBD,MAAM;wBAAe;qBAAE;oBAC9Ed,OAAOhB;gBACT;YACF;SACD;KACF,EAAW,iDAAiD,CAACkF,QAAQ7C;QACpE,MAAM2C,wBAAwB;YAC5B,GAAG/C,SAAS;YACZC,YAAY;gBAAC;aAAW;QAC1B;QAEAlD,OAAO,IAAMoD,WAAW;gBAAER,SAASS;gBAAYC,OAAO0C;YAAsB,IAAIJ,OAAO,CACrF,CAAC,+CAA+C,EAAEM,OAAO,QAAQ,CAAC;IAEtE;AACF"}
|
|
@@ -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"}
|