mikser-io 9.1.0 → 9.2.0
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 +1 -1
- package/src/catalog.js +24 -5
- package/src/plugins/api.js +8 -1
- package/src/render.js +22 -13
package/package.json
CHANGED
package/src/catalog.js
CHANGED
|
@@ -567,19 +567,38 @@ async function expandAndProject(entity, expand) {
|
|
|
567
567
|
return { ...result, meta: projectMeta(result.meta) }
|
|
568
568
|
}
|
|
569
569
|
|
|
570
|
+
// Combine a caller's filter with an endpoint scope. A sift-shaped scope
|
|
571
|
+
// becomes part of the query so sift-to-sql can push it down; a function scope
|
|
572
|
+
// returns the filter untouched and is applied by the caller after the fetch.
|
|
573
|
+
export function scopedFilter(filter, scope) {
|
|
574
|
+
if (!scope || typeof scope === 'function') return filter
|
|
575
|
+
const hasFilter = filter && Object.keys(filter).length > 0
|
|
576
|
+
return hasFilter ? { $and: [filter, scope] } : scope
|
|
577
|
+
}
|
|
578
|
+
|
|
570
579
|
export async function queryEntities({
|
|
571
580
|
filter, sort, fields, skip, limit, expand, scope,
|
|
572
581
|
} = {}) {
|
|
573
582
|
const effectiveLimit = Math.min(100, Math.max(1, limit ?? 25))
|
|
574
583
|
const effectiveSkip = Math.max(0, skip ?? 0)
|
|
575
584
|
|
|
576
|
-
|
|
585
|
+
// A sift-shaped `scope` is merged into the filter so it reaches
|
|
586
|
+
// findEntities, where sift-to-sql pushes what it can into the WHERE
|
|
587
|
+
// clause. A function `scope` cannot be translated and stays a post-fetch
|
|
588
|
+
// predicate — which means the query materializes every row the caller's
|
|
589
|
+
// own filter matched, including the ones the endpoint would then reject.
|
|
590
|
+
// For an endpoint whose filter is broad (or absent) that is the entire
|
|
591
|
+
// catalog, per request, and `limit` does not help: it is applied after
|
|
592
|
+
// this. Prefer the object form.
|
|
593
|
+
const scopePredicate = typeof scope === 'function' ? scope : null
|
|
594
|
+
const effectiveFilter = scopedFilter(filter, scope)
|
|
595
|
+
|
|
596
|
+
recordQuery(effectiveFilter)
|
|
577
597
|
|
|
578
598
|
// Materialize via findEntities (which handles sqlite + shim
|
|
579
|
-
// dispatch + js fallback).
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
if (scope) all = all.filter(scope)
|
|
599
|
+
// dispatch + js fallback).
|
|
600
|
+
let all = await findEntities(effectiveFilter)
|
|
601
|
+
if (scopePredicate) all = all.filter(scopePredicate)
|
|
583
602
|
|
|
584
603
|
const total = all.length
|
|
585
604
|
|
package/src/plugins/api.js
CHANGED
|
@@ -407,7 +407,14 @@ export function api(options = {}) {
|
|
|
407
407
|
: ['list']
|
|
408
408
|
const allowedOps = new Set(ep.operations ?? defaultOps)
|
|
409
409
|
|
|
410
|
-
|
|
410
|
+
// The endpoint's scope. A sift filter is the form to prefer —
|
|
411
|
+
// queryEntities merges it into the WHERE clause, so the endpoint
|
|
412
|
+
// never materializes rows it would only reject. A function still
|
|
413
|
+
// works and is applied post-fetch, which costs every row the
|
|
414
|
+
// caller's filter matched.
|
|
415
|
+
const query = (typeof ep.query === 'function' || (ep.query && typeof ep.query === 'object'))
|
|
416
|
+
? ep.query
|
|
417
|
+
: null
|
|
411
418
|
const pageSize = ep.pageSize ?? globalPageSize
|
|
412
419
|
const renderTimeout = ep.renderTimeout ?? globalRenderTimeout
|
|
413
420
|
|
package/src/render.js
CHANGED
|
@@ -376,7 +376,10 @@ export function useRenderer(runtime, { defaultTimeout = 30_000 } = {}) {
|
|
|
376
376
|
* - `catalog: true` (default) — keep the entity in the catalog after
|
|
377
377
|
* the render. Pass `catalog: false` to prune the catalog row;
|
|
378
378
|
* useful for on-demand renders where the metadata row would just
|
|
379
|
-
* accumulate.
|
|
379
|
+
* accumulate. Requires `save: false` — the prune goes through the
|
|
380
|
+
* journal, and a DELETE takes the manifest's file cleanup with it,
|
|
381
|
+
* so it is only safe for a render that wrote nothing. With
|
|
382
|
+
* `save: true` the row is kept and a warning is logged.
|
|
380
383
|
* - `save: true` (default) — write the rendered output to disk at
|
|
381
384
|
* `<outputFolder>/<entity.destination>`. Pass `save: false` to
|
|
382
385
|
* skip the final disk write; the bytes still come back via
|
|
@@ -439,18 +442,24 @@ export function useRenderer(runtime, { defaultTimeout = 30_000 } = {}) {
|
|
|
439
442
|
})
|
|
440
443
|
|
|
441
444
|
if (catalog === false) {
|
|
442
|
-
//
|
|
443
|
-
//
|
|
444
|
-
//
|
|
445
|
-
//
|
|
446
|
-
//
|
|
447
|
-
//
|
|
448
|
-
//
|
|
449
|
-
//
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
445
|
+
// Prune the row through the journal, so the DELETE lands in
|
|
446
|
+
// sqlite at onPersist alongside the CREATE that put it there.
|
|
447
|
+
// Strict equality — null / "false" / 0 keep the row.
|
|
448
|
+
//
|
|
449
|
+
// Only when `save` is also false. A DELETE carries the
|
|
450
|
+
// manifest's file cleanup with it, which unlinks the render's
|
|
451
|
+
// output; that is correct for an entity that produced no file
|
|
452
|
+
// and wrong for one that did. `catalog: false, save: true`
|
|
453
|
+
// therefore keeps its row, and says so rather than dropping
|
|
454
|
+
// the output on the floor.
|
|
455
|
+
if (save === false) {
|
|
456
|
+
await runtime.delete(result.entity)
|
|
457
|
+
} else {
|
|
458
|
+
useLogger()?.warn(
|
|
459
|
+
'render: catalog:false ignored for %s — it needs save:false, ' +
|
|
460
|
+
'because pruning the row also unlinks the rendered output',
|
|
461
|
+
result.entity.id,
|
|
462
|
+
)
|
|
454
463
|
}
|
|
455
464
|
}
|
|
456
465
|
|