@eienjs/adonisjs-api-query 2.0.0 → 3.0.1
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/README.md +138 -0
- package/build/configure.d.ts +1 -5
- package/build/configure.js +1 -2
- package/build/index.d.ts +12 -6
- package/build/index.js +26 -20
- package/build/providers/api_query_provider.d.ts +19 -12
- package/build/providers/api_query_provider.js +7 -3
- package/build/src/allowed_filter.d.ts +14 -10
- package/build/src/allowed_filter.js +34 -12
- package/build/src/allowed_include.d.ts +6 -11
- package/build/src/allowed_include.js +14 -15
- package/build/src/allowed_sort.d.ts +2 -6
- package/build/src/allowed_sort.js +1 -2
- package/build/src/api_query_builder_request.d.ts +33 -12
- package/build/src/api_query_builder_request.js +119 -41
- package/build/src/base_filterable.d.ts +45 -0
- package/build/src/base_filterable.js +172 -0
- package/build/src/bindings/api_query_request.js +3 -3
- package/build/src/bindings/filterable_query.js +51 -0
- package/build/src/bindings/filters_query.js +21 -23
- package/build/src/bindings/includes_query.js +32 -33
- package/build/src/bindings/sorts_query.js +20 -23
- package/build/src/bindings/validation_query.js +27 -0
- package/build/src/decorators/filterable.d.ts +20 -0
- package/build/src/decorators/filterable.js +24 -0
- package/build/src/define_config.d.ts +1 -5
- package/build/src/define_config.js +3 -3
- package/build/src/enums/filter_operator.d.ts +2 -5
- package/build/src/enums/filter_operator.js +1 -2
- package/build/src/enums/sort_direction.d.ts +2 -5
- package/build/src/enums/sort_direction.js +1 -2
- package/build/src/exceptions/allowed_fields_must_be_called_before_allowed_includes.d.ts +4 -8
- package/build/src/exceptions/allowed_fields_must_be_called_before_allowed_includes.js +3 -4
- package/build/src/exceptions/filterable_not_configured.d.ts +5 -0
- package/build/src/exceptions/filterable_not_configured.js +12 -0
- package/build/src/exceptions/invalid_append_query.d.ts +4 -6
- package/build/src/exceptions/invalid_append_query.js +5 -2
- package/build/src/exceptions/invalid_direction.d.ts +2 -6
- package/build/src/exceptions/invalid_direction.js +1 -2
- package/build/src/exceptions/invalid_field_query.d.ts +7 -0
- package/build/src/exceptions/invalid_field_query.js +17 -0
- package/build/src/exceptions/invalid_filter_query.d.ts +2 -6
- package/build/src/exceptions/invalid_filter_query.js +1 -2
- package/build/src/exceptions/invalid_filter_value.d.ts +2 -6
- package/build/src/exceptions/invalid_filter_value.js +1 -2
- package/build/src/exceptions/invalid_include_query.d.ts +2 -6
- package/build/src/exceptions/invalid_include_query.js +1 -2
- package/build/src/exceptions/invalid_query.d.ts +2 -6
- package/build/src/exceptions/invalid_query.js +1 -2
- package/build/src/exceptions/invalid_sort_query.d.ts +2 -6
- package/build/src/exceptions/invalid_sort_query.js +1 -2
- package/build/src/exceptions/unknown_included_fields_query.d.ts +2 -6
- package/build/src/exceptions/unknown_included_fields_query.js +1 -2
- package/build/src/exceptions/vine_not_installed.d.ts +5 -0
- package/build/src/exceptions/vine_not_installed.js +12 -0
- package/build/src/filters/filters_begin_with_strict.d.ts +2 -6
- package/build/src/filters/filters_begin_with_strict.js +2 -3
- package/build/src/filters/filters_callback.d.ts +2 -6
- package/build/src/filters/filters_callback.js +1 -2
- package/build/src/filters/filters_ends_with_strict.d.ts +2 -6
- package/build/src/filters/filters_ends_with_strict.js +2 -3
- package/build/src/filters/filters_exact.d.ts +2 -6
- package/build/src/filters/filters_exact.js +15 -12
- package/build/src/filters/filters_operator.d.ts +3 -7
- package/build/src/filters/filters_operator.js +10 -11
- package/build/src/filters/filters_partial.d.ts +2 -8
- package/build/src/filters/filters_partial.js +7 -9
- package/build/src/filters/filters_scope.d.ts +12 -0
- package/build/src/filters/filters_scope.js +98 -0
- package/build/src/filters/filters_trashed.d.ts +2 -6
- package/build/src/filters/filters_trashed.js +1 -2
- package/build/src/includes/included_callback.d.ts +2 -6
- package/build/src/includes/included_callback.js +1 -2
- package/build/src/includes/included_count.d.ts +2 -6
- package/build/src/includes/included_count.js +2 -2
- package/build/src/includes/included_relationship.d.ts +4 -8
- package/build/src/includes/included_relationship.js +19 -22
- package/build/src/sorts/sorts_callback.d.ts +2 -6
- package/build/src/sorts/sorts_callback.js +1 -2
- package/build/src/sorts/sorts_field.d.ts +2 -6
- package/build/src/sorts/sorts_field.js +1 -2
- package/build/src/utils/helpers.js +2 -14
- package/build/src/validation/schema_builder.d.ts +3 -0
- package/build/src/validation/schema_builder.js +38 -0
- package/build/src/validation/vine_resolver.js +13 -0
- package/build/stubs/main.d.ts +1 -4
- package/build/stubs/main.js +1 -2
- package/build/types.d.ts +44 -19
- package/package.json +31 -24
|
@@ -2,10 +2,6 @@ import { Filter } from "../../types.js";
|
|
|
2
2
|
import { FiltersPartial } from "./filters_partial.js";
|
|
3
3
|
import { LucidModel } from "@adonisjs/lucid/types/model";
|
|
4
4
|
import { StrictValuesWithoutRaw } from "@adonisjs/lucid/types/querybuilder";
|
|
5
|
-
|
|
6
|
-
//#region src/filters/filters_begin_with_strict.d.ts
|
|
7
|
-
declare class FiltersBeginWithStrict<Model extends LucidModel> extends FiltersPartial<Model> implements Filter<Model> {
|
|
5
|
+
export declare class FiltersBeginWithStrict<Model extends LucidModel> extends FiltersPartial<Model> implements Filter<Model> {
|
|
8
6
|
protected getWhereRawParameters(value: StrictValuesWithoutRaw, property: string): [string, string[]];
|
|
9
|
-
}
|
|
10
|
-
//#endregion
|
|
11
|
-
export { FiltersBeginWithStrict };
|
|
7
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { FiltersPartial } from "./filters_partial.js";
|
|
2
|
-
|
|
2
|
+
// src/filters/filters_begin_with_strict.ts
|
|
3
3
|
var FiltersBeginWithStrict = class FiltersBeginWithStrict extends FiltersPartial {
|
|
4
4
|
getWhereRawParameters(value, property) {
|
|
5
|
-
return [
|
|
5
|
+
return ["?? LIKE ?", [property, `${FiltersBeginWithStrict.escapeLike(value.toString())}%`]];
|
|
6
6
|
}
|
|
7
7
|
};
|
|
8
|
-
//#endregion
|
|
9
8
|
export { FiltersBeginWithStrict };
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { Filter } from "../../types.js";
|
|
2
2
|
import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
3
|
-
|
|
4
|
-
//#region src/filters/filters_callback.d.ts
|
|
5
|
-
declare class FiltersCallback<Model extends LucidModel> implements Filter<Model> {
|
|
3
|
+
export declare class FiltersCallback<Model extends LucidModel> implements Filter<Model> {
|
|
6
4
|
private callback;
|
|
7
5
|
constructor(callback: (query: ModelQueryBuilderContract<Model>, value: unknown, property: string) => void);
|
|
8
6
|
handle(query: ModelQueryBuilderContract<Model, InstanceType<Model>>, value: unknown, property: string): void;
|
|
9
|
-
}
|
|
10
|
-
//#endregion
|
|
11
|
-
export { FiltersCallback };
|
|
7
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/filters/filters_callback.ts
|
|
2
2
|
var FiltersCallback = class {
|
|
3
3
|
callback;
|
|
4
4
|
constructor(callback) {
|
|
@@ -8,5 +8,4 @@ var FiltersCallback = class {
|
|
|
8
8
|
this.callback(query, value, property);
|
|
9
9
|
}
|
|
10
10
|
};
|
|
11
|
-
//#endregion
|
|
12
11
|
export { FiltersCallback };
|
|
@@ -2,10 +2,6 @@ import { Filter } from "../../types.js";
|
|
|
2
2
|
import { FiltersPartial } from "./filters_partial.js";
|
|
3
3
|
import { LucidModel } from "@adonisjs/lucid/types/model";
|
|
4
4
|
import { StrictValuesWithoutRaw } from "@adonisjs/lucid/types/querybuilder";
|
|
5
|
-
|
|
6
|
-
//#region src/filters/filters_ends_with_strict.d.ts
|
|
7
|
-
declare class FiltersEndsWithStrict<Model extends LucidModel> extends FiltersPartial<Model> implements Filter<Model> {
|
|
5
|
+
export declare class FiltersEndsWithStrict<Model extends LucidModel> extends FiltersPartial<Model> implements Filter<Model> {
|
|
8
6
|
protected getWhereRawParameters(value: StrictValuesWithoutRaw, property: string): [string, string[]];
|
|
9
|
-
}
|
|
10
|
-
//#endregion
|
|
11
|
-
export { FiltersEndsWithStrict };
|
|
7
|
+
}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { FiltersPartial } from "./filters_partial.js";
|
|
2
|
-
|
|
2
|
+
// src/filters/filters_ends_with_strict.ts
|
|
3
3
|
var FiltersEndsWithStrict = class FiltersEndsWithStrict extends FiltersPartial {
|
|
4
4
|
getWhereRawParameters(value, property) {
|
|
5
|
-
return [
|
|
5
|
+
return ["?? LIKE ?", [property, `%${FiltersEndsWithStrict.escapeLike(value.toString())}`]];
|
|
6
6
|
}
|
|
7
7
|
};
|
|
8
|
-
//#endregion
|
|
9
8
|
export { FiltersEndsWithStrict };
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Filter } from "../../types.js";
|
|
2
2
|
import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
3
3
|
import { StrictValuesWithoutRaw } from "@adonisjs/lucid/types/querybuilder";
|
|
4
|
-
|
|
5
|
-
//#region src/filters/filters_exact.d.ts
|
|
6
|
-
declare class FiltersExact<Model extends LucidModel> implements Filter<Model> {
|
|
4
|
+
export declare class FiltersExact<Model extends LucidModel> implements Filter<Model> {
|
|
7
5
|
protected shouldAddRelationConstraint: boolean;
|
|
8
6
|
protected relationConstraints: string[];
|
|
9
7
|
constructor(shouldAddRelationConstraint?: boolean);
|
|
@@ -11,6 +9,4 @@ declare class FiltersExact<Model extends LucidModel> implements Filter<Model> {
|
|
|
11
9
|
protected qualifyColumn(query: ModelQueryBuilderContract<Model, InstanceType<Model>>, column: string): string;
|
|
12
10
|
protected isRelationProperty(query: ModelQueryBuilderContract<Model, InstanceType<Model>>, property: string): boolean;
|
|
13
11
|
protected withRelationConstraint(query: ModelQueryBuilderContract<Model, InstanceType<Model>>, value: StrictValuesWithoutRaw | null, property: string): void;
|
|
14
|
-
}
|
|
15
|
-
//#endregion
|
|
16
|
-
export { FiltersExact };
|
|
12
|
+
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
//#region src/filters/filters_exact.ts
|
|
1
|
+
// src/filters/filters_exact.ts
|
|
3
2
|
var FiltersExact = class {
|
|
4
3
|
shouldAddRelationConstraint;
|
|
5
4
|
relationConstraints = [];
|
|
@@ -12,36 +11,40 @@ var FiltersExact = class {
|
|
|
12
11
|
return;
|
|
13
12
|
}
|
|
14
13
|
if (Array.isArray(value)) {
|
|
15
|
-
|
|
14
|
+
const flatValues = value.flat(Infinity).filter((item) => typeof item !== "object" || item === null);
|
|
15
|
+
if (flatValues.length === 0) return;
|
|
16
|
+
query.whereIn(this.qualifyColumn(query, property), flatValues);
|
|
16
17
|
return;
|
|
17
18
|
}
|
|
18
19
|
if (value === null) {
|
|
19
20
|
query.whereNull(this.qualifyColumn(query, property));
|
|
20
21
|
return;
|
|
21
22
|
}
|
|
23
|
+
if (typeof value === "object") return;
|
|
22
24
|
query.where(this.qualifyColumn(query, property), "=", value);
|
|
23
25
|
}
|
|
24
26
|
qualifyColumn(query, column) {
|
|
25
27
|
if (column.includes(".")) return column;
|
|
26
|
-
return `${query.model.table}.${query.model.$getColumn(column)?.columnName}`;
|
|
28
|
+
return `${query.model.table}.${query.model.$getColumn(column)?.columnName ?? column}`;
|
|
27
29
|
}
|
|
28
30
|
isRelationProperty(query, property) {
|
|
29
|
-
if (!property.includes(".")) return false;
|
|
30
|
-
if (this.relationConstraints.includes(property)) return false;
|
|
31
|
+
if (!property.includes(".") || this.relationConstraints.includes(property)) return false;
|
|
31
32
|
const firstRelationShip = property.split(".", 1)[0];
|
|
32
33
|
return query.model.$relationsDefinitions.has(firstRelationShip);
|
|
33
34
|
}
|
|
34
35
|
withRelationConstraint(query, value, property) {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
36
|
+
const parts = property.split(".");
|
|
37
|
+
const relationProperty = parts.pop();
|
|
38
|
+
const relation = parts.join(".");
|
|
39
39
|
query.whereHas(relation, (subQuery) => {
|
|
40
40
|
const columnName = this.qualifyColumn(subQuery, relationProperty);
|
|
41
41
|
this.relationConstraints.push(columnName);
|
|
42
|
-
|
|
42
|
+
try {
|
|
43
|
+
this.handle(subQuery, value, columnName);
|
|
44
|
+
} finally {
|
|
45
|
+
this.relationConstraints.pop();
|
|
46
|
+
}
|
|
43
47
|
});
|
|
44
48
|
}
|
|
45
49
|
};
|
|
46
|
-
//#endregion
|
|
47
50
|
export { FiltersExact };
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { FilterOperator } from "../enums/filter_operator.js";
|
|
2
1
|
import { EnumType, Filter } from "../../types.js";
|
|
2
|
+
import { FilterOperator } from "../enums/filter_operator.js";
|
|
3
3
|
import { FiltersExact } from "./filters_exact.js";
|
|
4
4
|
import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
5
5
|
import { StrictValuesWithoutRaw } from "@adonisjs/lucid/types/querybuilder";
|
|
6
|
-
|
|
7
|
-
//#region src/filters/filters_operator.d.ts
|
|
8
|
-
declare class FiltersOperator<Model extends LucidModel> extends FiltersExact<Model> implements Filter<Model> {
|
|
6
|
+
export declare class FiltersOperator<Model extends LucidModel> extends FiltersExact<Model> implements Filter<Model> {
|
|
9
7
|
protected shouldAddRelationConstraint: boolean;
|
|
10
8
|
protected filterOperator: EnumType<typeof FilterOperator>;
|
|
11
9
|
protected boolean: 'and' | 'or';
|
|
@@ -13,6 +11,4 @@ declare class FiltersOperator<Model extends LucidModel> extends FiltersExact<Mod
|
|
|
13
11
|
handle(query: ModelQueryBuilderContract<Model, InstanceType<Model>>, value: StrictValuesWithoutRaw | null, property: string): void;
|
|
14
12
|
protected getDynamicFilterOperator(value: string): EnumType<typeof FilterOperator>;
|
|
15
13
|
protected removeDynamicFilterOperatorFromValue(value: string, filterOperator: EnumType<typeof FilterOperator>): string;
|
|
16
|
-
}
|
|
17
|
-
//#endregion
|
|
18
|
-
export { FiltersOperator };
|
|
14
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { substrReplace } from "../utils/helpers.js";
|
|
2
|
-
import { FiltersExact } from "./filters_exact.js";
|
|
3
1
|
import { FilterOperator } from "../enums/filter_operator.js";
|
|
4
|
-
|
|
2
|
+
import { FiltersExact } from "./filters_exact.js";
|
|
3
|
+
// src/filters/filters_operator.ts
|
|
4
|
+
const SORTED_OPERATORS = Object.values(FilterOperator).filter((op) => op !== FilterOperator.Dynamic).toSorted((a, b) => b.length - a.length);
|
|
5
5
|
var FiltersOperator = class extends FiltersExact {
|
|
6
6
|
shouldAddRelationConstraint;
|
|
7
7
|
filterOperator;
|
|
@@ -29,9 +29,11 @@ var FiltersOperator = class extends FiltersExact {
|
|
|
29
29
|
query.whereNull(this.qualifyColumn(query, property));
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
|
+
if (typeof value === "object") return;
|
|
32
33
|
if (filterOperator === FilterOperator.Dynamic) {
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
const strValue = value.toString();
|
|
35
|
+
filterOperator = this.getDynamicFilterOperator(strValue);
|
|
36
|
+
value = this.removeDynamicFilterOperatorFromValue(strValue, filterOperator);
|
|
35
37
|
}
|
|
36
38
|
if (this.boolean === "and") {
|
|
37
39
|
query.where(this.qualifyColumn(query, property), filterOperator, value);
|
|
@@ -40,14 +42,11 @@ var FiltersOperator = class extends FiltersExact {
|
|
|
40
42
|
query.orWhere(this.qualifyColumn(query, property), filterOperator, value);
|
|
41
43
|
}
|
|
42
44
|
getDynamicFilterOperator(value) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
return filterOperator;
|
|
45
|
+
for (const filterOperatorCase of SORTED_OPERATORS) if (value.startsWith(filterOperatorCase)) return filterOperatorCase;
|
|
46
|
+
return FilterOperator.Equal;
|
|
46
47
|
}
|
|
47
48
|
removeDynamicFilterOperatorFromValue(value, filterOperator) {
|
|
48
|
-
|
|
49
|
-
return value;
|
|
49
|
+
return value.startsWith(filterOperator) ? value.slice(filterOperator.length) : value;
|
|
50
50
|
}
|
|
51
51
|
};
|
|
52
|
-
//#endregion
|
|
53
52
|
export { FiltersOperator };
|
|
@@ -2,15 +2,9 @@ import { Filter } from "../../types.js";
|
|
|
2
2
|
import { FiltersExact } from "./filters_exact.js";
|
|
3
3
|
import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
4
4
|
import { StrictValuesWithoutRaw } from "@adonisjs/lucid/types/querybuilder";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
//#region src/filters/filters_partial.d.ts
|
|
8
|
-
declare class FiltersPartial<Model extends LucidModel> extends FiltersExact<Model> implements Filter<Model> {
|
|
5
|
+
export declare class FiltersPartial<Model extends LucidModel> extends FiltersExact<Model> implements Filter<Model> {
|
|
9
6
|
handle(query: ModelQueryBuilderContract<Model, InstanceType<Model>>, value: StrictValuesWithoutRaw | null, property: string): void;
|
|
10
7
|
protected parsePropertyToColumn(query: ModelQueryBuilderContract<Model, InstanceType<Model>>, property: string): string;
|
|
11
|
-
protected getDatabaseDialect(query: ModelQueryBuilderContract<Model, InstanceType<Model>>): DialectContract['name'];
|
|
12
8
|
protected getWhereRawParameters(value: StrictValuesWithoutRaw | null, property: string): [string, string[]];
|
|
13
9
|
protected static escapeLike(value: string): string;
|
|
14
|
-
}
|
|
15
|
-
//#endregion
|
|
16
|
-
export { FiltersPartial };
|
|
10
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FiltersExact } from "./filters_exact.js";
|
|
2
|
-
|
|
2
|
+
// src/filters/filters_partial.ts
|
|
3
3
|
var FiltersPartial = class FiltersPartial extends FiltersExact {
|
|
4
4
|
handle(query, value, property) {
|
|
5
5
|
if (this.shouldAddRelationConstraint && this.isRelationProperty(query, property)) {
|
|
@@ -7,16 +7,18 @@ var FiltersPartial = class FiltersPartial extends FiltersExact {
|
|
|
7
7
|
return;
|
|
8
8
|
}
|
|
9
9
|
if (Array.isArray(value)) {
|
|
10
|
-
|
|
10
|
+
const subValues = value.flat(Infinity).filter((item) => item !== null && typeof item !== "object" && String(item).length > 0);
|
|
11
|
+
if (subValues.length === 0) return;
|
|
11
12
|
query.where((subQuery) => {
|
|
12
|
-
const
|
|
13
|
+
const column = this.parsePropertyToColumn(subQuery, property);
|
|
13
14
|
for (const partialValue of subValues) {
|
|
14
|
-
const [innerSql, innerBindings] = this.getWhereRawParameters(partialValue,
|
|
15
|
+
const [innerSql, innerBindings] = this.getWhereRawParameters(partialValue, column);
|
|
15
16
|
subQuery.orWhereRaw(innerSql, innerBindings);
|
|
16
17
|
}
|
|
17
18
|
});
|
|
18
19
|
return;
|
|
19
20
|
}
|
|
21
|
+
if (value === null || typeof value === "object") return;
|
|
20
22
|
const [sql, bindings] = this.getWhereRawParameters(value, this.parsePropertyToColumn(query, property));
|
|
21
23
|
query.whereRaw(sql, bindings);
|
|
22
24
|
}
|
|
@@ -24,16 +26,12 @@ var FiltersPartial = class FiltersPartial extends FiltersExact {
|
|
|
24
26
|
if (property.includes(".")) return property;
|
|
25
27
|
return query.model.$getColumn(property)?.columnName ?? property;
|
|
26
28
|
}
|
|
27
|
-
getDatabaseDialect(query) {
|
|
28
|
-
return query.client.dialect.name;
|
|
29
|
-
}
|
|
30
29
|
getWhereRawParameters(value, property) {
|
|
31
30
|
const resolvedValue = String(value).toLowerCase();
|
|
32
31
|
return ["LOWER(??) LIKE ?", [property, `%${FiltersPartial.escapeLike(resolvedValue)}%`]];
|
|
33
32
|
}
|
|
34
33
|
static escapeLike(value) {
|
|
35
|
-
return value.replaceAll("\\",
|
|
34
|
+
return value.replaceAll("\\", String.raw`\\`).replaceAll("_", String.raw`\_`).replaceAll("%", String.raw`\%`);
|
|
36
35
|
}
|
|
37
36
|
};
|
|
38
|
-
//#endregion
|
|
39
37
|
export { FiltersPartial };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Filter } from "../../types.js";
|
|
2
|
+
import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
3
|
+
export declare class FiltersScope<Model extends LucidModel> implements Filter<Model> {
|
|
4
|
+
handle(query: ModelQueryBuilderContract<Model, InstanceType<Model>>, value: unknown, property: string): void;
|
|
5
|
+
protected applyScope(query: ModelQueryBuilderContract<Model, InstanceType<Model>>, value: unknown, property: string): void;
|
|
6
|
+
protected getModelScopeFunction(model: LucidModel, candidate: string): ((...args: unknown[]) => void) | undefined;
|
|
7
|
+
protected resolveScopeMethod(model: Model, property: string): string;
|
|
8
|
+
protected extractParametersString(fn: (...args: unknown[]) => void): string | null;
|
|
9
|
+
protected hasParameters(fn: (...args: unknown[]) => void): boolean;
|
|
10
|
+
protected countParameters(fn: (...args: unknown[]) => void): number;
|
|
11
|
+
protected resolveArguments(scopeFn: ((...args: unknown[]) => void) | undefined, value: unknown, resolvedParamCount?: number): unknown[];
|
|
12
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import string from "@adonisjs/core/helpers/string";
|
|
2
|
+
import { BaseModel } from "@adonisjs/lucid/orm";
|
|
3
|
+
// src/filters/filters_scope.ts
|
|
4
|
+
const FN_PARAMS_REGEX = /^(?:async\s*)?(?:function[^(]*\(([^)]*)\)|\(([^)]*)\)\s*=>|([^\s(=>]+)\s*=>)/;
|
|
5
|
+
const RESERVED_MODEL_METHODS = /* @__PURE__ */ new Set([
|
|
6
|
+
"boot",
|
|
7
|
+
"before",
|
|
8
|
+
"after",
|
|
9
|
+
"saving",
|
|
10
|
+
"creating",
|
|
11
|
+
"updating",
|
|
12
|
+
"deleting",
|
|
13
|
+
"finding",
|
|
14
|
+
"fetching",
|
|
15
|
+
"paginating",
|
|
16
|
+
"constructor",
|
|
17
|
+
"prototype"
|
|
18
|
+
]);
|
|
19
|
+
var FiltersScope = class {
|
|
20
|
+
handle(query, value, property) {
|
|
21
|
+
const dotIndex = property.indexOf(".");
|
|
22
|
+
if (dotIndex !== -1) {
|
|
23
|
+
const firstRelation = property.slice(0, dotIndex);
|
|
24
|
+
if (query.model.$relationsDefinitions.has(firstRelation)) {
|
|
25
|
+
const remainingProperty = property.slice(dotIndex + 1);
|
|
26
|
+
query.whereHas(firstRelation, (subQuery) => {
|
|
27
|
+
this.handle(subQuery, value, remainingProperty);
|
|
28
|
+
});
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
this.applyScope(query, value, property);
|
|
33
|
+
}
|
|
34
|
+
applyScope(query, value, property) {
|
|
35
|
+
const scopeMethod = this.resolveScopeMethod(query.model, property);
|
|
36
|
+
const scopeFn = this.getModelScopeFunction(query.model, scopeMethod);
|
|
37
|
+
if (!scopeFn) throw new Error(`"${scopeMethod}" is not defined as a query scope on "${query.model.name}" model`);
|
|
38
|
+
const paramCount = this.countParameters(scopeFn);
|
|
39
|
+
if (paramCount <= 1) {
|
|
40
|
+
if (value === false) return;
|
|
41
|
+
query.withScopes((scopes) => {
|
|
42
|
+
scopes[scopeMethod]();
|
|
43
|
+
});
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const args = this.resolveArguments(scopeFn, value, paramCount);
|
|
47
|
+
query.withScopes((scopes) => {
|
|
48
|
+
scopes[scopeMethod](...args);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
getModelScopeFunction(model, candidate) {
|
|
52
|
+
if (!candidate || candidate.startsWith("$") || candidate.startsWith("_") || RESERVED_MODEL_METHODS.has(candidate)) return;
|
|
53
|
+
let current = model;
|
|
54
|
+
while (typeof current === "function" && current !== BaseModel && current !== Function.prototype && current !== Object.prototype) {
|
|
55
|
+
if (Object.hasOwn(current, candidate)) {
|
|
56
|
+
const fn = current[candidate];
|
|
57
|
+
return typeof fn === "function" ? fn : void 0;
|
|
58
|
+
}
|
|
59
|
+
current = Object.getPrototypeOf(current);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
resolveScopeMethod(model, property) {
|
|
63
|
+
const camelCased = string.camelCase(property);
|
|
64
|
+
const propertyWithScope = `${property}Scope`;
|
|
65
|
+
const camelCasedWithScope = `${camelCased}Scope`;
|
|
66
|
+
const candidates = property === camelCased ? [property, propertyWithScope] : [
|
|
67
|
+
property,
|
|
68
|
+
camelCased,
|
|
69
|
+
propertyWithScope,
|
|
70
|
+
camelCasedWithScope
|
|
71
|
+
];
|
|
72
|
+
for (const candidate of candidates) if (this.getModelScopeFunction(model, candidate)) return candidate;
|
|
73
|
+
return camelCased;
|
|
74
|
+
}
|
|
75
|
+
extractParametersString(fn) {
|
|
76
|
+
const match = FN_PARAMS_REGEX.exec(fn.toString());
|
|
77
|
+
if (!match) return null;
|
|
78
|
+
return (match.at(1) ?? match.at(2) ?? match.at(3) ?? "").trim();
|
|
79
|
+
}
|
|
80
|
+
hasParameters(fn) {
|
|
81
|
+
return this.countParameters(fn) > 1;
|
|
82
|
+
}
|
|
83
|
+
countParameters(fn) {
|
|
84
|
+
if (fn.length > 1) return fn.length;
|
|
85
|
+
const params = this.extractParametersString(fn);
|
|
86
|
+
if (!params) return fn.length;
|
|
87
|
+
return params.split(",").length;
|
|
88
|
+
}
|
|
89
|
+
resolveArguments(scopeFn, value, resolvedParamCount) {
|
|
90
|
+
if (Array.isArray(value)) return value;
|
|
91
|
+
if (typeof value === "object" && value !== null) {
|
|
92
|
+
if ((resolvedParamCount ?? (scopeFn ? this.countParameters(scopeFn) : 0)) > 2) return Object.values(value);
|
|
93
|
+
return [value];
|
|
94
|
+
}
|
|
95
|
+
return [value];
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
export { FiltersScope };
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { Filter } from "../../types.js";
|
|
2
2
|
import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
3
3
|
import { StrictValuesWithoutRaw } from "@adonisjs/lucid/types/querybuilder";
|
|
4
|
-
|
|
5
|
-
//#region src/filters/filters_trashed.d.ts
|
|
6
|
-
declare class FiltersTrashed<Model extends LucidModel> implements Filter<Model> {
|
|
4
|
+
export declare class FiltersTrashed<Model extends LucidModel> implements Filter<Model> {
|
|
7
5
|
handle(query: ModelQueryBuilderContract<Model, InstanceType<Model>>, value: StrictValuesWithoutRaw | null, _property: string): void;
|
|
8
|
-
}
|
|
9
|
-
//#endregion
|
|
10
|
-
export { FiltersTrashed };
|
|
6
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/filters/filters_trashed.ts
|
|
2
2
|
var FiltersTrashed = class {
|
|
3
3
|
handle(query, value, _property) {
|
|
4
4
|
if (!("withTrashed" in query && "onlyTrashed" in query)) return;
|
|
@@ -10,5 +10,4 @@ var FiltersTrashed = class {
|
|
|
10
10
|
if (value === "only") queryWithSoftDeletes.onlyTrashed();
|
|
11
11
|
}
|
|
12
12
|
};
|
|
13
|
-
//#endregion
|
|
14
13
|
export { FiltersTrashed };
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { Include } from "../../types.js";
|
|
2
2
|
import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
3
3
|
import { ModelRelations } from "@adonisjs/lucid/types/relations";
|
|
4
|
-
|
|
5
|
-
//#region src/includes/included_callback.d.ts
|
|
6
|
-
declare class IncludedCallback<ParentModel extends LucidModel, RelatedModel extends LucidModel> implements Include<ParentModel> {
|
|
4
|
+
export declare class IncludedCallback<ParentModel extends LucidModel, RelatedModel extends LucidModel> implements Include<ParentModel> {
|
|
7
5
|
readonly callback: (query: ModelRelations<RelatedModel, ParentModel>['builder'] | ModelRelations<RelatedModel, ParentModel>['subQuery']) => void;
|
|
8
6
|
constructor(callback: (query: ModelRelations<RelatedModel, ParentModel>['builder'] | ModelRelations<RelatedModel, ParentModel>['subQuery']) => void);
|
|
9
7
|
handle(query: ModelQueryBuilderContract<ParentModel, InstanceType<ParentModel>>, include: string): void;
|
|
10
|
-
}
|
|
11
|
-
//#endregion
|
|
12
|
-
export { IncludedCallback };
|
|
8
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/includes/included_callback.ts
|
|
2
2
|
var IncludedCallback = class {
|
|
3
3
|
callback;
|
|
4
4
|
constructor(callback) {
|
|
@@ -8,5 +8,4 @@ var IncludedCallback = class {
|
|
|
8
8
|
query.preload(include, this.callback);
|
|
9
9
|
}
|
|
10
10
|
};
|
|
11
|
-
//#endregion
|
|
12
11
|
export { IncludedCallback };
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { Include } from "../../types.js";
|
|
2
2
|
import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
3
|
-
|
|
4
|
-
//#region src/includes/included_count.d.ts
|
|
5
|
-
declare class IncludedCount<ParentModel extends LucidModel> implements Include<ParentModel> {
|
|
3
|
+
export declare class IncludedCount<ParentModel extends LucidModel> implements Include<ParentModel> {
|
|
6
4
|
handle(query: ModelQueryBuilderContract<ParentModel, InstanceType<ParentModel>>, count: string): void;
|
|
7
|
-
}
|
|
8
|
-
//#endregion
|
|
9
|
-
export { IncludedCount };
|
|
5
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import app from "@adonisjs/core/services/app";
|
|
2
|
-
|
|
2
|
+
// src/includes/included_count.ts
|
|
3
3
|
var IncludedCount = class {
|
|
4
4
|
handle(query, count) {
|
|
5
5
|
const suffix = app.config.get("apiquery.countSuffix", "Count");
|
|
6
6
|
const relation = count.endsWith(suffix) ? count.slice(0, -suffix.length) : count;
|
|
7
|
+
if (!query.model.$hasRelation(relation)) return;
|
|
7
8
|
query.withCount(relation);
|
|
8
9
|
}
|
|
9
10
|
};
|
|
10
|
-
//#endregion
|
|
11
11
|
export { IncludedCount };
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import { Include } from "../../types.js";
|
|
2
|
-
import { Collection } from "collect.js";
|
|
3
2
|
import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
4
|
-
|
|
5
|
-
//#region src/includes/included_relationship.d.ts
|
|
6
|
-
declare class IncludedRelationship<ParentModel extends LucidModel> implements Include<ParentModel> {
|
|
3
|
+
export declare class IncludedRelationship<ParentModel extends LucidModel> implements Include<ParentModel> {
|
|
7
4
|
getRequestedFieldsForRelatedTable?: (relationship: string) => string[];
|
|
8
5
|
handle(query: ModelQueryBuilderContract<ParentModel, InstanceType<ParentModel>>, relationship: string): void;
|
|
9
|
-
static getIndividualRelationshipPathsFromInclude(include: string):
|
|
6
|
+
static getIndividualRelationshipPathsFromInclude(include: string): string[];
|
|
7
|
+
private applyRequestedFields;
|
|
10
8
|
private buildNestedQuery;
|
|
11
|
-
}
|
|
12
|
-
//#endregion
|
|
13
|
-
export { IncludedRelationship };
|
|
9
|
+
}
|
|
@@ -1,40 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
//#region src/includes/included_relationship.ts
|
|
1
|
+
// src/includes/included_relationship.ts
|
|
3
2
|
var IncludedRelationship = class {
|
|
4
3
|
getRequestedFieldsForRelatedTable;
|
|
5
4
|
handle(query, relationship) {
|
|
6
|
-
const
|
|
7
|
-
if (
|
|
8
|
-
const [relation, ...rest] = relatedTables;
|
|
9
|
-
if (!query.model.$hasRelation(relation)) return;
|
|
5
|
+
const [relation, ...rest] = relationship.split(".");
|
|
6
|
+
if (!relation || !query.model.$hasRelation(relation)) return;
|
|
10
7
|
query.preload(relation, (subQuery) => {
|
|
11
|
-
|
|
12
|
-
const fields = this.getRequestedFieldsForRelatedTable(relation);
|
|
13
|
-
if (fields.length > 0) subQuery.select(fields);
|
|
14
|
-
}
|
|
8
|
+
this.applyRequestedFields(subQuery, relation);
|
|
15
9
|
this.buildNestedQuery(rest, subQuery, relation);
|
|
16
10
|
});
|
|
17
11
|
}
|
|
18
12
|
static getIndividualRelationshipPathsFromInclude(include) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
13
|
+
const parts = include.split(".");
|
|
14
|
+
const includes = [];
|
|
15
|
+
let current = "";
|
|
16
|
+
for (const part of parts) {
|
|
17
|
+
current = current ? `${current}.${part}` : part;
|
|
18
|
+
includes.push(current);
|
|
19
|
+
}
|
|
20
|
+
return includes;
|
|
21
|
+
}
|
|
22
|
+
applyRequestedFields(query, relationshipName) {
|
|
23
|
+
if (this.getRequestedFieldsForRelatedTable === void 0) return;
|
|
24
|
+
const fields = this.getRequestedFieldsForRelatedTable(relationshipName);
|
|
25
|
+
if (fields.length > 0) query.select(fields);
|
|
24
26
|
}
|
|
25
27
|
buildNestedQuery(relatedTables, subQuery, parent = "") {
|
|
26
|
-
if (relatedTables.length === 0) return;
|
|
27
28
|
const [relation, ...rest] = relatedTables;
|
|
28
|
-
if (!subQuery.model.$hasRelation(relation)) return;
|
|
29
|
+
if (!relation || !subQuery.model.$hasRelation(relation)) return;
|
|
29
30
|
subQuery.preload(relation, (nestedQuery) => {
|
|
30
31
|
const fullRelationName = parent === "" ? relation : `${parent}.${relation}`;
|
|
31
|
-
|
|
32
|
-
const fields = this.getRequestedFieldsForRelatedTable(fullRelationName);
|
|
33
|
-
if (fields.length > 0) nestedQuery.select(fields);
|
|
34
|
-
}
|
|
32
|
+
this.applyRequestedFields(nestedQuery, fullRelationName);
|
|
35
33
|
this.buildNestedQuery(rest, nestedQuery, fullRelationName);
|
|
36
34
|
});
|
|
37
35
|
}
|
|
38
36
|
};
|
|
39
|
-
//#endregion
|
|
40
37
|
export { IncludedRelationship };
|
|
@@ -1,11 +1,7 @@
|
|
|
1
1
|
import { Sort } from "../../types.js";
|
|
2
2
|
import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
3
|
-
|
|
4
|
-
//#region src/sorts/sorts_callback.d.ts
|
|
5
|
-
declare class SortsCallback<Model extends LucidModel> implements Sort<Model> {
|
|
3
|
+
export declare class SortsCallback<Model extends LucidModel> implements Sort<Model> {
|
|
6
4
|
private readonly _callback;
|
|
7
5
|
constructor(_callback: (query: ModelQueryBuilderContract<Model>, isDescending: boolean, property: string) => void);
|
|
8
6
|
handle(query: ModelQueryBuilderContract<Model>, isDescending: boolean, property: string): void;
|
|
9
|
-
}
|
|
10
|
-
//#endregion
|
|
11
|
-
export { SortsCallback };
|
|
7
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/sorts/sorts_callback.ts
|
|
2
2
|
var SortsCallback = class {
|
|
3
3
|
_callback;
|
|
4
4
|
constructor(_callback) {
|
|
@@ -8,5 +8,4 @@ var SortsCallback = class {
|
|
|
8
8
|
this._callback(query, isDescending, property);
|
|
9
9
|
}
|
|
10
10
|
};
|
|
11
|
-
//#endregion
|
|
12
11
|
export { SortsCallback };
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { Sort } from "../../types.js";
|
|
2
2
|
import { LucidModel, ModelQueryBuilderContract } from "@adonisjs/lucid/types/model";
|
|
3
|
-
|
|
4
|
-
//#region src/sorts/sorts_field.d.ts
|
|
5
|
-
declare class SortsField<Model extends LucidModel> implements Sort<Model> {
|
|
3
|
+
export declare class SortsField<Model extends LucidModel> implements Sort<Model> {
|
|
6
4
|
handle(query: ModelQueryBuilderContract<Model>, isDescending: boolean, property: string): void;
|
|
7
|
-
}
|
|
8
|
-
//#endregion
|
|
9
|
-
export { SortsField };
|
|
5
|
+
}
|
|
@@ -1,15 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const substrReplace = (str, replace, start, length) => {
|
|
3
|
-
if (start < 0) start += str.length;
|
|
4
|
-
length ??= str.length;
|
|
5
|
-
if (length < 0) length = length + str.length - start;
|
|
6
|
-
return [
|
|
7
|
-
str.slice(0, start),
|
|
8
|
-
replace.slice(0, Math.max(0, length)),
|
|
9
|
-
replace.slice(length),
|
|
10
|
-
str.slice(start + length)
|
|
11
|
-
].join("");
|
|
12
|
-
};
|
|
1
|
+
// src/utils/helpers.ts
|
|
13
2
|
const strBeforeLast = (subject, search) => {
|
|
14
3
|
if (search === "") return subject;
|
|
15
4
|
const pos = subject.lastIndexOf(search);
|
|
@@ -22,5 +11,4 @@ const strAfterLast = (subject, search) => {
|
|
|
22
11
|
if (pos === -1) return subject;
|
|
23
12
|
return subject.slice(pos + search.length);
|
|
24
13
|
};
|
|
25
|
-
|
|
26
|
-
export { strAfterLast, strBeforeLast, substrReplace };
|
|
14
|
+
export { strAfterLast, strBeforeLast };
|