axe-api 0.30.0-rc2 → 0.30.0-rc4

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 (116) hide show
  1. package/build/index.d.ts +3 -3
  2. package/build/index.js +4 -1
  3. package/build/src/Enums.d.ts +31 -1
  4. package/build/src/Enums.js +33 -1
  5. package/build/src/Handlers/AllHandler.js +1 -1
  6. package/build/src/Handlers/Helpers.d.ts +1 -0
  7. package/build/src/Handlers/Helpers.js +20 -3
  8. package/build/src/Handlers/PaginateHandler.js +1 -1
  9. package/build/src/Handlers/ShowHandler.js +1 -1
  10. package/build/src/Interfaces.d.ts +18 -1
  11. package/build/src/Model.d.ts +2 -1
  12. package/build/src/Model.js +3 -0
  13. package/build/src/Resolvers/ModelResolver.d.ts +1 -0
  14. package/build/src/Resolvers/ModelResolver.js +18 -0
  15. package/build/src/Services/APIService.js +3 -0
  16. package/build/src/Services/LimitService.d.ts +5 -0
  17. package/build/src/Services/LimitService.js +116 -0
  18. package/build/src/Services/ModelService.d.ts +3 -1
  19. package/build/src/Services/ModelService.js +4 -0
  20. package/build/src/Services/QueryService.d.ts +3 -2
  21. package/build/src/Services/QueryService.js +32 -7
  22. package/build/src/Services/SchemaValidatorService.d.ts +4 -0
  23. package/build/src/Services/SchemaValidatorService.js +50 -0
  24. package/build/src/Services/index.d.ts +2 -1
  25. package/build/src/Services/index.js +4 -1
  26. package/build/src/constants.d.ts +5 -1
  27. package/build/src/constants.js +43 -1
  28. package/package.json +7 -6
  29. package/build/dev-kit/app/Config/Application.d.ts +0 -3
  30. package/build/dev-kit/app/Config/Application.js +0 -14
  31. package/build/dev-kit/app/Config/Database.d.ts +0 -3
  32. package/build/dev-kit/app/Config/Database.js +0 -24
  33. package/build/dev-kit/app/Events/UserEvent.d.ts +0 -3
  34. package/build/dev-kit/app/Events/UserEvent.js +0 -16
  35. package/build/dev-kit/app/Hooks/CustomerHook.d.ts +0 -3
  36. package/build/dev-kit/app/Hooks/CustomerHook.js +0 -16
  37. package/build/dev-kit/app/Hooks/EmployeeHook.d.ts +0 -2
  38. package/build/dev-kit/app/Hooks/EmployeeHook.js +0 -16
  39. package/build/dev-kit/app/Hooks/UserHook.d.ts +0 -3
  40. package/build/dev-kit/app/Hooks/UserHook.js +0 -17
  41. package/build/dev-kit/app/Models/Customer.d.ts +0 -7
  42. package/build/dev-kit/app/Models/Customer.js +0 -15
  43. package/build/dev-kit/app/Models/Employee.d.ts +0 -9
  44. package/build/dev-kit/app/Models/Employee.js +0 -21
  45. package/build/dev-kit/app/Models/EmployeeAddress.d.ts +0 -8
  46. package/build/dev-kit/app/Models/EmployeeAddress.js +0 -18
  47. package/build/dev-kit/app/Models/Post.d.ts +0 -6
  48. package/build/dev-kit/app/Models/Post.js +0 -14
  49. package/build/dev-kit/app/Models/User.d.ts +0 -7
  50. package/build/dev-kit/app/Models/User.js +0 -23
  51. package/build/dev-kit/app/Serialization/UserSerialization.d.ts +0 -3
  52. package/build/dev-kit/app/Serialization/UserSerialization.js +0 -6
  53. package/build/dev-kit/app/config.d.ts +0 -3
  54. package/build/dev-kit/app/config.js +0 -31
  55. package/build/dev-kit/app/init.d.ts +0 -4
  56. package/build/dev-kit/app/init.js +0 -16
  57. package/build/dev-kit/app/v1/Events/UserEvent.d.ts +0 -3
  58. package/build/dev-kit/app/v1/Events/UserEvent.js +0 -16
  59. package/build/dev-kit/app/v1/Hooks/Customer/onBeforeForceDelete.d.ts +0 -3
  60. package/build/dev-kit/app/v1/Hooks/Customer/onBeforeForceDelete.js +0 -14
  61. package/build/dev-kit/app/v1/Hooks/CustomerHook.d.ts +0 -3
  62. package/build/dev-kit/app/v1/Hooks/CustomerHook.js +0 -16
  63. package/build/dev-kit/app/v1/Hooks/Employee/onBeforeForceDelete.d.ts +0 -2
  64. package/build/dev-kit/app/v1/Hooks/Employee/onBeforeForceDelete.js +0 -14
  65. package/build/dev-kit/app/v1/Hooks/EmployeeHook.d.ts +0 -2
  66. package/build/dev-kit/app/v1/Hooks/EmployeeHook.js +0 -16
  67. package/build/dev-kit/app/v1/Hooks/User/onBeforeInsert.d.ts +0 -2
  68. package/build/dev-kit/app/v1/Hooks/User/onBeforeInsert.js +0 -14
  69. package/build/dev-kit/app/v1/Hooks/UserHook.d.ts +0 -3
  70. package/build/dev-kit/app/v1/Hooks/UserHook.js +0 -17
  71. package/build/dev-kit/app/v1/Models/Customer.d.ts +0 -7
  72. package/build/dev-kit/app/v1/Models/Customer.js +0 -15
  73. package/build/dev-kit/app/v1/Models/Employee.d.ts +0 -9
  74. package/build/dev-kit/app/v1/Models/Employee.js +0 -21
  75. package/build/dev-kit/app/v1/Models/EmployeeAddress.d.ts +0 -8
  76. package/build/dev-kit/app/v1/Models/EmployeeAddress.js +0 -18
  77. package/build/dev-kit/app/v1/Models/Post.d.ts +0 -6
  78. package/build/dev-kit/app/v1/Models/Post.js +0 -14
  79. package/build/dev-kit/app/v1/Models/User.d.ts +0 -7
  80. package/build/dev-kit/app/v1/Models/User.js +0 -23
  81. package/build/dev-kit/app/v1/Serialization/PostSerialization.d.ts +0 -3
  82. package/build/dev-kit/app/v1/Serialization/PostSerialization.js +0 -6
  83. package/build/dev-kit/app/v1/Serialization/UserSerialization.d.ts +0 -3
  84. package/build/dev-kit/app/v1/Serialization/UserSerialization.js +0 -5
  85. package/build/dev-kit/app/v1/config.d.ts +0 -3
  86. package/build/dev-kit/app/v1/config.js +0 -19
  87. package/build/dev-kit/app/v1/init.d.ts +0 -4
  88. package/build/dev-kit/app/v1/init.js +0 -16
  89. package/build/dev-kit/app/v2/Events/UserEvent.d.ts +0 -3
  90. package/build/dev-kit/app/v2/Events/UserEvent.js +0 -16
  91. package/build/dev-kit/app/v2/Hooks/CustomerHook.d.ts +0 -3
  92. package/build/dev-kit/app/v2/Hooks/CustomerHook.js +0 -16
  93. package/build/dev-kit/app/v2/Hooks/EmployeeHook.d.ts +0 -2
  94. package/build/dev-kit/app/v2/Hooks/EmployeeHook.js +0 -16
  95. package/build/dev-kit/app/v2/Hooks/UserHook.d.ts +0 -3
  96. package/build/dev-kit/app/v2/Hooks/UserHook.js +0 -17
  97. package/build/dev-kit/app/v2/Models/Customer.d.ts +0 -10
  98. package/build/dev-kit/app/v2/Models/Customer.js +0 -20
  99. package/build/dev-kit/app/v2/Models/Employee.d.ts +0 -9
  100. package/build/dev-kit/app/v2/Models/Employee.js +0 -21
  101. package/build/dev-kit/app/v2/Models/EmployeeAddress.d.ts +0 -8
  102. package/build/dev-kit/app/v2/Models/EmployeeAddress.js +0 -18
  103. package/build/dev-kit/app/v2/Models/Post.d.ts +0 -6
  104. package/build/dev-kit/app/v2/Models/Post.js +0 -14
  105. package/build/dev-kit/app/v2/Models/User.d.ts +0 -7
  106. package/build/dev-kit/app/v2/Models/User.js +0 -23
  107. package/build/dev-kit/app/v2/Serialization/UserSerialization.d.ts +0 -3
  108. package/build/dev-kit/app/v2/Serialization/UserSerialization.js +0 -5
  109. package/build/dev-kit/app/v2/config.d.ts +0 -3
  110. package/build/dev-kit/app/v2/config.js +0 -9
  111. package/build/dev-kit/app/v2/init.d.ts +0 -4
  112. package/build/dev-kit/app/v2/init.js +0 -16
  113. package/build/dev-kit/app/v3/config.d.ts +0 -3
  114. package/build/dev-kit/app/v3/config.js +0 -9
  115. package/build/dev-kit/config.d.ts +0 -3
  116. package/build/dev-kit/config.js +0 -31
package/build/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import Server from "./src/Server";
2
2
  import Model from "./src/Model";
3
3
  import ApiError from "./src/Exceptions/ApiError";
4
- import { DEFAULT_HANDLERS } from "./src/constants";
5
- import { IoCService } from "./src/Services";
4
+ import { DEFAULT_HANDLERS, DEFAULT_VERSION_CONFIG } from "./src/constants";
5
+ import { IoCService, allow, deny } from "./src/Services";
6
6
  export * from "./src/Enums";
7
7
  export * from "./src/Interfaces";
8
- export { Server, Model, ApiError, DEFAULT_HANDLERS, IoCService };
8
+ export { Server, Model, ApiError, DEFAULT_HANDLERS, DEFAULT_VERSION_CONFIG, IoCService, allow, deny, };
package/build/index.js CHANGED
@@ -17,7 +17,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.IoCService = exports.DEFAULT_HANDLERS = exports.ApiError = exports.Model = exports.Server = void 0;
20
+ exports.deny = exports.allow = exports.IoCService = exports.DEFAULT_VERSION_CONFIG = exports.DEFAULT_HANDLERS = exports.ApiError = exports.Model = exports.Server = void 0;
21
21
  const Server_1 = __importDefault(require("./src/Server"));
22
22
  exports.Server = Server_1.default;
23
23
  const Model_1 = __importDefault(require("./src/Model"));
@@ -26,7 +26,10 @@ const ApiError_1 = __importDefault(require("./src/Exceptions/ApiError"));
26
26
  exports.ApiError = ApiError_1.default;
27
27
  const constants_1 = require("./src/constants");
28
28
  Object.defineProperty(exports, "DEFAULT_HANDLERS", { enumerable: true, get: function () { return constants_1.DEFAULT_HANDLERS; } });
29
+ Object.defineProperty(exports, "DEFAULT_VERSION_CONFIG", { enumerable: true, get: function () { return constants_1.DEFAULT_VERSION_CONFIG; } });
29
30
  const Services_1 = require("./src/Services");
30
31
  Object.defineProperty(exports, "IoCService", { enumerable: true, get: function () { return Services_1.IoCService; } });
32
+ Object.defineProperty(exports, "allow", { enumerable: true, get: function () { return Services_1.allow; } });
33
+ Object.defineProperty(exports, "deny", { enumerable: true, get: function () { return Services_1.deny; } });
31
34
  __exportStar(require("./src/Enums"), exports);
32
35
  __exportStar(require("./src/Interfaces"), exports);
@@ -88,5 +88,35 @@ export declare enum AxeErrorCode {
88
88
  UNDEFINED_COLUMN = "UNDEFINED_COLUMN",
89
89
  UNDEFINED_RELATION_MODEL = "UNDEFINED_RELATION_MODEL",
90
90
  UNDEFINED_HOOK_MODEL_RELATION = "UNDEFINED_HOOK_MODEL_RELATION",
91
- UNACCEPTABLE_HOOK_FILE = "UNACCEPTABLE_HOOK_FILE"
91
+ UNACCEPTABLE_HOOK_FILE = "UNACCEPTABLE_HOOK_FILE",
92
+ UNDEFINED_RELATION_NAME = "UNDEFINED_RELATION_NAME"
93
+ }
94
+ export declare enum QueryFeatureType {
95
+ Allow = "Allow",
96
+ Deny = "Deny"
97
+ }
98
+ export declare enum QueryFeature {
99
+ All = "all",
100
+ FieldsAll = "fieldsAll",
101
+ Sorting = "sorting",
102
+ Limits = "limits",
103
+ WhereAll = "where.*",
104
+ WhereEqual = "where.equal",
105
+ WhereNotEqual = "where.notEqual",
106
+ WhereGt = "where.gt",
107
+ WhereGte = "where.gte",
108
+ WhereLt = "where.lt",
109
+ WhereLte = "where.lte",
110
+ WhereLike = "where.like",
111
+ WhereNotLike = "where.notLike",
112
+ WhereIn = "where.in",
113
+ WhereNotIn = "where.notIn",
114
+ WhereBetween = "where.between",
115
+ WhereNotBetween = "where.notBetween",
116
+ WhereNull = "where.null",
117
+ WhereNotNull = "where.notNull",
118
+ Trashed = "trashed",
119
+ WithAll = "with.*",
120
+ WithHasOne = "with.hasOne",
121
+ WithHasMany = "with.hasMany"
92
122
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AxeErrorCode = exports.TimestampColumns = exports.SortTypes = exports.Relationships = exports.LogLevels = exports.HttpMethods = exports.Extensions = exports.HookFunctionTypes = exports.HandlerTypes = exports.DependencyTypes = exports.ConditionTypes = void 0;
3
+ exports.QueryFeature = exports.QueryFeatureType = exports.AxeErrorCode = exports.TimestampColumns = exports.SortTypes = exports.Relationships = exports.LogLevels = exports.HttpMethods = exports.Extensions = exports.HookFunctionTypes = exports.HandlerTypes = exports.DependencyTypes = exports.ConditionTypes = void 0;
4
4
  var ConditionTypes;
5
5
  (function (ConditionTypes) {
6
6
  ConditionTypes["NotNull"] = "NotNull";
@@ -103,4 +103,36 @@ var AxeErrorCode;
103
103
  AxeErrorCode["UNDEFINED_RELATION_MODEL"] = "UNDEFINED_RELATION_MODEL";
104
104
  AxeErrorCode["UNDEFINED_HOOK_MODEL_RELATION"] = "UNDEFINED_HOOK_MODEL_RELATION";
105
105
  AxeErrorCode["UNACCEPTABLE_HOOK_FILE"] = "UNACCEPTABLE_HOOK_FILE";
106
+ AxeErrorCode["UNDEFINED_RELATION_NAME"] = "UNDEFINED_RELATION_NAME";
106
107
  })(AxeErrorCode = exports.AxeErrorCode || (exports.AxeErrorCode = {}));
108
+ var QueryFeatureType;
109
+ (function (QueryFeatureType) {
110
+ QueryFeatureType["Allow"] = "Allow";
111
+ QueryFeatureType["Deny"] = "Deny";
112
+ })(QueryFeatureType = exports.QueryFeatureType || (exports.QueryFeatureType = {}));
113
+ var QueryFeature;
114
+ (function (QueryFeature) {
115
+ QueryFeature["All"] = "all";
116
+ QueryFeature["FieldsAll"] = "fieldsAll";
117
+ QueryFeature["Sorting"] = "sorting";
118
+ QueryFeature["Limits"] = "limits";
119
+ QueryFeature["WhereAll"] = "where.*";
120
+ QueryFeature["WhereEqual"] = "where.equal";
121
+ QueryFeature["WhereNotEqual"] = "where.notEqual";
122
+ QueryFeature["WhereGt"] = "where.gt";
123
+ QueryFeature["WhereGte"] = "where.gte";
124
+ QueryFeature["WhereLt"] = "where.lt";
125
+ QueryFeature["WhereLte"] = "where.lte";
126
+ QueryFeature["WhereLike"] = "where.like";
127
+ QueryFeature["WhereNotLike"] = "where.notLike";
128
+ QueryFeature["WhereIn"] = "where.in";
129
+ QueryFeature["WhereNotIn"] = "where.notIn";
130
+ QueryFeature["WhereBetween"] = "where.between";
131
+ QueryFeature["WhereNotBetween"] = "where.notBetween";
132
+ QueryFeature["WhereNull"] = "where.null";
133
+ QueryFeature["WhereNotNull"] = "where.notNull";
134
+ QueryFeature["Trashed"] = "trashed";
135
+ QueryFeature["WithAll"] = "with.*";
136
+ QueryFeature["WithHasOne"] = "with.hasOne";
137
+ QueryFeature["WithHasMany"] = "with.hasMany";
138
+ })(QueryFeature = exports.QueryFeature || (exports.QueryFeature = {}));
@@ -14,7 +14,7 @@ const Services_1 = require("../Services");
14
14
  const Enums_1 = require("../Enums");
15
15
  exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
16
16
  const { version, model, req, res, database, relation, parentModel } = pack;
17
- const queryParser = new Services_1.QueryService(model, version.modelList.get());
17
+ const queryParser = new Services_1.QueryService(model, version.modelList.get(), version.config);
18
18
  // We should parse URL query string to use as condition in Lucid query
19
19
  const conditions = queryParser.get(req.query);
20
20
  // Creating a new database query
@@ -14,3 +14,4 @@ export declare const serializeData: (version: IVersion, itemArray: any[] | any,
14
14
  export declare const filterHiddenFields: (itemArray: any[], hiddens: string[] | null) => void;
15
15
  export declare const addSoftDeleteQuery: (model: IModelService, conditions: IQuery | null, query: Knex.QueryBuilder) => void;
16
16
  export declare const getRelatedData: (version: IVersion, data: any[], withArray: IWith[], model: IModelService, modelList: ModelListService, database: Knex | Knex.Transaction, handler: HandlerTypes, request: Request) => Promise<void>;
17
+ export declare const isBoolean: (value: any) => boolean;
@@ -12,11 +12,13 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
12
12
  return (mod && mod.__esModule) ? mod : { "default": mod };
13
13
  };
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.getRelatedData = exports.addSoftDeleteQuery = exports.filterHiddenFields = exports.serializeData = exports.addForeignKeyQuery = exports.getParentColumn = exports.callHooks = exports.getMergedFormData = exports.bindTimestampValues = void 0;
15
+ exports.isBoolean = exports.getRelatedData = exports.addSoftDeleteQuery = exports.filterHiddenFields = exports.serializeData = exports.addForeignKeyQuery = exports.getParentColumn = exports.callHooks = exports.getMergedFormData = exports.bindTimestampValues = void 0;
16
16
  const change_case_1 = require("change-case");
17
17
  const Enums_1 = require("../Enums");
18
18
  const ApiError_1 = __importDefault(require("../Exceptions/ApiError"));
19
19
  const Services_1 = require("../Services");
20
+ const LimitService_1 = require("../Services/LimitService");
21
+ const constants_1 = require("../constants");
20
22
  const bindTimestampValues = (formData, columnTypes = [], model) => {
21
23
  if (columnTypes.includes(Enums_1.TimestampColumns.CREATED_AT) &&
22
24
  model.instance.createdAtColumn) {
@@ -138,8 +140,10 @@ const filterHiddenFields = (itemArray, hiddens) => {
138
140
  };
139
141
  exports.filterHiddenFields = filterHiddenFields;
140
142
  const addSoftDeleteQuery = (model, conditions, query) => {
141
- // TODO: Trashed feature will be implemented later
142
- // (conditions === null || conditions?.trashed === false)
143
+ if (conditions !== null && (conditions === null || conditions === void 0 ? void 0 : conditions.trashed) === true) {
144
+ (0, LimitService_1.valideteQueryFeature)(model, Enums_1.QueryFeature.Trashed);
145
+ return;
146
+ }
143
147
  if (model.instance.deletedAtColumn) {
144
148
  query.whereNull(model.instance.deletedAtColumn);
145
149
  }
@@ -162,6 +166,8 @@ const getRelatedData = (version, data, withArray, model, modelList, database, ha
162
166
  if (!foreignModel) {
163
167
  continue;
164
168
  }
169
+ // Validating the query limit
170
+ (0, LimitService_1.valideteQueryFeature)(model, constants_1.RelationQueryFeatureMap[definedRelation.type], `${model.instance.table}.${definedRelation.name}`, `${model.instance.table}.${definedRelation.name}`);
165
171
  let dataField = "primaryKey";
166
172
  let searchField = "foreignKey";
167
173
  if (definedRelation.type !== Enums_1.Relationships.HAS_MANY) {
@@ -225,3 +231,14 @@ const getRelatedData = (version, data, withArray, model, modelList, database, ha
225
231
  }
226
232
  });
227
233
  exports.getRelatedData = getRelatedData;
234
+ const isBoolean = (value) => {
235
+ if (value === undefined || value === null) {
236
+ return false;
237
+ }
238
+ value = (value || "").trim().toLocaleLowerCase();
239
+ if (value === "true" || value === "1" || value === "on" || value === "yes") {
240
+ return true;
241
+ }
242
+ return false;
243
+ };
244
+ exports.isBoolean = isBoolean;
@@ -14,7 +14,7 @@ const Enums_1 = require("../Enums");
14
14
  const Services_1 = require("../Services");
15
15
  exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
16
16
  const { version, model, req, database, relation, parentModel } = pack;
17
- const queryParser = new Services_1.QueryService(model, version.modelList.get());
17
+ const queryParser = new Services_1.QueryService(model, version.modelList.get(), version.config);
18
18
  // We should parse URL query string to use as condition in Lucid query
19
19
  const conditions = queryParser.get(req.query);
20
20
  // Creating a new database query
@@ -18,7 +18,7 @@ const ApiError_1 = __importDefault(require("../Exceptions/ApiError"));
18
18
  const Services_1 = require("../Services");
19
19
  exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
20
20
  const { version, model, req, res, database, relation, parentModel } = pack;
21
- const queryParser = new Services_1.QueryService(model, version.modelList.get());
21
+ const queryParser = new Services_1.QueryService(model, version.modelList.get(), version.config);
22
22
  // We should parse URL query string to use as condition in Lucid query
23
23
  const conditions = queryParser.get(req.query);
24
24
  // Fetching item
@@ -1,7 +1,7 @@
1
1
  import { Knex } from "knex";
2
2
  import { Express, Request, Response, NextFunction } from "express";
3
3
  import { Column } from "knex-schema-inspector/lib/types/column";
4
- import { HandlerTypes, LogLevels, HttpMethods, HookFunctionTypes, Extensions, Relationships, SortTypes, ConditionTypes, DependencyTypes } from "./Enums";
4
+ import { HandlerTypes, LogLevels, HttpMethods, HookFunctionTypes, Extensions, Relationships, SortTypes, ConditionTypes, DependencyTypes, QueryFeature, QueryFeatureType } from "./Enums";
5
5
  import Model from "./Model";
6
6
  import { SerializationFunction } from "./Types";
7
7
  import { ModelListService } from "./Services";
@@ -18,11 +18,26 @@ interface IHandlerBasedSerializer {
18
18
  handler: HandlerTypes[];
19
19
  serializer: ((data: any, request: Request) => void)[];
20
20
  }
21
+ export interface IQueryLimitConfig {
22
+ feature: QueryFeature;
23
+ type: QueryFeatureType;
24
+ key: string | null;
25
+ }
26
+ export interface IQueryDefaultConfig {
27
+ perPage?: number;
28
+ minPerPage?: number;
29
+ maxPerPage?: number;
30
+ }
31
+ export interface IQueryConfig {
32
+ limits: Array<IQueryLimitConfig[]>;
33
+ defaults?: IQueryDefaultConfig;
34
+ }
21
35
  export interface IVersionConfig {
22
36
  transaction: boolean | IHandlerBasedTransactionConfig | IHandlerBasedTransactionConfig[];
23
37
  serializers: ((data: any, request: Request) => void)[] | IHandlerBasedSerializer[];
24
38
  supportedLanguages: string[];
25
39
  defaultLanguage: string;
40
+ query: IQueryConfig;
26
41
  }
27
42
  export interface IApplicationConfig extends IConfig {
28
43
  env: string;
@@ -104,9 +119,11 @@ export interface IModelService {
104
119
  events: Record<HookFunctionTypes, (params: IHookParameter) => void>;
105
120
  isRecursive: boolean;
106
121
  children: IModelService[];
122
+ queryLimits: IQueryLimitConfig[];
107
123
  serialize: SerializationFunction | null;
108
124
  setColumns(columns: IColumn[]): void;
109
125
  setExtensions(type: Extensions, hookFunctionType: HookFunctionTypes, data: (params: IHookParameter) => void): void;
126
+ setQueryLimits(limits: IQueryLimitConfig[]): void;
110
127
  setSerialization(callback: SerializationFunction): void;
111
128
  }
112
129
  export interface IRelation {
@@ -1,5 +1,5 @@
1
1
  import { Request, Response, NextFunction } from "express";
2
- import { IRelation, IMethodBaseConfig, IMethodBaseValidations, IHandlerBaseMiddleware, IHandlerBasedTransactionConfig } from "./Interfaces";
2
+ import { IRelation, IMethodBaseConfig, IMethodBaseValidations, IHandlerBaseMiddleware, IHandlerBasedTransactionConfig, IQueryLimitConfig } from "./Interfaces";
3
3
  import { HandlerTypes, HttpMethods } from "./Enums";
4
4
  declare class Model {
5
5
  get primaryKey(): string;
@@ -14,6 +14,7 @@ declare class Model {
14
14
  get deletedAtColumn(): string | null;
15
15
  get transaction(): boolean | IHandlerBasedTransactionConfig | IHandlerBasedTransactionConfig[] | null;
16
16
  get ignore(): boolean;
17
+ get limits(): Array<IQueryLimitConfig[]>;
17
18
  getFillableFields(methodType: HttpMethods): string[];
18
19
  getValidationRules(methodType: HttpMethods): Record<string, string> | null;
19
20
  getMiddlewares(handlerType: HandlerTypes): ((req: Request, res: Response, next: NextFunction) => void)[];
@@ -44,6 +44,9 @@ class Model {
44
44
  get ignore() {
45
45
  return false;
46
46
  }
47
+ get limits() {
48
+ return [];
49
+ }
47
50
  getFillableFields(methodType) {
48
51
  if (this.fillable === null) {
49
52
  return [];
@@ -10,6 +10,7 @@ declare class ModelResolver {
10
10
  private getDirectories;
11
11
  private checkOldStyleHookFiles;
12
12
  private setModelSerializations;
13
+ private setModelQueryLimits;
13
14
  private getInstanceMethods;
14
15
  }
15
16
  export default ModelResolver;
@@ -33,6 +33,7 @@ class ModelResolver {
33
33
  yield this.setModelHooks(modelList, Enums_1.Extensions.Hooks);
34
34
  yield this.setModelHooks(modelList, Enums_1.Extensions.Events);
35
35
  yield this.setModelSerializations(modelList);
36
+ yield this.setModelQueryLimits(modelList);
36
37
  this.version.modelList = modelList;
37
38
  logger.info(`[${this.version.name}] All models have been resolved.`);
38
39
  });
@@ -161,6 +162,23 @@ class ModelResolver {
161
162
  }
162
163
  });
163
164
  }
165
+ setModelQueryLimits(modelList) {
166
+ return __awaiter(this, void 0, void 0, function* () {
167
+ for (const model of modelList.get()) {
168
+ // We should use the full field name like `users.name`
169
+ const modelLimits = model.instance.limits.flat().map((item) => {
170
+ if (item.key) {
171
+ item.key = `${model.instance.table}.${item.key}`;
172
+ }
173
+ return Object.assign({}, item);
174
+ });
175
+ model.setQueryLimits([
176
+ ...this.version.config.query.limits.flat(),
177
+ ...modelLimits,
178
+ ]);
179
+ }
180
+ });
181
+ }
164
182
  getInstanceMethods(obj) {
165
183
  const properties = Object.getOwnPropertyNames(obj.instance.constructor.prototype);
166
184
  return properties.filter((name) => !constants_1.DEFAULT_METHODS_OF_MODELS.includes(name));
@@ -54,6 +54,9 @@ class APIService {
54
54
  serializers: [],
55
55
  supportedLanguages: ["en"],
56
56
  defaultLanguage: "en",
57
+ query: {
58
+ limits: [],
59
+ },
57
60
  },
58
61
  folders: {
59
62
  root,
@@ -0,0 +1,5 @@
1
+ import { QueryFeature } from "../Enums";
2
+ import { IModelService, IQueryLimitConfig } from "../Interfaces";
3
+ export declare const allow: (feature: QueryFeature, keys?: string[]) => IQueryLimitConfig[];
4
+ export declare const deny: (feature: QueryFeature, keys?: string[]) => IQueryLimitConfig[];
5
+ export declare const valideteQueryFeature: (model: IModelService, feature: QueryFeature, key?: string | null, errorDescription?: string) => void;
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.valideteQueryFeature = exports.deny = exports.allow = void 0;
7
+ const Enums_1 = require("../Enums");
8
+ const ApiError_1 = __importDefault(require("../Exceptions/ApiError"));
9
+ const QueryFeatureMap = {
10
+ [Enums_1.QueryFeature.All]: [
11
+ Enums_1.QueryFeature.FieldsAll,
12
+ Enums_1.QueryFeature.Sorting,
13
+ Enums_1.QueryFeature.Limits,
14
+ Enums_1.QueryFeature.WhereEqual,
15
+ Enums_1.QueryFeature.WhereNotEqual,
16
+ Enums_1.QueryFeature.WhereGt,
17
+ Enums_1.QueryFeature.WhereGte,
18
+ Enums_1.QueryFeature.WhereLt,
19
+ Enums_1.QueryFeature.WhereLte,
20
+ Enums_1.QueryFeature.WhereLike,
21
+ Enums_1.QueryFeature.WhereNotLike,
22
+ Enums_1.QueryFeature.WhereIn,
23
+ Enums_1.QueryFeature.WhereNotIn,
24
+ Enums_1.QueryFeature.WhereBetween,
25
+ Enums_1.QueryFeature.WhereNotBetween,
26
+ Enums_1.QueryFeature.WhereNull,
27
+ Enums_1.QueryFeature.WhereNotNull,
28
+ Enums_1.QueryFeature.Trashed,
29
+ Enums_1.QueryFeature.WithHasOne,
30
+ Enums_1.QueryFeature.WithHasMany,
31
+ ],
32
+ [Enums_1.QueryFeature.FieldsAll]: [Enums_1.QueryFeature.FieldsAll],
33
+ [Enums_1.QueryFeature.Sorting]: [Enums_1.QueryFeature.Sorting],
34
+ [Enums_1.QueryFeature.Limits]: [Enums_1.QueryFeature.Limits],
35
+ [Enums_1.QueryFeature.WhereAll]: [
36
+ Enums_1.QueryFeature.WhereEqual,
37
+ Enums_1.QueryFeature.WhereNotEqual,
38
+ Enums_1.QueryFeature.WhereGt,
39
+ Enums_1.QueryFeature.WhereGte,
40
+ Enums_1.QueryFeature.WhereLt,
41
+ Enums_1.QueryFeature.WhereLte,
42
+ Enums_1.QueryFeature.WhereLike,
43
+ Enums_1.QueryFeature.WhereNotLike,
44
+ Enums_1.QueryFeature.WhereIn,
45
+ Enums_1.QueryFeature.WhereNotIn,
46
+ Enums_1.QueryFeature.WhereBetween,
47
+ Enums_1.QueryFeature.WhereNotBetween,
48
+ Enums_1.QueryFeature.WhereNull,
49
+ Enums_1.QueryFeature.WhereNotNull,
50
+ ],
51
+ [Enums_1.QueryFeature.WhereEqual]: [Enums_1.QueryFeature.WhereEqual],
52
+ [Enums_1.QueryFeature.WhereNotEqual]: [Enums_1.QueryFeature.WhereNotEqual],
53
+ [Enums_1.QueryFeature.WhereGt]: [Enums_1.QueryFeature.WhereGt],
54
+ [Enums_1.QueryFeature.WhereGte]: [Enums_1.QueryFeature.WhereGte],
55
+ [Enums_1.QueryFeature.WhereLt]: [Enums_1.QueryFeature.WhereLt],
56
+ [Enums_1.QueryFeature.WhereLte]: [Enums_1.QueryFeature.WhereLte],
57
+ [Enums_1.QueryFeature.WhereLike]: [Enums_1.QueryFeature.WhereLike],
58
+ [Enums_1.QueryFeature.WhereNotLike]: [Enums_1.QueryFeature.WhereNotLike],
59
+ [Enums_1.QueryFeature.WhereIn]: [Enums_1.QueryFeature.WhereIn],
60
+ [Enums_1.QueryFeature.WhereNotIn]: [Enums_1.QueryFeature.WhereNotIn],
61
+ [Enums_1.QueryFeature.WhereBetween]: [Enums_1.QueryFeature.WhereBetween],
62
+ [Enums_1.QueryFeature.WhereNotBetween]: [Enums_1.QueryFeature.WhereNotBetween],
63
+ [Enums_1.QueryFeature.WhereNull]: [Enums_1.QueryFeature.WhereNull],
64
+ [Enums_1.QueryFeature.WhereNotNull]: [Enums_1.QueryFeature.WhereNotNull],
65
+ [Enums_1.QueryFeature.Trashed]: [Enums_1.QueryFeature.Trashed],
66
+ [Enums_1.QueryFeature.WithAll]: [Enums_1.QueryFeature.WithHasOne, Enums_1.QueryFeature.WithHasMany],
67
+ [Enums_1.QueryFeature.WithHasOne]: [Enums_1.QueryFeature.WithHasOne],
68
+ [Enums_1.QueryFeature.WithHasMany]: [Enums_1.QueryFeature.WithHasMany],
69
+ };
70
+ const generatePermission = (type, feature, keys = []) => {
71
+ const features = QueryFeatureMap[feature];
72
+ if (keys.length === 0) {
73
+ keys = [null];
74
+ }
75
+ return features
76
+ .map((subFeature) => {
77
+ return keys.map((key) => {
78
+ return {
79
+ type,
80
+ feature: subFeature,
81
+ key,
82
+ };
83
+ });
84
+ })
85
+ .flat();
86
+ };
87
+ const allow = (feature, keys = []) => {
88
+ return generatePermission(Enums_1.QueryFeatureType.Allow, feature, keys);
89
+ };
90
+ exports.allow = allow;
91
+ const deny = (feature, keys = []) => {
92
+ return generatePermission(Enums_1.QueryFeatureType.Deny, feature, keys);
93
+ };
94
+ exports.deny = deny;
95
+ const valideteQueryFeature = (model, feature, key = null, errorDescription) => {
96
+ const errorDetail = errorDescription ? ` (${errorDescription})` : "";
97
+ const rules = model.queryLimits.filter((limit) => limit.feature === feature && limit.key === null);
98
+ if (key) {
99
+ const keyRules = model.queryLimits.filter((limit) => limit.feature === feature && limit.key === key);
100
+ if (keyRules.length > 0) {
101
+ const lastKeyRule = keyRules[keyRules.length - 1];
102
+ if ((lastKeyRule === null || lastKeyRule === void 0 ? void 0 : lastKeyRule.type) === Enums_1.QueryFeatureType.Deny) {
103
+ throw new ApiError_1.default(`Unsupported query feature${errorDetail}: ${feature.toString()} [${key}]`);
104
+ }
105
+ return;
106
+ }
107
+ }
108
+ if (rules.length === 0) {
109
+ throw new ApiError_1.default(`Unsupported query feature${errorDetail}: ${feature.toString()}`);
110
+ }
111
+ const lastRule = rules[rules.length - 1];
112
+ if ((lastRule === null || lastRule === void 0 ? void 0 : lastRule.type) === Enums_1.QueryFeatureType.Deny) {
113
+ throw new ApiError_1.default(`Unsupported query feature${errorDetail}: ${feature.toString()}`);
114
+ }
115
+ };
116
+ exports.valideteQueryFeature = valideteQueryFeature;
@@ -1,5 +1,5 @@
1
1
  import { HookFunctionTypes, Extensions } from "../Enums";
2
- import { IColumn, IHookParameter, IModelService, IRelation } from "../Interfaces";
2
+ import { IColumn, IHookParameter, IModelService, IQueryLimitConfig, IRelation } from "../Interfaces";
3
3
  import Model from "./../Model";
4
4
  import { SerializationFunction } from "../Types";
5
5
  declare class ModelService implements IModelService {
@@ -12,10 +12,12 @@ declare class ModelService implements IModelService {
12
12
  events: Record<HookFunctionTypes, (params: IHookParameter) => void>;
13
13
  children: IModelService[];
14
14
  isRecursive: boolean;
15
+ queryLimits: IQueryLimitConfig[];
15
16
  serialize: SerializationFunction | null;
16
17
  constructor(name: string, instance: Model);
17
18
  setColumns(columns: IColumn[]): void;
18
19
  setExtensions(type: Extensions, hookFunctionType: HookFunctionTypes, data: (params: IHookParameter) => void): void;
20
+ setQueryLimits(limits: IQueryLimitConfig[]): void;
19
21
  setSerialization(callback: SerializationFunction): void;
20
22
  private setHooks;
21
23
  private setEvents;
@@ -12,6 +12,7 @@ class ModelService {
12
12
  this.columnNames = [];
13
13
  this.children = [];
14
14
  this.isRecursive = false;
15
+ this.queryLimits = [];
15
16
  this.serialize = null;
16
17
  }
17
18
  setColumns(columns) {
@@ -29,6 +30,9 @@ class ModelService {
29
30
  throw new Error("Undefined hook type.");
30
31
  }
31
32
  }
33
+ setQueryLimits(limits) {
34
+ this.queryLimits = limits;
35
+ }
32
36
  setSerialization(callback) {
33
37
  this.serialize = callback;
34
38
  }
@@ -1,4 +1,4 @@
1
- import { IQuery, ISortField, NestedWhere, IWhere, IModelService } from "../Interfaces";
1
+ import { IQuery, ISortField, NestedWhere, IWhere, IModelService, IVersionConfig } from "../Interfaces";
2
2
  import { Knex } from "knex";
3
3
  declare class QueryService {
4
4
  model: IModelService;
@@ -6,7 +6,8 @@ declare class QueryService {
6
6
  usedConditionColumns: string[];
7
7
  relationColumns: string[];
8
8
  createdJoins: string[];
9
- constructor(model: IModelService, models: IModelService[]);
9
+ config: IVersionConfig;
10
+ constructor(model: IModelService, models: IModelService[], config: IVersionConfig);
10
11
  applyFields(query: Knex.QueryBuilder, fields: string[]): void;
11
12
  applySorting(query: Knex.QueryBuilder, sort: ISortField[]): void;
12
13
  applyWheresInsideGroup(sub: Knex.QueryBuilder, ruleSet: NestedWhere | IWhere): void;
@@ -6,10 +6,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const Enums_1 = require("../Enums");
7
7
  const ApiError_1 = __importDefault(require("../Exceptions/ApiError"));
8
8
  const Resolvers_1 = require("../Resolvers");
9
+ const constants_1 = require("../constants");
10
+ const LimitService_1 = require("./LimitService");
11
+ const Helpers_1 = require("../Handlers/Helpers");
9
12
  class QueryService {
10
- constructor(model, models) {
13
+ constructor(model, models, config) {
11
14
  this.model = model;
12
15
  this.models = models;
16
+ this.config = config;
13
17
  this.createdJoins = [];
14
18
  this.relationColumns = [];
15
19
  this.usedConditionColumns = [];
@@ -17,6 +21,7 @@ class QueryService {
17
21
  applyFields(query, fields) {
18
22
  // Users should be able to select some fields to show.
19
23
  if (fields.length === 0 || (fields.length === 1 && fields[0] === "*")) {
24
+ (0, LimitService_1.valideteQueryFeature)(this.model, Enums_1.QueryFeature.FieldsAll);
20
25
  query.select(`${this.model.instance.table}.*`);
21
26
  }
22
27
  else {
@@ -33,7 +38,9 @@ class QueryService {
33
38
  if (sort.length === 0) {
34
39
  return;
35
40
  }
41
+ (0, LimitService_1.valideteQueryFeature)(this.model, Enums_1.QueryFeature.Sorting);
36
42
  sort.forEach((item) => {
43
+ (0, LimitService_1.valideteQueryFeature)(this.model, Enums_1.QueryFeature.Sorting, `${this.model.instance.table}.${item.name}`);
37
44
  query.orderBy(item.name, item.type);
38
45
  });
39
46
  }
@@ -156,6 +163,7 @@ class QueryService {
156
163
  this.createdJoins.push(relation.name);
157
164
  }
158
165
  parseSections(sections) {
166
+ var _a, _b, _c, _d;
159
167
  if (sections.q) {
160
168
  const queryContent = sections.q.replace(/%20/g, "").replace(/ /g, "");
161
169
  // Users can send an unacceptable query string. We shouldn't allow them to
@@ -175,10 +183,14 @@ class QueryService {
175
183
  sort: this.parseSortingOptions(sections.sort),
176
184
  q: this.parseCondition(sections.q),
177
185
  with: withQueryResolver.resolve((sections === null || sections === void 0 ? void 0 : sections.with) || ""),
178
- trashed: (sections === null || sections === void 0 ? void 0 : sections.trashed)
179
- ? sections.trashed.trim() === "true" || sections.trashed.trim() === "1"
180
- : false,
186
+ trashed: (sections === null || sections === void 0 ? void 0 : sections.trashed) ? (0, Helpers_1.isBoolean)(sections.trashed) : false,
181
187
  };
188
+ const configPerPage = ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.query.defaults) === null || _b === void 0 ? void 0 : _b.perPage) ||
189
+ ((_d = (_c = constants_1.DEFAULT_VERSION_CONFIG.query) === null || _c === void 0 ? void 0 : _c.defaults) === null || _d === void 0 ? void 0 : _d.perPage) ||
190
+ 10;
191
+ if (query.per_page !== configPerPage) {
192
+ (0, LimitService_1.valideteQueryFeature)(this.model, Enums_1.QueryFeature.Limits);
193
+ }
182
194
  this.addRelationColumns(query.with);
183
195
  return query;
184
196
  }
@@ -193,9 +205,21 @@ class QueryService {
193
205
  return value;
194
206
  }
195
207
  parsePerPage(content) {
196
- const value = parseInt(content);
197
- if (isNaN(value) || value <= 1 || value > 10000) {
198
- return 10;
208
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
209
+ const value = parseInt(content ||
210
+ ((_b = (_a = this.config.query) === null || _a === void 0 ? void 0 : _a.defaults) === null || _b === void 0 ? void 0 : _b.perPage) ||
211
+ ((_c = constants_1.DEFAULT_VERSION_CONFIG.query.defaults) === null || _c === void 0 ? void 0 : _c.perPage) ||
212
+ 10);
213
+ const minPerPage = ((_e = (_d = this.config.query) === null || _d === void 0 ? void 0 : _d.defaults) === null || _e === void 0 ? void 0 : _e.minPerPage) ||
214
+ ((_f = constants_1.DEFAULT_VERSION_CONFIG.query.defaults) === null || _f === void 0 ? void 0 : _f.minPerPage) ||
215
+ 1;
216
+ const maxPerPage = ((_h = (_g = this.config.query) === null || _g === void 0 ? void 0 : _g.defaults) === null || _h === void 0 ? void 0 : _h.maxPerPage) ||
217
+ ((_j = constants_1.DEFAULT_VERSION_CONFIG.query.defaults) === null || _j === void 0 ? void 0 : _j.maxPerPage) ||
218
+ 100;
219
+ if (isNaN(value) || value <= minPerPage || value > maxPerPage) {
220
+ return (((_l = (_k = this.config.query) === null || _k === void 0 ? void 0 : _k.defaults) === null || _l === void 0 ? void 0 : _l.perPage) ||
221
+ ((_m = constants_1.DEFAULT_VERSION_CONFIG.query.defaults) === null || _m === void 0 ? void 0 : _m.perPage) ||
222
+ 10);
199
223
  }
200
224
  return value;
201
225
  }
@@ -332,6 +356,7 @@ class QueryService {
332
356
  where.relation = relation;
333
357
  where.field = field;
334
358
  }
359
+ (0, LimitService_1.valideteQueryFeature)(this.model, constants_1.ConditionQueryFeatureMap[where.condition], `${where.table}.${where.field}`);
335
360
  this.shouldBeAcceptableColumn(where.field);
336
361
  this.usedConditionColumns.push(`${where.table}.${where.field}`);
337
362
  return where;
@@ -4,6 +4,10 @@ declare class SchemaValidatorService {
4
4
  constructor(version: IVersion);
5
5
  validate(): Promise<void>;
6
6
  private checkModelColumnsOrFail;
7
+ private checkRelationNamesOrFail;
8
+ private getQueryLimitRelations;
9
+ private getQueryLimitColumns;
10
+ private getQueryLimitKeyByFilter;
7
11
  private getModelFillableColumns;
8
12
  private getModelFormValidationColumns;
9
13
  private getModelHiddenColumns;