@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.
- package/CHANGELOG.md +417 -0
- package/LICENSE +21 -0
- package/README.md +75 -0
- package/dist/commands/main.d.ts +19 -0
- package/dist/commands/main.d.ts.map +1 -0
- package/dist/commands/main.js +19 -0
- package/dist/commands/main.js.map +1 -0
- package/dist/commands/make_filter.d.ts +18 -0
- package/dist/commands/make_filter.d.ts.map +1 -0
- package/dist/commands/make_filter.js +32 -0
- package/dist/commands/make_filter.js.map +1 -0
- package/dist/commands/make_filter_client.d.ts +35 -0
- package/dist/commands/make_filter_client.d.ts.map +1 -0
- package/dist/commands/make_filter_client.js +85 -0
- package/dist/commands/make_filter_client.js.map +1 -0
- package/dist/configure.d.ts +15 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +20 -0
- package/dist/configure.js.map +1 -0
- package/dist/providers/filter_provider.d.ts +28 -0
- package/dist/providers/filter_provider.d.ts.map +1 -0
- package/dist/providers/filter_provider.js +33 -0
- package/dist/providers/filter_provider.js.map +1 -0
- package/dist/src/aggregate.d.ts +70 -0
- package/dist/src/aggregate.d.ts.map +1 -0
- package/dist/src/aggregate.js +195 -0
- package/dist/src/aggregate.js.map +1 -0
- package/dist/src/aggregate_path.d.ts +25 -0
- package/dist/src/aggregate_path.d.ts.map +1 -0
- package/dist/src/aggregate_path.js +35 -0
- package/dist/src/aggregate_path.js.map +1 -0
- package/dist/src/apply_from_request.d.ts +85 -0
- package/dist/src/apply_from_request.d.ts.map +1 -0
- package/dist/src/apply_from_request.js +164 -0
- package/dist/src/apply_from_request.js.map +1 -0
- package/dist/src/base_filter.d.ts +49 -0
- package/dist/src/base_filter.d.ts.map +1 -0
- package/dist/src/base_filter.js +33 -0
- package/dist/src/base_filter.js.map +1 -0
- package/dist/src/base_model_filter.d.ts +90 -0
- package/dist/src/base_model_filter.d.ts.map +1 -0
- package/dist/src/base_model_filter.js +85 -0
- package/dist/src/base_model_filter.js.map +1 -0
- package/dist/src/coerce_value.d.ts +26 -0
- package/dist/src/coerce_value.d.ts.map +1 -0
- package/dist/src/coerce_value.js +82 -0
- package/dist/src/coerce_value.js.map +1 -0
- package/dist/src/cursor.d.ts +92 -0
- package/dist/src/cursor.d.ts.map +1 -0
- package/dist/src/cursor.js +107 -0
- package/dist/src/cursor.js.map +1 -0
- package/dist/src/custom_filter.d.ts +36 -0
- package/dist/src/custom_filter.d.ts.map +1 -0
- package/dist/src/custom_filter.js +127 -0
- package/dist/src/custom_filter.js.map +1 -0
- package/dist/src/decorator_metadata.d.ts +41 -0
- package/dist/src/decorator_metadata.d.ts.map +1 -0
- package/dist/src/decorator_metadata.js +83 -0
- package/dist/src/decorator_metadata.js.map +1 -0
- package/dist/src/decorators.d.ts +73 -0
- package/dist/src/decorators.d.ts.map +1 -0
- package/dist/src/decorators.js +118 -0
- package/dist/src/decorators.js.map +1 -0
- package/dist/src/escape-like.d.ts +10 -0
- package/dist/src/escape-like.d.ts.map +1 -0
- package/dist/src/escape-like.js +15 -0
- package/dist/src/escape-like.js.map +1 -0
- package/dist/src/field_aliases.d.ts +30 -0
- package/dist/src/field_aliases.d.ts.map +1 -0
- package/dist/src/field_aliases.js +65 -0
- package/dist/src/field_aliases.js.map +1 -0
- package/dist/src/filter_class.d.ts +46 -0
- package/dist/src/filter_class.d.ts.map +1 -0
- package/dist/src/filter_class.js +244 -0
- package/dist/src/filter_class.js.map +1 -0
- package/dist/src/filter_spec.d.ts +231 -0
- package/dist/src/filter_spec.d.ts.map +1 -0
- package/dist/src/filter_spec.js +182 -0
- package/dist/src/filter_spec.js.map +1 -0
- package/dist/src/filterable_mixin.d.ts +49 -0
- package/dist/src/filterable_mixin.d.ts.map +1 -0
- package/dist/src/filterable_mixin.js +47 -0
- package/dist/src/filterable_mixin.js.map +1 -0
- package/dist/src/generate_client.d.ts +107 -0
- package/dist/src/generate_client.d.ts.map +1 -0
- package/dist/src/generate_client.js +164 -0
- package/dist/src/generate_client.js.map +1 -0
- package/dist/src/group_by_count.d.ts +67 -0
- package/dist/src/group_by_count.d.ts.map +1 -0
- package/dist/src/group_by_count.js +71 -0
- package/dist/src/group_by_count.js.map +1 -0
- package/dist/src/in_memory.d.ts +279 -0
- package/dist/src/in_memory.d.ts.map +1 -0
- package/dist/src/in_memory.js +810 -0
- package/dist/src/in_memory.js.map +1 -0
- package/dist/src/index.d.ts +51 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +33 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lucid_adapter.d.ts +311 -0
- package/dist/src/lucid_adapter.d.ts.map +1 -0
- package/dist/src/lucid_adapter.js +469 -0
- package/dist/src/lucid_adapter.js.map +1 -0
- package/dist/src/lucid_macros.d.ts +87 -0
- package/dist/src/lucid_macros.d.ts.map +1 -0
- package/dist/src/lucid_macros.js +67 -0
- package/dist/src/lucid_macros.js.map +1 -0
- package/dist/src/normalizer.d.ts +21 -0
- package/dist/src/normalizer.d.ts.map +1 -0
- package/dist/src/normalizer.js +61 -0
- package/dist/src/normalizer.js.map +1 -0
- package/dist/src/operators.d.ts +37 -0
- package/dist/src/operators.d.ts.map +1 -0
- package/dist/src/operators.js +43 -0
- package/dist/src/operators.js.map +1 -0
- package/dist/src/paginate.d.ts +12 -0
- package/dist/src/paginate.d.ts.map +1 -0
- package/dist/src/paginate.js +88 -0
- package/dist/src/paginate.js.map +1 -0
- package/dist/src/pagination_stash.d.ts +4 -0
- package/dist/src/pagination_stash.d.ts.map +1 -0
- package/dist/src/pagination_stash.js +19 -0
- package/dist/src/pagination_stash.js.map +1 -0
- package/dist/src/parse_request.d.ts +50 -0
- package/dist/src/parse_request.d.ts.map +1 -0
- package/dist/src/parse_request.js +220 -0
- package/dist/src/parse_request.js.map +1 -0
- package/dist/src/runner.d.ts +65 -0
- package/dist/src/runner.d.ts.map +1 -0
- package/dist/src/runner.js +371 -0
- package/dist/src/runner.js.map +1 -0
- package/dist/src/source_resolver.d.ts +18 -0
- package/dist/src/source_resolver.d.ts.map +1 -0
- package/dist/src/source_resolver.js +64 -0
- package/dist/src/source_resolver.js.map +1 -0
- package/dist/src/spatie_parser.d.ts +39 -0
- package/dist/src/spatie_parser.d.ts.map +1 -0
- package/dist/src/spatie_parser.js +134 -0
- package/dist/src/spatie_parser.js.map +1 -0
- package/dist/src/testing.d.ts +73 -0
- package/dist/src/testing.d.ts.map +1 -0
- package/dist/src/testing.js +136 -0
- package/dist/src/testing.js.map +1 -0
- package/dist/src/types.d.ts +226 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/validate-column-filter.d.ts +30 -0
- package/dist/src/validate-column-filter.d.ts.map +1 -0
- package/dist/src/validate-column-filter.js +148 -0
- package/dist/src/validate-column-filter.js.map +1 -0
- package/dist/src/value-shape.d.ts +18 -0
- package/dist/src/value-shape.d.ts.map +1 -0
- package/dist/src/value-shape.js +36 -0
- package/dist/src/value-shape.js.map +1 -0
- package/dist/stubs/main.d.ts +3 -0
- package/dist/stubs/main.d.ts.map +1 -0
- package/dist/stubs/main.js +4 -0
- package/dist/stubs/main.js.map +1 -0
- package/dist/stubs/make/filter/main.stub +45 -0
- package/package.json +102 -0
- package/skills/filter-basics/SKILL.md +285 -0
- package/skills/filter-codegen/SKILL.md +246 -0
- package/skills/filter-definitions/SKILL.md +340 -0
- package/skills/filter-querying/SKILL.md +319 -0
- package/skills/filter-safety/SKILL.md +304 -0
- package/stubs/main.ts +4 -0
- package/stubs/make/filter/main.stub +45 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { InputNormalizer } from './types.js';
|
|
2
|
+
export interface NormalizeOptions {
|
|
3
|
+
/** Key transform — a built-in case mode or a custom mapping function. */
|
|
4
|
+
normalizer: InputNormalizer;
|
|
5
|
+
/** Strip a trailing `Id`/`_id` (and drop a bare `id`) from each key. Default false. */
|
|
6
|
+
dropId?: boolean;
|
|
7
|
+
/** Strip `null`/`undefined`/empty-string values. Default true. */
|
|
8
|
+
stripEmpty?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Normalize a decoded input object's top-level keys — case-transforming them via
|
|
12
|
+
* the chosen {@link InputNormalizer}, optionally stripping `Id` suffixes and
|
|
13
|
+
* empty values — into a null-prototype object.
|
|
14
|
+
*
|
|
15
|
+
* Prototype-pollution keys (`__proto__`, `constructor`, `prototype`, `toString`,
|
|
16
|
+
* `valueOf`) are dropped both before and after normalization, and the result has
|
|
17
|
+
* a null prototype, so a hostile key can never reach `Object.prototype`. Nested
|
|
18
|
+
* values are left untouched — only top-level keys are normalized.
|
|
19
|
+
*/
|
|
20
|
+
export declare function normalizeInput(input: unknown, options: NormalizeOptions): Record<string, unknown>;
|
|
21
|
+
//# sourceMappingURL=normalizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalizer.d.ts","sourceRoot":"","sources":["../../src/normalizer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,MAAM,WAAW,gBAAgB;IAC/B,yEAAyE;IACzE,UAAU,EAAE,eAAe,CAAC;IAC5B,uFAAuF;IACvF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,kEAAkE;IAClE,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAID;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAgBjG"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const BLOCKED_KEYS = new Set(['__proto__', 'constructor', 'prototype', 'toString', 'valueOf']);
|
|
2
|
+
/**
|
|
3
|
+
* Normalize a decoded input object's top-level keys — case-transforming them via
|
|
4
|
+
* the chosen {@link InputNormalizer}, optionally stripping `Id` suffixes and
|
|
5
|
+
* empty values — into a null-prototype object.
|
|
6
|
+
*
|
|
7
|
+
* Prototype-pollution keys (`__proto__`, `constructor`, `prototype`, `toString`,
|
|
8
|
+
* `valueOf`) are dropped both before and after normalization, and the result has
|
|
9
|
+
* a null prototype, so a hostile key can never reach `Object.prototype`. Nested
|
|
10
|
+
* values are left untouched — only top-level keys are normalized.
|
|
11
|
+
*/
|
|
12
|
+
export function normalizeInput(input, options) {
|
|
13
|
+
if (input == null || typeof input !== 'object')
|
|
14
|
+
return {};
|
|
15
|
+
const norm = pickNormalizer(options.normalizer);
|
|
16
|
+
const drop = options.dropId === true;
|
|
17
|
+
const strip = options.stripEmpty !== false;
|
|
18
|
+
const out = Object.create(null);
|
|
19
|
+
for (const [rawKey, value] of Object.entries(input)) {
|
|
20
|
+
if (BLOCKED_KEYS.has(rawKey))
|
|
21
|
+
continue;
|
|
22
|
+
if (strip && (value === null || value === undefined || value === ''))
|
|
23
|
+
continue;
|
|
24
|
+
let key = norm(rawKey);
|
|
25
|
+
if (BLOCKED_KEYS.has(key))
|
|
26
|
+
continue;
|
|
27
|
+
if (drop)
|
|
28
|
+
key = stripId(key);
|
|
29
|
+
if (key.length === 0)
|
|
30
|
+
continue;
|
|
31
|
+
out[key] = value;
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
function pickNormalizer(spec) {
|
|
36
|
+
if (typeof spec === 'function')
|
|
37
|
+
return spec;
|
|
38
|
+
if (spec === 'camelCase')
|
|
39
|
+
return toCamelCase;
|
|
40
|
+
return toSnakeCase;
|
|
41
|
+
}
|
|
42
|
+
function toCamelCase(key) {
|
|
43
|
+
const result = key.replace(/[_-](\w)/g, (_, c) => c.toUpperCase());
|
|
44
|
+
return result.charAt(0).toLowerCase() + result.slice(1);
|
|
45
|
+
}
|
|
46
|
+
function toSnakeCase(key) {
|
|
47
|
+
return key
|
|
48
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
|
|
49
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
50
|
+
.toLowerCase();
|
|
51
|
+
}
|
|
52
|
+
function stripId(key) {
|
|
53
|
+
if (key.endsWith('Id'))
|
|
54
|
+
return key.slice(0, -2);
|
|
55
|
+
if (key.endsWith('_id'))
|
|
56
|
+
return key.slice(0, -3);
|
|
57
|
+
if (key === 'id')
|
|
58
|
+
return '';
|
|
59
|
+
return key;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=normalizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalizer.js","sourceRoot":"","sources":["../../src/normalizer.ts"],"names":[],"mappings":"AAWA,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC,CAAC;AAE/F;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAAC,KAAc,EAAE,OAAyB;IACtE,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IAC1D,MAAM,IAAI,GAAG,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,KAAK,IAAI,CAAC;IACrC,MAAM,KAAK,GAAG,OAAO,CAAC,UAAU,KAAK,KAAK,CAAC;IAC3C,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAA4B,CAAC;IAC3D,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;QAC/E,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,SAAS;QACvC,IAAI,KAAK,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC;YAAE,SAAS;QAC/E,IAAI,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QACvB,IAAI,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QACpC,IAAI,IAAI;YAAE,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QAC/B,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACnB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,SAAS,cAAc,CAAC,IAAqB;IAC3C,IAAI,OAAO,IAAI,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAC5C,IAAI,IAAI,KAAK,WAAW;QAAE,OAAO,WAAW,CAAC;IAC7C,OAAO,WAAW,CAAC;AACrB,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAE,CAAY,CAAC,WAAW,EAAE,CAAC,CAAC;IAC/E,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,OAAO,GAAG;SACP,OAAO,CAAC,uBAAuB,EAAE,OAAO,CAAC;SACzC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC;SACtC,WAAW,EAAE,CAAC;AACnB,CAAC;AAED,SAAS,OAAO,CAAC,GAAW;IAC1B,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACjD,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAC5B,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Supported filter operators for generic column-based filtering.
|
|
3
|
+
*
|
|
4
|
+
* Compatible with flip-nestjs SqlQueryBuilderService ColumnFilter[].
|
|
5
|
+
*/
|
|
6
|
+
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';
|
|
7
|
+
/**
|
|
8
|
+
* All valid operator strings, used for runtime validation.
|
|
9
|
+
*/
|
|
10
|
+
export declare const FILTER_OPERATORS: readonly FilterOperator[];
|
|
11
|
+
/**
|
|
12
|
+
* SQL-symbol aliases accepted on input and normalized to a canonical
|
|
13
|
+
* {@link FilterOperator} before validation and query building. Lets callers
|
|
14
|
+
* write the familiar `=`/`!=`/`<`/`>` shorthands instead of the named form.
|
|
15
|
+
*/
|
|
16
|
+
export declare const OPERATOR_ALIASES: Readonly<Record<string, FilterOperator>>;
|
|
17
|
+
/**
|
|
18
|
+
* An operator alias string (e.g. `'='`). Always normalized to a canonical
|
|
19
|
+
* {@link FilterOperator} via `normalizeOperator`.
|
|
20
|
+
*/
|
|
21
|
+
export type FilterOperatorAlias = keyof typeof OPERATOR_ALIASES;
|
|
22
|
+
/**
|
|
23
|
+
* Operator value accepted on input: either a canonical {@link FilterOperator}
|
|
24
|
+
* or one of its SQL-symbol {@link FilterOperatorAlias aliases}.
|
|
25
|
+
*/
|
|
26
|
+
export type FilterOperatorInput = FilterOperator | FilterOperatorAlias;
|
|
27
|
+
/**
|
|
28
|
+
* A single column filter condition with optional AND/OR composition.
|
|
29
|
+
*/
|
|
30
|
+
export interface ColumnFilter {
|
|
31
|
+
field: string;
|
|
32
|
+
operator: FilterOperatorInput;
|
|
33
|
+
value?: unknown;
|
|
34
|
+
AND?: ColumnFilter[];
|
|
35
|
+
OR?: ColumnFilter[];
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=operators.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operators.d.ts","sourceRoot":"","sources":["../../src/operators.ts"],"names":[],"mappings":"AAAA;;;;GAIG;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;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAS5D,CAAC;AAEX;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,OAAO,gBAAgB,CAAC;AAEhE;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,cAAc,GAAG,mBAAmB,CAAC;AAEvE;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,mBAAmB,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,GAAG,CAAC,EAAE,YAAY,EAAE,CAAC;IACrB,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC;CACrB"}
|
|
@@ -0,0 +1,43 @@
|
|
|
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
|
+
/**
|
|
29
|
+
* SQL-symbol aliases accepted on input and normalized to a canonical
|
|
30
|
+
* {@link FilterOperator} before validation and query building. Lets callers
|
|
31
|
+
* write the familiar `=`/`!=`/`<`/`>` shorthands instead of the named form.
|
|
32
|
+
*/
|
|
33
|
+
export const OPERATOR_ALIASES = {
|
|
34
|
+
'=': 'equals',
|
|
35
|
+
'==': 'equals',
|
|
36
|
+
'!=': 'notEquals',
|
|
37
|
+
'<>': 'notEquals',
|
|
38
|
+
'>': 'gt',
|
|
39
|
+
'>=': 'gte',
|
|
40
|
+
'<': 'lt',
|
|
41
|
+
'<=': 'lte',
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=operators.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operators.js","sourceRoot":"","sources":["../../src/operators.ts"],"names":[],"mappings":"AA6BA;;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;AAEX;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAA6C;IACxE,GAAG,EAAE,QAAQ;IACb,IAAI,EAAE,QAAQ;IACd,IAAI,EAAE,WAAW;IACjB,IAAI,EAAE,WAAW;IACjB,GAAG,EAAE,IAAI;IACT,IAAI,EAAE,KAAK;IACX,GAAG,EAAE,IAAI;IACT,IAAI,EAAE,KAAK;CACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lucid's `query.paginate(page, perPage)`, fetching the page before the total.
|
|
3
|
+
*
|
|
4
|
+
* Lucid counts every matching row before it reads the page. A page that comes back shorter than
|
|
5
|
+
* `perPage` already pins the total (`offset + rows`), so the count runs only for a full page, or
|
|
6
|
+
* an empty page past the first. Same paginator class, same meta, same `after:*` hooks. A model
|
|
7
|
+
* with a `before:paginate` or `before:fetch` hook is left to Lucid, since those hooks may change
|
|
8
|
+
* the count query and the page query differently; so is a select list that changes the row count
|
|
9
|
+
* (see {@link selectKeepsRowCount}).
|
|
10
|
+
*/
|
|
11
|
+
export declare function paginate(query: object, page: number, perPage: number): unknown;
|
|
12
|
+
//# sourceMappingURL=paginate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paginate.d.ts","sourceRoot":"","sources":["../../src/paginate.ts"],"names":[],"mappings":"AAwEA;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAiB9E"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lucid counts the query with its select list cleared, so the page has as many rows as the count
|
|
3
|
+
* only while the select list cannot change how many rows come back: plain columns and scalar
|
|
4
|
+
* subqueries (`withCount`). A `distinct`, an aggregate, a raw expression or a `union` can, and
|
|
5
|
+
* then the page does not pin Lucid's total.
|
|
6
|
+
*/
|
|
7
|
+
function selectKeepsRowCount(statements) {
|
|
8
|
+
if (!statements)
|
|
9
|
+
return false;
|
|
10
|
+
return statements.every((statement) => {
|
|
11
|
+
if (statement.grouping === 'union')
|
|
12
|
+
return false;
|
|
13
|
+
if (statement.grouping !== 'columns')
|
|
14
|
+
return true;
|
|
15
|
+
if (statement.distinct || statement.distinctOn || statement.type !== undefined)
|
|
16
|
+
return false;
|
|
17
|
+
return (Array.isArray(statement.value) &&
|
|
18
|
+
statement.value.every((column) => typeof column === 'string' ||
|
|
19
|
+
(typeof column === 'object' &&
|
|
20
|
+
column !== null &&
|
|
21
|
+
!column.isRawInstance)));
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
function isLucidModelQuery(query) {
|
|
25
|
+
const q = query;
|
|
26
|
+
return (typeof q.forPage === 'function' &&
|
|
27
|
+
typeof q.execQuery === 'function' &&
|
|
28
|
+
typeof q.clone === 'function' &&
|
|
29
|
+
typeof q.model?.$hooks?.has === 'function');
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Lucid's `query.paginate(page, perPage)`, fetching the page before the total.
|
|
33
|
+
*
|
|
34
|
+
* Lucid counts every matching row before it reads the page. A page that comes back shorter than
|
|
35
|
+
* `perPage` already pins the total (`offset + rows`), so the count runs only for a full page, or
|
|
36
|
+
* an empty page past the first. Same paginator class, same meta, same `after:*` hooks. A model
|
|
37
|
+
* with a `before:paginate` or `before:fetch` hook is left to Lucid, since those hooks may change
|
|
38
|
+
* the count query and the page query differently; so is a select list that changes the row count
|
|
39
|
+
* (see {@link selectKeepsRowCount}).
|
|
40
|
+
*/
|
|
41
|
+
export function paginate(query, page, perPage) {
|
|
42
|
+
const q = query;
|
|
43
|
+
page = Number(page);
|
|
44
|
+
perPage = Number(perPage);
|
|
45
|
+
if (!isLucidModelQuery(query) ||
|
|
46
|
+
q.model.$hooks.has('before:paginate') ||
|
|
47
|
+
q.model.$hooks.has('before:fetch') ||
|
|
48
|
+
!selectKeepsRowCount(q.knexQuery._statements) ||
|
|
49
|
+
!Number.isInteger(page) ||
|
|
50
|
+
page < 1 ||
|
|
51
|
+
!Number.isInteger(perPage) ||
|
|
52
|
+
perPage < 1) {
|
|
53
|
+
return q.paginate(page, perPage);
|
|
54
|
+
}
|
|
55
|
+
return pageThenCount(q, page, perPage);
|
|
56
|
+
}
|
|
57
|
+
async function pageThenCount(q, page, perPage) {
|
|
58
|
+
const isFetchCall = q.wrapResultsToModelInstances && q.knexQuery._method === 'select';
|
|
59
|
+
const countQuery = q
|
|
60
|
+
.clone()
|
|
61
|
+
.clearOrder()
|
|
62
|
+
.clearLimit()
|
|
63
|
+
.clearOffset()
|
|
64
|
+
.clearSelect()
|
|
65
|
+
.count('* as total')
|
|
66
|
+
.pojo();
|
|
67
|
+
const results = await q.forPage(page, perPage).execQuery();
|
|
68
|
+
let total;
|
|
69
|
+
if (results.length < perPage && (results.length > 0 || page === 1)) {
|
|
70
|
+
total = (page - 1) * perPage + results.length;
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
const aggregate = await countQuery.exec();
|
|
74
|
+
total = q.hasGroupBy ? aggregate.length : aggregate[0]?.total;
|
|
75
|
+
}
|
|
76
|
+
const { ModelPaginator } = await import('@adonisjs/lucid/orm');
|
|
77
|
+
const { SimplePaginator } = await import('@adonisjs/lucid/database');
|
|
78
|
+
const paginator = q.wrapResultsToModelInstances
|
|
79
|
+
? new ModelPaginator(total, perPage, page, ...results)
|
|
80
|
+
: new SimplePaginator(total, perPage, page, ...results);
|
|
81
|
+
paginator.namingStrategy = q.model.namingStrategy;
|
|
82
|
+
if (isFetchCall) {
|
|
83
|
+
await q.model.$hooks.runner('after:paginate').run(paginator);
|
|
84
|
+
await q.model.$hooks.runner('after:fetch').run(results);
|
|
85
|
+
}
|
|
86
|
+
return paginator;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=paginate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paginate.js","sourceRoot":"","sources":["../../src/paginate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ResolvedPagination } from './runner.js';
|
|
2
|
+
export declare function stashPagination(query: unknown, pagination: ResolvedPagination): void;
|
|
3
|
+
export declare function readPagination(query: unknown): ResolvedPagination | undefined;
|
|
4
|
+
//# sourceMappingURL=pagination_stash.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination_stash.d.ts","sourceRoot":"","sources":["../../src/pagination_stash.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAWtD,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,kBAAkB,GAAG,IAAI,CAIpF;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,kBAAkB,GAAG,SAAS,CAG7E"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a filtered query remembers the pagination the request resolved to.
|
|
3
|
+
*
|
|
4
|
+
* The builder is handed back to the caller so the endpoint can keep composing on it; the page and
|
|
5
|
+
* size it already resolved ride along on this symbol, so a later `filterPaginate()` needs no
|
|
6
|
+
* arguments and no second read of the request.
|
|
7
|
+
*/
|
|
8
|
+
const PAGINATION = Symbol.for('@adonis-agora/filter:pagination');
|
|
9
|
+
export function stashPagination(query, pagination) {
|
|
10
|
+
if (query !== null && typeof query === 'object') {
|
|
11
|
+
query[PAGINATION] = pagination;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function readPagination(query) {
|
|
15
|
+
if (query === null || typeof query !== 'object')
|
|
16
|
+
return undefined;
|
|
17
|
+
return query[PAGINATION];
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=pagination_stash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pagination_stash.js","sourceRoot":"","sources":["../../src/pagination_stash.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;AAEjE,MAAM,UAAU,eAAe,CAAC,KAAc,EAAE,UAA8B;IAC5E,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC/C,KAAiC,CAAC,UAAU,CAAC,GAAG,UAAU,CAAC;IAC9D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,KAAc;IAC3C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAClE,OAAQ,KAAwD,CAAC,UAAU,CAAC,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ColumnFilter } from './operators.js';
|
|
2
|
+
import type { FilterInput, GroupByCountRequest, SortItem } from './types.js';
|
|
3
|
+
/** Map one `filter[field]=…` entry to `ColumnFilter[]` (Spatie/JSON:API shapes). */
|
|
4
|
+
export declare function toColumnFilters(field: string, value: unknown): ColumnFilter[];
|
|
5
|
+
/**
|
|
6
|
+
* Parse the `distinct` param into a de-duplicated list of field names. Accepts a
|
|
7
|
+
* comma-separated string (`distinct=afsc,base`) or a repeated/array form
|
|
8
|
+
* (`distinct[]=afsc&distinct[]=base`) — the shapes the client's `toQueryString()`
|
|
9
|
+
* and structured `build()` emit. Non-string entries are ignored.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseDistinct(distinct: unknown): string[];
|
|
12
|
+
/**
|
|
13
|
+
* Parse the `sort` param into ordered {@link SortItem}s. Accepts the string form
|
|
14
|
+
* (`-createdAt,name` or `sort[]=name`) and the already-structured
|
|
15
|
+
* `[{ field, direction }]` form the client builder's `build()` emits — the
|
|
16
|
+
* latter used to be filtered out entirely as "not a string", silently dropping
|
|
17
|
+
* the ordering.
|
|
18
|
+
*/
|
|
19
|
+
export declare function parseSort(sort: unknown): SortItem[];
|
|
20
|
+
/**
|
|
21
|
+
* Parse a decoded request query object — e.g. AdonisJS `ctx.request.qs()` — into
|
|
22
|
+
* a structured {@link FilterInput}. Understands the Spatie / JSON:API shapes the
|
|
23
|
+
* `@adonis-agora/filter-client` builder emits:
|
|
24
|
+
*
|
|
25
|
+
* - `filter[status]=active` → equals
|
|
26
|
+
* - `filter[id]=1,2,3` / `filter[id][]=1&filter[id][]=2` → IN
|
|
27
|
+
* - `filter[age][gte]=18` → operator filter
|
|
28
|
+
* - `sort=-createdAt,name` → sort items
|
|
29
|
+
* - `distinct=afsc,base` / `distinct[]=afsc&distinct[]=base` → distinct fields
|
|
30
|
+
* - `groupByCount[field]=tag&groupByCount[limit]=20` → value enumeration
|
|
31
|
+
* - `search=term`, `page`/`size` (or `page[number]`/`page[size]`)
|
|
32
|
+
*
|
|
33
|
+
* It also accepts the structured shape the client builder's `build()` returns —
|
|
34
|
+
* `{ filter: { where: [...] }, sort: [{ field, direction }], paginate: { page, size } }`
|
|
35
|
+
* — so a POST search body can be handed straight in, and so OR/AND groups (which
|
|
36
|
+
* serialize to a top-level `where[0][field]=…`) survive the round trip.
|
|
37
|
+
* `include` is not consumed here: eager-loading is the caller's `preload` call.
|
|
38
|
+
*
|
|
39
|
+
* Pure reshape — no validation or allow-listing here; that happens in
|
|
40
|
+
* {@link applyFilter} against the {@link FilterConfig}.
|
|
41
|
+
*/
|
|
42
|
+
export declare function parseFilterRequest(qs: Record<string, unknown>): FilterInput;
|
|
43
|
+
/**
|
|
44
|
+
* Parse the `groupByCount` block the client builder emits
|
|
45
|
+
* (`groupByCount[field]=tag&groupByCount[limit]=20&groupByCount[offset]=…&groupByCount[search]=…`).
|
|
46
|
+
* Returns `undefined` when no usable block is present. Pure reshape, like the rest of this
|
|
47
|
+
* module — field validation happens at execution, against the allow-list.
|
|
48
|
+
*/
|
|
49
|
+
export declare function parseGroupByCount(value: unknown): GroupByCountRequest | undefined;
|
|
50
|
+
//# sourceMappingURL=parse_request.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse_request.d.ts","sourceRoot":"","sources":["../../src/parse_request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAuB,MAAM,gBAAgB,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAW7E,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,YAAY,EAAE,CA4B7E;AA+BD;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,GAAG,MAAM,EAAE,CAYzD;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,EAAE,CAwBnD;AAqBD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,WAAW,CAkC3E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,GAAG,SAAS,CAWjF"}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
function toInt(value) {
|
|
2
|
+
if (typeof value === 'number' && Number.isFinite(value))
|
|
3
|
+
return value;
|
|
4
|
+
if (typeof value === 'string' && value.trim() !== '') {
|
|
5
|
+
const n = Number(value);
|
|
6
|
+
if (Number.isFinite(n))
|
|
7
|
+
return n;
|
|
8
|
+
}
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|
|
11
|
+
/** Map one `filter[field]=…` entry to `ColumnFilter[]` (Spatie/JSON:API shapes). */
|
|
12
|
+
export function toColumnFilters(field, value) {
|
|
13
|
+
// Array (`filter[id][]=1&filter[id][]=2`) → IN.
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
return [{ field, operator: 'in', value }];
|
|
16
|
+
}
|
|
17
|
+
// Operator object (`filter[age][gte]=18`) → one filter per operator key.
|
|
18
|
+
if (value != null && typeof value === 'object') {
|
|
19
|
+
return Object.entries(value).map(([operator, opValue]) => ({
|
|
20
|
+
field,
|
|
21
|
+
operator: operator,
|
|
22
|
+
value: opValue,
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
// Comma-separated scalar (Spatie multi-value convention) → IN.
|
|
26
|
+
if (typeof value === 'string' && value.includes(',')) {
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
field,
|
|
30
|
+
operator: 'in',
|
|
31
|
+
value: value
|
|
32
|
+
.split(',')
|
|
33
|
+
.map((s) => s.trim())
|
|
34
|
+
.filter((s) => s.length > 0),
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
}
|
|
38
|
+
// Bare scalar → equals.
|
|
39
|
+
return [{ field, operator: 'equals', value }];
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* True when `value` is an already-structured `ColumnFilter[]` rather than the
|
|
43
|
+
* `filter[field]=…` shape `toColumnFilters` reshapes.
|
|
44
|
+
*
|
|
45
|
+
* Two wire forms produce it. A POST body carrying the client builder's
|
|
46
|
+
* `build()` output nests it under `filter.where`; a GET whose query string was
|
|
47
|
+
* serialized from OR/AND groups decodes to the same array of
|
|
48
|
+
* `{ field, operator, value }` records. Both used to fall through to the
|
|
49
|
+
* scalar path, where an array becomes a single `in` filter on a field literally
|
|
50
|
+
* named `where` — dropped by the allow-list, leaving the query unfiltered.
|
|
51
|
+
*
|
|
52
|
+
* A real column named `where` arrives as `filter[where]=x` (a string) or
|
|
53
|
+
* `filter[where][gte]=1` (an operator object), so neither is mistaken for this.
|
|
54
|
+
*/
|
|
55
|
+
function isStructuredFilterList(value) {
|
|
56
|
+
return (Array.isArray(value) &&
|
|
57
|
+
value.length > 0 &&
|
|
58
|
+
value.every((entry) => entry != null &&
|
|
59
|
+
typeof entry === 'object' &&
|
|
60
|
+
!Array.isArray(entry) &&
|
|
61
|
+
typeof entry.field === 'string' &&
|
|
62
|
+
typeof entry.operator === 'string'));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Parse the `distinct` param into a de-duplicated list of field names. Accepts a
|
|
66
|
+
* comma-separated string (`distinct=afsc,base`) or a repeated/array form
|
|
67
|
+
* (`distinct[]=afsc&distinct[]=base`) — the shapes the client's `toQueryString()`
|
|
68
|
+
* and structured `build()` emit. Non-string entries are ignored.
|
|
69
|
+
*/
|
|
70
|
+
export function parseDistinct(distinct) {
|
|
71
|
+
let raw = [];
|
|
72
|
+
if (typeof distinct === 'string')
|
|
73
|
+
raw = distinct.split(',');
|
|
74
|
+
else if (Array.isArray(distinct))
|
|
75
|
+
raw = distinct.filter((s) => typeof s === 'string');
|
|
76
|
+
const out = [];
|
|
77
|
+
for (const entry of raw) {
|
|
78
|
+
const field = entry.trim();
|
|
79
|
+
if (field.length > 0 && !out.includes(field))
|
|
80
|
+
out.push(field);
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Parse the `sort` param into ordered {@link SortItem}s. Accepts the string form
|
|
86
|
+
* (`-createdAt,name` or `sort[]=name`) and the already-structured
|
|
87
|
+
* `[{ field, direction }]` form the client builder's `build()` emits — the
|
|
88
|
+
* latter used to be filtered out entirely as "not a string", silently dropping
|
|
89
|
+
* the ordering.
|
|
90
|
+
*/
|
|
91
|
+
export function parseSort(sort) {
|
|
92
|
+
if (Array.isArray(sort) && sort.some((s) => s != null && typeof s === 'object')) {
|
|
93
|
+
const items = [];
|
|
94
|
+
for (const entry of sort) {
|
|
95
|
+
if (entry == null || typeof entry !== 'object')
|
|
96
|
+
continue;
|
|
97
|
+
const { field, direction } = entry;
|
|
98
|
+
if (typeof field !== 'string' || field.length === 0)
|
|
99
|
+
continue;
|
|
100
|
+
items.push({ field, direction: direction === 'desc' ? 'desc' : 'asc' });
|
|
101
|
+
}
|
|
102
|
+
return items;
|
|
103
|
+
}
|
|
104
|
+
let raw = [];
|
|
105
|
+
if (typeof sort === 'string')
|
|
106
|
+
raw = sort.split(',');
|
|
107
|
+
else if (Array.isArray(sort))
|
|
108
|
+
raw = sort.filter((s) => typeof s === 'string');
|
|
109
|
+
const items = [];
|
|
110
|
+
for (const entry of raw) {
|
|
111
|
+
const field = entry.trim();
|
|
112
|
+
if (field.length === 0)
|
|
113
|
+
continue;
|
|
114
|
+
if (field.startsWith('-'))
|
|
115
|
+
items.push({ field: field.slice(1), direction: 'desc' });
|
|
116
|
+
else
|
|
117
|
+
items.push({ field, direction: 'asc' });
|
|
118
|
+
}
|
|
119
|
+
return items;
|
|
120
|
+
}
|
|
121
|
+
function parsePagination(qs) {
|
|
122
|
+
let page = toInt(qs.page);
|
|
123
|
+
let size = toInt(qs.size);
|
|
124
|
+
// JSON:API nested form: page[number] / page[size].
|
|
125
|
+
if (qs.page != null && typeof qs.page === 'object' && !Array.isArray(qs.page)) {
|
|
126
|
+
const p = qs.page;
|
|
127
|
+
page = toInt(p.number) ?? page;
|
|
128
|
+
size = toInt(p.size) ?? size;
|
|
129
|
+
}
|
|
130
|
+
// The client builder's `build()` nests the same two numbers under `paginate`,
|
|
131
|
+
// which is what a POST search body carries.
|
|
132
|
+
if (qs.paginate != null && typeof qs.paginate === 'object' && !Array.isArray(qs.paginate)) {
|
|
133
|
+
const p = qs.paginate;
|
|
134
|
+
page = toInt(p.page) ?? page;
|
|
135
|
+
size = toInt(p.size) ?? size;
|
|
136
|
+
}
|
|
137
|
+
return { ...(page !== undefined && { page }), ...(size !== undefined && { size }) };
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Parse a decoded request query object — e.g. AdonisJS `ctx.request.qs()` — into
|
|
141
|
+
* a structured {@link FilterInput}. Understands the Spatie / JSON:API shapes the
|
|
142
|
+
* `@adonis-agora/filter-client` builder emits:
|
|
143
|
+
*
|
|
144
|
+
* - `filter[status]=active` → equals
|
|
145
|
+
* - `filter[id]=1,2,3` / `filter[id][]=1&filter[id][]=2` → IN
|
|
146
|
+
* - `filter[age][gte]=18` → operator filter
|
|
147
|
+
* - `sort=-createdAt,name` → sort items
|
|
148
|
+
* - `distinct=afsc,base` / `distinct[]=afsc&distinct[]=base` → distinct fields
|
|
149
|
+
* - `groupByCount[field]=tag&groupByCount[limit]=20` → value enumeration
|
|
150
|
+
* - `search=term`, `page`/`size` (or `page[number]`/`page[size]`)
|
|
151
|
+
*
|
|
152
|
+
* It also accepts the structured shape the client builder's `build()` returns —
|
|
153
|
+
* `{ filter: { where: [...] }, sort: [{ field, direction }], paginate: { page, size } }`
|
|
154
|
+
* — so a POST search body can be handed straight in, and so OR/AND groups (which
|
|
155
|
+
* serialize to a top-level `where[0][field]=…`) survive the round trip.
|
|
156
|
+
* `include` is not consumed here: eager-loading is the caller's `preload` call.
|
|
157
|
+
*
|
|
158
|
+
* Pure reshape — no validation or allow-listing here; that happens in
|
|
159
|
+
* {@link applyFilter} against the {@link FilterConfig}.
|
|
160
|
+
*/
|
|
161
|
+
export function parseFilterRequest(qs) {
|
|
162
|
+
const out = {};
|
|
163
|
+
const filters = [];
|
|
164
|
+
if (qs.filter != null && typeof qs.filter === 'object' && !Array.isArray(qs.filter)) {
|
|
165
|
+
for (const [field, value] of Object.entries(qs.filter)) {
|
|
166
|
+
if (field === 'where' && isStructuredFilterList(value)) {
|
|
167
|
+
filters.push(...value);
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
filters.push(...toColumnFilters(field, value));
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// OR/AND groups serialize to a top-level `where[0][field]=…`, with no `filter`
|
|
174
|
+
// wrapper, so they decode beside `filter` rather than inside it.
|
|
175
|
+
if (isStructuredFilterList(qs.where))
|
|
176
|
+
filters.push(...qs.where);
|
|
177
|
+
if (filters.length > 0)
|
|
178
|
+
out.filters = filters;
|
|
179
|
+
const sort = parseSort(qs.sort);
|
|
180
|
+
if (sort.length > 0)
|
|
181
|
+
out.sort = sort;
|
|
182
|
+
const distinct = parseDistinct(qs.distinct);
|
|
183
|
+
if (distinct.length > 0)
|
|
184
|
+
out.distinct = distinct;
|
|
185
|
+
if (typeof qs.search === 'string' && qs.search.length > 0)
|
|
186
|
+
out.search = qs.search;
|
|
187
|
+
const { page, size } = parsePagination(qs);
|
|
188
|
+
if (page !== undefined)
|
|
189
|
+
out.page = page;
|
|
190
|
+
if (size !== undefined)
|
|
191
|
+
out.size = size;
|
|
192
|
+
const groupByCount = parseGroupByCount(qs.groupByCount);
|
|
193
|
+
if (groupByCount !== undefined)
|
|
194
|
+
out.groupByCount = groupByCount;
|
|
195
|
+
return out;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Parse the `groupByCount` block the client builder emits
|
|
199
|
+
* (`groupByCount[field]=tag&groupByCount[limit]=20&groupByCount[offset]=…&groupByCount[search]=…`).
|
|
200
|
+
* Returns `undefined` when no usable block is present. Pure reshape, like the rest of this
|
|
201
|
+
* module — field validation happens at execution, against the allow-list.
|
|
202
|
+
*/
|
|
203
|
+
export function parseGroupByCount(value) {
|
|
204
|
+
if (value == null || typeof value !== 'object' || Array.isArray(value))
|
|
205
|
+
return undefined;
|
|
206
|
+
const block = value;
|
|
207
|
+
if (typeof block.field !== 'string' || block.field.trim() === '')
|
|
208
|
+
return undefined;
|
|
209
|
+
const out = { field: block.field };
|
|
210
|
+
const limit = toInt(block.limit);
|
|
211
|
+
if (limit !== undefined)
|
|
212
|
+
out.limit = limit;
|
|
213
|
+
const offset = toInt(block.offset);
|
|
214
|
+
if (offset !== undefined)
|
|
215
|
+
out.offset = offset;
|
|
216
|
+
if (typeof block.search === 'string' && block.search.length > 0)
|
|
217
|
+
out.search = block.search;
|
|
218
|
+
return out;
|
|
219
|
+
}
|
|
220
|
+
//# sourceMappingURL=parse_request.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse_request.js","sourceRoot":"","sources":["../../src/parse_request.ts"],"names":[],"mappings":"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"}
|