@forestadmin/agent 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (109) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +0 -0
  3. package/dist/agent/forestadmin-http-driver.d.ts +34 -0
  4. package/dist/agent/forestadmin-http-driver.js +73 -0
  5. package/dist/agent/routes/access/chart.d.ts +17 -0
  6. package/dist/agent/routes/access/chart.js +125 -0
  7. package/dist/agent/routes/access/count-related.d.ts +9 -0
  8. package/dist/agent/routes/access/count-related.js +24 -0
  9. package/dist/agent/routes/access/count.d.ts +9 -0
  10. package/dist/agent/routes/access/count.js +24 -0
  11. package/dist/agent/routes/access/csv-related.d.ts +9 -0
  12. package/dist/agent/routes/access/csv-related.js +33 -0
  13. package/dist/agent/routes/access/csv.d.ts +9 -0
  14. package/dist/agent/routes/access/csv.js +30 -0
  15. package/dist/agent/routes/access/get.d.ts +9 -0
  16. package/dist/agent/routes/access/get.js +28 -0
  17. package/dist/agent/routes/access/list-related.d.ts +9 -0
  18. package/dist/agent/routes/access/list-related.js +26 -0
  19. package/dist/agent/routes/access/list.d.ts +9 -0
  20. package/dist/agent/routes/access/list.js +23 -0
  21. package/dist/agent/routes/base-route.d.ts +14 -0
  22. package/dist/agent/routes/base-route.js +16 -0
  23. package/dist/agent/routes/collection-route.d.ts +12 -0
  24. package/dist/agent/routes/collection-route.js +20 -0
  25. package/dist/agent/routes/index.d.ts +30 -0
  26. package/dist/agent/routes/index.js +90 -0
  27. package/dist/agent/routes/modification/action.d.ts +17 -0
  28. package/dist/agent/routes/modification/action.js +103 -0
  29. package/dist/agent/routes/modification/associate-related.d.ts +12 -0
  30. package/dist/agent/routes/modification/associate-related.js +49 -0
  31. package/dist/agent/routes/modification/create.d.ts +14 -0
  32. package/dist/agent/routes/modification/create.js +81 -0
  33. package/dist/agent/routes/modification/delete.d.ts +11 -0
  34. package/dist/agent/routes/modification/delete.js +40 -0
  35. package/dist/agent/routes/modification/dissociate-delete-related.d.ts +20 -0
  36. package/dist/agent/routes/modification/dissociate-delete-related.js +88 -0
  37. package/dist/agent/routes/modification/update-relation.d.ts +11 -0
  38. package/dist/agent/routes/modification/update-relation.js +53 -0
  39. package/dist/agent/routes/modification/update.d.ts +9 -0
  40. package/dist/agent/routes/modification/update.js +29 -0
  41. package/dist/agent/routes/relation-route.d.ts +10 -0
  42. package/dist/agent/routes/relation-route.js +18 -0
  43. package/dist/agent/routes/security/authentication.d.ts +17 -0
  44. package/dist/agent/routes/security/authentication.js +86 -0
  45. package/dist/agent/routes/security/ip-whitelist.d.ts +14 -0
  46. package/dist/agent/routes/security/ip-whitelist.js +35 -0
  47. package/dist/agent/routes/security/scope-invalidation.d.ts +11 -0
  48. package/dist/agent/routes/security/scope-invalidation.js +28 -0
  49. package/dist/agent/routes/system/error-handling.d.ts +11 -0
  50. package/dist/agent/routes/system/error-handling.js +56 -0
  51. package/dist/agent/routes/system/healthcheck.d.ts +11 -0
  52. package/dist/agent/routes/system/healthcheck.js +22 -0
  53. package/dist/agent/routes/system/logger.d.ts +10 -0
  54. package/dist/agent/routes/system/logger.js +36 -0
  55. package/dist/agent/services/index.d.ts +10 -0
  56. package/dist/agent/services/index.js +12 -0
  57. package/dist/agent/services/permissions.d.ts +19 -0
  58. package/dist/agent/services/permissions.js +79 -0
  59. package/dist/agent/services/serializer.d.ts +17 -0
  60. package/dist/agent/services/serializer.js +120 -0
  61. package/dist/agent/types.d.ts +23 -0
  62. package/dist/agent/types.js +22 -0
  63. package/dist/agent/utils/body-parser.d.ts +7 -0
  64. package/dist/agent/utils/body-parser.js +18 -0
  65. package/dist/agent/utils/context-filter-factory.d.ts +7 -0
  66. package/dist/agent/utils/context-filter-factory.js +29 -0
  67. package/dist/agent/utils/csv-generator.d.ts +12 -0
  68. package/dist/agent/utils/csv-generator.js +39 -0
  69. package/dist/agent/utils/csv-route-context.d.ts +5 -0
  70. package/dist/agent/utils/csv-route-context.js +14 -0
  71. package/dist/agent/utils/forest-http-api.d.ts +63 -0
  72. package/dist/agent/utils/forest-http-api.js +173 -0
  73. package/dist/agent/utils/forest-schema/action-values.d.ts +34 -0
  74. package/dist/agent/utils/forest-schema/action-values.js +144 -0
  75. package/dist/agent/utils/forest-schema/emitter.d.ts +20 -0
  76. package/dist/agent/utils/forest-schema/emitter.js +70 -0
  77. package/dist/agent/utils/forest-schema/filterable.d.ts +16 -0
  78. package/dist/agent/utils/forest-schema/filterable.js +68 -0
  79. package/dist/agent/utils/forest-schema/generator-actions.d.ts +14 -0
  80. package/dist/agent/utils/forest-schema/generator-actions.js +99 -0
  81. package/dist/agent/utils/forest-schema/generator-collection.d.ts +7 -0
  82. package/dist/agent/utils/forest-schema/generator-collection.js +31 -0
  83. package/dist/agent/utils/forest-schema/generator-fields.d.ts +13 -0
  84. package/dist/agent/utils/forest-schema/generator-fields.js +131 -0
  85. package/dist/agent/utils/forest-schema/generator-segments.d.ts +6 -0
  86. package/dist/agent/utils/forest-schema/generator-segments.js +9 -0
  87. package/dist/agent/utils/forest-schema/types.d.ts +79 -0
  88. package/dist/agent/utils/forest-schema/types.js +16 -0
  89. package/dist/agent/utils/forest-schema/validation.d.ts +10 -0
  90. package/dist/agent/utils/forest-schema/validation.js +26 -0
  91. package/dist/agent/utils/http-driver-options.d.ts +13 -0
  92. package/dist/agent/utils/http-driver-options.js +86 -0
  93. package/dist/agent/utils/id.d.ts +8 -0
  94. package/dist/agent/utils/id.js +43 -0
  95. package/dist/agent/utils/query-string.d.ts +14 -0
  96. package/dist/agent/utils/query-string.js +130 -0
  97. package/dist/builder/agent.d.ts +81 -0
  98. package/dist/builder/agent.js +113 -0
  99. package/dist/builder/collection.d.ts +148 -0
  100. package/dist/builder/collection.js +226 -0
  101. package/dist/builder/types.d.ts +5 -0
  102. package/dist/builder/types.js +3 -0
  103. package/dist/index.d.ts +5 -0
  104. package/dist/index.js +22 -0
  105. package/dist/types.d.ts +22 -0
  106. package/dist/types.js +11 -0
  107. package/dist/utils/csv-generator.d.ts +12 -0
  108. package/dist/utils/csv-generator.js +39 -0
  109. package/package.json +55 -0
@@ -0,0 +1,30 @@
1
+ import { DataSource } from '@forestadmin/datasource-toolkit';
2
+ import { AgentOptionsWithDefaults as Options } from '../types';
3
+ import { ForestAdminHttpDriverServices as Services } from '../services';
4
+ import AssociateRelated from './modification/associate-related';
5
+ import Authentication from './security/authentication';
6
+ import BaseRoute from './base-route';
7
+ import Chart from './access/chart';
8
+ import Count from './access/count';
9
+ import CountRelated from './access/count-related';
10
+ import Create from './modification/create';
11
+ import Csv from './access/csv';
12
+ import CsvRelated from './access/csv-related';
13
+ import Delete from './modification/delete';
14
+ import DissociateDeleteRelated from './modification/dissociate-delete-related';
15
+ import ErrorHandling from './system/error-handling';
16
+ import Get from './access/get';
17
+ import HealthCheck from './system/healthcheck';
18
+ import IpWhitelist from './security/ip-whitelist';
19
+ import List from './access/list';
20
+ import ListRelated from './access/list-related';
21
+ import Logger from './system/logger';
22
+ import ScopeInvalidation from './security/scope-invalidation';
23
+ import Update from './modification/update';
24
+ import UpdateRelation from './modification/update-relation';
25
+ export declare const ROOT_ROUTES_CTOR: (typeof Authentication | typeof ErrorHandling | typeof HealthCheck | typeof IpWhitelist | typeof Logger | typeof ScopeInvalidation)[];
26
+ export declare const COLLECTION_ROUTES_CTOR: (typeof Chart | typeof Count | typeof Create | typeof Csv | typeof Delete | typeof Get | typeof List | typeof Update)[];
27
+ export declare const RELATED_ROUTES_CTOR: (typeof AssociateRelated | typeof CountRelated | typeof CsvRelated | typeof DissociateDeleteRelated | typeof ListRelated)[];
28
+ export declare const RELATED_RELATION_ROUTES_CTOR: (typeof UpdateRelation)[];
29
+ export default function makeRoutes(dataSource: DataSource, options: Options, services: Services): BaseRoute[];
30
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,90 @@
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.RELATED_RELATION_ROUTES_CTOR = exports.RELATED_ROUTES_CTOR = exports.COLLECTION_ROUTES_CTOR = exports.ROOT_ROUTES_CTOR = void 0;
7
+ const action_1 = __importDefault(require("./modification/action"));
8
+ const associate_related_1 = __importDefault(require("./modification/associate-related"));
9
+ const authentication_1 = __importDefault(require("./security/authentication"));
10
+ const chart_1 = __importDefault(require("./access/chart"));
11
+ const count_1 = __importDefault(require("./access/count"));
12
+ const count_related_1 = __importDefault(require("./access/count-related"));
13
+ const create_1 = __importDefault(require("./modification/create"));
14
+ const csv_1 = __importDefault(require("./access/csv"));
15
+ const csv_related_1 = __importDefault(require("./access/csv-related"));
16
+ const delete_1 = __importDefault(require("./modification/delete"));
17
+ const dissociate_delete_related_1 = __importDefault(require("./modification/dissociate-delete-related"));
18
+ const error_handling_1 = __importDefault(require("./system/error-handling"));
19
+ const get_1 = __importDefault(require("./access/get"));
20
+ const healthcheck_1 = __importDefault(require("./system/healthcheck"));
21
+ const ip_whitelist_1 = __importDefault(require("./security/ip-whitelist"));
22
+ const list_1 = __importDefault(require("./access/list"));
23
+ const list_related_1 = __importDefault(require("./access/list-related"));
24
+ const logger_1 = __importDefault(require("./system/logger"));
25
+ const scope_invalidation_1 = __importDefault(require("./security/scope-invalidation"));
26
+ const update_1 = __importDefault(require("./modification/update"));
27
+ const update_relation_1 = __importDefault(require("./modification/update-relation"));
28
+ exports.ROOT_ROUTES_CTOR = [
29
+ authentication_1.default,
30
+ error_handling_1.default,
31
+ healthcheck_1.default,
32
+ ip_whitelist_1.default,
33
+ logger_1.default,
34
+ scope_invalidation_1.default,
35
+ ];
36
+ exports.COLLECTION_ROUTES_CTOR = [chart_1.default, count_1.default, create_1.default, csv_1.default, delete_1.default, get_1.default, list_1.default, update_1.default];
37
+ exports.RELATED_ROUTES_CTOR = [
38
+ associate_related_1.default,
39
+ count_related_1.default,
40
+ csv_related_1.default,
41
+ dissociate_delete_related_1.default,
42
+ list_related_1.default,
43
+ ];
44
+ exports.RELATED_RELATION_ROUTES_CTOR = [update_relation_1.default];
45
+ function getRootRoutes(options, services) {
46
+ return exports.ROOT_ROUTES_CTOR.map(Route => new Route(services, options));
47
+ }
48
+ function getCrudRoutes(dataSource, options, services) {
49
+ const routes = [];
50
+ dataSource.collections.forEach(collection => {
51
+ routes.push(...exports.COLLECTION_ROUTES_CTOR.map(Route => new Route(services, options, dataSource, collection.name)));
52
+ });
53
+ return routes;
54
+ }
55
+ function getRelatedRoutes(dataSource, options, services) {
56
+ const routes = [];
57
+ const routesToBuild = [
58
+ { list: exports.RELATED_ROUTES_CTOR, relations: ['ManyToMany', 'OneToMany'] },
59
+ { list: exports.RELATED_RELATION_ROUTES_CTOR, relations: ['OneToOne', 'ManyToOne'] },
60
+ ];
61
+ dataSource.collections.forEach(collection => {
62
+ routesToBuild.forEach(route => {
63
+ const fields = Object.entries(collection.schema.fields);
64
+ const relationFields = fields.filter(([, schema]) => route.relations.includes(schema.type));
65
+ relationFields.forEach(([relationName]) => {
66
+ routes.push(...route.list.map(Route => new Route(services, options, dataSource, collection.name, relationName)));
67
+ });
68
+ });
69
+ });
70
+ return routes;
71
+ }
72
+ function getActionRoutes(dataSource, options, services) {
73
+ const routes = [];
74
+ for (const collection of dataSource.collections)
75
+ for (const actionName of Object.keys(collection.schema.actions))
76
+ routes.push(new action_1.default(services, options, dataSource, collection.name, actionName));
77
+ return routes;
78
+ }
79
+ function makeRoutes(dataSource, options, services) {
80
+ const routes = [
81
+ ...getRootRoutes(options, services),
82
+ ...getCrudRoutes(dataSource, options, services),
83
+ ...getRelatedRoutes(dataSource, options, services),
84
+ ...getActionRoutes(dataSource, options, services),
85
+ ];
86
+ // Ensure routes and middlewares are loaded in the right order.
87
+ return routes.sort((a, b) => a.type - b.type);
88
+ }
89
+ exports.default = makeRoutes;
90
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYWdlbnQvcm91dGVzL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUlBLG1FQUFnRDtBQUNoRCx5RkFBZ0U7QUFDaEUsK0VBQXVEO0FBRXZELDJEQUFtQztBQUNuQywyREFBbUM7QUFDbkMsMkVBQWtEO0FBQ2xELG1FQUEyQztBQUMzQyx1REFBK0I7QUFDL0IsdUVBQThDO0FBQzlDLG1FQUEyQztBQUMzQyx5R0FBK0U7QUFDL0UsNkVBQW9EO0FBQ3BELHVEQUErQjtBQUMvQix1RUFBK0M7QUFDL0MsMkVBQWtEO0FBQ2xELHlEQUFpQztBQUNqQyx5RUFBZ0Q7QUFDaEQsNkRBQXFDO0FBQ3JDLHVGQUE4RDtBQUM5RCxtRUFBMkM7QUFDM0MscUZBQTREO0FBRS9DLFFBQUEsZ0JBQWdCLEdBQUc7SUFDOUIsd0JBQWM7SUFDZCx3QkFBYTtJQUNiLHFCQUFXO0lBQ1gsc0JBQVc7SUFDWCxnQkFBTTtJQUNOLDRCQUFpQjtDQUNsQixDQUFDO0FBQ1csUUFBQSxzQkFBc0IsR0FBRyxDQUFDLGVBQUssRUFBRSxlQUFLLEVBQUUsZ0JBQU0sRUFBRSxhQUFHLEVBQUUsZ0JBQU0sRUFBRSxhQUFHLEVBQUUsY0FBSSxFQUFFLGdCQUFNLENBQUMsQ0FBQztBQUNoRixRQUFBLG1CQUFtQixHQUFHO0lBQ2pDLDJCQUFnQjtJQUNoQix1QkFBWTtJQUNaLHFCQUFVO0lBQ1YsbUNBQXVCO0lBQ3ZCLHNCQUFXO0NBQ1osQ0FBQztBQUNXLFFBQUEsNEJBQTRCLEdBQUcsQ0FBQyx5QkFBYyxDQUFDLENBQUM7QUFFN0QsU0FBUyxhQUFhLENBQUMsT0FBZ0IsRUFBRSxRQUFrQjtJQUN6RCxPQUFPLHdCQUFnQixDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLElBQUksS0FBSyxDQUFDLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO0FBQ3JFLENBQUM7QUFF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
@@ -0,0 +1,17 @@
1
+ /// <reference types="koa__router" />
2
+ import { DataSource } from '@forestadmin/datasource-toolkit';
3
+ import Router from '@koa/router';
4
+ import { AgentOptionsWithDefaults } from '../../types';
5
+ import { ForestAdminHttpDriverServices } from '../../services';
6
+ import CollectionRoute from '../collection-route';
7
+ export default class ActionRoute extends CollectionRoute {
8
+ private readonly actionName;
9
+ constructor(services: ForestAdminHttpDriverServices, options: AgentOptionsWithDefaults, dataSource: DataSource, collectionName: string, actionName: string);
10
+ setupRoutes(router: Router): void;
11
+ private handleExecute;
12
+ private handleHook;
13
+ private checkPermissions;
14
+ private getRecordSelection;
15
+ private applyActionOnlyOnRelation;
16
+ }
17
+ //# sourceMappingURL=action.d.ts.map
@@ -0,0 +1,103 @@
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
+ const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
7
+ const types_1 = require("../../types");
8
+ const body_parser_1 = __importDefault(require("../../utils/body-parser"));
9
+ const collection_route_1 = __importDefault(require("../collection-route"));
10
+ const context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
11
+ const action_values_1 = __importDefault(require("../../utils/forest-schema/action-values"));
12
+ const id_1 = __importDefault(require("../../utils/id"));
13
+ const query_string_1 = __importDefault(require("../../utils/query-string"));
14
+ const generator_actions_1 = __importDefault(require("../../utils/forest-schema/generator-actions"));
15
+ class ActionRoute extends collection_route_1.default {
16
+ constructor(services, options, dataSource, collectionName, actionName) {
17
+ super(services, options, dataSource, collectionName);
18
+ this.actionName = actionName;
19
+ }
20
+ setupRoutes(router) {
21
+ const actionIndex = Object.keys(this.collection.schema.actions).indexOf(this.actionName);
22
+ const path = `/_actions/${this.collection.name}/${actionIndex}`;
23
+ router.post(`${path}/:slug`, this.handleExecute.bind(this));
24
+ router.post(`${path}/:slug/hooks/load`, this.handleHook.bind(this));
25
+ router.post(`${path}/:slug/hooks/change`, this.handleHook.bind(this));
26
+ }
27
+ async handleExecute(context) {
28
+ await this.checkPermissions(context);
29
+ const { dataSource } = this.collection;
30
+ const filter = await this.getRecordSelection(context);
31
+ const rawData = context.request.body.data.attributes.values;
32
+ // As forms are dynamic, we don't have any way to ensure that we're parsing the data correctly
33
+ // => better send invalid data to the getForm() customer handler than to the execute() one.
34
+ const unsafeData = action_values_1.default.makeFormDataUnsafe(rawData);
35
+ const fields = await this.collection.getForm(this.actionName, unsafeData, filter);
36
+ // Now that we have the field list, we can parse the data again.
37
+ const data = action_values_1.default.makeFormData(dataSource, rawData, fields);
38
+ const result = await this.collection.execute(this.actionName, data, filter);
39
+ if (result?.type === 'Error') {
40
+ context.response.status = types_1.HttpCode.BadRequest;
41
+ context.response.body = { error: result.message };
42
+ }
43
+ else if (result?.type === 'Success') {
44
+ context.response.body = {
45
+ [result.format === 'text' ? 'success' : 'html']: result.message,
46
+ refresh: { relationships: [...result.invalidated] },
47
+ };
48
+ }
49
+ else if (result?.type === 'Webhook') {
50
+ const { url, method, headers, body } = result;
51
+ context.response.body = { webhook: { url, method, headers, body } };
52
+ }
53
+ else if (result?.type === 'Redirect') {
54
+ context.response.body = { redirectTo: result.path };
55
+ }
56
+ else if (result?.type === 'File') {
57
+ context.response.attachment(result.name);
58
+ context.response.set('Access-Control-Expose-Headers', 'Content-Disposition');
59
+ context.response.type = result.mimeType;
60
+ context.response.body = result.stream;
61
+ }
62
+ else {
63
+ throw new Error('Unexpected Action result.');
64
+ }
65
+ }
66
+ async handleHook(context) {
67
+ await this.checkPermissions(context);
68
+ const { dataSource } = this.collection;
69
+ const forestFields = context.request.body?.data?.attributes?.fields;
70
+ const data = forestFields
71
+ ? action_values_1.default.makeFormDataFromFields(dataSource, forestFields)
72
+ : null;
73
+ const filter = await this.getRecordSelection(context);
74
+ const fields = await this.collection.getForm(this.actionName, data, filter);
75
+ context.response.body = {
76
+ fields: fields.map(field => generator_actions_1.default.buildFieldSchema(this.collection.dataSource, field)),
77
+ };
78
+ }
79
+ async checkPermissions(context) {
80
+ await this.services.permissions.can(context, `custom:${this.actionName}:${this.collection.name}`);
81
+ }
82
+ async getRecordSelection(context) {
83
+ const selectionIds = body_parser_1.default.parseSelectionIds(this.collection.schema, context);
84
+ let selectedIds = datasource_toolkit_1.ConditionTreeFactory.matchIds(this.collection.schema, selectionIds.ids);
85
+ if (selectionIds.areExcluded)
86
+ selectedIds = selectedIds.inverse();
87
+ const conditionTree = datasource_toolkit_1.ConditionTreeFactory.intersect(selectedIds, query_string_1.default.parseConditionTree(this.collection, context), await this.services.permissions.getScope(this.collection, context));
88
+ const filter = context_filter_factory_1.default.build(this.collection, context, null, { conditionTree });
89
+ const attributes = context.request?.body?.data?.attributes;
90
+ if (attributes?.parent_association_name) {
91
+ return this.applyActionOnlyOnRelation(attributes, filter);
92
+ }
93
+ return filter;
94
+ }
95
+ applyActionOnlyOnRelation(attributes, filter) {
96
+ const relation = attributes?.parent_association_name;
97
+ const parentCollection = this.dataSource.getCollection(attributes.parent_collection_name);
98
+ const parentId = id_1.default.unpackId(parentCollection.schema, attributes.parent_collection_id);
99
+ return datasource_toolkit_1.FilterFactory.makeForeignFilter(parentCollection, parentId, relation, filter);
100
+ }
101
+ }
102
+ exports.default = ActionRoute;
103
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FnZW50L3JvdXRlcy9tb2RpZmljYXRpb24vYWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBTXlDO0FBSXpDLHVDQUFpRTtBQUVqRSwwRUFBaUQ7QUFDakQsMkVBQWtEO0FBQ2xELGdHQUFzRTtBQUN0RSw0RkFBMkU7QUFDM0Usd0RBQXFDO0FBQ3JDLDRFQUF5RDtBQUN6RCxvR0FBaUY7QUFFakYsTUFBcUIsV0FBWSxTQUFRLDBCQUFlO0lBR3RELFlBQ0UsUUFBdUMsRUFDdkMsT0FBaUMsRUFDakMsVUFBc0IsRUFDdEIsY0FBc0IsRUFDdEIsVUFBa0I7UUFFbEIsS0FBSyxDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBQ3JELElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO0lBQy9CLENBQUM7SUFFRCxXQUFXLENBQUMsTUFBYztRQUN4QixNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDekYsTUFBTSxJQUFJLEdBQUcsYUFBYSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUVoRSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxRQUFRLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUM1RCxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxtQkFBbUIsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3BFLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJ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
@@ -0,0 +1,12 @@
1
+ /// <reference types="koa__router" />
2
+ import { CompositeId, ConditionTree, ManyToManySchema, OneToManySchema } from '@forestadmin/datasource-toolkit';
3
+ import { Context } from 'koa';
4
+ import Router from '@koa/router';
5
+ import RelationRoute from '../relation-route';
6
+ export default class AssociateRelatedRoute extends RelationRoute {
7
+ setupRoutes(router: Router): void;
8
+ handleAssociateRelatedRoute(context: Context): Promise<void>;
9
+ associateOneToMany(scope: ConditionTree, relation: OneToManySchema, parentId: CompositeId, targetedRelationId: CompositeId, context: Context): Promise<void>;
10
+ associateManyToMany(relation: ManyToManySchema, parentId: CompositeId, targetedRelationId: CompositeId): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=associate-related.d.ts.map
@@ -0,0 +1,49 @@
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
+ const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
7
+ const types_1 = require("../../types");
8
+ const context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
9
+ const id_1 = __importDefault(require("../../utils/id"));
10
+ const relation_route_1 = __importDefault(require("../relation-route"));
11
+ class AssociateRelatedRoute extends relation_route_1.default {
12
+ setupRoutes(router) {
13
+ router.post(`/${this.collection.name}/:parentId/relationships/${this.relationName}`, this.handleAssociateRelatedRoute.bind(this));
14
+ }
15
+ async handleAssociateRelatedRoute(context) {
16
+ await this.services.permissions.can(context, `edit:${this.collection.name}`);
17
+ const parentId = id_1.default.unpackId(this.collection.schema, context.params.parentId);
18
+ const targetedRelationId = id_1.default.unpackId(this.foreignCollection.schema, context.request.body?.data[0].id);
19
+ const scope = await this.services.permissions.getScope(this.foreignCollection, context);
20
+ const relation = datasource_toolkit_1.SchemaUtils.getToManyRelation(this.collection.schema, this.relationName);
21
+ if (relation.type === 'OneToMany') {
22
+ await this.associateOneToMany(scope, relation, parentId, targetedRelationId, context);
23
+ }
24
+ else {
25
+ await this.associateManyToMany(relation, parentId, targetedRelationId);
26
+ }
27
+ context.response.status = types_1.HttpCode.NoContent;
28
+ }
29
+ async associateOneToMany(scope, relation, parentId, targetedRelationId, context) {
30
+ const [id] = datasource_toolkit_1.SchemaUtils.getPrimaryKeys(this.foreignCollection.schema);
31
+ let value = await datasource_toolkit_1.CollectionUtils.getValue(this.foreignCollection, targetedRelationId, id);
32
+ const filter = context_filter_factory_1.default.build(this.collection, context, scope, {
33
+ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(new datasource_toolkit_1.ConditionTreeLeaf(id, 'Equal', value), scope),
34
+ });
35
+ value = await datasource_toolkit_1.CollectionUtils.getValue(this.collection, parentId, relation.originKeyTarget);
36
+ await this.foreignCollection.update(filter, { [relation.originKey]: value });
37
+ }
38
+ async associateManyToMany(relation, parentId, targetedRelationId) {
39
+ let [id] = datasource_toolkit_1.SchemaUtils.getPrimaryKeys(this.foreignCollection.schema);
40
+ const foreign = await datasource_toolkit_1.CollectionUtils.getValue(this.foreignCollection, targetedRelationId, id);
41
+ [id] = datasource_toolkit_1.SchemaUtils.getPrimaryKeys(this.collection.schema);
42
+ const origin = await datasource_toolkit_1.CollectionUtils.getValue(this.collection, parentId, id);
43
+ const record = { [relation.originKey]: origin, [relation.foreignKey]: foreign };
44
+ const throughCollection = this.dataSource.getCollection(relation.throughCollection);
45
+ await throughCollection.create([record]);
46
+ }
47
+ }
48
+ exports.default = AssociateRelatedRoute;
49
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzb2NpYXRlLXJlbGF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYWdlbnQvcm91dGVzL21vZGlmaWNhdGlvbi9hc3NvY2lhdGUtcmVsYXRlZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHdFQVN5QztBQUl6Qyx1Q0FBdUM7QUFDdkMsZ0dBQXNFO0FBQ3RFLHdEQUFxQztBQUNyQyx1RUFBOEM7QUFFOUMsTUFBcUIscUJBQXNCLFNBQVEsd0JBQWE7SUFDOUQsV0FBVyxDQUFDLE1BQWM7UUFDeEIsTUFBTSxDQUFDLElBQUksQ0FDVCxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSw0QkFBNEIsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUN2RSxJQUFJLENBQUMsMkJBQTJCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUM1QyxDQUFDO0lBQ0osQ0FBQztJQUVNLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxPQUFnQjtRQUN2RCxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFDN0UsTUFBTSxRQUFRLEdBQUcsWUFBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ25GLE1BQU0sa0JBQWtCLEdBQUcsWUFBTyxDQUFDLFFBQVEsQ0FDekMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sRUFDN0IsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FDakMsQ0FBQztRQUNGLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxp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
@@ -0,0 +1,14 @@
1
+ /// <reference types="koa__router" />
2
+ import { Context } from 'koa';
3
+ import Router from '@koa/router';
4
+ import CollectionRoute from '../collection-route';
5
+ export default class CreateRoute extends CollectionRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleCreate(context: Context): Promise<void>;
8
+ private makeRecord;
9
+ private createRecord;
10
+ private linkOneToOneRelations;
11
+ private getRelationRecord;
12
+ private getManyToOneTarget;
13
+ }
14
+ //# sourceMappingURL=create.d.ts.map
@@ -0,0 +1,81 @@
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
+ const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
7
+ const collection_route_1 = __importDefault(require("../collection-route"));
8
+ const query_string_1 = __importDefault(require("../../utils/query-string"));
9
+ class CreateRoute extends collection_route_1.default {
10
+ setupRoutes(router) {
11
+ router.post(`/${this.collection.name}`, this.handleCreate.bind(this));
12
+ }
13
+ async handleCreate(context) {
14
+ await this.services.permissions.can(context, `add:${this.collection.name}`);
15
+ const { serializer } = this.services;
16
+ const rawRecord = serializer.deserialize(this.collection, context.request.body);
17
+ const [record, relations] = await this.makeRecord(rawRecord);
18
+ const newRecord = await this.createRecord(record);
19
+ await this.linkOneToOneRelations(context, newRecord, relations);
20
+ context.response.body = serializer.serialize(this.collection, { ...newRecord, ...relations });
21
+ }
22
+ async makeRecord(record) {
23
+ const patch = {};
24
+ const relations = {};
25
+ const promises = Object.entries(record).map(async ([field, value]) => {
26
+ const schema = this.collection.schema.fields[field];
27
+ if (schema?.type === 'OneToOne' || schema?.type === 'ManyToOne') {
28
+ relations[field] = this.getRelationRecord(field, value);
29
+ }
30
+ if (schema?.type === 'ManyToOne') {
31
+ patch[schema.foreignKey] = await this.getManyToOneTarget(field, value);
32
+ }
33
+ if (schema?.type === 'Column') {
34
+ patch[field] = value;
35
+ }
36
+ });
37
+ await Promise.all(promises);
38
+ return [patch, relations];
39
+ }
40
+ async createRecord(patch) {
41
+ if (Object.keys(patch).length) {
42
+ datasource_toolkit_1.RecordValidator.validate(this.collection, patch);
43
+ }
44
+ const [record] = await this.collection.create([patch]);
45
+ return record;
46
+ }
47
+ async linkOneToOneRelations(context, record, relations) {
48
+ const timezone = query_string_1.default.parseTimezone(context);
49
+ const promises = Object.entries(relations).map(async ([field, linked]) => {
50
+ const relation = this.collection.schema.fields[field];
51
+ if (relation.type !== 'OneToOne')
52
+ return;
53
+ // Permissions
54
+ const foreignCollection = this.dataSource.getCollection(relation.foreignCollection);
55
+ const scope = await this.services.permissions.getScope(foreignCollection, context);
56
+ await this.services.permissions.can(context, `edit:${this.collection.name}`);
57
+ // Load the value that will be used as originKey (=== parentId[0] most of the time)
58
+ const originValue = record[relation.originKeyTarget];
59
+ // Break old relation (may update zero or one records).
60
+ const oldFkOwner = new datasource_toolkit_1.ConditionTreeLeaf(relation.originKey, 'Equal', originValue);
61
+ await foreignCollection.update(new datasource_toolkit_1.Filter({ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(oldFkOwner, scope), timezone }), { [relation.originKey]: null });
62
+ // Create new relation (will update exactly one record).
63
+ const newFkOwner = datasource_toolkit_1.ConditionTreeFactory.matchRecords(foreignCollection.schema, [linked]);
64
+ await foreignCollection.update(new datasource_toolkit_1.Filter({ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(newFkOwner, scope), timezone }), { [relation.originKey]: originValue });
65
+ });
66
+ await Promise.all(promises);
67
+ }
68
+ getRelationRecord(field, id) {
69
+ const schema = this.collection.schema.fields[field];
70
+ const foreignCollection = this.dataSource.getCollection(schema.foreignCollection);
71
+ const pkName = datasource_toolkit_1.SchemaUtils.getPrimaryKeys(foreignCollection.schema);
72
+ return pkName.reduce((memo, key, index) => ({ ...memo, [key]: id[index] }), {});
73
+ }
74
+ async getManyToOneTarget(field, id) {
75
+ const schema = this.collection.schema.fields[field];
76
+ const foreignCollection = this.dataSource.getCollection(schema.foreignCollection);
77
+ return datasource_toolkit_1.CollectionUtils.getValue(foreignCollection, id, schema.foreignKeyTarget);
78
+ }
79
+ }
80
+ exports.default = CreateRoute;
81
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FnZW50L3JvdXRlcy9tb2RpZmljYXRpb24vY3JlYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBV3lDO0FBSXpDLDJFQUFrRDtBQUNsRCw0RUFBeUQ7QUFFekQsTUFBcUIsV0FBWSxTQUFRLDBCQUFlO0lBQ3RELFdBQVcsQ0FBQyxNQUFjO1FBQ3hCLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUVNLEtBQUssQ0FBQyxZQUFZLENBQUMsT0FBZ0I7UUFDeEMsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBRTVFLE1BQU0sRUFBRSxVQUFVLEVBQUUsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDO1FBQ3JDLE1BQU0sU0FBUyxHQUFHLFVBQVUsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWhGLE1BQU0sQ0FBQyxNQUFNLEVBQUUsU0FBUyxDQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzdELE1BQU0sU0FBUyxHQUFHLE1BQU0sSUFBSSxDQUFDLFlBQVksQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUVsRCxNQUFNLElBQUksQ0FBQyxxQkFBcUIsQ0FBQyxPQUFPLEVBQUUsU0FBUyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBRWhFLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxHQUFHLFVBQVUsQ0FBQyxTQUFT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
@@ -0,0 +1,11 @@
1
+ /// <reference types="koa__router" />
2
+ import { Context } from 'koa';
3
+ import Router from '@koa/router';
4
+ import CollectionRoute from '../collection-route';
5
+ export default class DeleteRoute extends CollectionRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleDelete(context: Context): Promise<void>;
8
+ handleListDelete(context: Context): Promise<void>;
9
+ private deleteRecords;
10
+ }
11
+ //# sourceMappingURL=delete.d.ts.map
@@ -0,0 +1,40 @@
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
+ const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
7
+ const types_1 = require("../../types");
8
+ const body_parser_1 = __importDefault(require("../../utils/body-parser"));
9
+ const collection_route_1 = __importDefault(require("../collection-route"));
10
+ const context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
11
+ const id_1 = __importDefault(require("../../utils/id"));
12
+ const query_string_1 = __importDefault(require("../../utils/query-string"));
13
+ class DeleteRoute extends collection_route_1.default {
14
+ setupRoutes(router) {
15
+ router.delete(`/${this.collection.name}`, this.handleListDelete.bind(this));
16
+ router.delete(`/${this.collection.name}/:id`, this.handleDelete.bind(this));
17
+ }
18
+ async handleDelete(context) {
19
+ await this.services.permissions.can(context, `delete:${this.collection.name}`);
20
+ const id = id_1.default.unpackId(this.collection.schema, context.params.id);
21
+ await this.deleteRecords(context, { ids: [id], areExcluded: false });
22
+ context.response.status = types_1.HttpCode.NoContent;
23
+ }
24
+ async handleListDelete(context) {
25
+ const selectionIds = body_parser_1.default.parseSelectionIds(this.collection.schema, context);
26
+ await this.deleteRecords(context, selectionIds);
27
+ context.response.status = types_1.HttpCode.NoContent;
28
+ }
29
+ async deleteRecords(context, selectionIds) {
30
+ let selectedIds = datasource_toolkit_1.ConditionTreeFactory.matchIds(this.collection.schema, selectionIds.ids);
31
+ if (selectionIds.areExcluded)
32
+ selectedIds = selectedIds.inverse();
33
+ const filter = context_filter_factory_1.default.build(this.collection, context, null, {
34
+ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(query_string_1.default.parseConditionTree(this.collection, context), await this.services.permissions.getScope(this.collection, context), selectedIds),
35
+ });
36
+ await this.collection.delete(filter);
37
+ }
38
+ }
39
+ exports.default = DeleteRoute;
40
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVsZXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FnZW50L3JvdXRlcy9tb2RpZmljYXRpb24vZGVsZXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBQXVFO0FBSXZFLHVDQUFxRDtBQUNyRCwwRUFBaUQ7QUFDakQsMkVBQWtEO0FBQ2xELGdHQUFzRTtBQUN0RSx3REFBcUM7QUFDckMsNEVBQXlEO0FBRXpELE1BQXFCLFdBQVksU0FBUSwwQkFBZTtJQUN0RCxXQUFXLENBQUMsTUFBYztRQUN4QixNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDNUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxNQUFNLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUM5RSxDQUFDO0lBRU0sS0FBSyxDQUFDLFlBQVksQ0FBQyxPQUFnQjtRQUN4QyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFL0UsTUFBTSxFQUFFLEdBQUcsWUFBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZFLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxPQUFPLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUVyRSxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxnQkFBUSxDQUFDLFNBQVMsQ0FBQztJQUMvQyxDQUFDO0lBRU0sS0FBSyxDQUFDLGdCQUFnQixDQUFDLE9BQWdCO1FBQzVDLE1BQU0sWUFBWSxHQUFHLHFCQUFVLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDbkYsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQztRQUVoRCxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxnQkFBUSxDQUFDLFNBQVMsQ0FBQztJQUMvQyxDQUFDO0lBRU8sS0FBSyxDQUFDLGFBQWEsQ0FBQyxPQUFnQixFQUFFLFlBQTBCO1FBQ3RFLElBQUksV0FBVyxHQUFHLHlDQUFvQixDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDMUYsSUFBSSxZQUFZLENBQUMsV0FBVztZQUFFLFdBQVcsR0FBRyxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFbEUsTUFBTSxNQUFNLEdBQUcsZ0NBQW9CLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRTtZQUN4RSxhQUFhLEVBQUUseUNBQW9CLENBQUMsU0FBUyxDQUMzQyxzQkFBaUIsQ0FBQyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxFQUM5RCxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxFQUNsRSxXQUFXLENBQ1o7U0FDRixDQUFDLENBQUM7UUFFSCxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7Q0FDRjtBQXBDRCw4QkFvQ0MifQ==
@@ -0,0 +1,20 @@
1
+ /// <reference types="koa__router" />
2
+ import { Context } from 'koa';
3
+ import Router from '@koa/router';
4
+ import RelationRoute from '../relation-route';
5
+ export default class DissociateDeleteRelatedRoute extends RelationRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleDissociateDeleteRelatedRoute(context: Context): Promise<void>;
8
+ private dissociateOrDeleteOneToMany;
9
+ private dissociateOrDeleteManyToMany;
10
+ /**
11
+ * Match selected records in the related data panel.
12
+ * The filter that is generated by this condition it _not_ restricted by the parent record
13
+ */
14
+ private getBaseForeignFilter;
15
+ /** Wrapper around the util to simplify the call */
16
+ private makeForeignFilter;
17
+ /** Wrapper around the util to simplify the call */
18
+ private makeThroughFilter;
19
+ }
20
+ //# sourceMappingURL=dissociate-delete-related.d.ts.map
@@ -0,0 +1,88 @@
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
+ const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
7
+ const types_1 = require("../../types");
8
+ const body_parser_1 = __importDefault(require("../../utils/body-parser"));
9
+ const context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
10
+ const id_1 = __importDefault(require("../../utils/id"));
11
+ const query_string_1 = __importDefault(require("../../utils/query-string"));
12
+ const relation_route_1 = __importDefault(require("../relation-route"));
13
+ class DissociateDeleteRelatedRoute extends relation_route_1.default {
14
+ setupRoutes(router) {
15
+ router.delete(`/${this.collection.name}/:parentId/relationships/${this.relationName}`, this.handleDissociateDeleteRelatedRoute.bind(this));
16
+ }
17
+ async handleDissociateDeleteRelatedRoute(context) {
18
+ await this.services.permissions.can(context, `delete:${this.collection.name}`);
19
+ // Parse route params
20
+ const parentId = id_1.default.unpackId(this.collection.schema, context.params.parentId);
21
+ const isDeleteMode = Boolean(context.request.query?.delete);
22
+ const filter = await this.getBaseForeignFilter(context);
23
+ // Dissociating a one to many or many many is quite a different job => delegate
24
+ const relation = datasource_toolkit_1.SchemaUtils.getToManyRelation(this.collection.schema, this.relationName);
25
+ if (relation.type === 'OneToMany') {
26
+ await this.dissociateOrDeleteOneToMany(relation, parentId, isDeleteMode, filter);
27
+ }
28
+ else {
29
+ await this.dissociateOrDeleteManyToMany(relation, parentId, isDeleteMode, filter);
30
+ }
31
+ context.response.status = types_1.HttpCode.NoContent;
32
+ }
33
+ async dissociateOrDeleteOneToMany(schema, parentId, isDeleteMode, baseTargetFilter) {
34
+ // Restrict baseTargetFilter to match only records under the parent record
35
+ const foreignFilter = await this.makeForeignFilter(parentId, baseTargetFilter);
36
+ if (isDeleteMode) {
37
+ await this.foreignCollection.delete(foreignFilter);
38
+ }
39
+ else {
40
+ await this.foreignCollection.update(foreignFilter, { [schema.originKey]: null });
41
+ }
42
+ }
43
+ async dissociateOrDeleteManyToMany(schema, parentId, isDeleteMode, baseTargetFilter) {
44
+ const throughCollection = this.collection.dataSource.getCollection(schema.throughCollection);
45
+ if (isDeleteMode) {
46
+ // Generate filters _BEFORE_ deleting stuff, otherwise things break.
47
+ const throughFilter = await this.makeThroughFilter(parentId, baseTargetFilter);
48
+ const foreignFilter = await this.makeForeignFilter(parentId, baseTargetFilter);
49
+ // Delete records from through collection
50
+ await throughCollection.delete(throughFilter);
51
+ // Let the datasource crash when:
52
+ // - the records in the foreignCollection are linked to other records in the origin collection
53
+ // - the underlying database/api is not cascading deletes
54
+ await this.foreignCollection.delete(foreignFilter);
55
+ }
56
+ else {
57
+ // Only delete records from through collection
58
+ const thoughFilter = await this.makeThroughFilter(parentId, baseTargetFilter);
59
+ await throughCollection.delete(thoughFilter);
60
+ }
61
+ }
62
+ /**
63
+ * Match selected records in the related data panel.
64
+ * The filter that is generated by this condition it _not_ restricted by the parent record
65
+ */
66
+ async getBaseForeignFilter(context) {
67
+ const selectionIds = body_parser_1.default.parseSelectionIds(this.foreignCollection.schema, context);
68
+ let selectedIds = datasource_toolkit_1.ConditionTreeFactory.matchIds(this.foreignCollection.schema, selectionIds.ids);
69
+ if (selectionIds.areExcluded)
70
+ selectedIds = selectedIds.inverse();
71
+ if (selectionIds.ids.length === 0 && !selectionIds.areExcluded) {
72
+ throw new datasource_toolkit_1.ValidationError('Expected no empty id list');
73
+ }
74
+ return context_filter_factory_1.default.build(this.foreignCollection, context, null, {
75
+ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(await this.services.permissions.getScope(this.foreignCollection, context), query_string_1.default.parseConditionTree(this.foreignCollection, context), selectedIds),
76
+ });
77
+ }
78
+ /** Wrapper around the util to simplify the call */
79
+ makeForeignFilter(parentId, baseForeignFilter) {
80
+ return datasource_toolkit_1.FilterFactory.makeForeignFilter(this.collection, parentId, this.relationName, baseForeignFilter);
81
+ }
82
+ /** Wrapper around the util to simplify the call */
83
+ makeThroughFilter(parentId, baseForeignFilter) {
84
+ return datasource_toolkit_1.FilterFactory.makeThroughFilter(this.collection, parentId, this.relationName, baseForeignFilter);
85
+ }
86
+ }
87
+ exports.default = DissociateDeleteRelatedRoute;
88
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzc29jaWF0ZS1kZWxldGUtcmVsYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hZ2VudC9yb3V0ZXMvbW9kaWZpY2F0aW9uL2Rpc3NvY2lhdGUtZGVsZXRlLXJlbGF0ZWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx3RUFTeUM7QUFJekMsdUNBQXVDO0FBQ3ZDLDBFQUFpRDtBQUNqRCxnR0FBc0U7QUFDdEUsd0RBQXFDO0FBQ3JDLDRFQUF5RDtBQUN6RCx1RUFBOEM7QUFFOUMsTUFBcUIsNEJBQTZCLFNBQVEsd0JBQWE7SUFDckUsV0FBVyxDQUFDLE1BQWM7UUFDeEIsTUFBTSxDQUFDLE1BQU0sQ0FDWCxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSw0QkFBNEIsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUN2RSxJQUFJLENBQUMsa0NBQWtDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUNuRCxDQUFDO0lBQ0osQ0FBQztJQUVNLEtBQUssQ0FBQyxrQ0FBa0MsQ0FBQyxPQUFnQjtRQUM5RCxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFL0UscUJBQXFCO1FBQ3JCLE1BQU0sUUFBUSxHQUFHLFlBQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNuRixNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDNUQsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsb0JBQW9CLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFeEQsK0VBQStFO1FBQy9FLE1BQU0sUUFBUSxH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
@@ -0,0 +1,11 @@
1
+ /// <reference types="koa__router" />
2
+ import { Context } from 'koa';
3
+ import Router from '@koa/router';
4
+ import RelationRoute from '../relation-route';
5
+ export default class UpdateRelation extends RelationRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleUpdateRelationRoute(context: Context): Promise<void>;
8
+ private updateManyToOne;
9
+ private updateOneToOne;
10
+ }
11
+ //# sourceMappingURL=update-relation.d.ts.map