axe-api 0.21.0 → 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 +10 -0
- package/build/src/Builders/RouterBuilder.js +5 -2
- package/build/src/Enums.d.ts +5 -0
- package/build/src/Enums.js +5 -0
- package/build/src/Handlers/AllHandler.js +2 -0
- package/build/src/Handlers/DestroyHandler.js +11 -1
- package/build/src/Handlers/ForceDestroyHandler.d.ts +3 -0
- package/build/src/Handlers/ForceDestroyHandler.js +41 -0
- package/build/src/Handlers/HandlerFactory.js +3 -0
- package/build/src/Handlers/Helpers.d.ts +2 -1
- package/build/src/Handlers/Helpers.js +15 -4
- package/build/src/Handlers/PaginateHandler.js +2 -0
- package/build/src/Handlers/PatchHandler.js +2 -0
- package/build/src/Handlers/ShowHandler.js +2 -0
- package/build/src/Handlers/UpdateHandler.js +2 -0
- package/build/src/Interfaces.d.ts +2 -0
- package/build/src/Model.d.ts +1 -0
- package/build/src/Model.js +3 -0
- package/build/src/Services/QueryService.js +3 -0
- package/build/src/Services/SchemaValidatorService.js +3 -0
- package/build/src/constants.d.ts +1 -0
- package/build/src/constants.js +2 -0
- package/package.json +1 -1
- package/readme.md +0 -24
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
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
|
+
|
|
3
13
|
## [0.21.0 (2022-12-28)](https://github.com/axe-api/axe-api/compare/0.21.0...0.20.4)
|
|
4
14
|
|
|
5
15
|
### Features
|
|
@@ -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}/:${
|
|
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);
|
package/build/src/Enums.d.ts
CHANGED
|
@@ -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"
|
package/build/src/Enums.js
CHANGED
|
@@ -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
|
-
|
|
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,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
|
|
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])
|
|
@@ -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
|
|
@@ -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])
|
|
@@ -120,6 +120,7 @@ export interface IRawQuery {
|
|
|
120
120
|
sort: string | null;
|
|
121
121
|
fields: string | null;
|
|
122
122
|
with: string | null;
|
|
123
|
+
trashed: string | null;
|
|
123
124
|
}
|
|
124
125
|
export interface ISortField {
|
|
125
126
|
name: string;
|
|
@@ -138,6 +139,7 @@ export interface IQuery {
|
|
|
138
139
|
sort: ISortField[];
|
|
139
140
|
fields: string[];
|
|
140
141
|
with: IWith[];
|
|
142
|
+
trashed: boolean;
|
|
141
143
|
}
|
|
142
144
|
export interface IWhere {
|
|
143
145
|
prefix: string | null;
|
package/build/src/Model.d.ts
CHANGED
|
@@ -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[];
|
package/build/src/Model.js
CHANGED
|
@@ -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) => {
|
package/build/src/constants.d.ts
CHANGED
|
@@ -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
|
};
|
package/build/src/constants.js
CHANGED
|
@@ -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
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)
|