@adonis-agora/filter-client 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 (39) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +21 -0
  3. package/dist/field-types.d.ts +68 -0
  4. package/dist/field-types.d.ts.map +1 -0
  5. package/dist/field-types.js +2 -0
  6. package/dist/field-types.js.map +1 -0
  7. package/dist/filter-query-builder.d.ts +301 -0
  8. package/dist/filter-query-builder.d.ts.map +1 -0
  9. package/dist/filter-query-builder.js +538 -0
  10. package/dist/filter-query-builder.js.map +1 -0
  11. package/dist/index.d.ts +11 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +6 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/tanstack.d.ts +58 -0
  16. package/dist/tanstack.d.ts.map +1 -0
  17. package/dist/tanstack.js +58 -0
  18. package/dist/tanstack.js.map +1 -0
  19. package/dist/to-query-string.d.ts +17 -0
  20. package/dist/to-query-string.d.ts.map +1 -0
  21. package/dist/to-query-string.js +72 -0
  22. package/dist/to-query-string.js.map +1 -0
  23. package/dist/typed-filter-query-builder.d.ts +78 -0
  24. package/dist/typed-filter-query-builder.d.ts.map +1 -0
  25. package/dist/typed-filter-query-builder.js +25 -0
  26. package/dist/typed-filter-query-builder.js.map +1 -0
  27. package/dist/typed-filter-query.d.ts +20 -0
  28. package/dist/typed-filter-query.d.ts.map +1 -0
  29. package/dist/typed-filter-query.js +2 -0
  30. package/dist/typed-filter-query.js.map +1 -0
  31. package/dist/types.d.ts +20 -0
  32. package/dist/types.d.ts.map +1 -0
  33. package/dist/types.js +28 -0
  34. package/dist/types.js.map +1 -0
  35. package/dist/validate-operator-value.d.ts +35 -0
  36. package/dist/validate-operator-value.d.ts.map +1 -0
  37. package/dist/validate-operator-value.js +91 -0
  38. package/dist/validate-operator-value.js.map +1 -0
  39. package/package.json +64 -0
@@ -0,0 +1,58 @@
1
+ import { FilterQueryBuilder } from './filter-query-builder.js';
2
+ const defaultResolveOperator = (_columnId, value) => {
3
+ if (Array.isArray(value))
4
+ return 'in';
5
+ if (typeof value === 'string')
6
+ return 'iContains';
7
+ return 'equals';
8
+ };
9
+ /**
10
+ * Applies vanilla TanStack Table state (column filters, sorting, pagination)
11
+ * onto an existing `FilterQueryBuilder`, then returns the same builder so you
12
+ * can chain `include`/`search`/extra `where` calls before `build()`.
13
+ *
14
+ * Framework-agnostic — works with any TanStack Table adapter (React, Vue,
15
+ * Svelte, Solid). `@tanstack/table-core` is a types-only peer.
16
+ *
17
+ * @example
18
+ * import { filterQuery } from '@adonis-agora/filter-client';
19
+ * import { applyTanstackTableState } from '@adonis-agora/filter-client/tanstack';
20
+ *
21
+ * const body = applyTanstackTableState(filterQuery(), {
22
+ * columnFilters: table.getState().columnFilters,
23
+ * sorting: table.getState().sorting,
24
+ * pagination: table.getState().pagination,
25
+ * resolveOperator: (id) => (id === 'createdAt' ? 'gte' : 'iContains'),
26
+ * })
27
+ * .include('author')
28
+ * .build();
29
+ */
30
+ export function applyTanstackTableState(builder, options = {}) {
31
+ const { columnFilters = [], sorting = [], pagination, resolveOperator = defaultResolveOperator, fields, } = options;
32
+ const allowed = fields ? new Set(fields) : null;
33
+ for (const { id, value } of columnFilters) {
34
+ if (value === null || value === undefined || value === '')
35
+ continue;
36
+ if (allowed && !allowed.has(id))
37
+ continue;
38
+ builder.where(id, resolveOperator(id, value), value);
39
+ }
40
+ for (const { id, desc } of sorting) {
41
+ if (allowed && !allowed.has(id))
42
+ continue;
43
+ builder.sort(id, desc ? 'desc' : 'asc');
44
+ }
45
+ if (pagination) {
46
+ builder.page(pagination.pageIndex, pagination.pageSize);
47
+ }
48
+ return builder;
49
+ }
50
+ /**
51
+ * One-shot convenience: builds a `FilterQueryResult` straight from vanilla
52
+ * TanStack Table state. Equivalent to
53
+ * `applyTanstackTableState(filterQuery(), options).build()`.
54
+ */
55
+ export function tanstackTableToFilterQuery(options = {}) {
56
+ return applyTanstackTableState(new FilterQueryBuilder(), options).build();
57
+ }
58
+ //# sourceMappingURL=tanstack.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tanstack.js","sourceRoot":"","sources":["../src/tanstack.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AA+B/D,MAAM,sBAAsB,GAAoB,CAAC,SAAS,EAAE,KAAK,EAAE,EAAE;IACnE,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,WAAW,CAAC;IAClD,OAAO,QAAQ,CAAC;AAClB,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,uBAAuB,CACrC,OAA2B,EAC3B,UAAqC,EAAE;IAEvC,MAAM,EACJ,aAAa,GAAG,EAAE,EAClB,OAAO,GAAG,EAAE,EACZ,UAAU,EACV,eAAe,GAAG,sBAAsB,EACxC,MAAM,GACP,GAAG,OAAO,CAAC;IACZ,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAEhD,KAAK,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,aAAa,EAAE,CAAC;QAC1C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;YAAE,SAAS;QACpE,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC1C,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,eAAe,CAAC,EAAE,EAAE,KAAK,CAAC,EAAE,KAAK,CAAC,CAAC;IACvD,CAAC;IAED,KAAK,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,OAAO,EAAE,CAAC;QACnC,IAAI,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,SAAS;QAC1C,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAED,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,0BAA0B,CACxC,UAAqC,EAAE;IAEvC,OAAO,uBAAuB,CAAC,IAAI,kBAAkB,EAAE,EAAE,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC;AAC5E,CAAC"}
@@ -0,0 +1,17 @@
1
+ import type { ColumnFilter } from './types.js';
2
+ /**
3
+ * Converts a flat object to a query string.
4
+ *
5
+ * Handles:
6
+ * - Simple value: `field=value`
7
+ * - Array: `field[]=a&field[]=b`
8
+ * - Operator object: `field[operator]=value`
9
+ * - Multiple operators: `field[gte]=a&field[lte]=b`
10
+ */
11
+ export declare function flatObjectToQueryString(obj: Record<string, unknown>): string;
12
+ /**
13
+ * Converts a ColumnFilter[] array to a query string using
14
+ * the `where[i][field]=...&where[i][operator]=...&where[i][value]=...` notation.
15
+ */
16
+ export declare function columnFiltersToQueryString(filters: ColumnFilter[]): string;
17
+ //# sourceMappingURL=to-query-string.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"to-query-string.d.ts","sourceRoot":"","sources":["../src/to-query-string.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAS/C;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAsB5E;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM,CAI1E"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Encodes a value for use in a URL query string.
3
+ */
4
+ function encode(value) {
5
+ return encodeURIComponent(String(value));
6
+ }
7
+ /**
8
+ * Converts a flat object to a query string.
9
+ *
10
+ * Handles:
11
+ * - Simple value: `field=value`
12
+ * - Array: `field[]=a&field[]=b`
13
+ * - Operator object: `field[operator]=value`
14
+ * - Multiple operators: `field[gte]=a&field[lte]=b`
15
+ */
16
+ export function flatObjectToQueryString(obj) {
17
+ const parts = [];
18
+ for (const [key, value] of Object.entries(obj)) {
19
+ if (value === undefined || value === null)
20
+ continue;
21
+ if (Array.isArray(value)) {
22
+ for (const item of value) {
23
+ parts.push(`${encode(key)}[]=${encode(item)}`);
24
+ }
25
+ }
26
+ else if (typeof value === 'object') {
27
+ for (const [op, opVal] of Object.entries(value)) {
28
+ if (opVal !== undefined && opVal !== null) {
29
+ parts.push(`${encode(key)}[${encode(op)}]=${encode(opVal)}`);
30
+ }
31
+ }
32
+ }
33
+ else {
34
+ parts.push(`${encode(key)}=${encode(value)}`);
35
+ }
36
+ }
37
+ return parts.join('&');
38
+ }
39
+ /**
40
+ * Converts a ColumnFilter[] array to a query string using
41
+ * the `where[i][field]=...&where[i][operator]=...&where[i][value]=...` notation.
42
+ */
43
+ export function columnFiltersToQueryString(filters) {
44
+ const parts = [];
45
+ serializeFilters(filters, 'where', parts);
46
+ return parts.join('&');
47
+ }
48
+ function serializeFilters(filters, prefix, parts) {
49
+ for (let i = 0; i < filters.length; i++) {
50
+ const filter = filters[i];
51
+ const base = `${prefix}[${i}]`;
52
+ parts.push(`${base}[field]=${encode(filter.field)}`);
53
+ parts.push(`${base}[operator]=${encode(filter.operator)}`);
54
+ if (filter.value !== undefined) {
55
+ if (Array.isArray(filter.value)) {
56
+ for (let j = 0; j < filter.value.length; j++) {
57
+ parts.push(`${base}[value][${j}]=${encode(filter.value[j])}`);
58
+ }
59
+ }
60
+ else {
61
+ parts.push(`${base}[value]=${encode(filter.value)}`);
62
+ }
63
+ }
64
+ if (filter.AND && filter.AND.length > 0) {
65
+ serializeFilters(filter.AND, `${base}[AND]`, parts);
66
+ }
67
+ if (filter.OR && filter.OR.length > 0) {
68
+ serializeFilters(filter.OR, `${base}[OR]`, parts);
69
+ }
70
+ }
71
+ }
72
+ //# sourceMappingURL=to-query-string.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"to-query-string.js","sourceRoot":"","sources":["../src/to-query-string.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,78 @@
1
+ import type { Base, EqValue, FieldsWithOp, FilterFieldTypes, OperatorsFor, OrderableFieldsOf, OrderingOps, StringFieldsOf, UnaryOf, ValueAt, ValueForOp } from './field-types.js';
2
+ import type { FilterQueryResult } from './filter-query-builder.js';
3
+ /**
4
+ * A type-safe wrapper interface over `FilterQueryBuilder` that restricts
5
+ * field name arguments to the `Fields` union type.
6
+ *
7
+ * At runtime this is identical to `FilterQueryBuilder` — the typing is the
8
+ * only difference. Zero runtime overhead.
9
+ *
10
+ * **Important:** This interface must mirror every public method of
11
+ * `FilterQueryBuilder` so the cast in `filterQueryTyped()` is safe.
12
+ */
13
+ export interface TypedFilterQueryBuilder<Fields extends string, M extends FilterFieldTypes<Fields> = Record<Fields, unknown>> {
14
+ where<K extends Fields>(field: K, operator: UnaryOf<ValueAt<M, K>>): this;
15
+ where<K extends Fields, Op extends OperatorsFor<ValueAt<M, K>>>(field: K, operator: Op, value: ValueForOp<ValueAt<M, K>, Op>): this;
16
+ where<K extends Fields>(field: K, value: EqValue<ValueAt<M, K>>): this;
17
+ add<K extends Fields, Op extends Extract<OperatorsFor<ValueAt<M, K>>, OrderingOps>>(field: K, operator: Op, value: ValueForOp<ValueAt<M, K>, Op>): this;
18
+ remove(field: Fields): this;
19
+ equals<K extends Fields>(field: K, value: EqValue<ValueAt<M, K>>): this;
20
+ notEquals<K extends Fields>(field: K, value: EqValue<ValueAt<M, K>>): this;
21
+ contains<K extends StringFieldsOf<M> & Fields>(field: K, value: string): this;
22
+ in<K extends Fields>(field: K, values: Base<ValueAt<M, K>>[]): this;
23
+ notIn<K extends Fields>(field: K, values: Base<ValueAt<M, K>>[]): this;
24
+ between<K extends OrderableFieldsOf<M> & Fields>(field: K, low: Base<ValueAt<M, K>>, high: Base<ValueAt<M, K>>): this;
25
+ gt<K extends OrderableFieldsOf<M> & Fields>(field: K, value: ValueForOp<ValueAt<M, K>, 'gt'>): this;
26
+ gte<K extends OrderableFieldsOf<M> & Fields>(field: K, value: ValueForOp<ValueAt<M, K>, 'gte'>): this;
27
+ lt<K extends OrderableFieldsOf<M> & Fields>(field: K, value: ValueForOp<ValueAt<M, K>, 'lt'>): this;
28
+ lte<K extends OrderableFieldsOf<M> & Fields>(field: K, value: ValueForOp<ValueAt<M, K>, 'lte'>): this;
29
+ isNull(field: Fields): this;
30
+ isNotNull(field: Fields): this;
31
+ isEmpty(field: FieldsWithOp<M, 'isEmpty'> & Fields): this;
32
+ isNotEmpty(field: FieldsWithOp<M, 'isNotEmpty'> & Fields): this;
33
+ startsWith<K extends StringFieldsOf<M> & Fields>(field: K, value: string): this;
34
+ endsWith<K extends StringFieldsOf<M> & Fields>(field: K, value: string): this;
35
+ addGte<K extends OrderableFieldsOf<M> & Fields>(field: K, value: Base<ValueAt<M, K>>): this;
36
+ addLte<K extends OrderableFieldsOf<M> & Fields>(field: K, value: Base<ValueAt<M, K>>): this;
37
+ addGt<K extends OrderableFieldsOf<M> & Fields>(field: K, value: Base<ValueAt<M, K>>): this;
38
+ addLt<K extends OrderableFieldsOf<M> & Fields>(field: K, value: Base<ValueAt<M, K>>): this;
39
+ sort(field: Fields, direction?: 'asc' | 'desc'): this;
40
+ sortAsc(field: Fields): this;
41
+ sortDesc(field: Fields): this;
42
+ distinct(...fields: Fields[]): this;
43
+ include(...relations: string[]): this;
44
+ search(term: string): this;
45
+ page(page: number, size?: number): this;
46
+ or(callback: (builder: TypedFilterQueryBuilder<Fields, M>) => void): this;
47
+ and(callback: (builder: TypedFilterQueryBuilder<Fields, M>) => void): this;
48
+ set(key: string, value: unknown): this;
49
+ clear(): this;
50
+ subscribe(listener: () => void): () => void;
51
+ getSnapshot(): FilterQueryResult;
52
+ getVersion(): number;
53
+ build(): FilterQueryResult;
54
+ toQueryString(): string;
55
+ toFlatObject(): Record<string, unknown>;
56
+ }
57
+ /**
58
+ * Creates a new type-safe `FilterQueryBuilder` that restricts field name
59
+ * arguments to the `Fields` union type.
60
+ *
61
+ * At runtime this returns the exact same `FilterQueryBuilder` instance —
62
+ * typing is the only difference. Zero runtime overhead.
63
+ *
64
+ * @example
65
+ * type UserFields = 'name' | 'age' | 'status';
66
+ *
67
+ * const q = filterQueryTyped<UserFields>()
68
+ * .contains('name', 'Al')
69
+ * .gte('age', 18)
70
+ * .sortDesc('name')
71
+ * .page(0, 25)
72
+ * .build();
73
+ *
74
+ * // TypeScript error — 'invalid' is not assignable to UserFields:
75
+ * // filterQueryTyped<UserFields>().where('invalid', 'foo');
76
+ */
77
+ export declare function filterQueryTyped<Fields extends string, M extends FilterFieldTypes<Fields> = Record<Fields, unknown>>(): TypedFilterQueryBuilder<Fields, M>;
78
+ //# sourceMappingURL=typed-filter-query-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-filter-query-builder.d.ts","sourceRoot":"","sources":["../src/typed-filter-query-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { FilterQueryBuilder } from './filter-query-builder.js';
2
+ /**
3
+ * Creates a new type-safe `FilterQueryBuilder` that restricts field name
4
+ * arguments to the `Fields` union type.
5
+ *
6
+ * At runtime this returns the exact same `FilterQueryBuilder` instance —
7
+ * typing is the only difference. Zero runtime overhead.
8
+ *
9
+ * @example
10
+ * type UserFields = 'name' | 'age' | 'status';
11
+ *
12
+ * const q = filterQueryTyped<UserFields>()
13
+ * .contains('name', 'Al')
14
+ * .gte('age', 18)
15
+ * .sortDesc('name')
16
+ * .page(0, 25)
17
+ * .build();
18
+ *
19
+ * // TypeScript error — 'invalid' is not assignable to UserFields:
20
+ * // filterQueryTyped<UserFields>().where('invalid', 'foo');
21
+ */
22
+ export function filterQueryTyped() {
23
+ return new FilterQueryBuilder();
24
+ }
25
+ //# sourceMappingURL=typed-filter-query-builder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-filter-query-builder.js","sourceRoot":"","sources":["../src/typed-filter-query-builder.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAoI/D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,gBAAgB;IAI9B,OAAO,IAAI,kBAAkB,EAAmD,CAAC;AACnF,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { FilterFieldTypes, OperatorsFor, ValueAt, ValueForOp } from './field-types.js';
2
+ export type TypedFilterQuery<Fields extends string, M extends FilterFieldTypes<Fields> = Record<Fields, unknown>> = {
3
+ filter?: {
4
+ [K in Fields]?: ValueAt<M, K> | {
5
+ [Op in OperatorsFor<ValueAt<M, K>>]?: ValueForOp<ValueAt<M, K>, Op>;
6
+ };
7
+ };
8
+ include?: string[];
9
+ search?: string;
10
+ sort?: Array<{
11
+ field: Fields;
12
+ direction: 'asc' | 'desc';
13
+ }>;
14
+ distinct?: Fields[];
15
+ paginate?: {
16
+ page: number;
17
+ size: number;
18
+ };
19
+ };
20
+ //# sourceMappingURL=typed-filter-query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-filter-query.d.ts","sourceRoot":"","sources":["../src/typed-filter-query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAE5F,MAAM,MAAM,gBAAgB,CAC1B,MAAM,SAAS,MAAM,EACrB,CAAC,SAAS,gBAAgB,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAC1D;IACF,MAAM,CAAC,EAAE;SACN,CAAC,IAAI,MAAM,CAAC,CAAC,EACV,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GACb;aAAG,EAAE,IAAI,YAAY,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC;SAAE;KAC5E,CAAC;IACF,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,KAAK,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3D,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=typed-filter-query.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"typed-filter-query.js","sourceRoot":"","sources":["../src/typed-filter-query.ts"],"names":[],"mappings":""}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Supported filter operators — mirrors the core package's FilterOperator
3
+ * but re-declared here to keep this package zero-dependency.
4
+ */
5
+ export type FilterOperator = 'equals' | 'notEquals' | 'contains' | 'notContains' | 'iContains' | 'startsWith' | 'endsWith' | 'gt' | 'gte' | 'lt' | 'lte' | 'between' | 'notBetween' | 'in' | 'notIn' | 'isAnyOf' | 'isEmpty' | 'isNotEmpty' | 'isNull' | 'isNotNull' | 'exists' | 'notExists';
6
+ /**
7
+ * All valid operator strings, used for runtime validation.
8
+ */
9
+ export declare const FILTER_OPERATORS: readonly FilterOperator[];
10
+ /**
11
+ * A single column filter condition with optional AND/OR composition.
12
+ */
13
+ export interface ColumnFilter {
14
+ field: string;
15
+ operator: FilterOperator;
16
+ value?: unknown;
17
+ AND?: ColumnFilter[];
18
+ OR?: ColumnFilter[];
19
+ }
20
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,WAAW,GACX,UAAU,GACV,aAAa,GACb,WAAW,GACX,YAAY,GACZ,UAAU,GACV,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,SAAS,GACT,YAAY,GACZ,IAAI,GACJ,OAAO,GACP,SAAS,GACT,SAAS,GACT,YAAY,GACZ,QAAQ,GACR,WAAW,GACX,QAAQ,GACR,WAAW,CAAC;AAEhB;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,cAAc,EAuB5C,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,YAAY,EAAE,CAAC;IACrB,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC;CACrB"}
package/dist/types.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * All valid operator strings, used for runtime validation.
3
+ */
4
+ export const FILTER_OPERATORS = [
5
+ 'equals',
6
+ 'notEquals',
7
+ 'contains',
8
+ 'notContains',
9
+ 'iContains',
10
+ 'startsWith',
11
+ 'endsWith',
12
+ 'gt',
13
+ 'gte',
14
+ 'lt',
15
+ 'lte',
16
+ 'between',
17
+ 'notBetween',
18
+ 'in',
19
+ 'notIn',
20
+ 'isAnyOf',
21
+ 'isEmpty',
22
+ 'isNotEmpty',
23
+ 'isNull',
24
+ 'isNotNull',
25
+ 'exists',
26
+ 'notExists',
27
+ ];
28
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA4BA;;GAEG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA8B;IACzD,QAAQ;IACR,WAAW;IACX,UAAU;IACV,aAAa;IACb,WAAW;IACX,YAAY;IACZ,UAAU;IACV,IAAI;IACJ,KAAK;IACL,IAAI;IACJ,KAAK;IACL,SAAS;IACT,YAAY;IACZ,IAAI;IACJ,OAAO;IACP,SAAS;IACT,SAAS;IACT,YAAY;IACZ,QAAQ;IACR,WAAW;IACX,QAAQ;IACR,WAAW;CACH,CAAC"}
@@ -0,0 +1,35 @@
1
+ import type { FilterOperator } from './types.js';
2
+ /** Operators that accept a non-array scalar: string | number | boolean | Date | null */
3
+ export declare const SCALAR_OPS: readonly ["equals", "notEquals", "gt", "gte", "lt", "lte"];
4
+ /** Operators that require a string value */
5
+ export declare const STRING_OPS: readonly ["contains", "notContains", "iContains", "startsWith", "endsWith"];
6
+ /** Operators that require an array value */
7
+ export declare const ARRAY_OPS: readonly ["in", "notIn", "isAnyOf"];
8
+ /** Operators that require a 2-element tuple [low, high] */
9
+ export declare const TUPLE_OPS: readonly ["between", "notBetween"];
10
+ /** Operators that accept no value (unary) */
11
+ export declare const UNARY_OPS: readonly ["isNull", "isNotNull", "isEmpty", "isNotEmpty", "exists", "notExists"];
12
+ /** Range operators — the only ones allowed in add() */
13
+ export declare const RANGE_OPS: readonly ["gt", "gte", "lt", "lte"];
14
+ export declare const SCALAR_OPERATORS: ReadonlySet<FilterOperator>;
15
+ export declare const STRING_OPERATORS: ReadonlySet<FilterOperator>;
16
+ export declare const ARRAY_OPERATORS: ReadonlySet<FilterOperator>;
17
+ export declare const TUPLE_OPERATORS: ReadonlySet<FilterOperator>;
18
+ export declare const UNARY_OPERATORS: ReadonlySet<FilterOperator>;
19
+ export declare const RANGE_OPERATORS: ReadonlySet<FilterOperator>;
20
+ /**
21
+ * Validates that the value matches the operator's expected type.
22
+ * Throws a descriptive `Error` on mismatch.
23
+ *
24
+ * @param operator - the filter operator
25
+ * @param value - the value supplied by the caller
26
+ */
27
+ export declare function validateOperatorValue(operator: FilterOperator, value: unknown): void;
28
+ /**
29
+ * Validates that an operator is allowed inside `add()`.
30
+ * Only range operators (gt, gte, lt, lte) make sense for accumulation.
31
+ *
32
+ * @param operator - the filter operator used in add()
33
+ */
34
+ export declare function validateAddOperator(operator: FilterOperator): void;
35
+ //# sourceMappingURL=validate-operator-value.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-operator-value.d.ts","sourceRoot":"","sources":["../src/validate-operator-value.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAUjD,wFAAwF;AACxF,eAAO,MAAM,UAAU,4DAA6D,CAAC;AACrF,4CAA4C;AAC5C,eAAO,MAAM,UAAU,6EAMb,CAAC;AACX,4CAA4C;AAC5C,eAAO,MAAM,SAAS,qCAAsC,CAAC;AAC7D,2DAA2D;AAC3D,eAAO,MAAM,SAAS,oCAAqC,CAAC;AAC5D,6CAA6C;AAC7C,eAAO,MAAM,SAAS,kFAOZ,CAAC;AACX,uDAAuD;AACvD,eAAO,MAAM,SAAS,qCAAsC,CAAC;AAE7D,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,cAAc,CAAuB,CAAC;AACjF,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,cAAc,CAAuB,CAAC;AACjF,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,cAAc,CAAsB,CAAC;AAC/E,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,cAAc,CAAsB,CAAC;AAC/E,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,cAAc,CAAsB,CAAC;AAC/E,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,cAAc,CAAsB,CAAC;AAI/E;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAsCpF;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAMlE"}
@@ -0,0 +1,91 @@
1
+ // ─── Operator categories ──────────────────────────────────────────────────────
2
+ // The `*_OPS` tuples are the SINGLE runtime source of truth for the operator
3
+ // matrix. Their narrow literal element types are asserted, per group, against
4
+ // the field-types.ts type-level groups in the drift-guard test — so the runtime
5
+ // validator and the compile-time builder cannot silently diverge. The
6
+ // `*_OPERATORS` Sets are derived from the tuples and keep their public
7
+ // `ReadonlySet<FilterOperator>` shape for consumers.
8
+ /** Operators that accept a non-array scalar: string | number | boolean | Date | null */
9
+ export const SCALAR_OPS = ['equals', 'notEquals', 'gt', 'gte', 'lt', 'lte'];
10
+ /** Operators that require a string value */
11
+ export const STRING_OPS = [
12
+ 'contains',
13
+ 'notContains',
14
+ 'iContains',
15
+ 'startsWith',
16
+ 'endsWith',
17
+ ];
18
+ /** Operators that require an array value */
19
+ export const ARRAY_OPS = ['in', 'notIn', 'isAnyOf'];
20
+ /** Operators that require a 2-element tuple [low, high] */
21
+ export const TUPLE_OPS = ['between', 'notBetween'];
22
+ /** Operators that accept no value (unary) */
23
+ export const UNARY_OPS = [
24
+ 'isNull',
25
+ 'isNotNull',
26
+ 'isEmpty',
27
+ 'isNotEmpty',
28
+ 'exists',
29
+ 'notExists',
30
+ ];
31
+ /** Range operators — the only ones allowed in add() */
32
+ export const RANGE_OPS = ['gt', 'gte', 'lt', 'lte'];
33
+ export const SCALAR_OPERATORS = new Set(SCALAR_OPS);
34
+ export const STRING_OPERATORS = new Set(STRING_OPS);
35
+ export const ARRAY_OPERATORS = new Set(ARRAY_OPS);
36
+ export const TUPLE_OPERATORS = new Set(TUPLE_OPS);
37
+ export const UNARY_OPERATORS = new Set(UNARY_OPS);
38
+ export const RANGE_OPERATORS = new Set(RANGE_OPS);
39
+ // ─── Validation ───────────────────────────────────────────────────────────────
40
+ /**
41
+ * Validates that the value matches the operator's expected type.
42
+ * Throws a descriptive `Error` on mismatch.
43
+ *
44
+ * @param operator - the filter operator
45
+ * @param value - the value supplied by the caller
46
+ */
47
+ export function validateOperatorValue(operator, value) {
48
+ if (UNARY_OPERATORS.has(operator)) {
49
+ // Unary operators accept only null or undefined (no meaningful value)
50
+ if (value !== null && value !== undefined) {
51
+ throw new Error(`Operator "${operator}" does not accept a value.`);
52
+ }
53
+ return;
54
+ }
55
+ if (STRING_OPERATORS.has(operator)) {
56
+ if (typeof value !== 'string') {
57
+ throw new Error(`Operator "${operator}" expects a string value.`);
58
+ }
59
+ return;
60
+ }
61
+ if (TUPLE_OPERATORS.has(operator)) {
62
+ if (!Array.isArray(value) || value.length !== 2) {
63
+ throw new Error(`Operator "${operator}" expects [low, high] tuple.`);
64
+ }
65
+ return;
66
+ }
67
+ if (ARRAY_OPERATORS.has(operator)) {
68
+ if (!Array.isArray(value)) {
69
+ throw new Error(`Operator "${operator}" expects an array value.`);
70
+ }
71
+ return;
72
+ }
73
+ if (SCALAR_OPERATORS.has(operator)) {
74
+ if (Array.isArray(value)) {
75
+ throw new Error(`Operator "${operator}" expects a scalar value, not an array. Use "in" for arrays.`);
76
+ }
77
+ return;
78
+ }
79
+ }
80
+ /**
81
+ * Validates that an operator is allowed inside `add()`.
82
+ * Only range operators (gt, gte, lt, lte) make sense for accumulation.
83
+ *
84
+ * @param operator - the filter operator used in add()
85
+ */
86
+ export function validateAddOperator(operator) {
87
+ if (!RANGE_OPERATORS.has(operator)) {
88
+ throw new Error(`Operator "${operator}" should use where() (replace), not add(). add() is for range operators (gt, gte, lt, lte) on the same field.`);
89
+ }
90
+ }
91
+ //# sourceMappingURL=validate-operator-value.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-operator-value.js","sourceRoot":"","sources":["../src/validate-operator-value.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@adonis-agora/filter-client",
3
+ "version": "0.1.0",
4
+ "description": "Client-side query builder for @agora/filter — build filter query strings, with optional TanStack Table state sync.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/DavideCarvalho/adonis-filter.git",
9
+ "directory": "packages/client"
10
+ },
11
+ "author": "Davi Carvalho <davi@goflip.ai>",
12
+ "type": "module",
13
+ "main": "./dist/index.js",
14
+ "types": "./dist/index.d.ts",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js",
19
+ "default": "./dist/index.js"
20
+ },
21
+ "./tanstack": {
22
+ "types": "./dist/tanstack.d.ts",
23
+ "import": "./dist/tanstack.js",
24
+ "default": "./dist/tanstack.js"
25
+ }
26
+ },
27
+ "files": [
28
+ "dist/",
29
+ "README.md",
30
+ "CHANGELOG.md"
31
+ ],
32
+ "sideEffects": false,
33
+ "peerDependencies": {
34
+ "@tanstack/table-core": ">=8.0.0"
35
+ },
36
+ "peerDependenciesMeta": {
37
+ "@tanstack/table-core": {
38
+ "optional": true
39
+ }
40
+ },
41
+ "devDependencies": {
42
+ "@tanstack/table-core": "^8.20.0",
43
+ "typescript": "^5.4.0",
44
+ "vitest": "^3.0.0"
45
+ },
46
+ "engines": {
47
+ "node": ">=20.6.0"
48
+ },
49
+ "keywords": [
50
+ "adonisjs",
51
+ "adonis",
52
+ "filter",
53
+ "query",
54
+ "client",
55
+ "builder",
56
+ "agora"
57
+ ],
58
+ "scripts": {
59
+ "build": "tsc -p tsconfig.json",
60
+ "test": "vitest run",
61
+ "test:types": "tsc -p tsconfig.typecheck.json",
62
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.typecheck.json"
63
+ }
64
+ }