@adonis-agora/filter 0.0.0-beta-20261110131309

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.
Files changed (168) hide show
  1. package/CHANGELOG.md +417 -0
  2. package/LICENSE +21 -0
  3. package/README.md +75 -0
  4. package/dist/commands/main.d.ts +19 -0
  5. package/dist/commands/main.d.ts.map +1 -0
  6. package/dist/commands/main.js +19 -0
  7. package/dist/commands/main.js.map +1 -0
  8. package/dist/commands/make_filter.d.ts +18 -0
  9. package/dist/commands/make_filter.d.ts.map +1 -0
  10. package/dist/commands/make_filter.js +32 -0
  11. package/dist/commands/make_filter.js.map +1 -0
  12. package/dist/commands/make_filter_client.d.ts +35 -0
  13. package/dist/commands/make_filter_client.d.ts.map +1 -0
  14. package/dist/commands/make_filter_client.js +85 -0
  15. package/dist/commands/make_filter_client.js.map +1 -0
  16. package/dist/configure.d.ts +15 -0
  17. package/dist/configure.d.ts.map +1 -0
  18. package/dist/configure.js +20 -0
  19. package/dist/configure.js.map +1 -0
  20. package/dist/providers/filter_provider.d.ts +28 -0
  21. package/dist/providers/filter_provider.d.ts.map +1 -0
  22. package/dist/providers/filter_provider.js +33 -0
  23. package/dist/providers/filter_provider.js.map +1 -0
  24. package/dist/src/aggregate.d.ts +70 -0
  25. package/dist/src/aggregate.d.ts.map +1 -0
  26. package/dist/src/aggregate.js +195 -0
  27. package/dist/src/aggregate.js.map +1 -0
  28. package/dist/src/aggregate_path.d.ts +25 -0
  29. package/dist/src/aggregate_path.d.ts.map +1 -0
  30. package/dist/src/aggregate_path.js +35 -0
  31. package/dist/src/aggregate_path.js.map +1 -0
  32. package/dist/src/apply_from_request.d.ts +85 -0
  33. package/dist/src/apply_from_request.d.ts.map +1 -0
  34. package/dist/src/apply_from_request.js +164 -0
  35. package/dist/src/apply_from_request.js.map +1 -0
  36. package/dist/src/base_filter.d.ts +49 -0
  37. package/dist/src/base_filter.d.ts.map +1 -0
  38. package/dist/src/base_filter.js +33 -0
  39. package/dist/src/base_filter.js.map +1 -0
  40. package/dist/src/base_model_filter.d.ts +90 -0
  41. package/dist/src/base_model_filter.d.ts.map +1 -0
  42. package/dist/src/base_model_filter.js +85 -0
  43. package/dist/src/base_model_filter.js.map +1 -0
  44. package/dist/src/coerce_value.d.ts +26 -0
  45. package/dist/src/coerce_value.d.ts.map +1 -0
  46. package/dist/src/coerce_value.js +82 -0
  47. package/dist/src/coerce_value.js.map +1 -0
  48. package/dist/src/cursor.d.ts +92 -0
  49. package/dist/src/cursor.d.ts.map +1 -0
  50. package/dist/src/cursor.js +107 -0
  51. package/dist/src/cursor.js.map +1 -0
  52. package/dist/src/custom_filter.d.ts +36 -0
  53. package/dist/src/custom_filter.d.ts.map +1 -0
  54. package/dist/src/custom_filter.js +127 -0
  55. package/dist/src/custom_filter.js.map +1 -0
  56. package/dist/src/decorator_metadata.d.ts +41 -0
  57. package/dist/src/decorator_metadata.d.ts.map +1 -0
  58. package/dist/src/decorator_metadata.js +83 -0
  59. package/dist/src/decorator_metadata.js.map +1 -0
  60. package/dist/src/decorators.d.ts +73 -0
  61. package/dist/src/decorators.d.ts.map +1 -0
  62. package/dist/src/decorators.js +118 -0
  63. package/dist/src/decorators.js.map +1 -0
  64. package/dist/src/escape-like.d.ts +10 -0
  65. package/dist/src/escape-like.d.ts.map +1 -0
  66. package/dist/src/escape-like.js +15 -0
  67. package/dist/src/escape-like.js.map +1 -0
  68. package/dist/src/field_aliases.d.ts +30 -0
  69. package/dist/src/field_aliases.d.ts.map +1 -0
  70. package/dist/src/field_aliases.js +65 -0
  71. package/dist/src/field_aliases.js.map +1 -0
  72. package/dist/src/filter_class.d.ts +46 -0
  73. package/dist/src/filter_class.d.ts.map +1 -0
  74. package/dist/src/filter_class.js +244 -0
  75. package/dist/src/filter_class.js.map +1 -0
  76. package/dist/src/filter_spec.d.ts +231 -0
  77. package/dist/src/filter_spec.d.ts.map +1 -0
  78. package/dist/src/filter_spec.js +182 -0
  79. package/dist/src/filter_spec.js.map +1 -0
  80. package/dist/src/filterable_mixin.d.ts +49 -0
  81. package/dist/src/filterable_mixin.d.ts.map +1 -0
  82. package/dist/src/filterable_mixin.js +47 -0
  83. package/dist/src/filterable_mixin.js.map +1 -0
  84. package/dist/src/generate_client.d.ts +107 -0
  85. package/dist/src/generate_client.d.ts.map +1 -0
  86. package/dist/src/generate_client.js +164 -0
  87. package/dist/src/generate_client.js.map +1 -0
  88. package/dist/src/group_by_count.d.ts +67 -0
  89. package/dist/src/group_by_count.d.ts.map +1 -0
  90. package/dist/src/group_by_count.js +71 -0
  91. package/dist/src/group_by_count.js.map +1 -0
  92. package/dist/src/in_memory.d.ts +279 -0
  93. package/dist/src/in_memory.d.ts.map +1 -0
  94. package/dist/src/in_memory.js +810 -0
  95. package/dist/src/in_memory.js.map +1 -0
  96. package/dist/src/index.d.ts +51 -0
  97. package/dist/src/index.d.ts.map +1 -0
  98. package/dist/src/index.js +33 -0
  99. package/dist/src/index.js.map +1 -0
  100. package/dist/src/lucid_adapter.d.ts +311 -0
  101. package/dist/src/lucid_adapter.d.ts.map +1 -0
  102. package/dist/src/lucid_adapter.js +469 -0
  103. package/dist/src/lucid_adapter.js.map +1 -0
  104. package/dist/src/lucid_macros.d.ts +87 -0
  105. package/dist/src/lucid_macros.d.ts.map +1 -0
  106. package/dist/src/lucid_macros.js +67 -0
  107. package/dist/src/lucid_macros.js.map +1 -0
  108. package/dist/src/normalizer.d.ts +21 -0
  109. package/dist/src/normalizer.d.ts.map +1 -0
  110. package/dist/src/normalizer.js +61 -0
  111. package/dist/src/normalizer.js.map +1 -0
  112. package/dist/src/operators.d.ts +37 -0
  113. package/dist/src/operators.d.ts.map +1 -0
  114. package/dist/src/operators.js +43 -0
  115. package/dist/src/operators.js.map +1 -0
  116. package/dist/src/paginate.d.ts +12 -0
  117. package/dist/src/paginate.d.ts.map +1 -0
  118. package/dist/src/paginate.js +88 -0
  119. package/dist/src/paginate.js.map +1 -0
  120. package/dist/src/pagination_stash.d.ts +4 -0
  121. package/dist/src/pagination_stash.d.ts.map +1 -0
  122. package/dist/src/pagination_stash.js +19 -0
  123. package/dist/src/pagination_stash.js.map +1 -0
  124. package/dist/src/parse_request.d.ts +50 -0
  125. package/dist/src/parse_request.d.ts.map +1 -0
  126. package/dist/src/parse_request.js +220 -0
  127. package/dist/src/parse_request.js.map +1 -0
  128. package/dist/src/runner.d.ts +65 -0
  129. package/dist/src/runner.d.ts.map +1 -0
  130. package/dist/src/runner.js +371 -0
  131. package/dist/src/runner.js.map +1 -0
  132. package/dist/src/source_resolver.d.ts +18 -0
  133. package/dist/src/source_resolver.d.ts.map +1 -0
  134. package/dist/src/source_resolver.js +64 -0
  135. package/dist/src/source_resolver.js.map +1 -0
  136. package/dist/src/spatie_parser.d.ts +39 -0
  137. package/dist/src/spatie_parser.d.ts.map +1 -0
  138. package/dist/src/spatie_parser.js +134 -0
  139. package/dist/src/spatie_parser.js.map +1 -0
  140. package/dist/src/testing.d.ts +73 -0
  141. package/dist/src/testing.d.ts.map +1 -0
  142. package/dist/src/testing.js +136 -0
  143. package/dist/src/testing.js.map +1 -0
  144. package/dist/src/types.d.ts +226 -0
  145. package/dist/src/types.d.ts.map +1 -0
  146. package/dist/src/types.js +2 -0
  147. package/dist/src/types.js.map +1 -0
  148. package/dist/src/validate-column-filter.d.ts +30 -0
  149. package/dist/src/validate-column-filter.d.ts.map +1 -0
  150. package/dist/src/validate-column-filter.js +148 -0
  151. package/dist/src/validate-column-filter.js.map +1 -0
  152. package/dist/src/value-shape.d.ts +18 -0
  153. package/dist/src/value-shape.d.ts.map +1 -0
  154. package/dist/src/value-shape.js +36 -0
  155. package/dist/src/value-shape.js.map +1 -0
  156. package/dist/stubs/main.d.ts +3 -0
  157. package/dist/stubs/main.d.ts.map +1 -0
  158. package/dist/stubs/main.js +4 -0
  159. package/dist/stubs/main.js.map +1 -0
  160. package/dist/stubs/make/filter/main.stub +45 -0
  161. package/package.json +102 -0
  162. package/skills/filter-basics/SKILL.md +285 -0
  163. package/skills/filter-codegen/SKILL.md +246 -0
  164. package/skills/filter-definitions/SKILL.md +340 -0
  165. package/skills/filter-querying/SKILL.md +319 -0
  166. package/skills/filter-safety/SKILL.md +304 -0
  167. package/stubs/main.ts +4 -0
  168. package/stubs/make/filter/main.stub +45 -0
@@ -0,0 +1,65 @@
1
+ import { type CursorParams, type ResolvedCursor } from './cursor.js';
2
+ import { type QueryBuilderLike } from './lucid_adapter.js';
3
+ import type { FilterConfig, FilterInput } from './types.js';
4
+ /** The resolved offset pagination to hand to Lucid's `query.paginate(page, size)`. */
5
+ export interface ResolvedPagination {
6
+ page: number;
7
+ size: number;
8
+ }
9
+ /**
10
+ * Resolve aliases, structurally validate, and prune `input.filters`/`input.search`
11
+ * against the allow-lists, applying the survivors to the builder. Shared by both
12
+ * {@link applyFilter} (offset) and {@link applyCursor} (keyset) so the security
13
+ * boundary is identical for either pagination style.
14
+ */
15
+ export declare function applyFilterConditions(qb: QueryBuilderLike, input: FilterInput, config: FilterConfig): void;
16
+ /**
17
+ * Resolve the alias-mapped, allow-listed distinct fields for the request. A
18
+ * distinct field is a projected column, so it is gated by the SAME `allowed`
19
+ * boundary a `where` field is — aliases resolve first, then the allow-list;
20
+ * unknown fields are dropped (or rejected under `throwOnInvalid`).
21
+ *
22
+ * A field that clears the allow-list but is not projectable
23
+ * ({@link isProjectable}) is dropped/rejected too, with its OWN message: it is
24
+ * not an allow-list problem, so pointing the reader at `allowed` would send them
25
+ * to edit the wrong thing.
26
+ */
27
+ export declare function resolveSafeDistinct(fields: string[], config: FilterConfig): string[];
28
+ /**
29
+ * Apply a parsed {@link FilterInput} to a Lucid query builder under a
30
+ * {@link FilterConfig} policy, and return the resolved offset pagination.
31
+ *
32
+ * The allow-lists are the security boundary — fields not in `allowed`/`sortable`/
33
+ * `searchable` are dropped (or rejected with `throwOnInvalid`). Pagination is
34
+ * returned (not applied) so the caller drives Lucid's `query.paginate()`:
35
+ *
36
+ * ```ts
37
+ * const { page, size } = applyFilter(Users.query(), input, { allowed: ['name', 'age'] })
38
+ * const result = await Users.query()... // or: await query.paginate(page, size)
39
+ * ```
40
+ */
41
+ export declare function applyFilter(qb: QueryBuilderLike, input: FilterInput, config: FilterConfig): ResolvedPagination;
42
+ /** Per-call policy for {@link applyCursor} — a {@link FilterConfig} plus the keyset tiebreaker. */
43
+ export interface CursorConfig extends FilterConfig {
44
+ /** Primary-key column appended to the keyset as a stable tiebreaker. Default `'id'`. */
45
+ primaryKey?: string;
46
+ }
47
+ /**
48
+ * Apply a parsed {@link FilterInput} plus {@link CursorParams} to a Lucid query
49
+ * builder as a **keyset (cursor) page** under a {@link CursorConfig} policy.
50
+ *
51
+ * Filters/search go through the same allow-list boundary as {@link applyFilter}.
52
+ * The effective (allow-listed) sort, plus the primary-key tiebreaker, forms the
53
+ * keyset; a supplied `after`/`before` cursor becomes a row-value seek predicate,
54
+ * and the builder is ordered + limited to `size + 1` (one extra row to detect a
55
+ * further page). Feed the fetched rows and the returned {@link ResolvedCursor}
56
+ * to {@link buildCursorPage} to assemble the page and its boundary cursors:
57
+ *
58
+ * ```ts
59
+ * const resolved = applyCursor(Users.query(), input, { allowed: ['name'], primaryKey: 'id' })
60
+ * const rows = await Users.query()...exec()
61
+ * const page = buildCursorPage(rows, resolved)
62
+ * ```
63
+ */
64
+ export declare function applyCursor(qb: QueryBuilderLike, input: FilterInput & CursorParams, config: CursorConfig): ResolvedCursor;
65
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/runner.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,YAAY,EAEjB,KAAK,cAAc,EAEpB,MAAM,aAAa,CAAC;AAOrB,OAAO,EAUL,KAAK,gBAAgB,EAEtB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,KAAK,EAA6B,YAAY,EAAE,WAAW,EAAY,MAAM,YAAY,CAAC;AAGjG,sFAAsF;AACtF,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAyID;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,EAAE,EAAE,gBAAgB,EACpB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,YAAY,GACnB,IAAI,CA4DN;AAyBD;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,GAAG,MAAM,EAAE,CA0BpF;AAwDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,EAAE,EAAE,gBAAgB,EACpB,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,YAAY,GACnB,kBAAkB,CAmCpB;AAED,mGAAmG;AACnG,MAAM,WAAW,YAAa,SAAQ,YAAY;IAChD,wFAAwF;IACxF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CACzB,EAAE,EAAE,gBAAgB,EACpB,KAAK,EAAE,WAAW,GAAG,YAAY,EACjC,MAAM,EAAE,YAAY,GACnB,cAAc,CA0BhB"}
@@ -0,0 +1,371 @@
1
+ import { countExistencePredicate } from './aggregate.js';
2
+ import { coerceFilterValue } from './coerce_value.js';
3
+ import { buildKeyset, decodeCursor, reverseKeyset, } from './cursor.js';
4
+ import { remapDistinctAliases, remapFilterAliases, remapSortAliases, resolveFieldAlias, } from './field_aliases.js';
5
+ import { applyColumnFilters, applyComputedField, applyComputedSort, applyDistinct, applyFullTextSearch, applyKeyset, applySearch, applySort, applyVectorSimilarity, resolveComputedExpression, } from './lucid_adapter.js';
6
+ import { InvalidColumnFilterError, validateColumnFilters } from './validate-column-filter.js';
7
+ function isAllowed(field, allow) {
8
+ if (allow === '*')
9
+ return true;
10
+ if (typeof allow === 'function')
11
+ return allow(field);
12
+ return allow.includes(field);
13
+ }
14
+ function clamp(n, min, max) {
15
+ return Math.min(max, Math.max(min, n));
16
+ }
17
+ /**
18
+ * Own-property lookup of a declared computed field. A client-supplied field name
19
+ * is never trusted as a bare map key (prototype-pollution guard) — only an
20
+ * OWN, non-inherited key resolves to a computed source.
21
+ */
22
+ function computedKey(computed, field) {
23
+ return (computed !== undefined &&
24
+ typeof field === 'string' &&
25
+ field.length > 0 &&
26
+ Object.hasOwn(computed, field));
27
+ }
28
+ /**
29
+ * A top-level filter that targets a declared computed field: a leaf (has a
30
+ * field, no AND/OR children) whose name is an own key of the computed map.
31
+ * Computed fields are only recognised at the top level of `input.filters` — the
32
+ * shape the client emits — never nested inside a boolean group.
33
+ */
34
+ function isComputedLeaf(filter, computed) {
35
+ return computedKey(computed, filter.field) && filter.AND === undefined && filter.OR === undefined;
36
+ }
37
+ /**
38
+ * Operators whose value is a LIKE pattern rather than a column-typed value. Their argument stays a
39
+ * string no matter what kind the column is declared as — coercing `contains: '3'` on a numeric
40
+ * column to the number `3` would destroy the pattern the caller asked for.
41
+ */
42
+ const PATTERN_OPERATORS = new Set([
43
+ 'contains',
44
+ 'notContains',
45
+ 'iContains',
46
+ 'startsWith',
47
+ 'endsWith',
48
+ ]);
49
+ /** Operators whose value is a list/tuple — each element is coerced independently. */
50
+ const ARRAY_OPERATORS = new Set(['in', 'notIn', 'isAnyOf', 'between', 'notBetween']);
51
+ /**
52
+ * Coerce one leaf's value against its declared column kind. Returns `ok` unchanged when the field
53
+ * has no declared type (backwards compatible), when the operator carries a LIKE pattern, or when
54
+ * the kind has no contract to enforce. An array-valued operator fails as a whole if ANY element
55
+ * fails — a partially-coerced list would silently filter on something the client never asked for.
56
+ */
57
+ function coerceFilterForField(filter, fieldTypes) {
58
+ const kind = fieldTypes?.[filter.field]?.kind;
59
+ if (!kind || PATTERN_OPERATORS.has(String(filter.operator))) {
60
+ return { ok: true, value: filter.value };
61
+ }
62
+ if (ARRAY_OPERATORS.has(String(filter.operator)) && Array.isArray(filter.value)) {
63
+ const out = [];
64
+ for (const element of filter.value) {
65
+ const r = coerceFilterValue(element, kind);
66
+ if (!r.ok)
67
+ return r;
68
+ out.push(r.value);
69
+ }
70
+ return { ok: true, value: out };
71
+ }
72
+ return coerceFilterValue(filter.value, kind);
73
+ }
74
+ /**
75
+ * Recursively prune a filter against the allow-list. A leaf on a disallowed field
76
+ * is dropped (or throws when `throwOnInvalid`). Group nodes keep only their
77
+ * surviving children; a group left empty is itself dropped (returns `null`).
78
+ */
79
+ function prune(filter, allowed, throwOnInvalid, fieldTypes) {
80
+ const hasField = typeof filter.field === 'string' && filter.field.length > 0;
81
+ if (hasField && !isAllowed(filter.field, allowed)) {
82
+ if (throwOnInvalid) {
83
+ throw new InvalidColumnFilterError(`Field "${filter.field}" is not filterable.`);
84
+ }
85
+ return null;
86
+ }
87
+ const next = { field: filter.field, operator: filter.operator };
88
+ if (filter.value !== undefined) {
89
+ // The field passed the allow-list; now guard the VALUE. An uncoercible value is treated
90
+ // exactly like a disallowed field (drop, or throw under `throwOnInvalid`) rather than being
91
+ // handed to the driver, where Postgres would reject it as a 500 from user input.
92
+ const coerced = coerceFilterForField(filter, fieldTypes);
93
+ if (!coerced.ok) {
94
+ if (throwOnInvalid) {
95
+ throw new InvalidColumnFilterError(`Value for field "${filter.field}" is invalid: ${coerced.reason}.`);
96
+ }
97
+ return null;
98
+ }
99
+ next.value = coerced.value;
100
+ }
101
+ if (filter.AND) {
102
+ const kept = filter.AND.map((f) => prune(f, allowed, throwOnInvalid, fieldTypes)).filter((f) => f !== null);
103
+ if (kept.length > 0)
104
+ next.AND = kept;
105
+ }
106
+ if (filter.OR) {
107
+ const kept = filter.OR.map((f) => prune(f, allowed, throwOnInvalid, fieldTypes)).filter((f) => f !== null);
108
+ if (kept.length > 0)
109
+ next.OR = kept;
110
+ }
111
+ // A pure group node (no field of its own) with no surviving children is empty.
112
+ if (!hasField && next.AND === undefined && next.OR === undefined) {
113
+ return null;
114
+ }
115
+ return next;
116
+ }
117
+ /**
118
+ * Resolve aliases, structurally validate, and prune `input.filters`/`input.search`
119
+ * against the allow-lists, applying the survivors to the builder. Shared by both
120
+ * {@link applyFilter} (offset) and {@link applyCursor} (keyset) so the security
121
+ * boundary is identical for either pagination style.
122
+ */
123
+ export function applyFilterConditions(qb, input, config) {
124
+ const throwOnInvalid = config.throwOnInvalid ?? false;
125
+ if (input.filters && input.filters.length > 0) {
126
+ // Computed fields are a separate namespace from real columns: a top-level
127
+ // leaf on a declared computed key is routed to the computed hook (its
128
+ // declaration IS its allow-list) and NEVER run through the column
129
+ // alias/validate/allow-list path below. Everything else is a normal column
130
+ // filter. Checked before alias resolution so a computed key is not remapped.
131
+ const columnFilters = [];
132
+ for (const filter of input.filters) {
133
+ if (isComputedLeaf(filter, config.computed)) {
134
+ const source = config.computed?.[filter.field];
135
+ const existence = countExistencePredicate(source, config.table ?? '', filter);
136
+ if (existence)
137
+ qb.whereRaw(existence);
138
+ else
139
+ applyComputedField(qb, resolveComputedExpression(source, config.table ?? ''), filter);
140
+ }
141
+ else {
142
+ columnFilters.push(filter);
143
+ }
144
+ }
145
+ if (columnFilters.length > 0) {
146
+ // Alias resolution runs FIRST — the allow-list, validation and query builder
147
+ // all see the resolved target column, never the client-facing alias key.
148
+ const aliased = config.aliases
149
+ ? columnFilters.map((f) => remapFilterAliases(f, config.aliases))
150
+ : columnFilters;
151
+ // Structural validation next (operator/value shape, depth, field charset).
152
+ validateColumnFilters(aliased);
153
+ const safe = aliased
154
+ .map((f) => prune(f, config.allowed, throwOnInvalid, config.fieldTypes))
155
+ .filter((f) => f !== null);
156
+ if (safe.length > 0) {
157
+ applyColumnFilters(qb, safe);
158
+ }
159
+ }
160
+ }
161
+ if (input.search) {
162
+ const term = input.search.trim();
163
+ if (term.length > 0) {
164
+ // tsvector full-text search is the primary path when the policy declares
165
+ // it; otherwise fall back to the portable ILIKE scan across `searchable`.
166
+ if (config.fullText) {
167
+ applyFullTextSearch(qb, {
168
+ query: term,
169
+ column: config.fullText.column,
170
+ ...(config.fullText.language !== undefined && { language: config.fullText.language }),
171
+ ...(config.fullText.rank !== undefined && { rank: config.fullText.rank }),
172
+ ...(config.fullText.columnKind !== undefined && {
173
+ columnKind: config.fullText.columnKind,
174
+ }),
175
+ });
176
+ }
177
+ else if (config.searchable && config.searchable.length > 0) {
178
+ applySearch(qb, term, config.searchable);
179
+ }
180
+ }
181
+ }
182
+ }
183
+ /**
184
+ * Is this (alias-resolved) field projectable in the outer SELECT?
185
+ *
186
+ * A `where` on a relation path is translated by `applyLeaf` into a nested Lucid
187
+ * `whereHas`, which compiles to a **correlated EXISTS subquery** — the relation
188
+ * is never added to the outer `FROM`. A projection has no such escape hatch: the
189
+ * outer SELECT can only name a column of something the outer FROM holds. So
190
+ * `distinct=posts.title` on a spec that (correctly) whitelists `posts.title` for
191
+ * filtering would emit `select distinct "posts"."title" from "users"` and
192
+ * Postgres answers `missing FROM-clause entry for table "posts"` — a 500 driven
193
+ * by user input.
194
+ *
195
+ * The one qualifier that IS in the outer FROM is the root table itself (Lucid
196
+ * gives the main table no generated alias, so the table name is the alias — the
197
+ * same fact {@link FilterConfig.table} already encodes for computed fields).
198
+ * A single-segment name is a plain root column and always projectable.
199
+ */
200
+ function isProjectable(field, config) {
201
+ const dot = field.indexOf('.');
202
+ if (dot === -1)
203
+ return true;
204
+ return config.table !== undefined && field.slice(0, dot) === config.table;
205
+ }
206
+ /**
207
+ * Resolve the alias-mapped, allow-listed distinct fields for the request. A
208
+ * distinct field is a projected column, so it is gated by the SAME `allowed`
209
+ * boundary a `where` field is — aliases resolve first, then the allow-list;
210
+ * unknown fields are dropped (or rejected under `throwOnInvalid`).
211
+ *
212
+ * A field that clears the allow-list but is not projectable
213
+ * ({@link isProjectable}) is dropped/rejected too, with its OWN message: it is
214
+ * not an allow-list problem, so pointing the reader at `allowed` would send them
215
+ * to edit the wrong thing.
216
+ */
217
+ export function resolveSafeDistinct(fields, config) {
218
+ const throwOnInvalid = config.throwOnInvalid ?? false;
219
+ const aliased = config.aliases
220
+ ? remapDistinctAliases(fields, config.aliases)
221
+ : fields;
222
+ const safe = [];
223
+ for (const field of aliased) {
224
+ if (!isAllowed(field, config.allowed)) {
225
+ if (throwOnInvalid) {
226
+ throw new InvalidColumnFilterError(`Field "${field}" is not a distinct-able column.`);
227
+ }
228
+ continue;
229
+ }
230
+ if (!isProjectable(field, config)) {
231
+ if (throwOnInvalid) {
232
+ const relation = field.slice(0, field.indexOf('.'));
233
+ throw new InvalidColumnFilterError(`Field "${field}" cannot be used for distinct: it is a relation path, and a relation is filtered through a correlated EXISTS subquery, never joined into the query's FROM — so there is no "${relation}" table whose column the SELECT could project. This is NOT an allow-list problem: filtering on "${field}" works, projecting it does not, and adding it to \`allowed\` will not change that. Use a column of the root table for distinct.`);
234
+ }
235
+ continue;
236
+ }
237
+ if (!safe.includes(field))
238
+ safe.push(field);
239
+ }
240
+ return safe;
241
+ }
242
+ /**
243
+ * Apply the request's sort directives in order, routing each to the right hook:
244
+ * a declared computed field goes to `applyComputedSort` (an appended
245
+ * `orderByRaw`), a real column goes through alias resolution + the `sortable`
246
+ * allow-list to `applySort` (an appended `orderBy`). Both hooks append, so a
247
+ * computed sort and a real-column sort compose in request order — a client can
248
+ * sort by `fullName` then `id` and get exactly that ORDER BY sequence.
249
+ */
250
+ function applySortsWithComputed(qb, sort, config) {
251
+ const throwOnInvalid = config.throwOnInvalid ?? false;
252
+ const sortable = config.sortable ?? config.allowed;
253
+ for (const item of sort) {
254
+ if (computedKey(config.computed, item.field)) {
255
+ const expression = resolveComputedExpression(config.computed?.[item.field], config.table ?? '');
256
+ applyComputedSort(qb, expression, item.direction);
257
+ continue;
258
+ }
259
+ const field = config.aliases
260
+ ? resolveFieldAlias(config.aliases, item.field)
261
+ : item.field;
262
+ if (isAllowed(field, sortable)) {
263
+ applySort(qb, [{ field, direction: item.direction }]);
264
+ }
265
+ else if (throwOnInvalid) {
266
+ throw new InvalidColumnFilterError(`Field "${item.field}" is not sortable.`);
267
+ }
268
+ }
269
+ }
270
+ /** Resolve the alias-mapped, allow-listed sort directives for the request. */
271
+ function resolveSafeSort(sort, config) {
272
+ const throwOnInvalid = config.throwOnInvalid ?? false;
273
+ const sortable = config.sortable ?? config.allowed;
274
+ const aliased = config.aliases
275
+ ? remapSortAliases(sort, config.aliases)
276
+ : sort;
277
+ const safe = [];
278
+ for (const item of aliased) {
279
+ if (isAllowed(item.field, sortable)) {
280
+ safe.push(item);
281
+ }
282
+ else if (throwOnInvalid) {
283
+ throw new InvalidColumnFilterError(`Field "${item.field}" is not sortable.`);
284
+ }
285
+ }
286
+ return safe;
287
+ }
288
+ /**
289
+ * Apply a parsed {@link FilterInput} to a Lucid query builder under a
290
+ * {@link FilterConfig} policy, and return the resolved offset pagination.
291
+ *
292
+ * The allow-lists are the security boundary — fields not in `allowed`/`sortable`/
293
+ * `searchable` are dropped (or rejected with `throwOnInvalid`). Pagination is
294
+ * returned (not applied) so the caller drives Lucid's `query.paginate()`:
295
+ *
296
+ * ```ts
297
+ * const { page, size } = applyFilter(Users.query(), input, { allowed: ['name', 'age'] })
298
+ * const result = await Users.query()... // or: await query.paginate(page, size)
299
+ * ```
300
+ */
301
+ export function applyFilter(qb, input, config) {
302
+ applyFilterConditions(qb, input, config);
303
+ // Embedding-similarity ranking (opt-in, additive): only when the policy declares
304
+ // a similarity column AND the request carries a query embedding. Applied before
305
+ // the user sort so nearest-first distance is the primary ordering; any allowed
306
+ // sort then acts as a tiebreaker.
307
+ if (config.vectorSimilarity && input.vectorSimilarity && input.vectorSimilarity.length > 0) {
308
+ applyVectorSimilarity(qb, {
309
+ column: config.vectorSimilarity.column,
310
+ vector: input.vectorSimilarity,
311
+ ...(config.vectorSimilarity.metric !== undefined && {
312
+ metric: config.vectorSimilarity.metric,
313
+ }),
314
+ ...(config.vectorSimilarity.threshold !== undefined && {
315
+ threshold: config.vectorSimilarity.threshold,
316
+ }),
317
+ ...(config.vectorSimilarity.topK !== undefined && { topK: config.vectorSimilarity.topK }),
318
+ });
319
+ }
320
+ if (input.sort && input.sort.length > 0) {
321
+ applySortsWithComputed(qb, input.sort, config);
322
+ }
323
+ if (input.distinct && input.distinct.length > 0) {
324
+ const safeDistinct = resolveSafeDistinct(input.distinct, config);
325
+ if (safeDistinct.length > 0) {
326
+ applyDistinct(qb, safeDistinct);
327
+ }
328
+ }
329
+ const size = clamp(input.size ?? config.defaultSize ?? 25, 1, config.maxSize ?? 100);
330
+ const page = Math.max(1, input.page ?? 1);
331
+ return { page, size };
332
+ }
333
+ /**
334
+ * Apply a parsed {@link FilterInput} plus {@link CursorParams} to a Lucid query
335
+ * builder as a **keyset (cursor) page** under a {@link CursorConfig} policy.
336
+ *
337
+ * Filters/search go through the same allow-list boundary as {@link applyFilter}.
338
+ * The effective (allow-listed) sort, plus the primary-key tiebreaker, forms the
339
+ * keyset; a supplied `after`/`before` cursor becomes a row-value seek predicate,
340
+ * and the builder is ordered + limited to `size + 1` (one extra row to detect a
341
+ * further page). Feed the fetched rows and the returned {@link ResolvedCursor}
342
+ * to {@link buildCursorPage} to assemble the page and its boundary cursors:
343
+ *
344
+ * ```ts
345
+ * const resolved = applyCursor(Users.query(), input, { allowed: ['name'], primaryKey: 'id' })
346
+ * const rows = await Users.query()...exec()
347
+ * const page = buildCursorPage(rows, resolved)
348
+ * ```
349
+ */
350
+ export function applyCursor(qb, input, config) {
351
+ applyFilterConditions(qb, input, config);
352
+ const safeSort = input.sort && input.sort.length > 0 ? resolveSafeSort(input.sort, config) : [];
353
+ const baseKeyset = buildKeyset(safeSort, config.primaryKey ?? 'id');
354
+ const backward = input.before !== undefined && input.after === undefined;
355
+ const cursorStr = input.after ?? input.before;
356
+ const requested = backward ? input.last : input.first;
357
+ const size = clamp(requested ?? config.defaultSize ?? 25, 1, config.maxSize ?? 100);
358
+ // For backward paging, reverse keyset directions so the boundary seek and
359
+ // ordering walk the other way; buildCursorPage re-reverses the rows.
360
+ const queryKeyset = backward ? reverseKeyset(baseKeyset) : baseKeyset;
361
+ if (cursorStr !== undefined) {
362
+ const values = decodeCursor(cursorStr);
363
+ if (values && values.length === queryKeyset.length) {
364
+ applyKeyset(qb, queryKeyset, values);
365
+ }
366
+ }
367
+ applySort(qb, queryKeyset);
368
+ qb.limit(size + 1);
369
+ return { keyset: baseKeyset, size, backward, hasCursor: cursorStr !== undefined };
370
+ }
371
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { InputSource } from './types.js';
2
+ /**
3
+ * Resolve the raw structured input from a request according to an
4
+ * {@link InputSource}:
5
+ *
6
+ * - a function — a custom extractor, called with the request.
7
+ * - `'query'` / `'body'` — always that container.
8
+ * - `'auto'` (or any other bare token) — query on reads (GET/HEAD), query+body
9
+ * merged (body wins) on writes (POST/PUT/PATCH/DELETE).
10
+ * - a dot-path (e.g. `'body.filters'`) — the nested object at that path, or `{}`
11
+ * when the path is missing or does not resolve to an object.
12
+ *
13
+ * The `req` is treated structurally (`{ method, query, body }`), so an AdonisJS
14
+ * `HttpContext.request` — whose `qs()`/`body()` you pass in — or a plain object
15
+ * both work. The result is always a fresh shallow copy.
16
+ */
17
+ export declare function resolveInputFromRequest(req: unknown, source: InputSource): Record<string, unknown>;
18
+ //# sourceMappingURL=source_resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source_resolver.d.ts","sourceRoot":"","sources":["../../src/source_resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAW9C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,uBAAuB,CACrC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,WAAW,GAClB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA+BzB"}
@@ -0,0 +1,64 @@
1
+ const WRITE_METHODS = new Set(['POST', 'PUT', 'PATCH', 'DELETE']);
2
+ const READ_METHODS = new Set(['GET', 'HEAD']);
3
+ /**
4
+ * Resolve the raw structured input from a request according to an
5
+ * {@link InputSource}:
6
+ *
7
+ * - a function — a custom extractor, called with the request.
8
+ * - `'query'` / `'body'` — always that container.
9
+ * - `'auto'` (or any other bare token) — query on reads (GET/HEAD), query+body
10
+ * merged (body wins) on writes (POST/PUT/PATCH/DELETE).
11
+ * - a dot-path (e.g. `'body.filters'`) — the nested object at that path, or `{}`
12
+ * when the path is missing or does not resolve to an object.
13
+ *
14
+ * The `req` is treated structurally (`{ method, query, body }`), so an AdonisJS
15
+ * `HttpContext.request` — whose `qs()`/`body()` you pass in — or a plain object
16
+ * both work. The result is always a fresh shallow copy.
17
+ */
18
+ export function resolveInputFromRequest(req, source) {
19
+ if (typeof source === 'function') {
20
+ const r = source(req);
21
+ return { ...(r ?? {}) };
22
+ }
23
+ const r = (req ?? {});
24
+ const query = (r.query ?? {});
25
+ const body = (r.body ?? {});
26
+ switch (source) {
27
+ case 'query':
28
+ return { ...query };
29
+ case 'body':
30
+ return { ...body };
31
+ case 'auto': {
32
+ const method = (r.method ?? 'GET').toUpperCase();
33
+ if (READ_METHODS.has(method))
34
+ return { ...query };
35
+ if (WRITE_METHODS.has(method))
36
+ return { ...query, ...body };
37
+ return { ...query };
38
+ }
39
+ default: {
40
+ if (source.includes('.')) {
41
+ const resolved = resolveDotPath(r, source);
42
+ return { ...(resolved ?? {}) };
43
+ }
44
+ const method = (r.method ?? 'GET').toUpperCase();
45
+ if (READ_METHODS.has(method))
46
+ return { ...query };
47
+ if (WRITE_METHODS.has(method))
48
+ return { ...query, ...body };
49
+ return { ...query };
50
+ }
51
+ }
52
+ }
53
+ function resolveDotPath(obj, path) {
54
+ let current = obj;
55
+ for (const segment of path.split('.')) {
56
+ if (current == null || typeof current !== 'object')
57
+ return undefined;
58
+ current = current[segment];
59
+ }
60
+ if (current == null || typeof current !== 'object')
61
+ return undefined;
62
+ return current;
63
+ }
64
+ //# sourceMappingURL=source_resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source_resolver.js","sourceRoot":"","sources":["../../src/source_resolver.ts"],"names":[],"mappings":"AAEA,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;AAClE,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;AAQ9C;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,uBAAuB,CACrC,GAAY,EACZ,MAAmB;IAEnB,IAAI,OAAO,MAAM,KAAK,UAAU,EAAE,CAAC;QACjC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAA6B,CAAC;IACrD,CAAC;IACD,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAY,CAAC;IACjC,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAA4B,CAAC;IACzD,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAA4B,CAAC;IAEvD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,OAAO;YACV,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,EAAE,GAAG,IAAI,EAAE,CAAC;QACrB,KAAK,MAAM,EAAE,CAAC;YACZ,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;YACjD,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;YAClD,IAAI,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO,EAAE,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,CAAC;YAC5D,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;QACtB,CAAC;QACD,SAAS,CAAC;YACR,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBACzB,MAAM,QAAQ,GAAG,cAAc,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;gBAC3C,OAAO,EAAE,GAAG,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,CAAC;YACjC,CAAC;YACD,MAAM,MAAM,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;YACjD,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;YAClD,IAAI,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC;gBAAE,OAAO,EAAE,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,CAAC;YAC5D,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;QACtB,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,GAAY,EAAE,IAAY;IAChD,IAAI,OAAO,GAAY,GAAG,CAAC;IAC3B,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACrE,OAAO,GAAI,OAAmC,CAAC,OAAO,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,OAAO,IAAI,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACrE,OAAO,OAAkC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,39 @@
1
+ import type { CursorParams } from './cursor.js';
2
+ import type { FilterInput } from './types.js';
3
+ /**
4
+ * The richer Spatie / JSON:API input shape produced by {@link parseSpatieRequest}.
5
+ * A superset of {@link FilterInput}: it adds cursor pagination
6
+ * ({@link CursorParams}), JSON:API sparse fieldsets (`select`) and relation
7
+ * includes (`include`). Ready to hand to `applyFilter` (offset) or `applyCursor`
8
+ * (keyset) — the extra fields are ignored by whichever runner does not use them.
9
+ */
10
+ export interface SpatieInput extends FilterInput, CursorParams {
11
+ /** JSON:API sparse fieldsets (`fields[resource]=a,b`), flattened + de-duped. */
12
+ select?: string[];
13
+ /** Relation includes (`include=posts,comments`). */
14
+ include?: string[];
15
+ }
16
+ /**
17
+ * Parse a decoded, Spatie-laravel-query-builder / JSON:API-style query object
18
+ * into a {@link SpatieInput}. This is the richer, additive counterpart to
19
+ * {@link parseFilterRequest}: it understands the same `filter`/`sort`/`search`
20
+ * shapes plus JSON:API `include`, sparse `fields[resource]` sets, and cursor
21
+ * pagination (`page[after]`/`page[before]`).
22
+ *
23
+ * | Query string | Decoded input | Mapped to |
24
+ * | ------------------------------- | ------------------------------------ | ------------------------------------------ |
25
+ * | `filter[name]=Al` | `{ filter: { name: 'Al' } }` | `equals` column filter |
26
+ * | `filter[id]=1,2,3` | `{ filter: { id: '1,2,3' } }` | `in` column filter |
27
+ * | `filter[age][gte]=18` | `{ filter: { age: { gte: '18' } } }` | operator column filter |
28
+ * | `sort=-createdAt,name` | `{ sort: '-createdAt,name' }` | sort items |
29
+ * | `distinct=city,tier` | `{ distinct: 'city,tier' }` | `distinct: ['city', 'tier']` |
30
+ * | `include=posts,comments` | `{ include: 'posts,comments' }` | `include: ['posts', 'comments']` |
31
+ * | `fields[users]=id,name` | `{ fields: { users: 'id,name' } }` | `select: ['id', 'name']` |
32
+ * | `page[number]=2&page[size]=10` | `{ page: { number, size } }` | offset (`page`/`size`) |
33
+ * | `page[after]=cur&page[size]=10`| `{ page: { after, size } }` | cursor (`after`/`first`) |
34
+ *
35
+ * A pure reshape — no validation or allow-listing here; that happens downstream
36
+ * in `applyFilter` / `applyCursor` against the `FilterConfig`.
37
+ */
38
+ export declare function parseSpatieRequest(qs: unknown): SpatieInput;
39
+ //# sourceMappingURL=spatie_parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spatie_parser.d.ts","sourceRoot":"","sources":["../../src/spatie_parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,WAAW,WAAY,SAAQ,WAAW,EAAE,YAAY;IAC5D,gFAAgF;IAChF,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,oDAAoD;IACpD,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAWD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,OAAO,GAAG,WAAW,CA8B3D"}