@eienjs/adonisjs-api-query 1.1.0 → 2.0.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 (105) hide show
  1. package/{LICENSE.md → LICENSE} +1 -1
  2. package/README.md +28 -2
  3. package/build/configure.d.ts +6 -2
  4. package/build/configure.js +11 -0
  5. package/build/index.d.ts +32 -31
  6. package/build/index.js +31 -153
  7. package/build/providers/api_query_provider.d.ts +41 -37
  8. package/build/providers/api_query_provider.js +21 -26
  9. package/build/src/allowed_filter.d.ts +40 -36
  10. package/build/src/allowed_filter.js +113 -0
  11. package/build/src/allowed_include.d.ts +20 -16
  12. package/build/src/allowed_include.js +48 -0
  13. package/build/src/allowed_sort.d.ts +21 -17
  14. package/build/src/allowed_sort.js +50 -0
  15. package/build/src/api_query_builder_request.d.ts +34 -30
  16. package/build/src/api_query_builder_request.js +122 -0
  17. package/build/src/bindings/api_query_request.js +13 -0
  18. package/build/src/bindings/filters_query.js +40 -0
  19. package/build/src/bindings/includes_query.js +51 -0
  20. package/build/src/bindings/sorts_query.js +45 -0
  21. package/build/src/define_config.d.ts +7 -3
  22. package/build/src/define_config.js +25 -0
  23. package/build/src/enums/filter_operator.d.ts +11 -9
  24. package/build/src/enums/filter_operator.js +12 -0
  25. package/build/src/enums/sort_direction.d.ts +6 -4
  26. package/build/src/enums/sort_direction.js +7 -0
  27. package/build/src/exceptions/allowed_fields_must_be_called_before_allowed_includes.d.ts +9 -5
  28. package/build/src/exceptions/allowed_fields_must_be_called_before_allowed_includes.js +11 -0
  29. package/build/src/exceptions/invalid_append_query.d.ts +8 -4
  30. package/build/src/exceptions/invalid_append_query.js +14 -0
  31. package/build/src/exceptions/invalid_direction.d.ts +7 -3
  32. package/build/src/exceptions/invalid_direction.js +10 -0
  33. package/build/src/exceptions/invalid_filter_query.d.ts +10 -6
  34. package/build/src/exceptions/invalid_filter_query.js +18 -0
  35. package/build/src/exceptions/invalid_filter_value.d.ts +7 -3
  36. package/build/src/exceptions/invalid_filter_value.js +9 -0
  37. package/build/src/exceptions/invalid_include_query.d.ts +10 -6
  38. package/build/src/exceptions/invalid_include_query.js +22 -0
  39. package/build/src/exceptions/invalid_query.d.ts +7 -3
  40. package/build/src/exceptions/invalid_query.js +7 -0
  41. package/build/src/exceptions/invalid_sort_query.d.ts +10 -6
  42. package/build/src/exceptions/invalid_sort_query.js +18 -0
  43. package/build/src/exceptions/unknown_included_fields_query.d.ts +8 -4
  44. package/build/src/exceptions/unknown_included_fields_query.js +13 -0
  45. package/build/src/filters/filters_begin_with_strict.d.ts +10 -6
  46. package/build/src/filters/filters_begin_with_strict.js +9 -0
  47. package/build/src/filters/filters_callback.d.ts +10 -6
  48. package/build/src/filters/filters_callback.js +12 -0
  49. package/build/src/filters/filters_ends_with_strict.d.ts +10 -6
  50. package/build/src/filters/filters_ends_with_strict.js +9 -0
  51. package/build/src/filters/filters_exact.d.ts +15 -11
  52. package/build/src/filters/filters_exact.js +47 -0
  53. package/build/src/filters/filters_operator.d.ts +17 -13
  54. package/build/src/filters/filters_operator.js +53 -0
  55. package/build/src/filters/filters_partial.d.ts +15 -11
  56. package/build/src/filters/filters_partial.js +39 -0
  57. package/build/src/filters/filters_trashed.d.ts +9 -5
  58. package/build/src/filters/filters_trashed.js +14 -0
  59. package/build/src/includes/included_callback.d.ts +11 -7
  60. package/build/src/includes/included_callback.js +12 -0
  61. package/build/src/includes/included_count.d.ts +8 -4
  62. package/build/src/includes/included_count.js +11 -0
  63. package/build/src/includes/included_relationship.d.ts +12 -8
  64. package/build/src/includes/included_relationship.js +40 -0
  65. package/build/src/sorts/sorts_callback.d.ts +10 -6
  66. package/build/src/sorts/sorts_callback.js +12 -0
  67. package/build/src/sorts/sorts_field.d.ts +8 -4
  68. package/build/src/sorts/sorts_field.js +8 -0
  69. package/build/src/utils/helpers.js +26 -0
  70. package/build/stubs/main.d.ts +4 -1
  71. package/build/stubs/main.js +4 -0
  72. package/build/types.d.ts +91 -0
  73. package/build/types.js +1 -0
  74. package/package.json +99 -88
  75. package/build/api_query_request-QXOB4BN6.js +0 -18
  76. package/build/api_query_request-QXOB4BN6.js.map +0 -1
  77. package/build/chunk-3ITWUZL5.js +0 -108
  78. package/build/chunk-3ITWUZL5.js.map +0 -1
  79. package/build/chunk-54HNQTDY.js +0 -348
  80. package/build/chunk-54HNQTDY.js.map +0 -1
  81. package/build/chunk-IV3B5WO7.js +0 -160
  82. package/build/chunk-IV3B5WO7.js.map +0 -1
  83. package/build/chunk-MKQ3HMMA.js +0 -198
  84. package/build/chunk-MKQ3HMMA.js.map +0 -1
  85. package/build/chunk-XIRHVLVQ.js +0 -10
  86. package/build/chunk-XIRHVLVQ.js.map +0 -1
  87. package/build/filters_query-LCFH2F2X.js +0 -55
  88. package/build/filters_query-LCFH2F2X.js.map +0 -1
  89. package/build/includes_query-PVONWQMC.js +0 -70
  90. package/build/includes_query-PVONWQMC.js.map +0 -1
  91. package/build/index.js.map +0 -1
  92. package/build/metafile-esm.json +0 -1
  93. package/build/providers/api_query_provider.js.map +0 -1
  94. package/build/sorts_query-NJTC5UXX.js +0 -63
  95. package/build/sorts_query-NJTC5UXX.js.map +0 -1
  96. package/build/src/bindings/api_query_request.d.ts +0 -2
  97. package/build/src/bindings/filters_query.d.ts +0 -3
  98. package/build/src/bindings/includes_query.d.ts +0 -3
  99. package/build/src/bindings/sorts_query.d.ts +0 -3
  100. package/build/src/exceptions/invalid_field_query.d.ts +0 -5
  101. package/build/src/types.d.ts +0 -90
  102. package/build/src/types.js +0 -1
  103. package/build/src/types.js.map +0 -1
  104. package/build/src/utils/helpers.d.ts +0 -3
  105. /package/build/{config.stub → stubs/config.stub} +0 -0
@@ -0,0 +1,113 @@
1
+ import { ApiQueryBuilderRequest } from "./api_query_builder_request.js";
2
+ import { FiltersExact } from "./filters/filters_exact.js";
3
+ import { FiltersPartial } from "./filters/filters_partial.js";
4
+ import { FiltersBeginWithStrict } from "./filters/filters_begin_with_strict.js";
5
+ import { FiltersCallback } from "./filters/filters_callback.js";
6
+ import { FiltersEndsWithStrict } from "./filters/filters_ends_with_strict.js";
7
+ import { FiltersOperator } from "./filters/filters_operator.js";
8
+ import { FiltersTrashed } from "./filters/filters_trashed.js";
9
+ import { Collection } from "collect.js";
10
+ //#region src/allowed_filter.ts
11
+ var AllowedFilter = class AllowedFilter {
12
+ name;
13
+ filterClass;
14
+ internalName;
15
+ ignored;
16
+ default;
17
+ $hasDefault = false;
18
+ nullable = false;
19
+ constructor(name, filterClass, internalName) {
20
+ this.name = name;
21
+ this.filterClass = filterClass;
22
+ this.ignored = new Collection();
23
+ this.internalName = internalName ?? this.name;
24
+ }
25
+ filter(query, value) {
26
+ const valueToFilter = this.resolveValueForFiltering(value);
27
+ if (!this.nullable && valueToFilter === null) return;
28
+ this.filterClass.handle(query, valueToFilter, this.internalName);
29
+ }
30
+ getFilterClass() {
31
+ return this.filterClass;
32
+ }
33
+ getName() {
34
+ return this.name;
35
+ }
36
+ isForFilter(filterName) {
37
+ return this.name === filterName;
38
+ }
39
+ ignore(...values) {
40
+ this.ignored = this.ignored.merge(values).flatten();
41
+ return this;
42
+ }
43
+ getIgnored() {
44
+ return this.ignored.toArray();
45
+ }
46
+ getInternalName() {
47
+ return this.internalName;
48
+ }
49
+ setDefault(defaultValue) {
50
+ this.default = defaultValue;
51
+ this.$hasDefault = true;
52
+ if (defaultValue === null) this.setNullable(true);
53
+ return this;
54
+ }
55
+ getDefault() {
56
+ return this.default;
57
+ }
58
+ hasDefault() {
59
+ return this.$hasDefault;
60
+ }
61
+ setNullable(isNullable = true) {
62
+ this.nullable = isNullable;
63
+ return this;
64
+ }
65
+ unsetDefault() {
66
+ this.$hasDefault = false;
67
+ this.default = void 0;
68
+ return this;
69
+ }
70
+ resolveValueForFiltering(value) {
71
+ if (Array.isArray(value)) {
72
+ const remainingProperties = value.map((subValue) => this.resolveValueForFiltering(subValue));
73
+ return remainingProperties.length === 0 ? null : remainingProperties;
74
+ }
75
+ return this.ignored.contains(value) ? null : value;
76
+ }
77
+ static setFilterArrayValueDelimiter(delimiter) {
78
+ if (delimiter) ApiQueryBuilderRequest.setFilterArrayValueDelimiter(delimiter);
79
+ }
80
+ static exact(name, internalName, shouldAddRelationConstraint = true, arrayValueDelimiter) {
81
+ this.setFilterArrayValueDelimiter(arrayValueDelimiter);
82
+ return new AllowedFilter(name, new FiltersExact(shouldAddRelationConstraint), internalName);
83
+ }
84
+ static partial(name, internalName, shouldAddRelationConstraint = true, arrayValueDelimiter) {
85
+ this.setFilterArrayValueDelimiter(arrayValueDelimiter);
86
+ return new AllowedFilter(name, new FiltersPartial(shouldAddRelationConstraint), internalName);
87
+ }
88
+ static beginsWithStrict(name, internalName, shouldAddRelationConstraint = true, arrayValueDelimiter) {
89
+ this.setFilterArrayValueDelimiter(arrayValueDelimiter);
90
+ return new AllowedFilter(name, new FiltersBeginWithStrict(shouldAddRelationConstraint), internalName);
91
+ }
92
+ static endsWithStrict(name, internalName, shouldAddRelationConstraint = true, arrayValueDelimiter) {
93
+ this.setFilterArrayValueDelimiter(arrayValueDelimiter);
94
+ return new AllowedFilter(name, new FiltersEndsWithStrict(shouldAddRelationConstraint), internalName);
95
+ }
96
+ static callback(name, callback, internalName, arrayValueDelimiter) {
97
+ this.setFilterArrayValueDelimiter(arrayValueDelimiter);
98
+ return new AllowedFilter(name, new FiltersCallback(callback), internalName);
99
+ }
100
+ static trashed(name = "trashed", internalName) {
101
+ return new AllowedFilter(name, new FiltersTrashed(), internalName);
102
+ }
103
+ static custom(name, filterClass, internalName, arrayValueDelimiter) {
104
+ this.setFilterArrayValueDelimiter(arrayValueDelimiter);
105
+ return new AllowedFilter(name, filterClass, internalName);
106
+ }
107
+ static operator(name, filterOperator, boolean = "and", internalName, shouldAddRelationConstraint = true, arrayValueDelimiter) {
108
+ this.setFilterArrayValueDelimiter(arrayValueDelimiter);
109
+ return new AllowedFilter(name, new FiltersOperator(shouldAddRelationConstraint, filterOperator, boolean), internalName);
110
+ }
111
+ };
112
+ //#endregion
113
+ export { AllowedFilter };
@@ -1,17 +1,21 @@
1
- import { type LucidModel, type ModelQueryBuilderContract } from '@adonisjs/lucid/types/model';
2
- import { type ModelRelations } from '@adonisjs/lucid/types/relations';
3
- import { Collection } from 'collect.js';
4
- import { type Include } from './types.js';
5
- export declare class AllowedInclude<Model extends LucidModel> {
6
- static relationship<ParentModel extends LucidModel>(name: string, internalName?: string): Collection<AllowedInclude<ParentModel>>;
7
- static count<ParentModel extends LucidModel>(name: string, internalName?: string): Collection<AllowedInclude<ParentModel>>;
8
- static callback<ParentModel extends LucidModel, RelatedModel extends LucidModel>(name: string, callback: (query: ModelRelations<RelatedModel, ParentModel>['builder'] | ModelRelations<RelatedModel, ParentModel>['subQuery']) => void, internalName?: string): Collection<AllowedInclude<ParentModel>>;
9
- static custom<ParentModel extends LucidModel>(name: string, includeClass: Include<ParentModel>, internalName?: string): Collection<AllowedInclude<ParentModel>>;
10
- protected internalName: string;
11
- protected name: string;
12
- protected includeClass: Include<Model>;
13
- constructor(name: string, includeClass: Include<Model>, internalName?: string);
14
- include(query: ModelQueryBuilderContract<Model>): void;
15
- getName(): string;
16
- isForInclude(includeName: string): boolean;
1
+ import { Include } from "../types.js";
2
+ import { Collection } from "collect.js";
3
+ import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
4
+ import { ModelRelations } from "@adonisjs/lucid/types/relations";
5
+
6
+ //#region src/allowed_include.d.ts
7
+ declare class AllowedInclude<Model extends LucidModel> {
8
+ protected internalName: string;
9
+ protected name: string;
10
+ protected includeClass: Include<Model>;
11
+ constructor(name: string, includeClass: Include<Model>, internalName?: string);
12
+ include(query: ModelQueryBuilderContract<Model>): void;
13
+ getName(): string;
14
+ isForInclude(includeName: string): boolean;
15
+ static relationship<ParentModel extends LucidModel>(name: string, internalName?: string): Collection<AllowedInclude<ParentModel>>;
16
+ static count<ParentModel extends LucidModel>(name: string, internalName?: string): Collection<AllowedInclude<ParentModel>>;
17
+ static callback<ParentModel extends LucidModel, RelatedModel extends LucidModel>(name: string, callback: (query: ModelRelations<RelatedModel, ParentModel>['builder'] | ModelRelations<RelatedModel, ParentModel>['subQuery']) => void, internalName?: string): Collection<AllowedInclude<ParentModel>>;
18
+ static custom<ParentModel extends LucidModel>(name: string, includeClass: Include<ParentModel>, internalName?: string): Collection<AllowedInclude<ParentModel>>;
17
19
  }
20
+ //#endregion
21
+ export { AllowedInclude };
@@ -0,0 +1,48 @@
1
+ import { IncludedCallback } from "./includes/included_callback.js";
2
+ import { IncludedCount } from "./includes/included_count.js";
3
+ import { IncludedRelationship } from "./includes/included_relationship.js";
4
+ import { Collection } from "collect.js";
5
+ import app from "@adonisjs/core/services/app";
6
+ //#region src/allowed_include.ts
7
+ var AllowedInclude = class AllowedInclude {
8
+ internalName;
9
+ name;
10
+ includeClass;
11
+ constructor(name, includeClass, internalName) {
12
+ this.name = name;
13
+ this.includeClass = includeClass;
14
+ this.internalName = internalName ?? this.name;
15
+ }
16
+ include(query) {
17
+ this.includeClass.handle(query, this.internalName);
18
+ }
19
+ getName() {
20
+ return this.name;
21
+ }
22
+ isForInclude(includeName) {
23
+ return this.name === includeName;
24
+ }
25
+ static relationship(name, internalName) {
26
+ internalName ??= name;
27
+ return IncludedRelationship.getIndividualRelationshipPathsFromInclude(internalName).zip(IncludedRelationship.getIndividualRelationshipPathsFromInclude(name).toArray()).reduce((includes, args) => {
28
+ const [relationship, alias] = args;
29
+ includes = includes.push(new AllowedInclude(alias, new IncludedRelationship(), relationship));
30
+ if (!relationship.includes(".")) {
31
+ const countSuffix = app.config.get("apiquery.countSuffix", "Count");
32
+ for (const countAllowedInclude of this.count(`${alias}${countSuffix}`, `${relationship}${countSuffix}`)) includes = includes.push(countAllowedInclude);
33
+ }
34
+ return includes;
35
+ }, new Collection());
36
+ }
37
+ static count(name, internalName) {
38
+ return new Collection([new AllowedInclude(name, new IncludedCount(), internalName)]);
39
+ }
40
+ static callback(name, callback, internalName) {
41
+ return new Collection([new AllowedInclude(name, new IncludedCallback(callback), internalName)]);
42
+ }
43
+ static custom(name, includeClass, internalName) {
44
+ return new Collection([new AllowedInclude(name, includeClass, internalName)]);
45
+ }
46
+ };
47
+ //#endregion
48
+ export { AllowedInclude };
@@ -1,18 +1,22 @@
1
- import { type LucidModel, type ModelAttributes, type ModelQueryBuilderContract } from '@adonisjs/lucid/types/model';
2
- import { type ExtractKeys, type Sort } from './types.js';
3
- export declare class AllowedSort<Model extends LucidModel> {
4
- static parseSortDirection(name: string): string;
5
- static field<Model extends LucidModel>(name: string, internalName?: ExtractKeys<ModelAttributes<InstanceType<Model>>>): AllowedSort<Model>;
6
- static custom<Model extends LucidModel>(name: string, sortClass: Sort<Model>, internalName?: ExtractKeys<ModelAttributes<InstanceType<Model>>>): AllowedSort<Model>;
7
- static callback<Model extends LucidModel>(name: string, callback: (query: ModelQueryBuilderContract<Model>, descending: boolean, property: string) => void, internalName?: ExtractKeys<ModelAttributes<InstanceType<Model>>>): AllowedSort<Model>;
8
- protected defaultDirection: string;
9
- protected internalName: string;
10
- protected name: string;
11
- protected sortClass: Sort<Model>;
12
- constructor(name: string, sortClass: Sort<Model>, internalName?: ExtractKeys<ModelAttributes<InstanceType<Model>>>);
13
- sort(query: ModelQueryBuilderContract<Model>, descending?: boolean): void;
14
- getName(): string;
15
- isSort(sortName: string): boolean;
16
- getInternalName(): string;
17
- setDefaultDirection(defaultDirection: string): this;
1
+ import { ExtractKeys, Sort } from "../types.js";
2
+ import { LucidModel, ModelAttributes, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
3
+
4
+ //#region src/allowed_sort.d.ts
5
+ declare class AllowedSort<Model extends LucidModel> {
6
+ protected defaultDirection: string;
7
+ protected internalName: string;
8
+ protected name: string;
9
+ protected sortClass: Sort<Model>;
10
+ constructor(name: string, sortClass: Sort<Model>, internalName?: ExtractKeys<ModelAttributes<InstanceType<Model>>>);
11
+ sort(query: ModelQueryBuilderContract<Model>, isDescending?: boolean): void;
12
+ getName(): string;
13
+ isSort(sortName: string): boolean;
14
+ getInternalName(): string;
15
+ setDefaultDirection(defaultDirection: string): this;
16
+ static parseSortDirection(name: string): string;
17
+ static field<Model extends LucidModel>(name: string, internalName?: ExtractKeys<ModelAttributes<InstanceType<Model>>>): AllowedSort<Model>;
18
+ static custom<Model extends LucidModel>(name: string, sortClass: Sort<Model>, internalName?: ExtractKeys<ModelAttributes<InstanceType<Model>>>): AllowedSort<Model>;
19
+ static callback<Model extends LucidModel>(name: string, callback: (query: ModelQueryBuilderContract<Model>, isDescending: boolean, property: string) => void, internalName?: ExtractKeys<ModelAttributes<InstanceType<Model>>>): AllowedSort<Model>;
18
20
  }
21
+ //#endregion
22
+ export { AllowedSort };
@@ -0,0 +1,50 @@
1
+ import { SortDirection } from "./enums/sort_direction.js";
2
+ import { InvalidDirection } from "./exceptions/invalid_direction.js";
3
+ import { SortsCallback } from "./sorts/sorts_callback.js";
4
+ import { SortsField } from "./sorts/sorts_field.js";
5
+ //#region src/allowed_sort.ts
6
+ const REMOVE_HYPHEN_STARTING_IN_ANY_POSITION = /^-+/;
7
+ var AllowedSort = class AllowedSort {
8
+ defaultDirection;
9
+ internalName;
10
+ name;
11
+ sortClass;
12
+ constructor(name, sortClass, internalName) {
13
+ this.name = name.replace(REMOVE_HYPHEN_STARTING_IN_ANY_POSITION, "");
14
+ this.defaultDirection = AllowedSort.parseSortDirection(name);
15
+ this.sortClass = sortClass;
16
+ this.internalName = internalName ?? this.name;
17
+ }
18
+ sort(query, isDescending) {
19
+ isDescending ??= this.defaultDirection === SortDirection.Descending;
20
+ this.sortClass.handle(query, isDescending, this.internalName);
21
+ }
22
+ getName() {
23
+ return this.name;
24
+ }
25
+ isSort(sortName) {
26
+ return this.name === sortName;
27
+ }
28
+ getInternalName() {
29
+ return this.internalName;
30
+ }
31
+ setDefaultDirection(defaultDirection) {
32
+ if (![SortDirection.Ascending, SortDirection.Descending].includes(defaultDirection)) throw InvalidDirection.make(defaultDirection);
33
+ this.defaultDirection = defaultDirection;
34
+ return this;
35
+ }
36
+ static parseSortDirection(name) {
37
+ return name.startsWith("-") ? SortDirection.Descending : SortDirection.Ascending;
38
+ }
39
+ static field(name, internalName) {
40
+ return new AllowedSort(name, new SortsField(), internalName);
41
+ }
42
+ static custom(name, sortClass, internalName) {
43
+ return new AllowedSort(name, sortClass, internalName);
44
+ }
45
+ static callback(name, callback, internalName) {
46
+ return new AllowedSort(name, new SortsCallback(callback), internalName);
47
+ }
48
+ };
49
+ //#endregion
50
+ export { AllowedSort };
@@ -1,31 +1,35 @@
1
- import { type Request } from '@adonisjs/core/http';
2
- import { Collection } from 'collect.js';
3
- export declare class ApiQueryBuilderRequest {
4
- protected static includesArrayValueDelimiter: string;
5
- protected static appendsArrayValueDelimiter: string;
6
- protected static fieldsArrayValueDelimiter: string;
7
- protected static sortsArrayValueDelimiter: string;
8
- protected static filterArrayValueDelimiter: string;
9
- static setArrayValueDelimiter(delimiter: string): void;
10
- static setIncludesArrayValueDelimiter(includesArrayValueDelimiter: string): void;
11
- static setAppendsArrayValueDelimiter(appendsArrayValueDelimiter: string): void;
12
- static setFieldsArrayValueDelimiter(fieldsArrayValueDelimiter: string): void;
13
- static setSortsArrayValueDelimiter(sortsArrayValueDelimiter: string): void;
14
- static setFilterArrayValueDelimiter(filterArrayValueDelimiter: string): void;
15
- static getIncludesArrayValueDelimiter(): string;
16
- static getAppendsArrayValueDelimiter(): string;
17
- static getFieldsArrayValueDelimiter(): string;
18
- static getSortsArrayValueDelimiter(): string;
19
- static getFilterArrayValueDelimiter(): string;
20
- static resetDelimiters(): void;
21
- static fromRequest(request: Request): ApiQueryBuilderRequest;
22
- private readonly _request;
23
- constructor(request?: Request);
24
- includes(): Collection<string>;
25
- appends(): Collection<unknown>;
26
- fields(): Collection<unknown>;
27
- sorts(): Collection<string>;
28
- filters(): Collection<unknown>;
29
- protected getFilterValue(value: unknown): unknown;
30
- protected getRequestData<T = unknown>(key: string, defaultValue?: T): T;
1
+ import { Collection } from "collect.js";
2
+ import { HttpRequest } from "@adonisjs/core/http";
3
+
4
+ //#region src/api_query_builder_request.d.ts
5
+ declare class ApiQueryBuilderRequest {
6
+ protected static includesArrayValueDelimiter: string;
7
+ protected static appendsArrayValueDelimiter: string;
8
+ protected static fieldsArrayValueDelimiter: string;
9
+ protected static sortsArrayValueDelimiter: string;
10
+ protected static filterArrayValueDelimiter: string;
11
+ private readonly _request;
12
+ constructor(request?: HttpRequest);
13
+ includes(): Collection<string>;
14
+ appends(): Collection<unknown>;
15
+ fields(): Collection<unknown>;
16
+ sorts(): Collection<string>;
17
+ filters(): Collection<unknown>;
18
+ protected getFilterValue(value: unknown): unknown;
19
+ protected getRequestData<T = unknown>(key: string, defaultValue?: T): T;
20
+ static setArrayValueDelimiter(delimiter: string): void;
21
+ static setIncludesArrayValueDelimiter(includesArrayValueDelimiter: string): void;
22
+ static setAppendsArrayValueDelimiter(appendsArrayValueDelimiter: string): void;
23
+ static setFieldsArrayValueDelimiter(fieldsArrayValueDelimiter: string): void;
24
+ static setSortsArrayValueDelimiter(sortsArrayValueDelimiter: string): void;
25
+ static setFilterArrayValueDelimiter(filterArrayValueDelimiter: string): void;
26
+ static getIncludesArrayValueDelimiter(): string;
27
+ static getAppendsArrayValueDelimiter(): string;
28
+ static getFieldsArrayValueDelimiter(): string;
29
+ static getSortsArrayValueDelimiter(): string;
30
+ static getFilterArrayValueDelimiter(): string;
31
+ static resetDelimiters(): void;
32
+ static fromRequest(request: HttpRequest): ApiQueryBuilderRequest;
31
33
  }
34
+ //#endregion
35
+ export { ApiQueryBuilderRequest };
@@ -0,0 +1,122 @@
1
+ import { strAfterLast, strBeforeLast } from "./utils/helpers.js";
2
+ import { Collection } from "collect.js";
3
+ import { HttpContext } from "@adonisjs/core/http";
4
+ import app from "@adonisjs/core/services/app";
5
+ //#region src/api_query_builder_request.ts
6
+ var ApiQueryBuilderRequest = class ApiQueryBuilderRequest {
7
+ static includesArrayValueDelimiter = ",";
8
+ static appendsArrayValueDelimiter = ",";
9
+ static fieldsArrayValueDelimiter = ",";
10
+ static sortsArrayValueDelimiter = ",";
11
+ static filterArrayValueDelimiter = ",";
12
+ _request;
13
+ constructor(request) {
14
+ if (!request) request = HttpContext.getOrFail().request;
15
+ this._request = request;
16
+ }
17
+ includes() {
18
+ const includeParameterName = app.config.get("apiquery.parameters.include", "include");
19
+ let includeParts = this.getRequestData(includeParameterName, []);
20
+ if (typeof includeParts === "string") includeParts = includeParts.split(ApiQueryBuilderRequest.getIncludesArrayValueDelimiter());
21
+ return new Collection(includeParts).filter();
22
+ }
23
+ appends() {
24
+ const appendParameterName = app.config.get("apiquery.parameters.append", "append");
25
+ let appendParts = this.getRequestData(appendParameterName, {});
26
+ if (typeof appendParts === "string") appendParts = appendParts.split(ApiQueryBuilderRequest.getAppendsArrayValueDelimiter());
27
+ return new Collection(appendParts).filter();
28
+ }
29
+ fields() {
30
+ const fieldsParameterName = app.config.get("apiquery.parameters.fields", "fields");
31
+ const fieldsData = this.getRequestData(fieldsParameterName, {});
32
+ const fieldsPerTable = new Collection(typeof fieldsData === "string" ? fieldsData.split(ApiQueryBuilderRequest.getFieldsArrayValueDelimiter()) : fieldsData);
33
+ if (fieldsPerTable.isEmpty()) return new Collection();
34
+ const fields = {};
35
+ fieldsPerTable.each((tableFields, model) => {
36
+ if (!model || typeof model === "number") model = typeof tableFields === "string" && tableFields.includes(".") ? strBeforeLast(tableFields, ".") : "_";
37
+ if (!Object.hasOwn(fields, model)) fields[model] = [];
38
+ if (typeof tableFields === "string") tableFields = tableFields.split(ApiQueryBuilderRequest.getFieldsArrayValueDelimiter()).map((field) => {
39
+ return strAfterLast(field, ".");
40
+ });
41
+ fields[model] = [...fields[model], ...tableFields];
42
+ });
43
+ return new Collection(fields);
44
+ }
45
+ sorts() {
46
+ const sortParameterName = app.config.get("apiquery.parameters.sort", "sort");
47
+ let sortParts = this.getRequestData(sortParameterName, []);
48
+ if (typeof sortParts === "string") sortParts = sortParts.split(ApiQueryBuilderRequest.getSortsArrayValueDelimiter());
49
+ return new Collection(sortParts).filter();
50
+ }
51
+ filters() {
52
+ const filterParameterName = app.config.get("apiquery.parameters.filter", "filter");
53
+ const filterParts = this.getRequestData(filterParameterName, []);
54
+ if (typeof filterParts === "string") return new Collection();
55
+ return new Collection(filterParts).map((value) => {
56
+ return this.getFilterValue(value);
57
+ });
58
+ }
59
+ getFilterValue(value) {
60
+ if (value === void 0 || value === null) return null;
61
+ if (value === "" || Array.isArray(value) && value.length === 0 || typeof value === "object" && Object.keys(value).length === 0) return typeof value === "object" ? [] : value;
62
+ if (Array.isArray(value) || typeof value === "object") return new Collection(value).map((valueValue) => {
63
+ return this.getFilterValue(valueValue);
64
+ }).all();
65
+ if (typeof value === "string" && value.includes(ApiQueryBuilderRequest.getFilterArrayValueDelimiter())) return value.split(ApiQueryBuilderRequest.getFilterArrayValueDelimiter());
66
+ if (value === "true") return true;
67
+ if (value === "false") return false;
68
+ return value;
69
+ }
70
+ getRequestData(key, defaultValue) {
71
+ return this._request.input(key, defaultValue);
72
+ }
73
+ static setArrayValueDelimiter(delimiter) {
74
+ this.includesArrayValueDelimiter = delimiter;
75
+ this.appendsArrayValueDelimiter = delimiter;
76
+ this.fieldsArrayValueDelimiter = delimiter;
77
+ this.sortsArrayValueDelimiter = delimiter;
78
+ this.filterArrayValueDelimiter = delimiter;
79
+ }
80
+ static setIncludesArrayValueDelimiter(includesArrayValueDelimiter) {
81
+ this.includesArrayValueDelimiter = includesArrayValueDelimiter;
82
+ }
83
+ static setAppendsArrayValueDelimiter(appendsArrayValueDelimiter) {
84
+ this.appendsArrayValueDelimiter = appendsArrayValueDelimiter;
85
+ }
86
+ static setFieldsArrayValueDelimiter(fieldsArrayValueDelimiter) {
87
+ this.fieldsArrayValueDelimiter = fieldsArrayValueDelimiter;
88
+ }
89
+ static setSortsArrayValueDelimiter(sortsArrayValueDelimiter) {
90
+ this.sortsArrayValueDelimiter = sortsArrayValueDelimiter;
91
+ }
92
+ static setFilterArrayValueDelimiter(filterArrayValueDelimiter) {
93
+ this.filterArrayValueDelimiter = filterArrayValueDelimiter;
94
+ }
95
+ static getIncludesArrayValueDelimiter() {
96
+ return this.includesArrayValueDelimiter;
97
+ }
98
+ static getAppendsArrayValueDelimiter() {
99
+ return this.appendsArrayValueDelimiter;
100
+ }
101
+ static getFieldsArrayValueDelimiter() {
102
+ return this.fieldsArrayValueDelimiter;
103
+ }
104
+ static getSortsArrayValueDelimiter() {
105
+ return this.sortsArrayValueDelimiter;
106
+ }
107
+ static getFilterArrayValueDelimiter() {
108
+ return this.filterArrayValueDelimiter;
109
+ }
110
+ static resetDelimiters() {
111
+ this.includesArrayValueDelimiter = ",";
112
+ this.appendsArrayValueDelimiter = ",";
113
+ this.fieldsArrayValueDelimiter = ",";
114
+ this.sortsArrayValueDelimiter = ",";
115
+ this.filterArrayValueDelimiter = ",";
116
+ }
117
+ static fromRequest(request) {
118
+ return new ApiQueryBuilderRequest(request);
119
+ }
120
+ };
121
+ //#endregion
122
+ export { ApiQueryBuilderRequest };
@@ -0,0 +1,13 @@
1
+ import { ApiQueryBuilderRequest } from "../api_query_builder_request.js";
2
+ //#region src/bindings/api_query_request.ts
3
+ const extendModelQueryBuilderWithRequest = function(builder) {
4
+ builder.macro("withRequest", function(request) {
5
+ this.$queryBuilderRequest = ApiQueryBuilderRequest.fromRequest(request);
6
+ return this;
7
+ });
8
+ builder.getter("$apiQueryBuilderRequest", function() {
9
+ return this.$queryBuilderRequest ?? new ApiQueryBuilderRequest();
10
+ });
11
+ };
12
+ //#endregion
13
+ export { extendModelQueryBuilderWithRequest };
@@ -0,0 +1,40 @@
1
+ import { AllowedFilter } from "../allowed_filter.js";
2
+ import { InvalidFilterQuery } from "../exceptions/invalid_filter_query.js";
3
+ import collect$1 from "collect.js";
4
+ //#region src/bindings/filters_query.ts
5
+ const extendModelQueryBuilderWithFiltersQuery = function(builder, config) {
6
+ const ensureAllFiltersExist = (self) => {
7
+ if (config.disableInvalidFilterQueryException) return;
8
+ const filterNames = self.$apiQueryBuilderRequest.filters().keys();
9
+ const allowedFilterNames = self._allowedFilters.map((allowedFilter) => {
10
+ return allowedFilter.getName();
11
+ });
12
+ const diff = filterNames.diff(allowedFilterNames);
13
+ if (diff.isNotEmpty()) throw InvalidFilterQuery.filtersNotAllowed(diff.all(), allowedFilterNames.all());
14
+ };
15
+ const isFilterRequested = (self, allowedFilter) => {
16
+ return self.$apiQueryBuilderRequest.filters().has(allowedFilter.getName());
17
+ };
18
+ const addRequestedFiltersToQuery = (query) => {
19
+ query._allowedFilters.each((allowedFilter) => {
20
+ if (isFilterRequested(query, allowedFilter)) {
21
+ const value = query.$apiQueryBuilderRequest.filters().get(allowedFilter.getName());
22
+ allowedFilter.filter(query, value);
23
+ return;
24
+ }
25
+ if (allowedFilter.hasDefault()) allowedFilter.filter(query, allowedFilter.getDefault());
26
+ });
27
+ };
28
+ builder.macro("allowedFilters", function(...filters) {
29
+ const arrayFilters = Array.isArray(filters.at(0)) ? filters.at(0) : filters;
30
+ this._allowedFilters = collect$1(arrayFilters).map((filter) => {
31
+ if (filter instanceof AllowedFilter) return filter;
32
+ return AllowedFilter.partial(filter);
33
+ });
34
+ ensureAllFiltersExist(this);
35
+ addRequestedFiltersToQuery(this);
36
+ return this;
37
+ });
38
+ };
39
+ //#endregion
40
+ export { extendModelQueryBuilderWithFiltersQuery };
@@ -0,0 +1,51 @@
1
+ import { AllowedInclude } from "../allowed_include.js";
2
+ import { InvalidIncludeQuery } from "../exceptions/invalid_include_query.js";
3
+ import { Collection } from "collect.js";
4
+ //#region src/bindings/includes_query.ts
5
+ const extendModelQueryBuilderWithIncludesQuery = function(builder, config) {
6
+ const ensureAllIncludesExist = (self) => {
7
+ if (config.disableInvalidIncludesQueryException) return;
8
+ const includes = self.$apiQueryBuilderRequest.includes();
9
+ const allowedIncludeNames = self._allowedIncludes.map((allowedInclude) => {
10
+ return allowedInclude.getName();
11
+ });
12
+ const diff = includes.diff(allowedIncludeNames);
13
+ if (diff.isNotEmpty()) throw InvalidIncludeQuery.includesNotAllowed(diff.all(), allowedIncludeNames.all());
14
+ };
15
+ const findInclude = (self, include) => {
16
+ return self._allowedIncludes.first((included) => included.isForInclude(include));
17
+ };
18
+ const filterNonExistingIncludes = (self) => {
19
+ const includes = self.$apiQueryBuilderRequest.includes();
20
+ if (!config.disableInvalidIncludesQueryException) return includes;
21
+ return includes.filter((include) => !findInclude(self, include));
22
+ };
23
+ const addIncludesToQuery = (self, includes) => {
24
+ includes.each((include) => {
25
+ findInclude(self, include)?.include(self);
26
+ });
27
+ };
28
+ builder.macro("allowedIncludes", function(...includes) {
29
+ const arrayIncludes = Array.isArray(includes.at(0)) ? includes.at(0) : includes;
30
+ this._allowedIncludes = new Collection(arrayIncludes).reject((include) => typeof include === "string" && include.length === 0).reduce((result, include) => {
31
+ if (include instanceof Collection) {
32
+ for (const allowedInclude of include) result = result.push(allowedInclude);
33
+ return result;
34
+ }
35
+ if (include.endsWith(config.countSuffix)) {
36
+ for (const allowedInclude of AllowedInclude.count(include)) result = result.push(allowedInclude);
37
+ return result;
38
+ }
39
+ for (const allowedInclude of AllowedInclude.relationship(include)) result = result.push(allowedInclude);
40
+ return result;
41
+ }, new Collection()).unique((allowedInclude) => {
42
+ return allowedInclude.getName();
43
+ });
44
+ ensureAllIncludesExist(this);
45
+ const resultIncludes = filterNonExistingIncludes(this);
46
+ addIncludesToQuery(this, resultIncludes);
47
+ return this;
48
+ });
49
+ };
50
+ //#endregion
51
+ export { extendModelQueryBuilderWithIncludesQuery };
@@ -0,0 +1,45 @@
1
+ import { AllowedSort } from "../allowed_sort.js";
2
+ import { InvalidSortQuery } from "../exceptions/invalid_sort_query.js";
3
+ import { collect } from "collect.js";
4
+ //#region src/bindings/sorts_query.ts
5
+ const DESCENDING_ORDER_PREFIX = /^-+/;
6
+ const extendModelQueryBuilderWithSortsQuery = function(builder, config) {
7
+ const ensureAllSortsExist = (self) => {
8
+ if (config.disableInvalidSortQueryException) return;
9
+ const requestedSortNames = self.$apiQueryBuilderRequest.sorts().map((sort) => sort.replace(DESCENDING_ORDER_PREFIX, ""));
10
+ const allowedSortNames = self._allowedSorts.map((sort) => sort.getName());
11
+ const unknownSort = requestedSortNames.diff(allowedSortNames);
12
+ if (unknownSort.isNotEmpty()) throw InvalidSortQuery.sortsNotAllowed(unknownSort.all(), allowedSortNames.all());
13
+ };
14
+ const findSort = (self, property) => {
15
+ return self._allowedSorts.first((sort) => sort.isSort(property));
16
+ };
17
+ const addRequestedSortsToQuery = (self) => {
18
+ self.$apiQueryBuilderRequest.sorts().each((property) => {
19
+ const isDescending = property.startsWith("-");
20
+ findSort(self, property.replace(DESCENDING_ORDER_PREFIX, ""))?.sort(self, isDescending);
21
+ });
22
+ };
23
+ builder.macro("allowedSorts", function(...sorts) {
24
+ const arraySorts = Array.isArray(sorts.at(0)) ? sorts.at(0) : sorts;
25
+ this._allowedSorts = collect(arraySorts).map((sort) => {
26
+ if (sort instanceof AllowedSort) return sort;
27
+ return AllowedSort.field(sort.replace(DESCENDING_ORDER_PREFIX, ""));
28
+ });
29
+ ensureAllSortsExist(this);
30
+ addRequestedSortsToQuery(this);
31
+ return this;
32
+ });
33
+ builder.macro("defaultSort", function(...sorts) {
34
+ if (this.$apiQueryBuilderRequest.sorts().isNotEmpty()) return this;
35
+ collect(Array.isArray(sorts.at(0)) ? sorts.at(0) : sorts).map((sort) => {
36
+ if (sort instanceof AllowedSort) return sort;
37
+ return AllowedSort.field(sort);
38
+ }).each((sort) => {
39
+ sort.sort(this);
40
+ });
41
+ return this;
42
+ });
43
+ };
44
+ //#endregion
45
+ export { extendModelQueryBuilderWithSortsQuery };
@@ -1,3 +1,7 @@
1
- import { type ConfigProvider } from '@adonisjs/core/types';
2
- import { type ApiQueryConfig, type ResolvedApiQueryConfig } from './types.js';
3
- export declare const defineConfig: (config: ApiQueryConfig) => ConfigProvider<ResolvedApiQueryConfig>;
1
+ import { ApiQueryConfig, ResolvedApiQueryConfig } from "../types.js";
2
+ import { ConfigProvider } from "@adonisjs/core/types";
3
+
4
+ //#region src/define_config.d.ts
5
+ declare const defineConfig: (config: ApiQueryConfig) => ConfigProvider<ResolvedApiQueryConfig>;
6
+ //#endregion
7
+ export { defineConfig };