@adonis-agora/filter 0.1.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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/dist/commands/main.d.ts +17 -0
  4. package/dist/commands/main.d.ts.map +1 -0
  5. package/dist/commands/main.js +17 -0
  6. package/dist/commands/main.js.map +1 -0
  7. package/dist/commands/make_filter_client.d.ts +35 -0
  8. package/dist/commands/make_filter_client.d.ts.map +1 -0
  9. package/dist/commands/make_filter_client.js +85 -0
  10. package/dist/commands/make_filter_client.js.map +1 -0
  11. package/dist/src/apply_from_request.d.ts +69 -0
  12. package/dist/src/apply_from_request.d.ts.map +1 -0
  13. package/dist/src/apply_from_request.js +115 -0
  14. package/dist/src/apply_from_request.js.map +1 -0
  15. package/dist/src/cursor.d.ts +92 -0
  16. package/dist/src/cursor.d.ts.map +1 -0
  17. package/dist/src/cursor.js +107 -0
  18. package/dist/src/cursor.js.map +1 -0
  19. package/dist/src/escape-like.d.ts +10 -0
  20. package/dist/src/escape-like.d.ts.map +1 -0
  21. package/dist/src/escape-like.js +15 -0
  22. package/dist/src/escape-like.js.map +1 -0
  23. package/dist/src/field_aliases.d.ts +28 -0
  24. package/dist/src/field_aliases.d.ts.map +1 -0
  25. package/dist/src/field_aliases.js +61 -0
  26. package/dist/src/field_aliases.js.map +1 -0
  27. package/dist/src/filter_spec.d.ts +146 -0
  28. package/dist/src/filter_spec.d.ts.map +1 -0
  29. package/dist/src/filter_spec.js +140 -0
  30. package/dist/src/filter_spec.js.map +1 -0
  31. package/dist/src/generate_client.d.ts +107 -0
  32. package/dist/src/generate_client.d.ts.map +1 -0
  33. package/dist/src/generate_client.js +154 -0
  34. package/dist/src/generate_client.js.map +1 -0
  35. package/dist/src/index.d.ts +28 -0
  36. package/dist/src/index.d.ts.map +1 -0
  37. package/dist/src/index.js +18 -0
  38. package/dist/src/index.js.map +1 -0
  39. package/dist/src/lucid_adapter.d.ts +213 -0
  40. package/dist/src/lucid_adapter.d.ts.map +1 -0
  41. package/dist/src/lucid_adapter.js +303 -0
  42. package/dist/src/lucid_adapter.js.map +1 -0
  43. package/dist/src/normalizer.d.ts +21 -0
  44. package/dist/src/normalizer.d.ts.map +1 -0
  45. package/dist/src/normalizer.js +61 -0
  46. package/dist/src/normalizer.js.map +1 -0
  47. package/dist/src/operators.d.ts +37 -0
  48. package/dist/src/operators.d.ts.map +1 -0
  49. package/dist/src/operators.js +43 -0
  50. package/dist/src/operators.js.map +1 -0
  51. package/dist/src/parse_request.d.ts +22 -0
  52. package/dist/src/parse_request.d.ts.map +1 -0
  53. package/dist/src/parse_request.js +107 -0
  54. package/dist/src/parse_request.js.map +1 -0
  55. package/dist/src/runner.d.ts +46 -0
  56. package/dist/src/runner.d.ts.map +1 -0
  57. package/dist/src/runner.js +190 -0
  58. package/dist/src/runner.js.map +1 -0
  59. package/dist/src/source_resolver.d.ts +18 -0
  60. package/dist/src/source_resolver.d.ts.map +1 -0
  61. package/dist/src/source_resolver.js +64 -0
  62. package/dist/src/source_resolver.js.map +1 -0
  63. package/dist/src/spatie_parser.d.ts +38 -0
  64. package/dist/src/spatie_parser.d.ts.map +1 -0
  65. package/dist/src/spatie_parser.js +130 -0
  66. package/dist/src/spatie_parser.js.map +1 -0
  67. package/dist/src/testing.d.ts +62 -0
  68. package/dist/src/testing.d.ts.map +1 -0
  69. package/dist/src/testing.js +113 -0
  70. package/dist/src/testing.js.map +1 -0
  71. package/dist/src/types.d.ts +130 -0
  72. package/dist/src/types.d.ts.map +1 -0
  73. package/dist/src/types.js +2 -0
  74. package/dist/src/types.js.map +1 -0
  75. package/dist/src/validate-column-filter.d.ts +30 -0
  76. package/dist/src/validate-column-filter.d.ts.map +1 -0
  77. package/dist/src/validate-column-filter.js +148 -0
  78. package/dist/src/validate-column-filter.js.map +1 -0
  79. package/dist/src/value-shape.d.ts +18 -0
  80. package/dist/src/value-shape.d.ts.map +1 -0
  81. package/dist/src/value-shape.js +36 -0
  82. package/dist/src/value-shape.js.map +1 -0
  83. package/package.json +71 -0
@@ -0,0 +1,154 @@
1
+ /** Enumerate the filterable field paths a spec admits, capped at `maxDepth` relation hops. */
2
+ export function filterableFieldPaths(spec, maxDepth = spec.maxDepth) {
3
+ return collectPaths(spec, 'filterable', maxDepth);
4
+ }
5
+ /** Enumerate the sortable field paths a spec admits, capped at `maxDepth` relation hops. */
6
+ export function sortableFieldPaths(spec, maxDepth = spec.maxDepth) {
7
+ return collectPaths(spec, 'sortable', maxDepth);
8
+ }
9
+ /**
10
+ * Walk the spec's base allow-list + relation whitelist into a flat, de-duped list
11
+ * of (dotted) field paths, bounded by `maxDepth` relation hops. A `'*'` allow-list
12
+ * cannot be enumerated (any column), so it contributes no concrete base names —
13
+ * the emitter then falls back to a permissive `string` field union.
14
+ */
15
+ function collectPaths(spec, kind, maxDepth) {
16
+ const out = [];
17
+ const base = kind === 'filterable' ? spec.filterable : spec.sortable;
18
+ if (Array.isArray(base))
19
+ out.push(...base);
20
+ const walk = (relations, prefix, depth) => {
21
+ if (depth > maxDepth)
22
+ return;
23
+ for (const [relName, rel] of Object.entries(relations)) {
24
+ const cols = kind === 'filterable' ? rel.filterable : (rel.sortable ?? rel.filterable);
25
+ if (Array.isArray(cols)) {
26
+ for (const col of cols)
27
+ out.push([...prefix, relName, col].join('.'));
28
+ }
29
+ if (rel.relations)
30
+ walk(rel.relations, [...prefix, relName], depth + 1);
31
+ }
32
+ };
33
+ walk(spec.relations, [], 1);
34
+ return [...new Set(out)];
35
+ }
36
+ /** `foo-bar_baz` → `FooBarBaz`. Strips non-identifier chars, PascalCases the rest. */
37
+ function toPascalCase(name) {
38
+ const parts = name.split(/[^A-Za-z0-9]+/).filter(Boolean);
39
+ const pascal = parts.map((p) => p.charAt(0).toUpperCase() + p.slice(1)).join('');
40
+ return /^[0-9]/.test(pascal) ? `_${pascal}` : pascal || 'Filter';
41
+ }
42
+ /** PascalCase but a lowercased first char — the value-identifier form (`peopleFilterQuery`). */
43
+ function toCamelCase(name) {
44
+ const pascal = toPascalCase(name);
45
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
46
+ }
47
+ /** `BlogPost`/`blog-post` → `blog_post` — the AdonisJS file-name convention. */
48
+ function toSnakeCase(name) {
49
+ return toPascalCase(name)
50
+ .replace(/([a-z0-9])([A-Z])/g, '$1_$2')
51
+ .toLowerCase();
52
+ }
53
+ /** Map a field's type info to a TS type literal. Mirrors the NestJS `kindToTs` emitter. */
54
+ function fieldTypeToTs(info) {
55
+ if (info.typeRef)
56
+ return info.typeRef;
57
+ if (info.enumValues && info.enumValues.length > 0) {
58
+ return info.enumValues
59
+ .map((v) => (typeof v === 'number' ? String(v) : JSON.stringify(v)))
60
+ .join(' | ');
61
+ }
62
+ switch (info.kind) {
63
+ case 'string':
64
+ return 'string';
65
+ case 'number':
66
+ return 'number';
67
+ case 'boolean':
68
+ return 'boolean';
69
+ case 'date':
70
+ return 'Date';
71
+ case 'json':
72
+ return 'Record<string, unknown>';
73
+ default:
74
+ return 'unknown';
75
+ }
76
+ }
77
+ /** The classifier kind stored in runtime meta (`typeRef`/enum collapse to their base bucket). */
78
+ function metaKind(info) {
79
+ return info.kind ?? 'unknown';
80
+ }
81
+ /**
82
+ * Generate a typed filter client module for one {@link FilterSpec} — a pure
83
+ * string transform. The emitted module exports, for a spec named `people`:
84
+ *
85
+ * - `type PeopleFilterFields` — the union of filterable field paths (the security
86
+ * boundary, as concrete string literals);
87
+ * - `interface PeopleFilterFieldTypes` — the per-field value-type map (only when
88
+ * `fieldTypes` is supplied), which drives the client's operator/value narrowing;
89
+ * - `const peopleFilterMeta` — runtime metadata (filterable/sortable/searchable
90
+ * fields, whitelisted relations, per-field kinds, and the default sort / page
91
+ * size / max size + cursor keyset the runner paginates by);
92
+ * - `function peopleFilterQuery()` — a `filterQueryTyped<Fields, FieldTypes>()`
93
+ * factory returning a type-safe builder scoped to this spec.
94
+ */
95
+ export function generateFilterClient(spec, options) {
96
+ const pascal = toPascalCase(options.name);
97
+ const camel = toCamelCase(options.name);
98
+ const clientModule = options.clientModule ?? '@adonis-agora/filter-client';
99
+ const maxDepth = options.maxDepth ?? spec.maxDepth;
100
+ const fieldTypes = options.fieldTypes ?? {};
101
+ const hasTypes = Object.keys(fieldTypes).length > 0;
102
+ const fields = filterableFieldPaths(spec, maxDepth);
103
+ const sortable = sortableFieldPaths(spec, maxDepth);
104
+ const relations = Object.keys(spec.relations);
105
+ const cursorKeyset = spec.defaultSort.map((s) => s.field);
106
+ const fieldsUnion = fields.length > 0 ? fields.map((f) => JSON.stringify(f)).join(' | ') : 'string';
107
+ const typesTypeName = `${pascal}FilterFieldTypes`;
108
+ const fieldsTypeName = `${pascal}FilterFields`;
109
+ const typeArgs = hasTypes ? `${fieldsTypeName}, ${typesTypeName}` : fieldsTypeName;
110
+ const lines = [];
111
+ if (options.banner ?? true) {
112
+ lines.push('// Code generated by @adonis-agora/filter. DO NOT EDIT.', `// Source: filter spec "${options.name}".`, '');
113
+ }
114
+ lines.push(`import { filterQueryTyped as _filterQueryTyped } from '${clientModule}';`, '', `/** Filterable field paths for \`${options.name}\` — the client's field-name allow-list. */`, `export type ${fieldsTypeName} = ${fieldsUnion};`, '');
115
+ if (hasTypes) {
116
+ lines.push(`/** Per-field value types for \`${options.name}\` (drives operator narrowing). */`);
117
+ lines.push(`export interface ${typesTypeName} {`);
118
+ for (const [field, info] of Object.entries(fieldTypes)) {
119
+ let ts = fieldTypeToTs(info);
120
+ if (info.nullable)
121
+ ts = `${ts} | null`;
122
+ lines.push(` ${JSON.stringify(field)}: ${ts};`);
123
+ }
124
+ lines.push('}', '');
125
+ }
126
+ const typesMeta = hasTypes
127
+ ? `{ ${Object.entries(fieldTypes)
128
+ .map(([field, info]) => `${JSON.stringify(field)}: ${JSON.stringify(metaKind(info))}`)
129
+ .join(', ')} }`
130
+ : '{}';
131
+ lines.push(`/** Runtime filter metadata for \`${options.name}\`. */`, `export const ${camel}FilterMeta = {`, ` fields: [${fields.map((f) => JSON.stringify(f)).join(', ')}],`, ` sortable: [${sortable.map((f) => JSON.stringify(f)).join(', ')}],`, ` searchable: [${spec.searchable.map((f) => JSON.stringify(f)).join(', ')}],`, ` relations: [${relations.map((r) => JSON.stringify(r)).join(', ')}],`, ` types: ${typesMeta},`, ` defaultSort: [${spec.defaultSort
132
+ .map((s) => `{ field: ${JSON.stringify(s.field)}, direction: ${JSON.stringify(s.direction)} }`)
133
+ .join(', ')}],`, ` cursorKeyset: [${cursorKeyset.map((f) => JSON.stringify(f)).join(', ')}],`, ` defaultSize: ${spec.defaultSize ?? 'undefined'},`, ` maxSize: ${spec.maxSize ?? 'undefined'},`, '} as const;', '', `/** A type-safe filter-query builder scoped to \`${options.name}\`'s filterable fields. */`, `export function ${camel}FilterQuery() {`, ` return _filterQueryTyped<${typeArgs}>();`, '}', '');
134
+ return lines.join('\n');
135
+ }
136
+ /**
137
+ * Expand a whole {@link FilterClientManifest} into per-spec generated modules —
138
+ * the pure core the `make:filter-client` ace command writes to disk. Kept pure
139
+ * (manifest in, modules out) so the command stays a thin IO wrapper and the
140
+ * expansion is itself testable without a running app.
141
+ */
142
+ export function generateFilterClients(manifest) {
143
+ return Object.entries(manifest).map(([name, entry]) => ({
144
+ name,
145
+ filename: `${toSnakeCase(name)}_filter_client.ts`,
146
+ code: generateFilterClient(entry.spec, {
147
+ name,
148
+ ...(entry.fieldTypes && { fieldTypes: entry.fieldTypes }),
149
+ ...(entry.clientModule && { clientModule: entry.clientModule }),
150
+ ...(entry.maxDepth !== undefined && { maxDepth: entry.maxDepth }),
151
+ }),
152
+ }));
153
+ }
154
+ //# sourceMappingURL=generate_client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate_client.js","sourceRoot":"","sources":["../../src/generate_client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /** Keep in sync with this package's `version` in package.json. */
2
+ export declare const VERSION = "0.1.0";
3
+ export type { ColumnFilter, FilterOperator, FilterOperatorAlias, FilterOperatorInput, } from './operators.js';
4
+ export { FILTER_OPERATORS, OPERATOR_ALIASES } from './operators.js';
5
+ export { InvalidColumnFilterError, MAX_FILTER_DEPTH, normalizeOperator, validateColumnFilter, validateColumnFilters, } from './validate-column-filter.js';
6
+ export { isOperatorObject, valueToColumnFilters } from './value-shape.js';
7
+ export { escapeLike } from './escape-like.js';
8
+ export type { AllowList, FilterConfig, FilterInput, FullTextSearchConfig, InputNormalizer, InputSource, SortItem, VectorSimilarityConfig, } from './types.js';
9
+ export { defineFilter, FilterDefinitionError, specToFilterConfig, } from './filter_spec.js';
10
+ export { filterableFieldPaths, generateFilterClient, generateFilterClients, sortableFieldPaths, } from './generate_client.js';
11
+ export type { FilterClientEntry, FilterClientManifest, FilterFieldKind, FilterFieldTypeInfo, GeneratedFilterClient, GenerateFilterClientOptions, } from './generate_client.js';
12
+ export type { DefineFilterOptions, FilterSpec, RelationColumns, RelationSpec, TenantResolver, TenantScopeSpec, } from './filter_spec.js';
13
+ export { applyCursorFromRequest, applyFilterFromRequest } from './apply_from_request.js';
14
+ export type { ApplyCursorFromRequestOptions, ApplyFromRequestOptions, FilterRequestContext, } from './apply_from_request.js';
15
+ export { parseFilterRequest, parseSort, toColumnFilters } from './parse_request.js';
16
+ export { parseSpatieRequest } from './spatie_parser.js';
17
+ export type { SpatieInput } from './spatie_parser.js';
18
+ export { applyCursor, applyFilter } from './runner.js';
19
+ export type { CursorConfig, ResolvedPagination } from './runner.js';
20
+ export { applyColumnFilters, applyFullTextSearch, applyKeyset, applySearch, applySort, applyVectorSimilarity, type FullTextSearchOptions, type QueryBuilderLike, type VectorDistanceMetric, type VectorSimilarityOptions, } from './lucid_adapter.js';
21
+ export { buildCursorPage, buildKeyset, decodeCursor, encodeCursor, extractCursorValues, reverseKeyset, } from './cursor.js';
22
+ export type { CursorPage, CursorParams, CursorValues, ResolvedCursor } from './cursor.js';
23
+ export { remapFilterAliases, remapSortAliases, resolveFieldAlias } from './field_aliases.js';
24
+ export type { FieldAliases } from './field_aliases.js';
25
+ export { normalizeInput } from './normalizer.js';
26
+ export type { NormalizeOptions } from './normalizer.js';
27
+ export { resolveInputFromRequest } from './source_resolver.js';
28
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,eAAO,MAAM,OAAO,UAAU,CAAC;AAE/B,YAAY,EACV,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,YAAY,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACX,oBAAoB,EACpB,eAAe,EACf,WAAW,EACX,QAAQ,EACR,sBAAsB,GACvB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,iBAAiB,EACjB,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,2BAA2B,GAC5B,MAAM,sBAAsB,CAAC;AAC9B,YAAY,EACV,mBAAmB,EACnB,UAAU,EACV,eAAe,EACf,YAAY,EACZ,cAAc,EACd,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACzF,YAAY,EACV,6BAA6B,EAC7B,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,GAC7B,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,eAAe,EACf,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,aAAa,GACd,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC1F,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC7F,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACjD,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,18 @@
1
+ /** Keep in sync with this package's `version` in package.json. */
2
+ export const VERSION = '0.1.0';
3
+ export { FILTER_OPERATORS, OPERATOR_ALIASES } from './operators.js';
4
+ export { InvalidColumnFilterError, MAX_FILTER_DEPTH, normalizeOperator, validateColumnFilter, validateColumnFilters, } from './validate-column-filter.js';
5
+ export { isOperatorObject, valueToColumnFilters } from './value-shape.js';
6
+ export { escapeLike } from './escape-like.js';
7
+ export { defineFilter, FilterDefinitionError, specToFilterConfig, } from './filter_spec.js';
8
+ export { filterableFieldPaths, generateFilterClient, generateFilterClients, sortableFieldPaths, } from './generate_client.js';
9
+ export { applyCursorFromRequest, applyFilterFromRequest } from './apply_from_request.js';
10
+ export { parseFilterRequest, parseSort, toColumnFilters } from './parse_request.js';
11
+ export { parseSpatieRequest } from './spatie_parser.js';
12
+ export { applyCursor, applyFilter } from './runner.js';
13
+ export { applyColumnFilters, applyFullTextSearch, applyKeyset, applySearch, applySort, applyVectorSimilarity, } from './lucid_adapter.js';
14
+ export { buildCursorPage, buildKeyset, decodeCursor, encodeCursor, extractCursorValues, reverseKeyset, } from './cursor.js';
15
+ export { remapFilterAliases, remapSortAliases, resolveFieldAlias } from './field_aliases.js';
16
+ export { normalizeInput } from './normalizer.js';
17
+ export { resolveInputFromRequest } from './source_resolver.js';
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAQ/B,OAAO,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AACpE,OAAO,EACL,wBAAwB,EACxB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAC1E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAW9C,OAAO,EACL,YAAY,EACZ,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,sBAAsB,CAAC;AAiB9B,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAMzF,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACpF,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAExD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAEvD,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,WAAW,EACX,WAAW,EACX,SAAS,EACT,qBAAqB,GAKtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,eAAe,EACf,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,aAAa,GACd,MAAM,aAAa,CAAC;AAErB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAE7F,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC"}
@@ -0,0 +1,213 @@
1
+ import type { ColumnFilter } from './operators.js';
2
+ import type { SortItem } from './types.js';
3
+ /**
4
+ * The structural subset of a Lucid `ModelQueryBuilder` / `DatabaseQueryBuilder`
5
+ * the adapter drives. An `@adonisjs/lucid` query builder satisfies it — declared
6
+ * locally so the adapter never hard-imports Lucid (and stays unit-testable with a
7
+ * recording mock). The nested-callback `where`/`orWhere` overloads model Lucid's
8
+ * grouping closures used for AND/OR composition.
9
+ */
10
+ export interface QueryBuilderLike {
11
+ where(callback: (qb: QueryBuilderLike) => void): QueryBuilderLike;
12
+ where(column: string, value: unknown): QueryBuilderLike;
13
+ where(column: string, operator: string, value: unknown): QueryBuilderLike;
14
+ orWhere(callback: (qb: QueryBuilderLike) => void): QueryBuilderLike;
15
+ /**
16
+ * Constrain the query to rows whose `relation` has at least one related row
17
+ * matching the nested conditions — Lucid's `whereHas`. Used to translate a
18
+ * dotted relation-path filter (`posts.title = x`) into a real subquery
19
+ * (`whereHas('posts', (q) => q.where('title', x))`) instead of a dotted
20
+ * column reference. Optional on real Lucid builders; the recording mock
21
+ * implements it so relation translation stays unit-testable.
22
+ */
23
+ whereHas(relation: string, callback: (qb: QueryBuilderLike) => void): QueryBuilderLike;
24
+ whereNot(column: string, value: unknown): QueryBuilderLike;
25
+ whereIn(column: string, values: unknown[]): QueryBuilderLike;
26
+ whereNotIn(column: string, values: unknown[]): QueryBuilderLike;
27
+ whereNull(column: string): QueryBuilderLike;
28
+ whereNotNull(column: string): QueryBuilderLike;
29
+ whereBetween(column: string, range: [unknown, unknown]): QueryBuilderLike;
30
+ whereNotBetween(column: string, range: [unknown, unknown]): QueryBuilderLike;
31
+ whereILike(column: string, value: string): QueryBuilderLike;
32
+ orWhereILike(column: string, value: string): QueryBuilderLike;
33
+ orderBy(column: string, direction: 'asc' | 'desc'): QueryBuilderLike;
34
+ /**
35
+ * Add a raw SQL predicate with positional bindings — Lucid's `whereRaw`. The
36
+ * escape hatch for constraints no structured method can express, used here for
37
+ * pgvector similarity (`embedding <=> ?::vector < ?`). `sql` is server-authored
38
+ * (never client text); every user value travels as a `?` binding. Optional on
39
+ * real Lucid builders; the recording mock implements it so vector translation
40
+ * stays unit-testable and the package stays framework-free.
41
+ */
42
+ whereRaw(sql: string, bindings?: readonly unknown[]): QueryBuilderLike;
43
+ /**
44
+ * Add a raw SQL ordering with positional bindings — Lucid's `orderByRaw`. Used
45
+ * to order by a pgvector distance expression (`embedding <=> ?::vector asc`),
46
+ * which no column-name `orderBy` can express. Same seam contract as
47
+ * {@link QueryBuilderLike.whereRaw}.
48
+ */
49
+ orderByRaw(sql: string, bindings?: readonly unknown[]): QueryBuilderLike;
50
+ limit(count: number): QueryBuilderLike;
51
+ }
52
+ /**
53
+ * A pgvector distance metric → the operator applied between the vector column and
54
+ * the query embedding:
55
+ *
56
+ * - `'cosine'` — cosine distance, pgvector `<=>` (default; the usual choice for
57
+ * normalized embeddings).
58
+ * - `'l2'` — Euclidean / L2 distance, pgvector `<->`.
59
+ * - `'innerProduct'` — negative inner product, pgvector `<#>`.
60
+ *
61
+ * All three are *distance* operators (smaller = more similar), so nearest-first
62
+ * ranking is always ascending order.
63
+ */
64
+ export type VectorDistanceMetric = 'cosine' | 'l2' | 'innerProduct';
65
+ /**
66
+ * Options for {@link applyVectorSimilarity} — an **embedding similarity** ordering
67
+ * (pgvector) against a `vector` column. This is DISTINCT from full-text search
68
+ * ({@link applyFullTextSearch}): here a query *embedding* is ranked against the
69
+ * column by a distance metric, optionally filtered by a distance threshold and
70
+ * truncated to the top-K nearest rows. (Full-text search matches a text *query
71
+ * string* against a tsvector document.)
72
+ */
73
+ export interface VectorSimilarityOptions {
74
+ /** The pgvector column to compare the query embedding against (e.g. `'embedding'`). */
75
+ column: string;
76
+ /** The query embedding — the vector rows are ranked by similarity to. */
77
+ vector: readonly number[];
78
+ /** Distance metric → pgvector operator. Default `'cosine'` (`<=>`). */
79
+ metric?: VectorDistanceMetric;
80
+ /**
81
+ * Keep only rows whose distance to the query embedding is strictly below this
82
+ * value (a `WHERE embedding <=> ? < threshold`). Omitted → no distance filter.
83
+ */
84
+ threshold?: number;
85
+ /**
86
+ * Limit the result to the K nearest rows (a `LIMIT`). Omitted → no limit is
87
+ * added here (the caller's pagination still applies).
88
+ */
89
+ topK?: number;
90
+ /**
91
+ * Order by ascending distance (nearest first). Default `true`. Set `false` to
92
+ * apply only a threshold filter without changing the query's ordering.
93
+ */
94
+ order?: boolean;
95
+ }
96
+ /**
97
+ * Apply an **embedding similarity** ordering (pgvector) to a Lucid query builder.
98
+ *
99
+ * This is *not* full-text search — it ranks rows by distance between a stored
100
+ * embedding column and a query *embedding vector*. For matching a text query
101
+ * string, use {@link applyFullTextSearch} instead.
102
+ *
103
+ * pgvector expresses similarity through raw distance operators (`<=>`, `<->`,
104
+ * `<#>`) that no structured query-builder method covers, so this drives the
105
+ * adapter's raw seam ({@link QueryBuilderLike.whereRaw}/`orderByRaw`) with the
106
+ * query embedding passed as a positional binding — the column name is the only
107
+ * interpolated fragment, and it is validated against a strict identifier charset
108
+ * so it can never carry injection. The distance expression is
109
+ * `<column> <op> ?::vector`, cast to `vector` so a text binding compares against
110
+ * the column.
111
+ *
112
+ * A no-op when the embedding is empty. When `order` is not `false`, rows are
113
+ * ordered nearest-first (ascending distance); `threshold` adds a max-distance
114
+ * filter; `topK` truncates to the K nearest.
115
+ */
116
+ export declare function applyVectorSimilarity(qb: QueryBuilderLike, opts: VectorSimilarityOptions): void;
117
+ /**
118
+ * Options for {@link applyFullTextSearch} — a Postgres **tsvector full-text
119
+ * search** (the parity behavior of the NestJS reference's `applyVectorSearch`).
120
+ * The user query string is matched against a text-search document with
121
+ * `websearch_to_tsquery` and the `@@` operator, optionally ranked by `ts_rank`.
122
+ *
123
+ * This is DISTINCT from {@link VectorSimilarityOptions} (embedding similarity):
124
+ * here the input is arbitrary *text*, tokenized by a language config; there the
125
+ * input is a numeric *embedding vector*.
126
+ */
127
+ export interface FullTextSearchOptions {
128
+ /**
129
+ * The user's raw search text. Always passed as a positional binding to
130
+ * `websearch_to_tsquery` — never interpolated into SQL. A no-op when blank.
131
+ */
132
+ query: string;
133
+ /**
134
+ * The document to match against. Either a single precomputed `tsvector`
135
+ * column (matched directly with `@@`), or one-or-more plain text columns that
136
+ * are wrapped in `to_tsvector(<language>, ...)` at query time (see
137
+ * {@link FullTextSearchOptions.columnKind}). Passing multiple columns implies
138
+ * `'text'`.
139
+ */
140
+ column: string | readonly string[];
141
+ /**
142
+ * Postgres text-search config / language used for both `websearch_to_tsquery`
143
+ * and any `to_tsvector` wrapping (e.g. `'english'`, `'simple'`). Default
144
+ * `'english'`. Validated against the strict identifier charset before it is
145
+ * spliced into SQL.
146
+ */
147
+ language?: string;
148
+ /**
149
+ * Add relevance ordering for matched rows (`ORDER BY ts_rank(...) DESC`). Off
150
+ * by default because it changes the query's default ordering; opt in for
151
+ * best-match-first results.
152
+ */
153
+ rank?: boolean;
154
+ /**
155
+ * How {@link FullTextSearchOptions.column} is treated:
156
+ * - `'tsvector'` — a precomputed `tsvector` column, matched directly (`col @@ ...`);
157
+ * - `'text'` — plain text column(s), wrapped in `to_tsvector(<language>, col ...)`.
158
+ *
159
+ * Defaults to `'tsvector'` for a single column and `'text'` when multiple
160
+ * columns are given.
161
+ */
162
+ columnKind?: 'tsvector' | 'text';
163
+ }
164
+ /**
165
+ * Apply a Postgres **tsvector full-text search** to a Lucid query builder — the
166
+ * parity port of the NestJS reference's `applyVectorSearch` (tsvector), NOT the
167
+ * embedding similarity {@link applyVectorSimilarity}.
168
+ *
169
+ * Injection-safety: the user `query` string ALWAYS travels as a positional
170
+ * binding (`websearch_to_tsquery('<lang>', ?)`); it is never interpolated.
171
+ * `websearch_to_tsquery` (not the raw `to_tsquery`) parses arbitrary user input
172
+ * — multi-word text, `"quoted phrases"`, `-exclude`, `or` — without throwing a
173
+ * syntax error. The only spliced fragments are the column name(s) and the
174
+ * language config, each validated against the strict identifier charset
175
+ * ({@link SAFE_IDENTIFIER}) before use, so neither can carry injection.
176
+ *
177
+ * The match predicate is `<document> @@ websearch_to_tsquery('<lang>', ?)` where
178
+ * `<document>` is either the tsvector column directly, or
179
+ * `to_tsvector('<lang>', coalesce(col1,'') || ' ' || coalesce(col2,''))` for
180
+ * text columns. When `rank` is set, rows are additionally ordered by descending
181
+ * `ts_rank(<document>, websearch_to_tsquery('<lang>', ?))`. A no-op for a blank
182
+ * query.
183
+ */
184
+ export declare function applyFullTextSearch(qb: QueryBuilderLike, opts: FullTextSearchOptions): void;
185
+ /** Apply an array of column filters (combined with AND) to a Lucid query builder. */
186
+ export declare function applyColumnFilters(qb: QueryBuilderLike, filters: ColumnFilter[]): void;
187
+ /** Apply sort directives to a Lucid query builder, in order. */
188
+ export declare function applySort(qb: QueryBuilderLike, sorts: SortItem[]): void;
189
+ /**
190
+ * Apply a keyset (cursor) seek predicate to a Lucid query builder for row-value
191
+ * comparison across the keyset columns.
192
+ *
193
+ * Given a keyset (the active sort columns plus a primary-key tiebreaker, each
194
+ * with a direction) and a boundary row's values, this constrains the query to
195
+ * rows strictly *after* the boundary in keyset order. The row-value comparison
196
+ * is expanded into the portable "OR of AND tiers" form that works across all
197
+ * SQL dialects:
198
+ *
199
+ * ```text
200
+ * (c0 OP0 v0)
201
+ * OR (c0 = v0 AND c1 OP1 v1)
202
+ * OR (c0 = v0 AND c1 = v1 AND c2 OP2 v2) ...
203
+ * ```
204
+ *
205
+ * where `OPi` is `>` for an `asc` column and `<` for a `desc` column. The whole
206
+ * predicate is wrapped in one AND-group so it composes with any existing
207
+ * `where` conditions. A no-op when the keyset is empty or `values` does not line
208
+ * up positionally with it.
209
+ */
210
+ export declare function applyKeyset(qb: QueryBuilderLike, keyset: SortItem[], values: unknown[]): void;
211
+ /** Apply a free-text ILIKE search across `columns` (OR-combined) to a Lucid query builder. */
212
+ export declare function applySearch(qb: QueryBuilderLike, term: string, columns: string[]): void;
213
+ //# sourceMappingURL=lucid_adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lucid_adapter.d.ts","sourceRoot":"","sources":["../../src/lucid_adapter.ts"],"names":[],"mappings":"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"}