axe-api 0.20.4 → 0.22.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Release Notes
2
2
 
3
+ ## [0.22.0 (2023-01-29)](https://github.com/axe-api/axe-api/compare/0.22.0...0.21.0)
4
+
5
+ ### Features
6
+
7
+ - Added Soft-Deleting feature [#41](https://github.com/axe-api/axe-api/issues/41)
8
+
9
+ ### Fixed
10
+
11
+ - Fixed model relation route URLs [#141](https://github.com/axe-api/axe-api/issues/141)
12
+
13
+ ## [0.21.0 (2022-12-28)](https://github.com/axe-api/axe-api/compare/0.21.0...0.20.4)
14
+
15
+ ### Features
16
+
17
+ - Added `i18n` support. [#44](https://github.com/axe-api/axe-api/issues/44)
18
+
3
19
  ## [0.20.4 (2022-12-24)](https://github.com/axe-api/axe-api/compare/0.20.4...0.20.3)
4
20
 
5
21
  ### Fixed
@@ -113,13 +113,12 @@ class RouterBuilder {
113
113
  return;
114
114
  }
115
115
  // We should different parameter name for child routes
116
- const primaryKey = this.getPrimaryKeyName(model);
117
116
  const subRelations = model.relations.filter((item) => item.type === Enums_1.Relationships.HAS_MANY);
118
117
  for (const relation of subRelations) {
119
118
  const child = model.children.find((item) => item.name === relation.model);
120
119
  // It should be recursive
121
120
  if (child) {
122
- yield this.createRouteByModel(child, modelList, `${urlPrefix}${resource}/:${primaryKey}/`, model, relation);
121
+ yield this.createRouteByModel(child, modelList, `${urlPrefix}${resource}/:${(0, change_case_1.camelCase)(relation.foreignKey)}/`, model, relation);
123
122
  }
124
123
  }
125
124
  });
@@ -140,6 +139,10 @@ class RouterBuilder {
140
139
  app.delete(url, middlewares, handler);
141
140
  docs.push(Enums_1.HttpMethods.DELETE, url, model);
142
141
  break;
142
+ case Enums_1.HandlerTypes.FORCE_DELETE:
143
+ app.delete(url, middlewares, handler);
144
+ docs.push(Enums_1.HttpMethods.DELETE, url, model);
145
+ break;
143
146
  case Enums_1.HandlerTypes.INSERT:
144
147
  app.post(url, middlewares, handler);
145
148
  docs.push(Enums_1.HttpMethods.POST, url, model);
@@ -24,6 +24,7 @@ export declare enum HandlerTypes {
24
24
  SHOW = "show",
25
25
  UPDATE = "update",
26
26
  DELETE = "destroy",
27
+ FORCE_DELETE = "force_delete",
27
28
  PATCH = "patch",
28
29
  ALL = "all"
29
30
  }
@@ -33,6 +34,8 @@ export declare enum HookFunctionTypes {
33
34
  onBeforeUpdate = "onBeforeUpdate",
34
35
  onBeforeDeleteQuery = "onBeforeDeleteQuery",
35
36
  onBeforeDelete = "onBeforeDelete",
37
+ onBeforeForceDeleteQuery = "onBeforeForceDeleteQuery",
38
+ onBeforeForceDelete = "onBeforeForceDelete",
36
39
  onBeforePaginate = "onBeforePaginate",
37
40
  onBeforeAll = "onBeforeAll",
38
41
  onBeforeShow = "onBeforeShow",
@@ -41,6 +44,8 @@ export declare enum HookFunctionTypes {
41
44
  onAfterUpdate = "onAfterUpdate",
42
45
  onAfterDeleteQuery = "onAfterDeleteQuery",
43
46
  onAfterDelete = "onAfterDelete",
47
+ onAfterForceDeleteQuery = "onAfterForceDeleteQuery",
48
+ onAfterForceDelete = "onAfterForceDelete",
44
49
  onAfterPaginate = "onAfterPaginate",
45
50
  onAfterAll = "onAfterAll",
46
51
  onAfterShow = "onAfterShow"
@@ -30,6 +30,7 @@ var HandlerTypes;
30
30
  HandlerTypes["SHOW"] = "show";
31
31
  HandlerTypes["UPDATE"] = "update";
32
32
  HandlerTypes["DELETE"] = "destroy";
33
+ HandlerTypes["FORCE_DELETE"] = "force_delete";
33
34
  HandlerTypes["PATCH"] = "patch";
34
35
  HandlerTypes["ALL"] = "all";
35
36
  })(HandlerTypes = exports.HandlerTypes || (exports.HandlerTypes = {}));
@@ -40,6 +41,8 @@ var HookFunctionTypes;
40
41
  HookFunctionTypes["onBeforeUpdate"] = "onBeforeUpdate";
41
42
  HookFunctionTypes["onBeforeDeleteQuery"] = "onBeforeDeleteQuery";
42
43
  HookFunctionTypes["onBeforeDelete"] = "onBeforeDelete";
44
+ HookFunctionTypes["onBeforeForceDeleteQuery"] = "onBeforeForceDeleteQuery";
45
+ HookFunctionTypes["onBeforeForceDelete"] = "onBeforeForceDelete";
43
46
  HookFunctionTypes["onBeforePaginate"] = "onBeforePaginate";
44
47
  HookFunctionTypes["onBeforeAll"] = "onBeforeAll";
45
48
  HookFunctionTypes["onBeforeShow"] = "onBeforeShow";
@@ -48,6 +51,8 @@ var HookFunctionTypes;
48
51
  HookFunctionTypes["onAfterUpdate"] = "onAfterUpdate";
49
52
  HookFunctionTypes["onAfterDeleteQuery"] = "onAfterDeleteQuery";
50
53
  HookFunctionTypes["onAfterDelete"] = "onAfterDelete";
54
+ HookFunctionTypes["onAfterForceDeleteQuery"] = "onAfterForceDeleteQuery";
55
+ HookFunctionTypes["onAfterForceDelete"] = "onAfterForceDelete";
51
56
  HookFunctionTypes["onAfterPaginate"] = "onAfterPaginate";
52
57
  HookFunctionTypes["onAfterAll"] = "onAfterAll";
53
58
  HookFunctionTypes["onAfterShow"] = "onAfterShow";
@@ -20,6 +20,8 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
20
20
  const conditions = queryParser.get(req.query);
21
21
  // Creating a new database query
22
22
  const query = database.from(model.instance.table);
23
+ // If there is a deletedAtColumn, it means that this table support soft-delete
24
+ (0, Helpers_1.addSoftDeleteQuery)(model, conditions, query);
23
25
  // Users should be able to select some fields to show.
24
26
  queryParser.applyFields(query, conditions.fields);
25
27
  // Binding parent id if there is.
@@ -20,6 +20,8 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
20
20
  const query = database
21
21
  .from(model.instance.table)
22
22
  .where(model.instance.primaryKey, req.params[model.instance.primaryKey]);
23
+ // If there is a deletedAtColumn, it means that this table support soft-delete
24
+ (0, Helpers_1.addSoftDeleteQuery)(model, null, query);
23
25
  // If there is a relation, we should bind it
24
26
  (0, Helpers_1.addForeignKeyQuery)(req, query, relation, parentModel);
25
27
  yield (0, Helpers_1.callHooks)(model, Enums_1.HookFunctionTypes.onBeforeDeleteQuery, Object.assign(Object.assign({}, pack), { query }));
@@ -31,7 +33,15 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
31
33
  item }));
32
34
  yield (0, Helpers_1.callHooks)(model, Enums_1.HookFunctionTypes.onBeforeDelete, Object.assign(Object.assign({}, pack), { query,
33
35
  item }));
34
- yield query.delete();
36
+ // If there is a deletedAtColumn, it means that this table support soft-delete
37
+ if (model.instance.deletedAtColumn) {
38
+ yield query.update({
39
+ [model.instance.deletedAtColumn]: new Date(),
40
+ });
41
+ }
42
+ else {
43
+ yield query.delete();
44
+ }
35
45
  yield (0, Helpers_1.callHooks)(model, Enums_1.HookFunctionTypes.onAfterDelete, Object.assign(Object.assign({}, pack), { item }));
36
46
  return res.json();
37
47
  });
@@ -0,0 +1,3 @@
1
+ import { IRequestPack } from "../Interfaces";
2
+ declare const _default: (pack: IRequestPack) => Promise<import("express").Response<any, Record<string, any>>>;
3
+ export default _default;
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ const Helpers_1 = require("./Helpers");
16
+ const Enums_1 = require("../Enums");
17
+ const ApiError_1 = __importDefault(require("../Exceptions/ApiError"));
18
+ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
19
+ const { model, req, res, database, relation, parentModel } = pack;
20
+ const query = database
21
+ .from(model.instance.table)
22
+ .where(model.instance.primaryKey, req.params[model.instance.primaryKey]);
23
+ // If there is a deletedAtColumn, it means that this table support soft-delete
24
+ if (model.instance.deletedAtColumn === null) {
25
+ throw new ApiError_1.default("You can use force delete only soft-delete supported models.");
26
+ }
27
+ // If there is a relation, we should bind it
28
+ (0, Helpers_1.addForeignKeyQuery)(req, query, relation, parentModel);
29
+ yield (0, Helpers_1.callHooks)(model, Enums_1.HookFunctionTypes.onBeforeForceDeleteQuery, Object.assign(Object.assign({}, pack), { query }));
30
+ const item = yield query.first();
31
+ if (!item) {
32
+ throw new ApiError_1.default(`The item is not found on ${model.name}.`);
33
+ }
34
+ yield (0, Helpers_1.callHooks)(model, Enums_1.HookFunctionTypes.onAfterForceDeleteQuery, Object.assign(Object.assign({}, pack), { query,
35
+ item }));
36
+ yield (0, Helpers_1.callHooks)(model, Enums_1.HookFunctionTypes.onBeforeForceDelete, Object.assign(Object.assign({}, pack), { query,
37
+ item }));
38
+ yield query.delete();
39
+ yield (0, Helpers_1.callHooks)(model, Enums_1.HookFunctionTypes.onAfterForceDelete, Object.assign(Object.assign({}, pack), { item }));
40
+ return res.json();
41
+ });
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const AllHandler_1 = __importDefault(require("./AllHandler"));
7
7
  const DestroyHandler_1 = __importDefault(require("./DestroyHandler"));
8
+ const ForceDestroyHandler_1 = __importDefault(require("./ForceDestroyHandler"));
8
9
  const PaginateHandler_1 = __importDefault(require("./PaginateHandler"));
9
10
  const PatchHandler_1 = __importDefault(require("./PatchHandler"));
10
11
  const UpdateHandler_1 = __importDefault(require("./UpdateHandler"));
@@ -18,6 +19,8 @@ class HandlerFactory {
18
19
  return AllHandler_1.default;
19
20
  case Enums_1.HandlerTypes.DELETE:
20
21
  return DestroyHandler_1.default;
22
+ case Enums_1.HandlerTypes.FORCE_DELETE:
23
+ return ForceDestroyHandler_1.default;
21
24
  case Enums_1.HandlerTypes.INSERT:
22
25
  return StoreHandler_1.default;
23
26
  case Enums_1.HandlerTypes.PAGINATE:
@@ -1,5 +1,5 @@
1
1
  import { Request } from "express";
2
- import { IModelService, IRelation, IHookParameter } from "../Interfaces";
2
+ import { IModelService, IRelation, IHookParameter, IQuery } from "../Interfaces";
3
3
  import { Knex } from "knex";
4
4
  import { IWith } from "../Interfaces";
5
5
  import { HandlerTypes, HookFunctionTypes, TimestampColumns } from "../Enums";
@@ -11,4 +11,5 @@ export declare const getParentColumn: (relation: IRelation | null) => string | n
11
11
  export declare const addForeignKeyQuery: (request: Request, query: Knex.QueryBuilder, relation: IRelation | null, parentModel: IModelService | null) => void;
12
12
  export declare const serializeData: (itemArray: any[] | any, modelSerializer: (data: any, request: Request) => void, handler: HandlerTypes, request: Request) => Promise<any[]>;
13
13
  export declare const filterHiddenFields: (itemArray: any[], hiddens: string[] | null) => void;
14
+ export declare const addSoftDeleteQuery: (model: IModelService, conditions: IQuery | null, query: Knex.QueryBuilder) => void;
14
15
  export declare const getRelatedData: (data: any[], withArray: IWith[], model: IModelService, modelList: ModelListService, database: Knex | Knex.Transaction, handler: HandlerTypes, request: Request) => Promise<void>;
@@ -12,7 +12,7 @@ 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.filterHiddenFields = exports.serializeData = exports.addForeignKeyQuery = exports.getParentColumn = exports.callHooks = exports.getMergedFormData = exports.bindTimestampValues = void 0;
15
+ 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"));
@@ -138,6 +138,14 @@ const filterHiddenFields = (itemArray, hiddens) => {
138
138
  });
139
139
  };
140
140
  exports.filterHiddenFields = filterHiddenFields;
141
+ const addSoftDeleteQuery = (model, conditions, query) => {
142
+ // TODO: Trashed feature will be implemented later
143
+ // (conditions === null || conditions?.trashed === false)
144
+ if (model.instance.deletedAtColumn) {
145
+ query.whereNull(model.instance.deletedAtColumn);
146
+ }
147
+ };
148
+ exports.addSoftDeleteQuery = addSoftDeleteQuery;
141
149
  const getRelatedData = (data, withArray, model, modelList, database, handler, request) => __awaiter(void 0, void 0, void 0, function* () {
142
150
  if (withArray.length === 0) {
143
151
  return;
@@ -192,10 +200,13 @@ const getRelatedData = (data, withArray, model, modelList, database, handler, re
192
200
  selectColumns.push(...requiredForeignKeys);
193
201
  }
194
202
  selectColumns = uniqueByMap(selectColumns);
203
+ const foreignModelQuery = database(foreignModel.instance.table).select(selectColumns);
204
+ // If the model is supported soft-delete we should check the data.
205
+ if (foreignModel.instance.deletedAtColumn) {
206
+ foreignModelQuery.whereNull(foreignModel.instance.deletedAtColumn);
207
+ }
195
208
  // Fetching related records by foreignKey and primary key values.
196
- let relatedRecords = yield database(foreignModel.instance.table)
197
- .select(selectColumns)
198
- .whereIn(searchFieldKey, parentPrimaryKeyValues);
209
+ let relatedRecords = yield foreignModelQuery.whereIn(searchFieldKey, parentPrimaryKeyValues);
199
210
  // We should serialize related data if there is any serialization function
200
211
  relatedRecords = yield (0, exports.serializeData)(relatedRecords, foreignModel.instance.serialize, handler, request);
201
212
  // We should hide hidden fields if there is any
@@ -20,6 +20,8 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
20
20
  const conditions = queryParser.get(req.query);
21
21
  // Creating a new database query
22
22
  const query = database.from(model.instance.table);
23
+ // If there is a deletedAtColumn, it means that this table support soft-delete
24
+ (0, Helpers_1.addSoftDeleteQuery)(model, conditions, query);
23
25
  // Users should be able to select some fields to show.
24
26
  queryParser.applyFields(query, conditions.fields);
25
27
  // Binding parent id if there is.
@@ -21,6 +21,8 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
21
21
  const query = database.from(model.instance.table);
22
22
  // If there is a relation, we should bind it
23
23
  (0, Helpers_1.addForeignKeyQuery)(req, query, relation, parentModel);
24
+ // If there is a deletedAtColumn, it means that this table support soft-delete
25
+ (0, Helpers_1.addSoftDeleteQuery)(model, null, query);
24
26
  yield (0, Helpers_1.callHooks)(model, Enums_1.HookFunctionTypes.onBeforeUpdateQuery, Object.assign(Object.assign({}, pack), { query }));
25
27
  let item = yield query
26
28
  .where(model.instance.primaryKey, req.params[model.instance.primaryKey])
@@ -36,7 +38,7 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
36
38
  const validationRules = model.instance.getValidationRules(requestMethod);
37
39
  if (validationRules) {
38
40
  // The validation language should be set
39
- validatorjs_1.default.useLang(req.language);
41
+ validatorjs_1.default.useLang(req.currentLanguage.language);
40
42
  // Validate the data
41
43
  const validation = new validatorjs_1.default(formData, validationRules);
42
44
  if (validation.fails()) {
@@ -24,6 +24,8 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
24
24
  const conditions = queryParser.get(req.query);
25
25
  // Fetching item
26
26
  const query = database.from(model.instance.table);
27
+ // If there is a deletedAtColumn, it means that this table support soft-delete
28
+ (0, Helpers_1.addSoftDeleteQuery)(model, conditions, query);
27
29
  // Users should be able to select some fields to show.
28
30
  queryParser.applyFields(query, conditions.fields);
29
31
  // If there is a relation, we should bind it
@@ -23,7 +23,7 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
23
23
  const validationRules = model.instance.getValidationRules(requestMethod);
24
24
  if (validationRules) {
25
25
  // The validation language should be set
26
- validatorjs_1.default.useLang(req.language);
26
+ validatorjs_1.default.useLang(req.currentLanguage.language);
27
27
  // Validate the data
28
28
  const validation = new validatorjs_1.default(formData, validationRules);
29
29
  if (validation.fails()) {
@@ -21,6 +21,8 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
21
21
  const query = database.from(model.instance.table);
22
22
  // If there is a relation, we should bind it
23
23
  (0, Helpers_1.addForeignKeyQuery)(req, query, relation, parentModel);
24
+ // If there is a deletedAtColumn, it means that this table support soft-delete
25
+ (0, Helpers_1.addSoftDeleteQuery)(model, null, query);
24
26
  yield (0, Helpers_1.callHooks)(model, Enums_1.HookFunctionTypes.onBeforeUpdateQuery, Object.assign(Object.assign({}, pack), { query }));
25
27
  let item = yield query
26
28
  .where(model.instance.primaryKey, req.params[model.instance.primaryKey])
@@ -36,7 +38,7 @@ exports.default = (pack) => __awaiter(void 0, void 0, void 0, function* () {
36
38
  const validationRules = model.instance.getValidationRules(requestMethod);
37
39
  if (validationRules) {
38
40
  // The validation language should be set
39
- validatorjs_1.default.useLang(req.language);
41
+ validatorjs_1.default.useLang(req.currentLanguage.language);
40
42
  // Validate the data
41
43
  const validation = new validatorjs_1.default(formData, validationRules);
42
44
  if (validation.fails()) {
@@ -23,8 +23,18 @@ export interface IApplicationConfig extends IConfig {
23
23
  prefix: string;
24
24
  transaction: boolean | IHandlerBasedTransactionConfig | IHandlerBasedTransactionConfig[];
25
25
  serializers: ((data: any, request: Request) => void)[] | IHandlerBasedSerializer[];
26
+ supportedLanguages: string[];
26
27
  defaultLanguage: string;
27
28
  }
29
+ export interface ILanguage {
30
+ title: string;
31
+ language: string;
32
+ region?: string | null;
33
+ }
34
+ export interface IAcceptedLanguage {
35
+ language: ILanguage;
36
+ quality: number;
37
+ }
28
38
  export declare type IDatabaseConfig = Knex.Config;
29
39
  export interface IFolders {
30
40
  App: string;
@@ -110,6 +120,7 @@ export interface IRawQuery {
110
120
  sort: string | null;
111
121
  fields: string | null;
112
122
  with: string | null;
123
+ trashed: string | null;
113
124
  }
114
125
  export interface ISortField {
115
126
  name: string;
@@ -128,6 +139,7 @@ export interface IQuery {
128
139
  sort: ISortField[];
129
140
  fields: string[];
130
141
  with: IWith[];
142
+ trashed: boolean;
131
143
  }
132
144
  export interface IWhere {
133
145
  prefix: string | null;
@@ -8,26 +8,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
- var __importDefault = (this && this.__importDefault) || function (mod) {
12
- return (mod && mod.__esModule) ? mod : { "default": mod };
13
- };
14
11
  Object.defineProperty(exports, "__esModule", { value: true });
15
- const accept_language_parser_1 = __importDefault(require("accept-language-parser"));
16
12
  const Services_1 = require("../Services");
13
+ const Resolvers_1 = require("../Resolvers");
17
14
  exports.default = (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
18
- var _a;
19
15
  // Application configuration is need for the default setting.
20
16
  const configs = yield Services_1.IoCService.use("Config");
21
17
  const application = configs.Application;
22
- const { defaultLanguage } = application;
23
- // Parsing the `accept-language` value
24
- req.acceptedLanguages = accept_language_parser_1.default.parse(req.headers["accept-language"] || defaultLanguage);
25
- // Getting the current language by the accept-langauge and the default language
26
- // value. This values can be used anywhere in the API because the values would
27
- // be carried by Express.Request
28
- req.language =
29
- req.acceptedLanguages.length > 0
30
- ? ((_a = req.acceptedLanguages.at(0)) === null || _a === void 0 ? void 0 : _a.code) || defaultLanguage
31
- : defaultLanguage;
18
+ const { supportedLanguages, defaultLanguage } = application;
19
+ // Setting the current language by the supported, default and the client prefences
20
+ req.currentLanguage = Resolvers_1.AcceptLanguageResolver.resolve(req.get("accept-language") || "", supportedLanguages || ["en"], defaultLanguage || "en");
21
+ // Adding the `Content-Language` header to the response object
22
+ res.setHeader("Content-Language", req.currentLanguage.title);
32
23
  next();
33
24
  });
@@ -11,6 +11,7 @@ declare class Model {
11
11
  get hiddens(): string[];
12
12
  get createdAtColumn(): string | null;
13
13
  get updatedAtColumn(): string | null;
14
+ get deletedAtColumn(): string | null;
14
15
  get transaction(): boolean | IHandlerBasedTransactionConfig | IHandlerBasedTransactionConfig[] | null;
15
16
  get ignore(): boolean;
16
17
  getFillableFields(methodType: HttpMethods): string[];
@@ -35,6 +35,9 @@ class Model {
35
35
  get updatedAtColumn() {
36
36
  return "updated_at";
37
37
  }
38
+ get deletedAtColumn() {
39
+ return null;
40
+ }
38
41
  get transaction() {
39
42
  return null;
40
43
  }
@@ -0,0 +1,7 @@
1
+ import { ILanguage } from "../Interfaces";
2
+ declare class AcceptLanguageResolver {
3
+ static resolve(value: string, supportedLanguages: string[], defaultLanguage: string): ILanguage;
4
+ static toLanguageObject(key?: string): ILanguage;
5
+ private static toSortedPreferences;
6
+ }
7
+ export default AcceptLanguageResolver;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class AcceptLanguageResolver {
4
+ static resolve(value, supportedLanguages, defaultLanguage) {
5
+ value = value.trim();
6
+ if (value === "*") {
7
+ return this.toLanguageObject(defaultLanguage);
8
+ }
9
+ const languages = this.toSortedPreferences(value);
10
+ const perfectMatch = languages.find((item) => supportedLanguages.includes(item.language.title));
11
+ const anyMatch = languages.find((item) => supportedLanguages.includes(item.language.language));
12
+ if (perfectMatch && !anyMatch) {
13
+ return perfectMatch.language;
14
+ }
15
+ if (!perfectMatch && anyMatch) {
16
+ return anyMatch.language;
17
+ }
18
+ if (perfectMatch && anyMatch) {
19
+ if (perfectMatch.quality >= anyMatch.quality) {
20
+ return perfectMatch.language;
21
+ }
22
+ else {
23
+ return this.toLanguageObject(anyMatch.language.language);
24
+ }
25
+ }
26
+ return this.toLanguageObject(defaultLanguage);
27
+ }
28
+ static toLanguageObject(key = "") {
29
+ const [language, region] = key.split("-");
30
+ return {
31
+ title: key,
32
+ language,
33
+ region: region || null,
34
+ };
35
+ }
36
+ static toSortedPreferences(value) {
37
+ // Splitting by language definitons
38
+ const keys = value.split(",").map((key) => key.trim());
39
+ const languages = [];
40
+ for (const key of keys) {
41
+ // Splitting by the quality values
42
+ const [code, quality] = key.split(";");
43
+ // Parsing the language code and the quality value
44
+ const item = {
45
+ language: this.toLanguageObject(code),
46
+ quality: quality ? parseFloat(quality.replace("q=", "")) : 1,
47
+ };
48
+ languages.push(item);
49
+ }
50
+ // Sorting ASC
51
+ languages.sort((a, b) => {
52
+ if (a.quality === b.quality) {
53
+ return 0;
54
+ }
55
+ if (a.quality === null) {
56
+ return 1;
57
+ }
58
+ if (b.quality === null) {
59
+ return -1;
60
+ }
61
+ return a.quality < b.quality ? 1 : -1;
62
+ });
63
+ return languages;
64
+ }
65
+ }
66
+ exports.default = AcceptLanguageResolver;
@@ -1,7 +1,8 @@
1
+ import AcceptLanguageResolver from "./AcceptLanguageResolver";
1
2
  import FileResolver from "./FileResolver";
2
3
  import FolderResolver from "./FolderResolver";
3
4
  import GeneralHookResolver from "./GeneralHookResolver";
4
5
  import ModelResolver from "./ModelResolver";
5
6
  import TransactionResolver from "./TransactionResolver";
6
7
  import WithQueryResolver from "./WithQueryResolver";
7
- export { FileResolver, FolderResolver, GeneralHookResolver, ModelResolver, TransactionResolver, WithQueryResolver, };
8
+ export { AcceptLanguageResolver, FileResolver, FolderResolver, GeneralHookResolver, ModelResolver, TransactionResolver, WithQueryResolver, };
@@ -3,7 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.WithQueryResolver = exports.TransactionResolver = exports.ModelResolver = exports.GeneralHookResolver = exports.FolderResolver = exports.FileResolver = void 0;
6
+ exports.WithQueryResolver = exports.TransactionResolver = exports.ModelResolver = exports.GeneralHookResolver = exports.FolderResolver = exports.FileResolver = exports.AcceptLanguageResolver = void 0;
7
+ const AcceptLanguageResolver_1 = __importDefault(require("./AcceptLanguageResolver"));
8
+ exports.AcceptLanguageResolver = AcceptLanguageResolver_1.default;
7
9
  const FileResolver_1 = __importDefault(require("./FileResolver"));
8
10
  exports.FileResolver = FileResolver_1.default;
9
11
  const FolderResolver_1 = __importDefault(require("./FolderResolver"));
@@ -175,6 +175,9 @@ class QueryService {
175
175
  sort: this.parseSortingOptions(sections.sort),
176
176
  q: this.parseCondition(sections.q),
177
177
  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,
178
181
  };
179
182
  this.addRelationColumns(query.with);
180
183
  return query;
@@ -57,6 +57,9 @@ class SchemaValidatorService {
57
57
  if (model.instance.updatedAtColumn) {
58
58
  columns.push(model.instance.updatedAtColumn);
59
59
  }
60
+ if (model.instance.deletedAtColumn) {
61
+ columns.push(model.instance.deletedAtColumn);
62
+ }
60
63
  return columns;
61
64
  };
62
65
  this.checkHasManyRelation = (modelList, model, relation) => {
@@ -20,4 +20,5 @@ export declare const API_ROUTE_TEMPLATES: {
20
20
  update: (prefix: string, parentUrl: string, resource: string, primaryKey: string) => string;
21
21
  patch: (prefix: string, parentUrl: string, resource: string, primaryKey: string) => string;
22
22
  destroy: (prefix: string, parentUrl: string, resource: string, primaryKey: string) => string;
23
+ force_delete: (prefix: string, parentUrl: string, resource: string, primaryKey: string) => string;
23
24
  };
@@ -46,6 +46,7 @@ exports.DEFAULT_METHODS_OF_MODELS = [
46
46
  "hiddens",
47
47
  "createdAtColumn",
48
48
  "updatedAtColumn",
49
+ "deletedAtColumn",
49
50
  "transaction",
50
51
  "ignore",
51
52
  "getFillableFields",
@@ -59,4 +60,5 @@ exports.API_ROUTE_TEMPLATES = {
59
60
  [Enums_1.HandlerTypes.UPDATE]: (prefix, parentUrl, resource, primaryKey) => `/${prefix}/${parentUrl}${resource}/:${primaryKey}`,
60
61
  [Enums_1.HandlerTypes.PATCH]: (prefix, parentUrl, resource, primaryKey) => `/${prefix}/${parentUrl}${resource}/:${primaryKey}`,
61
62
  [Enums_1.HandlerTypes.DELETE]: (prefix, parentUrl, resource, primaryKey) => `/${prefix}/${parentUrl}${resource}/:${primaryKey}`,
63
+ [Enums_1.HandlerTypes.FORCE_DELETE]: (prefix, parentUrl, resource, primaryKey) => `/${prefix}/${parentUrl}${resource}/:${primaryKey}/force`,
62
64
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "axe-api",
3
- "version": "0.20.4",
3
+ "version": "0.22.0",
4
4
  "description": "AXE API is a simple tool which has been created based on Express and Knex.js to create Rest APIs quickly.",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -30,7 +30,6 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@types/express": "^4.17.15",
33
- "accept-language-parser": "^1.5.0",
34
33
  "change-case": "^4.1.2",
35
34
  "dotenv": "^14.2.0",
36
35
  "express": "^4.18.2",
package/readme.md CHANGED
@@ -145,30 +145,6 @@ If you can see that response, it means that your project is running properly.
145
145
 
146
146
  Axe API has great documentation. Please [check it out in here](https://axe-api.com/).
147
147
 
148
- ## How To Run Integration Tests
149
-
150
- > You have to have **Docker** and **Docker Compose** on your local development environment to run integration tests.
151
-
152
- Execute the following commands to prepare the integration app
153
-
154
- ```sh
155
- cd tests/integrations && npm install && npm ci && npm run build --if-present
156
- ```
157
-
158
- Execute the following commands to prepare the database;
159
-
160
- ```sh
161
- docker-compose -f "./tests/integrations/docker-compose.mysql8.yml" up -d --build
162
- ```
163
-
164
- > To down the database, you can use the following command; `docker-compose -f "./tests/integrations/docker-compose.mysql8.yml" up -d --build`
165
-
166
- You can execute the following command to execute tests;
167
-
168
- ```sh
169
- npm run test:integration:mysql8
170
- ```
171
-
172
148
  ## License
173
149
 
174
150
  [MIT License](LICENSE)