UNPKG

@adonis-agora/filter

Version:

Server-side query filtering/sorting/pagination for AdonisJS — Spatie-style input, a Lucid adapter, and field allow-listing. Part of the Agora ecosystem.

133 lines 5.08 kB
/** * A recording stand-in for a Lucid query builder, published under * `@adonis-agora/filter/testing` so consumers can unit-test their own filter * definitions without a database. It satisfies {@link QueryBuilderLike}, so any * of the adapter/runner helpers (or {@link applyFilterFromRequest}) can be * driven against it and the resulting translation asserted. * * Nested `where`/`orWhere` closures run against child recorders, and a dotted * relation-path filter's `whereHas` records the relation name plus runs its * nested callback against a child. {@link flatten} collects every leaf call * (across all groups and relation subqueries) so tests can assert a translation * appeared without caring about the exact grouping nesting. */ export class MockQueryBuilder { calls = []; children = []; record(method, ...args) { this.calls.push({ method, args }); return this; } group(method, cb) { const child = new MockQueryBuilder(); this.children.push(child); this.calls.push({ method, args: ['<group>'] }); cb(child); return this; } // biome-ignore lint/suspicious/noExplicitAny: structural overloads for the mock. where(a, b, c) { if (typeof a === 'function') return this.group('where', a); return c !== undefined ? this.record('where', a, b, c) : this.record('where', a, b); } orWhere(cb) { return this.group('orWhere', cb); } /** * Record a relation subquery: the `whereHas` call is captured with the * relation name (so `find('whereHas')?.args[0]` is the relation), and the * nested callback runs against a child recorder whose calls surface via * {@link flatten}. */ whereHas(relation, cb) { const child = new MockQueryBuilder(); this.children.push(child); this.calls.push({ method: 'whereHas', args: [relation] }); cb(child); return this; } whereNot(column, value) { return this.record('whereNot', column, value); } whereIn(column, values) { return this.record('whereIn', column, values); } whereNotIn(column, values) { return this.record('whereNotIn', column, values); } whereNull(column) { return this.record('whereNull', column); } whereNotNull(column) { return this.record('whereNotNull', column); } whereBetween(column, range) { return this.record('whereBetween', column, range); } whereNotBetween(column, range) { return this.record('whereNotBetween', column, range); } whereILike(column, value) { return this.record('whereILike', column, value); } orWhereILike(column, value) { return this.record('orWhereILike', column, value); } orderBy(column, direction) { return this.record('orderBy', column, direction); } /** Record a raw predicate: `args` are `[sql, bindings]` (bindings default `[]`). */ whereRaw(sql, bindings = []) { return this.record('whereRaw', sql, bindings); } /** Record a raw ordering: `args` are `[sql, bindings]` (bindings default `[]`). */ orderByRaw(sql, bindings = []) { return this.record('orderByRaw', sql, bindings); } limit(count) { return this.record('limit', count); } /** Record a row skip: `args` are `[n]`. Only the group-by-count aggregation pages this way. */ offset(n) { return this.record('offset', n); } /** Record a projection: `args` are the select expressions (aggregates included). */ select(...columns) { return this.record('select', ...columns); } /** Record an aggregation: `args` are `[column]` (e.g. `'* AS count'`). */ count(column) { return this.record('count', column); } /** Record a grouping: `args` are the group columns. */ groupBy(...columns) { return this.record('groupBy', ...columns); } /** Record a DISTINCT projection: `args` are the distinct column names. */ distinct(...columns) { return this.record('distinct', ...columns); } /** * Every recorded call across this builder and all nested groups and relation * subqueries (excludes the anonymous group markers, but keeps `whereHas` since * its recorded arg is the relation name, not a marker). */ flatten() { const own = this.calls.filter((c) => c.args[0] !== '<group>'); return [...own, ...this.children.flatMap((c) => c.flatten())]; } /** Find the first flattened call matching `method`. */ find(method) { return this.flatten().find((c) => c.method === method); } /** Every flattened call matching `method` (handy for asserting relation subqueries). */ findAll(method) { return this.flatten().filter((c) => c.method === method); } } /** Factory for a fresh {@link MockQueryBuilder} — the recording Lucid stand-in. */ export function makeMockQueryBuilder() { return new MockQueryBuilder(); } //# sourceMappingURL=testing.js.map