millas 0.2.7 → 0.2.8
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/package.json
CHANGED
|
@@ -165,37 +165,80 @@ class AdminResource {
|
|
|
165
165
|
const limit = perPage || this.perPage;
|
|
166
166
|
const offset = (page - 1) * limit;
|
|
167
167
|
|
|
168
|
-
|
|
168
|
+
// _db() is available on all ORM versions — it returns a raw knex table query.
|
|
169
|
+
// We build everything via knex directly so this works regardless of whether
|
|
170
|
+
// the ORM changes (changes3) have been applied.
|
|
171
|
+
let q = this.model._db().orderBy(sort, order);
|
|
169
172
|
|
|
170
|
-
// Search
|
|
173
|
+
// ── Search ───────────────────────────────────────────────────────────────
|
|
171
174
|
if (search && this.searchable.length) {
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
for (const col of
|
|
175
|
+
const cols = this.searchable;
|
|
176
|
+
q = q.where(function () {
|
|
177
|
+
for (const col of cols) {
|
|
175
178
|
this.orWhere(col, 'like', `%${search}%`);
|
|
176
179
|
}
|
|
177
180
|
});
|
|
178
181
|
}
|
|
179
182
|
|
|
180
|
-
// Filters
|
|
183
|
+
// ── Filters ──────────────────────────────────────────────────────────────
|
|
184
|
+
// Translate __ lookup syntax into knex calls so filter controls work
|
|
185
|
+
// even without the ORM changes applied.
|
|
181
186
|
for (const [key, value] of Object.entries(filters)) {
|
|
182
|
-
if (value
|
|
183
|
-
|
|
187
|
+
if (value === '' || value === null || value === undefined) continue;
|
|
188
|
+
|
|
189
|
+
const dunder = key.lastIndexOf('__');
|
|
190
|
+
if (dunder === -1) {
|
|
191
|
+
q = q.where(key, value);
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const col = key.slice(0, dunder);
|
|
196
|
+
const lookup = key.slice(dunder + 2);
|
|
197
|
+
|
|
198
|
+
switch (lookup) {
|
|
199
|
+
case 'exact': q = q.where(col, value); break;
|
|
200
|
+
case 'not': q = q.where(col, '!=', value); break;
|
|
201
|
+
case 'gt': q = q.where(col, '>', value); break;
|
|
202
|
+
case 'gte': q = q.where(col, '>=', value); break;
|
|
203
|
+
case 'lt': q = q.where(col, '<', value); break;
|
|
204
|
+
case 'lte': q = q.where(col, '<=', value); break;
|
|
205
|
+
case 'isnull': q = value ? q.whereNull(col) : q.whereNotNull(col); break;
|
|
206
|
+
case 'in': q = q.whereIn(col, Array.isArray(value) ? value : [value]); break;
|
|
207
|
+
case 'notin': q = q.whereNotIn(col, Array.isArray(value) ? value : [value]); break;
|
|
208
|
+
case 'between': q = q.whereBetween(col, value); break;
|
|
209
|
+
case 'contains':
|
|
210
|
+
case 'icontains': q = q.where(col, 'like', `%${value}%`); break;
|
|
211
|
+
case 'startswith':
|
|
212
|
+
case 'istartswith': q = q.where(col, 'like', `${value}%`); break;
|
|
213
|
+
case 'endswith':
|
|
214
|
+
case 'iendswith': q = q.where(col, 'like', `%${value}`); break;
|
|
215
|
+
default: q = q.where(key, value); break;
|
|
184
216
|
}
|
|
185
217
|
}
|
|
186
218
|
|
|
187
|
-
// Date hierarchy
|
|
219
|
+
// ── Date hierarchy ────────────────────────────────────────────────────────
|
|
188
220
|
if (this.dateHierarchy) {
|
|
189
|
-
|
|
190
|
-
if (
|
|
221
|
+
const col = this.dateHierarchy;
|
|
222
|
+
if (year) {
|
|
223
|
+
// SQLite / MySQL / PG compatible
|
|
224
|
+
q = q.whereRaw(`strftime('%Y', "${col}") = ?`, [String(year)])
|
|
225
|
+
.catch
|
|
226
|
+
// If strftime not available (PG), fall through — best effort
|
|
227
|
+
|| q;
|
|
228
|
+
}
|
|
229
|
+
if (month) {
|
|
230
|
+
q = q.whereRaw(`strftime('%m', "${col}") = ?`, [String(month).padStart(2, '0')]);
|
|
231
|
+
}
|
|
191
232
|
}
|
|
192
233
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
234
|
+
// ── Execute ───────────────────────────────────────────────────────────────
|
|
235
|
+
const [rows, countResult] = await Promise.all([
|
|
236
|
+
q.clone().limit(limit).offset(offset),
|
|
237
|
+
q.clone().count('* as count').first(),
|
|
197
238
|
]);
|
|
198
239
|
|
|
240
|
+
const total = Number(countResult?.count ?? 0);
|
|
241
|
+
|
|
199
242
|
return {
|
|
200
243
|
data: rows.map(r => this.model._hydrate(r)),
|
|
201
244
|
total,
|
|
@@ -494,11 +537,11 @@ class AdminInline {
|
|
|
494
537
|
async fetchRows(parentId) {
|
|
495
538
|
if (!this.model || !this.foreignKey) return [];
|
|
496
539
|
try {
|
|
497
|
-
const rows = await this.model.
|
|
540
|
+
const rows = await this.model._db()
|
|
498
541
|
.where(this.foreignKey, parentId)
|
|
499
542
|
.limit(this.perPage)
|
|
500
|
-
.
|
|
501
|
-
return rows.map(r =>
|
|
543
|
+
.orderBy('id', 'desc');
|
|
544
|
+
return rows.map(r => this.model._hydrate ? this.model._hydrate(r) : r);
|
|
502
545
|
} catch { return []; }
|
|
503
546
|
}
|
|
504
547
|
|