@forestadmin/agent 1.0.0-beta.6 → 1.0.0-beta.61

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 (151) hide show
  1. package/dist/agent.d.ts +76 -0
  2. package/dist/agent.js +133 -0
  3. package/dist/framework-mounter.d.ts +43 -0
  4. package/dist/framework-mounter.js +157 -0
  5. package/dist/index.d.ts +7 -4
  6. package/dist/index.js +10 -17
  7. package/dist/routes/access/api-chart.d.ts +16 -0
  8. package/dist/routes/access/api-chart.js +47 -0
  9. package/dist/{agent/routes → routes}/access/chart.d.ts +1 -0
  10. package/dist/routes/access/chart.js +162 -0
  11. package/dist/{agent/routes → routes}/access/count-related.d.ts +0 -0
  12. package/dist/routes/access/count-related.js +31 -0
  13. package/dist/{agent/routes → routes}/access/count.d.ts +0 -0
  14. package/dist/routes/access/count.js +31 -0
  15. package/dist/{agent/routes → routes}/access/csv-related.d.ts +0 -0
  16. package/dist/routes/access/csv-related.js +33 -0
  17. package/dist/{agent/routes → routes}/access/csv.d.ts +0 -0
  18. package/dist/routes/access/csv.js +31 -0
  19. package/dist/{agent/routes → routes}/access/get.d.ts +0 -0
  20. package/dist/routes/access/get.js +29 -0
  21. package/dist/{agent/routes → routes}/access/list-related.d.ts +0 -0
  22. package/dist/routes/access/list-related.js +25 -0
  23. package/dist/{agent/routes → routes}/access/list.d.ts +0 -0
  24. package/dist/routes/access/list.js +22 -0
  25. package/dist/{agent/routes → routes}/base-route.d.ts +0 -1
  26. package/dist/routes/base-route.js +13 -0
  27. package/dist/{agent/routes → routes}/collection-route.d.ts +0 -0
  28. package/dist/{agent/routes → routes}/collection-route.js +1 -1
  29. package/dist/{agent/routes → routes}/index.d.ts +0 -0
  30. package/dist/routes/index.js +108 -0
  31. package/dist/{agent/routes → routes}/modification/action.d.ts +0 -1
  32. package/dist/routes/modification/action.js +104 -0
  33. package/dist/routes/modification/associate-related.d.ts +12 -0
  34. package/dist/routes/modification/associate-related.js +51 -0
  35. package/dist/{agent/routes → routes}/modification/create.d.ts +0 -0
  36. package/dist/routes/modification/create.js +83 -0
  37. package/dist/{agent/routes → routes}/modification/delete.d.ts +0 -0
  38. package/dist/routes/modification/delete.js +41 -0
  39. package/dist/{agent/routes → routes}/modification/dissociate-delete-related.d.ts +0 -0
  40. package/dist/routes/modification/dissociate-delete-related.js +89 -0
  41. package/dist/routes/modification/update-field.d.ts +9 -0
  42. package/dist/routes/modification/update-field.js +39 -0
  43. package/dist/{agent/routes → routes}/modification/update-relation.d.ts +0 -0
  44. package/dist/routes/modification/update-relation.js +59 -0
  45. package/dist/{agent/routes → routes}/modification/update.d.ts +0 -0
  46. package/dist/routes/modification/update.js +31 -0
  47. package/dist/{agent/routes → routes}/relation-route.d.ts +0 -0
  48. package/dist/{agent/routes → routes}/relation-route.js +1 -1
  49. package/dist/{agent/routes → routes}/security/authentication.d.ts +1 -3
  50. package/dist/routes/security/authentication.js +74 -0
  51. package/dist/{agent/routes → routes}/security/ip-whitelist.d.ts +0 -0
  52. package/dist/{agent/routes → routes}/security/ip-whitelist.js +1 -1
  53. package/dist/{agent/routes → routes}/security/scope-invalidation.d.ts +0 -0
  54. package/dist/{agent/routes → routes}/security/scope-invalidation.js +1 -1
  55. package/dist/{agent/routes → routes}/system/error-handling.d.ts +2 -0
  56. package/dist/routes/system/error-handling.js +75 -0
  57. package/dist/{agent/routes → routes}/system/healthcheck.d.ts +0 -0
  58. package/dist/{agent/routes → routes}/system/healthcheck.js +1 -1
  59. package/dist/{agent/routes → routes}/system/logger.d.ts +0 -0
  60. package/dist/routes/system/logger.js +35 -0
  61. package/dist/{agent/services → services}/index.d.ts +0 -0
  62. package/dist/{agent/services → services}/index.js +2 -2
  63. package/dist/{agent/services → services}/permissions.d.ts +0 -0
  64. package/dist/services/permissions.js +85 -0
  65. package/dist/{agent/services → services}/serializer.d.ts +0 -5
  66. package/dist/services/serializer.js +120 -0
  67. package/dist/types.d.ts +29 -10
  68. package/dist/types.js +21 -9
  69. package/dist/{agent/utils → utils}/body-parser.d.ts +0 -0
  70. package/dist/{agent/utils → utils}/body-parser.js +1 -1
  71. package/dist/utils/condition-tree-parser.d.ts +11 -0
  72. package/dist/utils/condition-tree-parser.js +53 -0
  73. package/dist/{agent/utils → utils}/context-filter-factory.d.ts +0 -0
  74. package/dist/{agent/utils → utils}/context-filter-factory.js +1 -2
  75. package/dist/{agent/utils → utils}/csv-generator.d.ts +2 -2
  76. package/dist/utils/csv-generator.js +39 -0
  77. package/dist/{agent/utils → utils}/csv-route-context.d.ts +0 -0
  78. package/dist/utils/csv-route-context.js +14 -0
  79. package/dist/{agent/utils → utils}/forest-http-api.d.ts +5 -3
  80. package/dist/utils/forest-http-api.js +180 -0
  81. package/dist/{agent/utils → utils}/forest-schema/action-values.d.ts +2 -2
  82. package/dist/utils/forest-schema/action-values.js +144 -0
  83. package/dist/{agent/utils → utils}/forest-schema/emitter.d.ts +2 -2
  84. package/dist/utils/forest-schema/emitter.js +70 -0
  85. package/dist/{agent/utils → utils}/forest-schema/filterable.d.ts +0 -0
  86. package/dist/{agent/utils → utils}/forest-schema/filterable.js +1 -1
  87. package/dist/{agent/utils → utils}/forest-schema/generator-actions.d.ts +1 -1
  88. package/dist/utils/forest-schema/generator-actions.js +99 -0
  89. package/dist/{agent/utils → utils}/forest-schema/generator-collection.d.ts +1 -1
  90. package/dist/utils/forest-schema/generator-collection.js +36 -0
  91. package/dist/{agent/utils → utils}/forest-schema/generator-fields.d.ts +1 -0
  92. package/dist/utils/forest-schema/generator-fields.js +160 -0
  93. package/dist/{agent/utils → utils}/forest-schema/generator-segments.d.ts +0 -0
  94. package/dist/{agent/utils → utils}/forest-schema/generator-segments.js +1 -1
  95. package/dist/{agent/utils → utils}/forest-schema/types.d.ts +10 -4
  96. package/dist/{agent/utils → utils}/forest-schema/types.js +1 -1
  97. package/dist/{agent/utils → utils}/forest-schema/validation.d.ts +1 -1
  98. package/dist/utils/forest-schema/validation.js +28 -0
  99. package/dist/{agent/utils → utils}/id.d.ts +0 -0
  100. package/dist/utils/id.js +43 -0
  101. package/dist/{agent/utils/http-driver-options.d.ts → utils/options-validator.d.ts} +4 -5
  102. package/dist/utils/options-validator.js +92 -0
  103. package/dist/{agent/utils → utils}/query-string.d.ts +2 -2
  104. package/dist/utils/query-string.js +134 -0
  105. package/package.json +16 -5
  106. package/CHANGELOG.md +0 -435
  107. package/dist/agent/forestadmin-http-driver.d.ts +0 -34
  108. package/dist/agent/forestadmin-http-driver.js +0 -73
  109. package/dist/agent/routes/access/chart.js +0 -147
  110. package/dist/agent/routes/access/count-related.js +0 -24
  111. package/dist/agent/routes/access/count.js +0 -24
  112. package/dist/agent/routes/access/csv-related.js +0 -33
  113. package/dist/agent/routes/access/csv.js +0 -30
  114. package/dist/agent/routes/access/get.js +0 -28
  115. package/dist/agent/routes/access/list-related.js +0 -26
  116. package/dist/agent/routes/access/list.js +0 -23
  117. package/dist/agent/routes/base-route.js +0 -16
  118. package/dist/agent/routes/index.js +0 -90
  119. package/dist/agent/routes/modification/action.js +0 -103
  120. package/dist/agent/routes/modification/associate-related.d.ts +0 -12
  121. package/dist/agent/routes/modification/associate-related.js +0 -49
  122. package/dist/agent/routes/modification/create.js +0 -81
  123. package/dist/agent/routes/modification/delete.js +0 -40
  124. package/dist/agent/routes/modification/dissociate-delete-related.js +0 -88
  125. package/dist/agent/routes/modification/update-relation.js +0 -53
  126. package/dist/agent/routes/modification/update.js +0 -29
  127. package/dist/agent/routes/security/authentication.js +0 -86
  128. package/dist/agent/routes/system/error-handling.js +0 -56
  129. package/dist/agent/routes/system/logger.js +0 -36
  130. package/dist/agent/services/permissions.js +0 -79
  131. package/dist/agent/services/serializer.js +0 -120
  132. package/dist/agent/types.d.ts +0 -23
  133. package/dist/agent/types.js +0 -22
  134. package/dist/agent/utils/csv-generator.js +0 -39
  135. package/dist/agent/utils/csv-route-context.js +0 -14
  136. package/dist/agent/utils/forest-http-api.js +0 -173
  137. package/dist/agent/utils/forest-schema/action-values.js +0 -144
  138. package/dist/agent/utils/forest-schema/emitter.js +0 -70
  139. package/dist/agent/utils/forest-schema/generator-actions.js +0 -99
  140. package/dist/agent/utils/forest-schema/generator-collection.js +0 -31
  141. package/dist/agent/utils/forest-schema/generator-fields.js +0 -131
  142. package/dist/agent/utils/forest-schema/validation.js +0 -26
  143. package/dist/agent/utils/http-driver-options.js +0 -86
  144. package/dist/agent/utils/id.js +0 -43
  145. package/dist/agent/utils/query-string.js +0 -130
  146. package/dist/builder/agent.d.ts +0 -81
  147. package/dist/builder/agent.js +0 -113
  148. package/dist/builder/collection.d.ts +0 -148
  149. package/dist/builder/collection.js +0 -226
  150. package/dist/builder/types.d.ts +0 -5
  151. package/dist/builder/types.js +0 -3
@@ -0,0 +1,104 @@
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 caller = query_string_1.default.parseCaller(context);
31
+ const filter = await this.getRecordSelection(context);
32
+ const rawData = context.request.body.data.attributes.values;
33
+ // As forms are dynamic, we don't have any way to ensure that we're parsing the data correctly
34
+ // => better send invalid data to the getForm() customer handler than to the execute() one.
35
+ const unsafeData = action_values_1.default.makeFormDataUnsafe(rawData);
36
+ const fields = await this.collection.getForm(caller, this.actionName, unsafeData, filter);
37
+ // Now that we have the field list, we can parse the data again.
38
+ const data = action_values_1.default.makeFormData(dataSource, rawData, fields);
39
+ const result = await this.collection.execute(caller, this.actionName, data, filter);
40
+ if (result?.type === 'Error') {
41
+ context.response.status = types_1.HttpCode.BadRequest;
42
+ context.response.body = { error: result.message, html: result.html };
43
+ }
44
+ else if (result?.type === 'Success') {
45
+ context.response.body = {
46
+ success: result.message,
47
+ html: result.html,
48
+ refresh: { relationships: [...result.invalidated] },
49
+ };
50
+ }
51
+ else if (result?.type === 'Webhook') {
52
+ const { url, method, headers, body } = result;
53
+ context.response.body = { webhook: { url, method, headers, body } };
54
+ }
55
+ else if (result?.type === 'Redirect') {
56
+ context.response.body = { redirectTo: result.path };
57
+ }
58
+ else if (result?.type === 'File') {
59
+ context.response.attachment(result.name);
60
+ context.response.set('Access-Control-Expose-Headers', 'Content-Disposition');
61
+ context.response.type = result.mimeType;
62
+ context.response.body = result.stream;
63
+ }
64
+ else {
65
+ throw new Error('Unexpected Action result.');
66
+ }
67
+ }
68
+ async handleHook(context) {
69
+ await this.checkPermissions(context);
70
+ const { dataSource } = this.collection;
71
+ const forestFields = context.request.body?.data?.attributes?.fields;
72
+ const data = forestFields
73
+ ? action_values_1.default.makeFormDataFromFields(dataSource, forestFields)
74
+ : null;
75
+ const caller = query_string_1.default.parseCaller(context);
76
+ const filter = await this.getRecordSelection(context);
77
+ const fields = await this.collection.getForm(caller, this.actionName, data, filter);
78
+ context.response.body = {
79
+ fields: fields.map(field => generator_actions_1.default.buildFieldSchema(this.collection.dataSource, field)),
80
+ };
81
+ }
82
+ async checkPermissions(context) {
83
+ await this.services.permissions.can(context, `custom:${this.actionName}:${this.collection.name}`);
84
+ }
85
+ async getRecordSelection(context) {
86
+ const selectionIds = body_parser_1.default.parseSelectionIds(this.collection.schema, context);
87
+ let selectedIds = datasource_toolkit_1.ConditionTreeFactory.matchIds(this.collection.schema, selectionIds.ids);
88
+ if (selectionIds.areExcluded)
89
+ selectedIds = selectedIds.inverse();
90
+ const conditionTree = datasource_toolkit_1.ConditionTreeFactory.intersect(selectedIds, query_string_1.default.parseConditionTree(this.collection, context), await this.services.permissions.getScope(this.collection, context));
91
+ const caller = query_string_1.default.parseCaller(context);
92
+ const filter = context_filter_factory_1.default.build(this.collection, context, null, { conditionTree });
93
+ const attributes = context.request?.body?.data?.attributes;
94
+ if (attributes?.parent_association_name) {
95
+ const relation = attributes?.parent_association_name;
96
+ const parentCollection = this.dataSource.getCollection(attributes.parent_collection_name);
97
+ const parentId = id_1.default.unpackId(parentCollection.schema, attributes.parent_collection_id);
98
+ return datasource_toolkit_1.FilterFactory.makeForeignFilter(parentCollection, parentId, relation, caller, filter);
99
+ }
100
+ return filter;
101
+ }
102
+ }
103
+ exports.default = ActionRoute;
104
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vYWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBS3lDO0FBSXpDLHVDQUFpRTtBQUVqRSwwRUFBaUQ7QUFDakQsMkVBQWtEO0FBQ2xELGdHQUFzRTtBQUN0RSw0RkFBMkU7QUFDM0Usd0RBQXFDO0FBQ3JDLDRFQUF5RDtBQUN6RCxvR0FBaUY7QUFFakYsTUFBcUIsV0FBWSxTQUFRLDBCQUFlO0lBR3RELFlBQ0UsUUFBdUMsRUFDdkMsT0FBaUMsRUFDakMsVUFBc0IsRUFDdEIsY0FBc0IsRUFDdEIsVUFBa0I7UUFFbEIsS0FBSyxDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLGNBQWMsQ0FBQyxDQUFDO1FBQ3JELElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO0lBQy9CLENBQUM7SUFFRCxXQUFXLENBQUMsTUFBYztRQUN4QixNQUFNLFdBQVcsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDekYsTUFBTSxJQUFJLEdBQUcsYUFBYSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksSUFBSSxXQUFXLEVBQUUsQ0FBQztRQUVoRSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxRQUFRLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUM1RCxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsSUFBSSxtQkFBbUIsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3BFLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxJQUFJLHFCQUFxQixF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
@@ -0,0 +1,12 @@
1
+ /// <reference types="koa__router" />
2
+ import { Caller, 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(caller: Caller, scope: ConditionTree, relation: OneToManySchema, parentId: CompositeId, targetedRelationId: CompositeId, context: Context): Promise<void>;
10
+ associateManyToMany(caller: Caller, relation: ManyToManySchema, parentId: CompositeId, targetedRelationId: CompositeId): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=associate-related.d.ts.map
@@ -0,0 +1,51 @@
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 query_string_1 = __importDefault(require("../../utils/query-string"));
11
+ const relation_route_1 = __importDefault(require("../relation-route"));
12
+ class AssociateRelatedRoute extends relation_route_1.default {
13
+ setupRoutes(router) {
14
+ router.post(`/${this.collection.name}/:parentId/relationships/${this.relationName}`, this.handleAssociateRelatedRoute.bind(this));
15
+ }
16
+ async handleAssociateRelatedRoute(context) {
17
+ await this.services.permissions.can(context, `edit:${this.collection.name}`);
18
+ const parentId = id_1.default.unpackId(this.collection.schema, context.params.parentId);
19
+ const targetedRelationId = id_1.default.unpackId(this.foreignCollection.schema, context.request.body?.data[0].id);
20
+ const scope = await this.services.permissions.getScope(this.foreignCollection, context);
21
+ const relation = datasource_toolkit_1.SchemaUtils.getToManyRelation(this.collection.schema, this.relationName);
22
+ const caller = query_string_1.default.parseCaller(context);
23
+ if (relation.type === 'OneToMany') {
24
+ await this.associateOneToMany(caller, scope, relation, parentId, targetedRelationId, context);
25
+ }
26
+ else {
27
+ await this.associateManyToMany(caller, relation, parentId, targetedRelationId);
28
+ }
29
+ context.response.status = types_1.HttpCode.NoContent;
30
+ }
31
+ async associateOneToMany(caller, scope, relation, parentId, targetedRelationId, context) {
32
+ const [id] = datasource_toolkit_1.SchemaUtils.getPrimaryKeys(this.foreignCollection.schema);
33
+ let value = await datasource_toolkit_1.CollectionUtils.getValue(this.foreignCollection, caller, targetedRelationId, id);
34
+ const filter = context_filter_factory_1.default.build(this.collection, context, scope, {
35
+ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(new datasource_toolkit_1.ConditionTreeLeaf(id, 'Equal', value), scope),
36
+ });
37
+ value = await datasource_toolkit_1.CollectionUtils.getValue(this.collection, caller, parentId, relation.originKeyTarget);
38
+ await this.foreignCollection.update(caller, filter, { [relation.originKey]: value });
39
+ }
40
+ async associateManyToMany(caller, relation, parentId, targetedRelationId) {
41
+ let [id] = datasource_toolkit_1.SchemaUtils.getPrimaryKeys(this.foreignCollection.schema);
42
+ const foreign = await datasource_toolkit_1.CollectionUtils.getValue(this.foreignCollection, caller, targetedRelationId, id);
43
+ [id] = datasource_toolkit_1.SchemaUtils.getPrimaryKeys(this.collection.schema);
44
+ const origin = await datasource_toolkit_1.CollectionUtils.getValue(this.collection, caller, parentId, id);
45
+ const record = { [relation.originKey]: origin, [relation.foreignKey]: foreign };
46
+ const throughCollection = this.dataSource.getCollection(relation.throughCollection);
47
+ await throughCollection.create(caller, [record]);
48
+ }
49
+ }
50
+ exports.default = AssociateRelatedRoute;
51
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYXNzb2NpYXRlLXJlbGF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvcm91dGVzL21vZGlmaWNhdGlvbi9hc3NvY2lhdGUtcmVsYXRlZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHdFQVV5QztBQUl6Qyx1Q0FBdUM7QUFDdkMsZ0dBQXNFO0FBQ3RFLHdEQUFxQztBQUNyQyw0RUFBeUQ7QUFDekQsdUVBQThDO0FBRTlDLE1BQXFCLHFCQUFzQixTQUFRLHdCQUFhO0lBQzlELFdBQVcsQ0FBQyxNQUFjO1FBQ3hCLE1BQU0sQ0FBQyxJQUFJLENBQ1QsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksNEJBQTRCLElBQUksQ0FBQyxZQUFZLEVBQUUsRUFDdkUsSUFBSSxDQUFDLDJCQUEyQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FDNUMsQ0FBQztJQUNKLENBQUM7SUFFTSxLQUFLLENBQUMsMkJBQTJCLENBQUMsT0FBZ0I7UUFDdkQsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLFFBQVEsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzdFLE1BQU0sUUFBUSxHQUFHLFlBQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNuRixNQUFNLGtCQUFrQixHQUFHLFlBQU8sQ0FBQyxRQUFRLENBQ3pDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxNQUFNLEVBQzdCLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQ2pDLENBQUM7UUFDRixNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENB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
@@ -0,0 +1,83 @@
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(context, rawRecord);
18
+ const newRecord = await this.createRecord(context, record);
19
+ await this.linkOneToOneRelations(context, newRecord, relations);
20
+ context.response.body = serializer.serialize(this.collection, { ...newRecord, ...relations });
21
+ }
22
+ async makeRecord(context, 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(context, 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(context, patch) {
41
+ const caller = query_string_1.default.parseCaller(context);
42
+ if (Object.keys(patch).length) {
43
+ datasource_toolkit_1.RecordValidator.validate(this.collection, patch);
44
+ }
45
+ const [record] = await this.collection.create(caller, [patch]);
46
+ return record;
47
+ }
48
+ async linkOneToOneRelations(context, record, relations) {
49
+ const caller = query_string_1.default.parseCaller(context);
50
+ const promises = Object.entries(relations).map(async ([field, linked]) => {
51
+ const relation = this.collection.schema.fields[field];
52
+ if (relation.type !== 'OneToOne')
53
+ return;
54
+ // Permissions
55
+ const foreignCollection = this.dataSource.getCollection(relation.foreignCollection);
56
+ const scope = await this.services.permissions.getScope(foreignCollection, context);
57
+ await this.services.permissions.can(context, `edit:${this.collection.name}`);
58
+ // Load the value that will be used as originKey (=== parentId[0] most of the time)
59
+ const originValue = record[relation.originKeyTarget];
60
+ // Break old relation (may update zero or one records).
61
+ const oldFkOwner = new datasource_toolkit_1.ConditionTreeLeaf(relation.originKey, 'Equal', originValue);
62
+ await foreignCollection.update(caller, new datasource_toolkit_1.Filter({ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(oldFkOwner, scope) }), { [relation.originKey]: null });
63
+ // Create new relation (will update exactly one record).
64
+ const newFkOwner = datasource_toolkit_1.ConditionTreeFactory.matchRecords(foreignCollection.schema, [linked]);
65
+ await foreignCollection.update(caller, new datasource_toolkit_1.Filter({ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(newFkOwner, scope) }), { [relation.originKey]: originValue });
66
+ });
67
+ await Promise.all(promises);
68
+ }
69
+ getRelationRecord(field, id) {
70
+ const schema = this.collection.schema.fields[field];
71
+ const foreignCollection = this.dataSource.getCollection(schema.foreignCollection);
72
+ const pkName = datasource_toolkit_1.SchemaUtils.getPrimaryKeys(foreignCollection.schema);
73
+ return pkName.reduce((memo, key, index) => ({ ...memo, [key]: id[index] }), {});
74
+ }
75
+ async getManyToOneTarget(context, field, id) {
76
+ const caller = query_string_1.default.parseCaller(context);
77
+ const schema = this.collection.schema.fields[field];
78
+ const foreignCollection = this.dataSource.getCollection(schema.foreignCollection);
79
+ return datasource_toolkit_1.CollectionUtils.getValue(foreignCollection, caller, id, schema.foreignKeyTarget);
80
+ }
81
+ }
82
+ exports.default = CreateRoute;
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3JlYXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vY3JlYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBV3lDO0FBSXpDLDJFQUFrRDtBQUNsRCw0RUFBeUQ7QUFFekQsTUFBcUIsV0FBWSxTQUFRLDBCQUFlO0lBQ3RELFdBQVcsQ0FBQyxNQUFjO1FBQ3hCLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxFQUFFLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUVNLEtBQUssQ0FBQyxZQUFZLENBQUMsT0FBZ0I7UUFDeEMsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBRTVFLE1BQU0sRUFBRSxVQUFVLEVBQUUsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDO1FBQ3JDLE1BQU0sU0FBUyxHQUFHLFVBQVUsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWhGLE1BQU0sQ0FBQyxNQUFNLEVBQUUsU0FBUyxDQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sRUFBRSxTQUFTLENBQUMsQ0FBQztRQUN0RSxNQUFNLFNBQVMsR0FBRyxNQUFNLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBRTNELE1BQU0sSUFBSSxDQUFDLHFCQUFxQixDQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFFaEUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEdBQUcsVUFB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
@@ -0,0 +1,41 @@
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 caller = query_string_1.default.parseCaller(context);
34
+ const filter = context_filter_factory_1.default.build(this.collection, context, null, {
35
+ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(query_string_1.default.parseConditionTree(this.collection, context), await this.services.permissions.getScope(this.collection, context), selectedIds),
36
+ });
37
+ await this.collection.delete(caller, filter);
38
+ }
39
+ }
40
+ exports.default = DeleteRoute;
41
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVsZXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vZGVsZXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBQXVFO0FBSXZFLHVDQUFxRDtBQUNyRCwwRUFBaUQ7QUFDakQsMkVBQWtEO0FBQ2xELGdHQUFzRTtBQUN0RSx3REFBcUM7QUFDckMsNEVBQXlEO0FBRXpELE1BQXFCLFdBQVksU0FBUSwwQkFBZTtJQUN0RCxXQUFXLENBQUMsTUFBYztRQUN4QixNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDNUUsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxNQUFNLEVBQUUsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUM5RSxDQUFDO0lBRU0sS0FBSyxDQUFDLFlBQVksQ0FBQyxPQUFnQjtRQUN4QyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFL0UsTUFBTSxFQUFFLEdBQUcsWUFBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3ZFLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxPQUFPLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUVyRSxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxnQkFBUSxDQUFDLFNBQVMsQ0FBQztJQUMvQyxDQUFDO0lBRU0sS0FBSyxDQUFDLGdCQUFnQixDQUFDLE9BQWdCO1FBQzVDLE1BQU0sWUFBWSxHQUFHLHFCQUFVLENBQUMsaUJBQWlCLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDbkYsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQztRQUVoRCxPQUFPLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxnQkFBUSxDQUFDLFNBQVMsQ0FBQztJQUMvQyxDQUFDO0lBRU8sS0FBSyxDQUFDLGFBQWEsQ0FBQyxPQUFnQixFQUFFLFlBQTBCO1FBQ3RFLElBQUksV0FBVyxHQUFHLHlDQUFvQixDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDMUYsSUFBSSxZQUFZLENBQUMsV0FBVztZQUFFLFdBQVcsR0FBRyxXQUFXLENBQUMsT0FBTyxFQUFFLENBQUM7UUFFbEUsTUFBTSxNQUFNLEdBQUcsc0JBQWlCLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3RELE1BQU0sTUFBTSxHQUFHLGdDQUFvQixDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUU7WUFDeEUsYUFBYSxFQUFFLHlDQUFvQixDQUFDLFNBQVMsQ0FDM0Msc0JBQWlCLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFDOUQsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsRUFDbEUsV0FBVyxDQUNaO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDL0MsQ0FBQztDQUNGO0FBckNELDhCQXFDQyJ9
@@ -0,0 +1,89 @@
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 caller = query_string_1.default.parseCaller(context);
23
+ const filter = await this.getBaseForeignFilter(context);
24
+ // Dissociating a one to many or many many is quite a different job => delegate
25
+ const relation = datasource_toolkit_1.SchemaUtils.getToManyRelation(this.collection.schema, this.relationName);
26
+ if (relation.type === 'OneToMany') {
27
+ await this.dissociateOrDeleteOneToMany(caller, relation, parentId, isDeleteMode, filter);
28
+ }
29
+ else {
30
+ await this.dissociateOrDeleteManyToMany(caller, relation, parentId, isDeleteMode, filter);
31
+ }
32
+ context.response.status = types_1.HttpCode.NoContent;
33
+ }
34
+ async dissociateOrDeleteOneToMany(caller, schema, parentId, isDeleteMode, baseTargetFilter) {
35
+ // Restrict baseTargetFilter to match only records under the parent record
36
+ const foreignFilter = await this.makeForeignFilter(caller, parentId, baseTargetFilter);
37
+ if (isDeleteMode) {
38
+ await this.foreignCollection.delete(caller, foreignFilter);
39
+ }
40
+ else {
41
+ await this.foreignCollection.update(caller, foreignFilter, { [schema.originKey]: null });
42
+ }
43
+ }
44
+ async dissociateOrDeleteManyToMany(caller, schema, parentId, isDeleteMode, baseTargetFilter) {
45
+ const throughCollection = this.collection.dataSource.getCollection(schema.throughCollection);
46
+ if (isDeleteMode) {
47
+ // Generate filters _BEFORE_ deleting stuff, otherwise things break.
48
+ const throughFilter = await this.makeThroughFilter(caller, parentId, baseTargetFilter);
49
+ const foreignFilter = await this.makeForeignFilter(caller, parentId, baseTargetFilter);
50
+ // Delete records from through collection
51
+ await throughCollection.delete(caller, throughFilter);
52
+ // Let the datasource crash when:
53
+ // - the records in the foreignCollection are linked to other records in the origin collection
54
+ // - the underlying database/api is not cascading deletes
55
+ await this.foreignCollection.delete(caller, foreignFilter);
56
+ }
57
+ else {
58
+ // Only delete records from through collection
59
+ const thoughFilter = await this.makeThroughFilter(caller, parentId, baseTargetFilter);
60
+ await throughCollection.delete(caller, thoughFilter);
61
+ }
62
+ }
63
+ /**
64
+ * Match selected records in the related data panel.
65
+ * The filter that is generated by this condition it _not_ restricted by the parent record
66
+ */
67
+ async getBaseForeignFilter(context) {
68
+ const selectionIds = body_parser_1.default.parseSelectionIds(this.foreignCollection.schema, context);
69
+ let selectedIds = datasource_toolkit_1.ConditionTreeFactory.matchIds(this.foreignCollection.schema, selectionIds.ids);
70
+ if (selectionIds.areExcluded)
71
+ selectedIds = selectedIds.inverse();
72
+ if (selectionIds.ids.length === 0 && !selectionIds.areExcluded) {
73
+ throw new datasource_toolkit_1.ValidationError('Expected no empty id list');
74
+ }
75
+ return context_filter_factory_1.default.build(this.foreignCollection, context, null, {
76
+ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(await this.services.permissions.getScope(this.foreignCollection, context), query_string_1.default.parseConditionTree(this.foreignCollection, context), selectedIds),
77
+ });
78
+ }
79
+ /** Wrapper around the util to simplify the call */
80
+ makeForeignFilter(caller, parentId, baseForeignFilter) {
81
+ return datasource_toolkit_1.FilterFactory.makeForeignFilter(this.collection, parentId, this.relationName, caller, baseForeignFilter);
82
+ }
83
+ /** Wrapper around the util to simplify the call */
84
+ makeThroughFilter(caller, parentId, baseForeignFilter) {
85
+ return datasource_toolkit_1.FilterFactory.makeThroughFilter(this.collection, parentId, this.relationName, caller, baseForeignFilter);
86
+ }
87
+ }
88
+ exports.default = DissociateDeleteRelatedRoute;
89
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlzc29jaWF0ZS1kZWxldGUtcmVsYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9yb3V0ZXMvbW9kaWZpY2F0aW9uL2Rpc3NvY2lhdGUtZGVsZXRlLXJlbGF0ZWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx3RUFVeUM7QUFJekMsdUNBQXVDO0FBQ3ZDLDBFQUFpRDtBQUNqRCxnR0FBc0U7QUFDdEUsd0RBQXFDO0FBQ3JDLDRFQUF5RDtBQUN6RCx1RUFBOEM7QUFFOUMsTUFBcUIsNEJBQTZCLFNBQVEsd0JBQWE7SUFDckUsV0FBVyxDQUFDLE1BQWM7UUFDeEIsTUFBTSxDQUFDLE1BQU0sQ0FDWCxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSw0QkFBNEIsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUN2RSxJQUFJLENBQUMsa0NBQWtDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUNuRCxDQUFDO0lBQ0osQ0FBQztJQUVNLEtBQUssQ0FBQyxrQ0FBa0MsQ0FBQyxPQUFnQjtRQUM5RCxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFL0UscUJBQXFCO1FBQ3JCLE1BQU0sUUFBUSxHQUFHLFlBQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNuRixNQUFNLFlBQVksR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDNUQsTUFBTSxNQUFNLEdBQUcsc0JBQWlCLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3RELE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLG9CQUFvQixD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
@@ -0,0 +1,9 @@
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 UpdateField extends CollectionRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleUpdate(context: Context): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=update-field.d.ts.map
@@ -0,0 +1,39 @@
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 collection_route_1 = __importDefault(require("../collection-route"));
9
+ const id_1 = __importDefault(require("../../utils/id"));
10
+ const query_string_1 = __importDefault(require("../../utils/query-string"));
11
+ class UpdateField extends collection_route_1.default {
12
+ setupRoutes(router) {
13
+ router.put(`/${this.collection.name}/:id/relationships/:field/:index(\\d+)`, this.handleUpdate.bind(this));
14
+ }
15
+ async handleUpdate(context) {
16
+ await this.services.permissions.can(context, `edit:${this.collection.name}`);
17
+ const { field, index, id } = context.params;
18
+ const subRecord = context.request.body?.data?.attributes;
19
+ // Validate parameters
20
+ // @fixme At the time of writing this route, the Validator does not support composite types
21
+ datasource_toolkit_1.FieldValidator.validate(this.collection, field, [{ [field]: [subRecord] }]);
22
+ // Create caller & filter
23
+ const unpackedId = id_1.default.unpackId(this.collection.schema, id);
24
+ const conditionTree = datasource_toolkit_1.ConditionTreeFactory.intersect(datasource_toolkit_1.ConditionTreeFactory.matchIds(this.collection.schema, [unpackedId]), await this.services.permissions.getScope(this.collection, context));
25
+ const caller = query_string_1.default.parseCaller(context);
26
+ const filter = new datasource_toolkit_1.Filter({ conditionTree });
27
+ // Load & check record
28
+ const [record] = await this.collection.list(caller, filter, new datasource_toolkit_1.Projection(field));
29
+ if (index > record[field]?.length) {
30
+ throw new datasource_toolkit_1.ValidationError(`Field '${field}' is too short`);
31
+ }
32
+ record[field][index] = subRecord;
33
+ // Update record
34
+ await this.collection.update(caller, filter, { [field]: record[field] });
35
+ context.response.status = types_1.HttpCode.NoContent;
36
+ }
37
+ }
38
+ exports.default = UpdateField;
39
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlLWZpZWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vdXBkYXRlLWZpZWxkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBTXlDO0FBSXpDLHVDQUF1QztBQUN2QywyRUFBa0Q7QUFDbEQsd0RBQXFDO0FBQ3JDLDRFQUF5RDtBQUV6RCxNQUFxQixXQUFZLFNBQVEsMEJBQWU7SUFDdEQsV0FBVyxDQUFDLE1BQWM7UUFDeEIsTUFBTSxDQUFDLEdBQUcsQ0FDUixJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSx3Q0FBd0MsRUFDaEUsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQzdCLENBQUM7SUFDSixDQUFDO0lBRU0sS0FBSyxDQUFDLFlBQVksQ0FBQyxPQUFnQjtRQUN4QyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsUUFBUSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFN0UsTUFBTSxFQUFFLEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQztRQUM1QyxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsVUFBVSxDQUFDO1FBRXpELHNCQUFzQjtRQUN0QiwyRkFBMkY7UUFDM0YsbUNBQWMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUU1RSx5QkFBeUI7UUFDekIsTUFBTSxVQUFVLEdBQUcsWUFBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNoRSxNQUFNLGFBQWEsR0FBRyx5Q0FBb0IsQ0FBQyxTQUFTLENBQ2xELHlDQUFvQixDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLFVBQVUsQ0FBQyxDQUFDLEVBQ25FLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQ25FLENBQUM7UUFFRixNQUFNLE1BQU0sR0FBRyxzQkFBaUIsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdEQsTUFBTSxNQUFNLEdBQUcsSUFBSSwyQkFBTSxDQUFDLEVBQUUsYUFBYSxFQUFFLENBQUMsQ0FBQztRQUU3QyxzQkFBc0I7UUFDdEIsTUFBTSxDQUFDLE1BQU0sQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxJQUFJLCtCQUFVLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUVuRixJQUFJLEtBQUssR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsTUFBTSxFQUFFO1lBQ2pDLE1BQU0sSUFBSSxvQ0FBZSxDQUFDLFVBQVUsS0FBSyxnQkFBZ0IsQ0FBQyxDQUFDO1NBQzVEO1FBRUQsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLFNBQVMsQ0FBQztRQUVqQyxnQkFBZ0I7UUFDaEIsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsRUFBRSxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBRXpFLE9BQU8sQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLGdCQUFRLENBQUMsU0FBUyxDQUFDO0lBQy9DLENBQUM7Q0FDRjtBQTFDRCw4QkEwQ0MifQ==
@@ -0,0 +1,59 @@
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 id_1 = __importDefault(require("../../utils/id"));
9
+ const query_string_1 = __importDefault(require("../../utils/query-string"));
10
+ const relation_route_1 = __importDefault(require("../relation-route"));
11
+ class UpdateRelation extends relation_route_1.default {
12
+ setupRoutes(router) {
13
+ router.put(`/${this.collection.name}/:parentId/relationships/${this.relationName}`, this.handleUpdateRelationRoute.bind(this));
14
+ }
15
+ async handleUpdateRelationRoute(context) {
16
+ const relation = this.collection.schema.fields[this.relationName];
17
+ const caller = query_string_1.default.parseCaller(context);
18
+ const parentId = id_1.default.unpackId(this.collection.schema, context.params.parentId);
19
+ const linkedId = context.request.body?.data?.id
20
+ ? id_1.default.unpackId(this.foreignCollection.schema, context.request.body.data.id)
21
+ : null;
22
+ if (relation.type === 'ManyToOne') {
23
+ await this.updateManyToOne(context, relation, parentId, linkedId, caller);
24
+ }
25
+ else if (relation.type === 'OneToOne') {
26
+ await this.updateOneToOne(context, relation, parentId, linkedId, caller);
27
+ }
28
+ context.response.status = types_1.HttpCode.NoContent;
29
+ }
30
+ async updateManyToOne(context, relation, parentId, linkedId, caller) {
31
+ // Perms
32
+ const scope = await this.services.permissions.getScope(this.collection, context);
33
+ await this.services.permissions.can(context, `edit:${this.collection.name}`);
34
+ // Load the value that will be used as foreignKey (=== linkedId[0] most of the time)
35
+ const foreignValue = linkedId
36
+ ? await datasource_toolkit_1.CollectionUtils.getValue(this.foreignCollection, caller, linkedId, relation.foreignKeyTarget)
37
+ : null;
38
+ // Overwrite old foreign key with new one (only one query needed).
39
+ const fkOwner = datasource_toolkit_1.ConditionTreeFactory.matchIds(this.collection.schema, [parentId]);
40
+ await this.collection.update(caller, new datasource_toolkit_1.Filter({ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(fkOwner, scope) }), { [relation.foreignKey]: foreignValue });
41
+ }
42
+ async updateOneToOne(context, relation, parentId, linkedId, caller) {
43
+ // Permissions
44
+ const scope = await this.services.permissions.getScope(this.foreignCollection, context);
45
+ await this.services.permissions.can(context, `edit:${this.foreignCollection.name}`);
46
+ // Load the value that will be used as originKey (=== parentId[0] most of the time)
47
+ const originValue = await datasource_toolkit_1.CollectionUtils.getValue(this.collection, caller, parentId, relation.originKeyTarget);
48
+ // Break old relation (may update zero or one records).
49
+ const oldFkOwner = new datasource_toolkit_1.ConditionTreeLeaf(relation.originKey, 'Equal', originValue);
50
+ await this.foreignCollection.update(caller, new datasource_toolkit_1.Filter({ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(oldFkOwner, scope) }), { [relation.originKey]: null });
51
+ // Create new relation (will update exactly one record).
52
+ if (linkedId) {
53
+ const newFkOwner = datasource_toolkit_1.ConditionTreeFactory.matchIds(this.foreignCollection.schema, [linkedId]);
54
+ await this.foreignCollection.update(caller, new datasource_toolkit_1.Filter({ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(newFkOwner, scope) }), { [relation.originKey]: originValue });
55
+ }
56
+ }
57
+ }
58
+ exports.default = UpdateRelation;
59
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlLXJlbGF0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vdXBkYXRlLXJlbGF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBU3lDO0FBSXpDLHVDQUF1QztBQUN2Qyx3REFBcUM7QUFDckMsNEVBQXlEO0FBQ3pELHVFQUE4QztBQUU5QyxNQUFxQixjQUFlLFNBQVEsd0JBQWE7SUFDdkQsV0FBVyxDQUFDLE1BQWM7UUFDeEIsTUFBTSxDQUFDLEdBQUcsQ0FDUixJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSw0QkFBNEIsSUFBSSxDQUFDLFlBQVksRUFBRSxFQUN2RSxJQUFJLENBQUMseUJBQXlCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUMxQyxDQUFDO0lBQ0osQ0FBQztJQUVNLEtBQUssQ0FBQyx5QkFBeUIsQ0FBQyxPQUFnQjtRQUNyRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQ2xFLE1BQU0sTUFBTSxHQUFHLHNCQUFpQixDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN0RCxNQUFNLFFBQVEsR0FBRyxZQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFbkYsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLEVBQUU7WUFDN0MsQ0FBQyxDQUFDLFlBQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQy9FLENBQUMsQ0FBQyxJ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
@@ -0,0 +1,31 @@
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 id_1 = __importDefault(require("../../utils/id"));
9
+ const query_string_1 = __importDefault(require("../../utils/query-string"));
10
+ class UpdateRoute extends collection_route_1.default {
11
+ setupRoutes(router) {
12
+ router.put(`/${this.collection.name}/:id`, this.handleUpdate.bind(this));
13
+ }
14
+ async handleUpdate(context) {
15
+ await this.services.permissions.can(context, `edit:${this.collection.name}`);
16
+ const id = id_1.default.unpackId(this.collection.schema, context.params.id);
17
+ const { body } = context.request;
18
+ if ('relationships' in body.data) {
19
+ delete body.data.relationships;
20
+ }
21
+ const record = this.services.serializer.deserialize(this.collection, body);
22
+ datasource_toolkit_1.RecordValidator.validate(this.collection, record);
23
+ const conditionTree = datasource_toolkit_1.ConditionTreeFactory.intersect(datasource_toolkit_1.ConditionTreeFactory.matchIds(this.collection.schema, [id]), await this.services.permissions.getScope(this.collection, context));
24
+ const caller = query_string_1.default.parseCaller(context);
25
+ await this.collection.update(caller, new datasource_toolkit_1.Filter({ conditionTree }), record);
26
+ const [updateResult] = await this.collection.list(caller, new datasource_toolkit_1.Filter({ conditionTree }), datasource_toolkit_1.ProjectionFactory.all(this.collection));
27
+ context.response.body = this.services.serializer.serialize(this.collection, updateResult);
28
+ }
29
+ }
30
+ exports.default = UpdateRoute;
31
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXBkYXRlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JvdXRlcy9tb2RpZmljYXRpb24vdXBkYXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBS3lDO0FBSXpDLDJFQUFrRDtBQUNsRCx3REFBcUM7QUFDckMsNEVBQXlEO0FBRXpELE1BQXFCLFdBQVksU0FBUSwwQkFBZTtJQUN0RCxXQUFXLENBQUMsTUFBYztRQUN4QixNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLE1BQU0sRUFBRSxJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzNFLENBQUM7SUFFTSxLQUFLLENBQUMsWUFBWSxDQUFDLE9BQWdCO1FBQ3hDLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxRQUFRLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUU3RSxNQUFNLEVBQUUsR0FBRyxZQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7UUFFdkUsTUFBTSxFQUFFLElBQUksRUFBRSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUM7UUFFakMsSUFBSSxlQUFlLElBQUksSUFBSSxDQUFDLElBQUksRUFBRTtZQUNoQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDO1NBQ2hDO1FBRUQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDM0Usb0NBQWUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUVsRCxNQUFNLGFBQWEsR0FBRyx5Q0FBb0IsQ0FBQyxTQUFTLENBQ2xELHlDQUFvQixDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQzNELE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQ25FLENBQUM7UUFDRixNQUFNLE1BQU0sR0FBRyxzQkFBaUIsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDdEQsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsSUFBSSwyQkFBTSxDQUFDLEVBQUUsYUFBYSxFQUFFLENBQUMsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUM1RSxNQUFNLENBQUMsWUFBWSxDQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FDL0MsTUFBTSxFQUNOLElBQUksMkJBQU0sQ0FBQyxFQUFFLGFBQWEsRUFBRSxDQUFDLEVBQzdCLHNDQUFpQixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQ3ZDLENBQUM7UUFFRixPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxZQUFZLENBQUMsQ0FBQztJQUM1RixDQUFDO0NBQ0Y7QUFqQ0QsOEJBaUNDIn0=
@@ -15,4 +15,4 @@ class RelationRoute extends collection_route_1.default {
15
15
  }
16
16
  }
17
17
  exports.default = RelationRoute;
18
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVsYXRpb24tcm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYWdlbnQvcm91dGVzL3JlbGF0aW9uLXJvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBSUEsMEVBQWlEO0FBRWpELE1BQThCLGFBQWMsU0FBUSwwQkFBZTtJQVNqRSxZQUNFLFFBQXVDLEVBQ3ZDLE9BQWlDLEVBQ2pDLFVBQXNCLEVBQ3RCLGNBQXNCLEVBQ3RCLFlBQW9CO1FBRXBCLEtBQUssQ0FBQyxRQUFRLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxjQUFjLENBQUMsQ0FBQztRQUNyRCxJQUFJLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztJQUNuQyxDQUFDO0lBZkQsSUFBYyxpQkFBaUI7UUFDN0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQW1CLENBQUM7UUFFbEYsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDNUUsQ0FBQztDQVlGO0FBbkJELGdDQW1CQyJ9
18
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVsYXRpb24tcm91dGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcm91dGVzL3JlbGF0aW9uLXJvdXRlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBSUEsMEVBQWlEO0FBRWpELE1BQThCLGFBQWMsU0FBUSwwQkFBZTtJQVNqRSxZQUNFLFFBQXVDLEVBQ3ZDLE9BQWlDLEVBQ2pDLFVBQXNCLEVBQ3RCLGNBQXNCLEVBQ3RCLFlBQW9CO1FBRXBCLEtBQUssQ0FBQyxRQUFRLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxjQUFjLENBQUMsQ0FBQztRQUNyRCxJQUFJLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztJQUNuQyxDQUFDO0lBZkQsSUFBYyxpQkFBaUI7UUFDN0IsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQW1CLENBQUM7UUFFbEYsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLGlCQUFpQixDQUFDLENBQUM7SUFDNUUsQ0FBQztDQVlGO0FBbkJELGdDQW1CQyJ9