rimecms 0.23.25 → 0.23.27
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.
|
@@ -100,12 +100,130 @@ export const buildWhereParam = ({ query, slug, db, locale, tables, configCtx })
|
|
|
100
100
|
// Return a condition that will always be false
|
|
101
101
|
return eq(table.id, '-1'); // No document will have ID = -1, so this will always be false
|
|
102
102
|
}
|
|
103
|
+
// Unsupported operator for multi-valued relations
|
|
104
|
+
const supportedRelationManyOperators = ['equals', 'not_equals', 'in_array', 'not_in_array'];
|
|
105
|
+
if (fieldConfig.many && !supportedRelationManyOperators.includes(operator)) {
|
|
106
|
+
logger.warn(`the operator "${operator}" is not supported for multi-valued relation field "${column}" in ${documentConfig.slug} document`);
|
|
107
|
+
// Return a condition that will always be false
|
|
108
|
+
return eq(table.id, '-1'); // No document will have ID = -1, so this will always be false
|
|
109
|
+
}
|
|
103
110
|
// Only compare with the relation ID for now
|
|
104
111
|
// @TODO handle relation props ex: author.email
|
|
105
112
|
const [to, localized] = [fieldConfig.relationTo, fieldConfig.localized];
|
|
106
113
|
const relationTableName = `${slug}Rels`;
|
|
107
114
|
const relationTable = getTable(relationTableName);
|
|
108
|
-
|
|
115
|
+
// Handle multi-valued relations specially when operator is `equals` to provide
|
|
116
|
+
// strict equality semantics (the relation set must equal the provided value(s)).
|
|
117
|
+
if (fieldConfig.many && operator === 'equals') {
|
|
118
|
+
// Accept array inputs, repeated params, or CSV values for equality checks
|
|
119
|
+
let values = (() => {
|
|
120
|
+
if (Array.isArray(rawValue))
|
|
121
|
+
return rawValue;
|
|
122
|
+
if (typeof rawValue === 'string' && rawValue.includes(','))
|
|
123
|
+
return rawValue.split(',');
|
|
124
|
+
if (Array.isArray(value))
|
|
125
|
+
return value;
|
|
126
|
+
return [value];
|
|
127
|
+
})();
|
|
128
|
+
// Ensure values are unique
|
|
129
|
+
values = Array.from(new Set(values));
|
|
130
|
+
// Owners with total relation count equal to values.length
|
|
131
|
+
const ownersWithTotalCount = db
|
|
132
|
+
.select({ id: relationTable.ownerId })
|
|
133
|
+
.from(relationTable)
|
|
134
|
+
.where(and(eq(relationTable.path, column), ...(localized ? [eq(relationTable.locale, locale)] : [])))
|
|
135
|
+
.groupBy(relationTable.ownerId)
|
|
136
|
+
.having(drizzleORM.eq(drizzleORM.count(relationTable.id), values.length));
|
|
137
|
+
// Owners with matching relations count equal to values.length
|
|
138
|
+
const ownersWithMatchingCount = db
|
|
139
|
+
.select({ id: relationTable.ownerId })
|
|
140
|
+
.from(relationTable)
|
|
141
|
+
.where(and(drizzleORM.inArray(relationTable[`${to}Id`], values), eq(relationTable.path, column), ...(localized ? [eq(relationTable.locale, locale)] : [])))
|
|
142
|
+
.groupBy(relationTable.ownerId)
|
|
143
|
+
.having(drizzleORM.eq(drizzleORM.count(relationTable.id), values.length));
|
|
144
|
+
return and(inArray(table.id, ownersWithTotalCount), inArray(table.id, ownersWithMatchingCount));
|
|
145
|
+
}
|
|
146
|
+
// For multi-valued relations, allow `in_array` to act as a subset check:
|
|
147
|
+
// The provided values must contain ALL relation values of the document.
|
|
148
|
+
if (fieldConfig.many && operator === 'in_array') {
|
|
149
|
+
// Accept array inputs, repeated params, or CSV values for in_array checks
|
|
150
|
+
let values = (() => {
|
|
151
|
+
if (Array.isArray(rawValue))
|
|
152
|
+
return rawValue;
|
|
153
|
+
if (typeof rawValue === 'string' && rawValue.includes(','))
|
|
154
|
+
return rawValue.split(',');
|
|
155
|
+
if (Array.isArray(value))
|
|
156
|
+
return value;
|
|
157
|
+
return [value];
|
|
158
|
+
})();
|
|
159
|
+
// Ensure values are unique
|
|
160
|
+
values = Array.from(new Set(values));
|
|
161
|
+
// Owners that have at least one relation row not included in the provided set
|
|
162
|
+
const ownersWithNonMatching = db
|
|
163
|
+
.select({ id: relationTable.ownerId })
|
|
164
|
+
.from(relationTable)
|
|
165
|
+
.where(and(drizzleORM.notInArray(relationTable[`${to}Id`], values), eq(relationTable.path, column), ...(localized ? [eq(relationTable.locale, locale)] : [])))
|
|
166
|
+
.groupBy(relationTable.ownerId)
|
|
167
|
+
.having(drizzleORM.gt(drizzleORM.count(relationTable.id), 0));
|
|
168
|
+
// Owners that have any relation rows (to exclude docs with no relations)
|
|
169
|
+
const ownersWithRelations = db
|
|
170
|
+
.select({ id: relationTable.ownerId })
|
|
171
|
+
.from(relationTable)
|
|
172
|
+
.where(and(eq(relationTable.path, column), ...(localized ? [eq(relationTable.locale, locale)] : [])))
|
|
173
|
+
.groupBy(relationTable.ownerId)
|
|
174
|
+
.having(drizzleORM.gt(drizzleORM.count(relationTable.id), 0));
|
|
175
|
+
// Match documents that have relations and do NOT have any non-matching relation rows
|
|
176
|
+
return and(drizzleORM.notInArray(table.id, ownersWithNonMatching), inArray(table.id, ownersWithRelations));
|
|
177
|
+
}
|
|
178
|
+
// For multi-valued relations, `not_in_array` should match documents where the provided
|
|
179
|
+
// set does NOT contain all of the document's relation values (inverse of `in_array`).
|
|
180
|
+
if (fieldConfig.many && operator === 'not_in_array') {
|
|
181
|
+
let values = (() => {
|
|
182
|
+
if (Array.isArray(rawValue))
|
|
183
|
+
return rawValue;
|
|
184
|
+
if (typeof rawValue === 'string' && rawValue.includes(','))
|
|
185
|
+
return rawValue.split(',');
|
|
186
|
+
if (Array.isArray(value))
|
|
187
|
+
return value;
|
|
188
|
+
return [value];
|
|
189
|
+
})();
|
|
190
|
+
values = Array.from(new Set(values));
|
|
191
|
+
const ownersWithNonMatching = db
|
|
192
|
+
.select({ id: relationTable.ownerId })
|
|
193
|
+
.from(relationTable)
|
|
194
|
+
.where(and(drizzleORM.notInArray(relationTable[`${to}Id`], values), eq(relationTable.path, column), ...(localized ? [eq(relationTable.locale, locale)] : [])))
|
|
195
|
+
.groupBy(relationTable.ownerId)
|
|
196
|
+
.having(drizzleORM.gt(drizzleORM.count(relationTable.id), 0));
|
|
197
|
+
return inArray(table.id, ownersWithNonMatching);
|
|
198
|
+
}
|
|
199
|
+
// For multi-valued relations, `not_equals` is the inverse of `equals` (exact-set inequality)
|
|
200
|
+
if (fieldConfig.many && operator === 'not_equals') {
|
|
201
|
+
let values = (() => {
|
|
202
|
+
if (Array.isArray(rawValue))
|
|
203
|
+
return rawValue;
|
|
204
|
+
if (typeof rawValue === 'string' && rawValue.includes(','))
|
|
205
|
+
return rawValue.split(',');
|
|
206
|
+
if (Array.isArray(value))
|
|
207
|
+
return value;
|
|
208
|
+
return [value];
|
|
209
|
+
})();
|
|
210
|
+
values = Array.from(new Set(values));
|
|
211
|
+
const ownersWithTotalCount = db
|
|
212
|
+
.select({ id: relationTable.ownerId })
|
|
213
|
+
.from(relationTable)
|
|
214
|
+
.where(and(eq(relationTable.path, column), ...(localized ? [eq(relationTable.locale, locale)] : [])))
|
|
215
|
+
.groupBy(relationTable.ownerId)
|
|
216
|
+
.having(drizzleORM.eq(drizzleORM.count(relationTable.id), values.length));
|
|
217
|
+
const ownersWithMatchingCount = db
|
|
218
|
+
.select({ id: relationTable.ownerId })
|
|
219
|
+
.from(relationTable)
|
|
220
|
+
.where(and(inArray(relationTable[`${to}Id`], values), eq(relationTable.path, column), ...(localized ? [eq(relationTable.locale, locale)] : [])))
|
|
221
|
+
.groupBy(relationTable.ownerId)
|
|
222
|
+
.having(drizzleORM.eq(drizzleORM.count(relationTable.id), values.length));
|
|
223
|
+
return or(drizzleORM.notInArray(table.id, ownersWithTotalCount), drizzleORM.notInArray(table.id, ownersWithMatchingCount));
|
|
224
|
+
}
|
|
225
|
+
// Default behavior (membership checks with in_array etc.)
|
|
226
|
+
const conditions = [eq(relationTable.path, column), fn(relationTable[`${to}Id`], value)];
|
|
109
227
|
if (localized) {
|
|
110
228
|
conditions.push(eq(relationTable.locale, locale));
|
|
111
229
|
}
|