@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,34 @@
1
+ /// <reference types="node" />
2
+ import { DataSource } from '@forestadmin/datasource-toolkit';
3
+ import { IncomingMessage, ServerResponse } from 'http';
4
+ import { AgentOptions } from '../types';
5
+ import { AgentOptionsWithDefaults } from './types';
6
+ import BaseRoute from './routes/base-route';
7
+ import { ForestAdminHttpDriverServices } from './services';
8
+ /** Native NodeJS callback that can be passed to an HTTP Server */
9
+ export declare type HttpCallback = (req: IncomingMessage, res: ServerResponse) => void;
10
+ export default class ForestAdminHttpDriver {
11
+ readonly dataSource: DataSource;
12
+ readonly options: AgentOptionsWithDefaults;
13
+ readonly services: ForestAdminHttpDriverServices;
14
+ routes: BaseRoute[];
15
+ private readonly app;
16
+ private status;
17
+ /**
18
+ * Native request handler.
19
+ * Can be used directly with express.js or the NodeJS http module.
20
+ * Other frameworks will require adapters.
21
+ */
22
+ get handler(): HttpCallback;
23
+ constructor(dataSource: DataSource, options: AgentOptions);
24
+ /**
25
+ * Builds the underlying application from the datasource.
26
+ * This method can only be called once.
27
+ */
28
+ start(): Promise<void>;
29
+ /**
30
+ * Tear down all routes (close open sockets, ...)
31
+ */
32
+ stop(): Promise<void>;
33
+ }
34
+ //# sourceMappingURL=forestadmin-http-driver.d.ts.map
@@ -0,0 +1,73 @@
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 koa_1 = __importDefault(require("koa"));
7
+ const router_1 = __importDefault(require("@koa/router"));
8
+ const koa_bodyparser_1 = __importDefault(require("koa-bodyparser"));
9
+ const cors_1 = __importDefault(require("@koa/cors"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const types_1 = require("../types");
12
+ const forest_http_api_1 = __importDefault(require("./utils/forest-http-api"));
13
+ const http_driver_options_1 = __importDefault(require("./utils/http-driver-options"));
14
+ const emitter_1 = __importDefault(require("./utils/forest-schema/emitter"));
15
+ const routes_1 = __importDefault(require("./routes"));
16
+ const services_1 = __importDefault(require("./services"));
17
+ class ForestAdminHttpDriver {
18
+ constructor(dataSource, options) {
19
+ this.routes = [];
20
+ this.app = new koa_1.default();
21
+ this.status = 'waiting';
22
+ this.dataSource = dataSource;
23
+ this.options = http_driver_options_1.default.withDefaults(options);
24
+ this.services = (0, services_1.default)(this.options);
25
+ http_driver_options_1.default.validate(this.options);
26
+ }
27
+ /**
28
+ * Native request handler.
29
+ * Can be used directly with express.js or the NodeJS http module.
30
+ * Other frameworks will require adapters.
31
+ */
32
+ get handler() {
33
+ return this.app.callback();
34
+ }
35
+ /**
36
+ * Builds the underlying application from the datasource.
37
+ * This method can only be called once.
38
+ */
39
+ async start() {
40
+ if (this.status !== 'waiting') {
41
+ throw new Error('Agent cannot be restarted.');
42
+ }
43
+ this.status = 'running';
44
+ // Build http application
45
+ const router = new router_1.default({ prefix: path_1.default.join('/', this.options.prefix) });
46
+ this.routes = (0, routes_1.default)(this.dataSource, this.options, this.services);
47
+ this.routes.forEach(route => route.setupRoutes(router));
48
+ await Promise.all(this.routes.map(route => route.bootstrap()));
49
+ this.app
50
+ .use((0, cors_1.default)({ credentials: true, maxAge: 24 * 3600 }))
51
+ .use((0, koa_bodyparser_1.default)({ jsonLimit: '50mb' }))
52
+ .use(router.routes());
53
+ // Send schema to forestadmin-server (if relevant).
54
+ const schema = await emitter_1.default.getSerializedSchema(this.options, this.dataSource);
55
+ const schemaIsKnown = await forest_http_api_1.default.hasSchema(this.options, schema.meta.schemaFileHash);
56
+ if (!schemaIsKnown) {
57
+ await forest_http_api_1.default.uploadSchema(this.options, schema);
58
+ }
59
+ this.options?.logger(types_1.LoggerLevel.Info, 'Started');
60
+ }
61
+ /**
62
+ * Tear down all routes (close open sockets, ...)
63
+ */
64
+ async stop() {
65
+ if (this.status !== 'running') {
66
+ throw new Error('Agent is not running.');
67
+ }
68
+ this.status = 'done';
69
+ await Promise.all(this.routes.map(route => route.tearDown()));
70
+ }
71
+ }
72
+ exports.default = ForestAdminHttpDriver;
73
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9yZXN0YWRtaW4taHR0cC1kcml2ZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYWdlbnQvZm9yZXN0YWRtaW4taHR0cC1kcml2ZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFFQSw4Q0FBc0I7QUFDdEIseURBQWlDO0FBQ2pDLG9FQUF3QztBQUN4QyxxREFBNkI7QUFDN0IsZ0RBQXdCO0FBRXhCLG9DQUFxRDtBQUdyRCw4RUFBb0Q7QUFDcEQsc0ZBQXVEO0FBQ3ZELDRFQUEwRDtBQUMxRCxzREFBa0M7QUFDbEMsMERBQXlFO0FBS3pFLE1BQXFCLHFCQUFxQjtJQWtCeEMsWUFBWSxVQUFzQixFQUFFLE9BQXFCO1FBZGxELFdBQU0sR0FBZ0IsRUFBRSxDQUFDO1FBRWYsUUFBRyxHQUFHLElBQUksYUFBRyxFQUFFLENBQUM7UUFDekIsV0FBTSxHQUFtQyxTQUFTLENBQUM7UUFZekQsSUFBSSxDQUFDLFVBQVUsR0FBRyxVQUFVLENBQUM7UUFDN0IsSUFBSSxDQUFDLE9BQU8sR0FBRyw2QkFBWSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNsRCxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUEsa0JBQVksRUFBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFM0MsNkJBQVksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3RDLENBQUM7SUFmRDs7OztPQUlHO0lBQ0gsSUFBSSxPQUFPO1FBQ1QsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQzdCLENBQUM7SUFVRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsS0FBSztRQUNULElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxTQUFTLEVBQUU7WUFDN0IsTUFBTSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO1NBQy9DO1FBRUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUM7UUFFeEIseUJBQXlCO1FBQ3pCLE1BQU0sTUFBTSxHQUFHLElBQUksZ0JBQU0sQ0FBQyxFQUFFLE1BQU0sRUFBRSxjQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUMzRSxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUEsZ0JBQVUsRUFBQyxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ3ZFLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3hELE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUM7UUFFL0QsSUFBSSxDQUFDLEdBQUc7YUFDTCxHQUFHLENBQUMsSUFBQSxjQUFJLEVBQUMsRUFBRSxXQUFXLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxFQUFFLEdBQUcsSUFBSSxFQUFFLENBQUMsQ0FBQzthQUNuRCxHQUFHLENBQUMsSUFBQSx3QkFBVSxFQUFDLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7YUFDdEMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBRXhCLG1EQUFtRDtRQUNuRCxNQUFNLE1BQU0sR0FBRyxNQUFNLGlCQUFhLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDdEYsTUFBTSxhQUFhLEdBQUcsTUFBTSx5QkFBYSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7UUFFOUYsSUFBSSxDQUFDLGFBQWEsRUFBRTtZQUNsQixNQUFNLHlCQUFhLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7U0FDeEQ7UUFFRCxJQUFJLENBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxtQkFBVyxDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxLQUFLLENBQUMsSUFBSTtRQUNSLElBQUksSUFBSSxDQUFDLE1BQU0sS0FBSyxTQUFTLEVBQUU7WUFDN0IsTUFBTSxJQUFJLEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO1NBQzFDO1FBRUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxNQUFNLENBQUM7UUFDckIsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsS0FBSyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUNoRSxDQUFDO0NBQ0Y7QUF0RUQsd0NBc0VDIn0=
@@ -0,0 +1,17 @@
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 Chart extends CollectionRoute {
6
+ private static readonly formats;
7
+ setupRoutes(router: Router): void;
8
+ handleChart(context: Context): Promise<void>;
9
+ private makeValueChart;
10
+ private makeObjectiveChart;
11
+ private makePieChart;
12
+ private makeLineChart;
13
+ private makeLeaderboardChart;
14
+ private computeValue;
15
+ private getFilter;
16
+ }
17
+ //# sourceMappingURL=chart.d.ts.map
@@ -0,0 +1,125 @@
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 luxon_1 = require("luxon");
8
+ const uuid_1 = require("uuid");
9
+ const collection_route_1 = __importDefault(require("../collection-route"));
10
+ const context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
11
+ var ChartType;
12
+ (function (ChartType) {
13
+ ChartType["Value"] = "Value";
14
+ ChartType["Objective"] = "Objective";
15
+ ChartType["Pie"] = "Pie";
16
+ ChartType["Line"] = "Line";
17
+ ChartType["Leaderboard"] = "Leaderboard";
18
+ })(ChartType || (ChartType = {}));
19
+ class Chart extends collection_route_1.default {
20
+ setupRoutes(router) {
21
+ router.post(`/stats/${this.collection.name}`, this.handleChart.bind(this));
22
+ }
23
+ async handleChart(context) {
24
+ const { body } = context.request;
25
+ await this.services.permissions.canChart(context);
26
+ if (!Object.values(ChartType).includes(body.type)) {
27
+ throw new datasource_toolkit_1.ValidationError(`Invalid Chart type "${body.type}"`);
28
+ }
29
+ context.response.body = {
30
+ data: {
31
+ id: (0, uuid_1.v1)(),
32
+ type: 'stats',
33
+ attributes: { value: await this[`make${body.type}Chart`](context) },
34
+ },
35
+ };
36
+ }
37
+ async makeValueChart(context) {
38
+ const currentFilter = await this.getFilter(context);
39
+ const result = {
40
+ countCurrent: await this.computeValue(context, currentFilter),
41
+ countPrevious: undefined,
42
+ };
43
+ const isAndAggregator = currentFilter.conditionTree?.aggregator === 'And';
44
+ const withCountPrevious = currentFilter.conditionTree?.someLeaf(leaf => leaf.useIntervalOperator);
45
+ if (withCountPrevious && !isAndAggregator) {
46
+ result.countPrevious = await this.computeValue(context, datasource_toolkit_1.FilterFactory.getPreviousPeriodFilter(currentFilter));
47
+ }
48
+ return result;
49
+ }
50
+ async makeObjectiveChart(context) {
51
+ return { value: await this.computeValue(context, await this.getFilter(context)) };
52
+ }
53
+ async makePieChart(context) {
54
+ const { group_by_field: groupByField, aggregate, aggregate_field: aggregateField, } = context.request.body;
55
+ const rows = await this.collection.aggregate(await this.getFilter(context), new datasource_toolkit_1.Aggregation({
56
+ operation: aggregate,
57
+ field: aggregateField,
58
+ groups: [{ field: groupByField }],
59
+ }));
60
+ return rows.map(row => ({
61
+ key: row.group[groupByField],
62
+ value: row.value,
63
+ }));
64
+ }
65
+ async makeLineChart(context) {
66
+ const { aggregate, aggregate_field: aggregateField, group_by_date_field: groupByDateField, time_range: timeRange, } = context.request.body;
67
+ const rows = await this.collection.aggregate(await this.getFilter(context), new datasource_toolkit_1.Aggregation({
68
+ operation: aggregate,
69
+ field: aggregateField,
70
+ groups: [
71
+ {
72
+ field: groupByDateField,
73
+ operation: timeRange,
74
+ },
75
+ ],
76
+ }));
77
+ const values = {};
78
+ rows.forEach(row => {
79
+ values[luxon_1.DateTime.fromISO(row.group[groupByDateField]).toISODate()] = Number(row.value);
80
+ });
81
+ const dates = Object.keys(values).sort((dateA, dateB) => dateA.localeCompare(dateB));
82
+ const last = luxon_1.DateTime.fromISO(dates[dates.length - 1]);
83
+ const dataPoints = [];
84
+ const format = Chart.formats[timeRange];
85
+ for (let current = luxon_1.DateTime.fromISO(dates[0]); current <= last; current = current.plus({ [timeRange]: 1 })) {
86
+ const label = current.toFormat(format);
87
+ const value = values[current.toISODate()] ?? 0;
88
+ dataPoints.push({ label, values: { value } });
89
+ }
90
+ return dataPoints;
91
+ }
92
+ async makeLeaderboardChart(context) {
93
+ const { aggregate, label_field: labelField, relationship_field: relationshipField, limit, } = context.request.body;
94
+ let { aggregate_field: aggregateField } = context.request.body;
95
+ if (!aggregateField) {
96
+ const relation = datasource_toolkit_1.SchemaUtils.getToManyRelation(this.collection.schema, relationshipField);
97
+ const collection = this.dataSource.getCollection(relation.type === 'OneToMany' ? relation.foreignCollection : relation.throughCollection);
98
+ [aggregateField] = datasource_toolkit_1.SchemaUtils.getPrimaryKeys(collection.schema);
99
+ }
100
+ const rows = await this.collection.aggregate(await this.getFilter(context), new datasource_toolkit_1.Aggregation({
101
+ operation: aggregate,
102
+ field: `${relationshipField}:${aggregateField}`,
103
+ groups: [{ field: labelField }],
104
+ }), Number(limit));
105
+ return rows.map(row => ({ key: row.group[labelField], value: row.value }));
106
+ }
107
+ async computeValue(context, filter) {
108
+ const { aggregate, aggregate_field: aggregateField } = context.request.body;
109
+ const aggregation = new datasource_toolkit_1.Aggregation({ operation: aggregate, field: aggregateField });
110
+ const rows = await this.collection.aggregate(filter, aggregation);
111
+ return rows.length ? rows[0].value : 0;
112
+ }
113
+ async getFilter(context) {
114
+ const scope = await this.services.permissions.getScope(this.collection, context);
115
+ return context_filter_factory_1.default.build(this.collection, context, scope);
116
+ }
117
+ }
118
+ exports.default = Chart;
119
+ Chart.formats = {
120
+ Day: 'dd/MM/yyyy',
121
+ Week: "'W'W-yyyy",
122
+ Month: 'MMM yy',
123
+ Year: 'yyyy',
124
+ };
125
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYWdlbnQvcm91dGVzL2FjY2Vzcy9jaGFydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHdFQVF5QztBQUV6QyxpQ0FBaUM7QUFDakMsK0JBQW9DO0FBR3BDLDJFQUFrRDtBQUNsRCxnR0FBc0U7QUFFdEUsSUFBSyxTQU1KO0FBTkQsV0FBSyxTQUFTO0lBQ1osNEJBQWUsQ0FBQTtJQUNmLG9DQUF1QixDQUFBO0lBQ3ZCLHdCQUFXLENBQUE7SUFDWCwwQkFBYSxDQUFBO0lBQ2Isd0NBQTJCLENBQUE7QUFDN0IsQ0FBQyxFQU5JLFNBQVMsS0FBVCxTQUFTLFFBTWI7QUFFRCxNQUFxQixLQUFNLFNBQVEsMEJBQWU7SUFRaEQsV0FBVyxDQUFDLE1BQWM7UUFDeEIsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFVLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEVBQUUsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUM3RSxDQUFDO0lBRUQsS0FBSyxDQUFDLFdBQVcsQ0FBQyxPQUFnQjtRQUNoQyxNQUFNLEVBQUUsSUFBSSxFQUFFLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQztRQUVqQyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUVsRCxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFO1lBQ2pELE1BQU0sSUFBSSxvQ0FBZSxDQUFDLHVCQUF1QixJQUFJLENBQUMsSUFBSSxHQUFHLENBQUMsQ0FBQztTQUNoRTtRQUVELE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxHQUFHO1lBQ3RCLElBQUksRUFBRTtnQkFDSixFQUFFLEVBQUUsSUFBQSxT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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 RelationRoute from '../relation-route';
5
+ export default class CountRelatedRoute extends RelationRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleCountRelated(context: Context): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=count-related.d.ts.map
@@ -0,0 +1,24 @@
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 context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
8
+ const id_1 = __importDefault(require("../../utils/id"));
9
+ const relation_route_1 = __importDefault(require("../relation-route"));
10
+ class CountRelatedRoute extends relation_route_1.default {
11
+ setupRoutes(router) {
12
+ router.get(`/${this.collection.name}/:parentId/relationships/${this.relationName}/count`, this.handleCountRelated.bind(this));
13
+ }
14
+ async handleCountRelated(context) {
15
+ await this.services.permissions.can(context, `browse:${this.collection.name}`);
16
+ const parentId = id_1.default.unpackId(this.collection.schema, context.params.parentId);
17
+ const scope = await this.services.permissions.getScope(this.foreignCollection, context);
18
+ const filter = context_filter_factory_1.default.build(this.foreignCollection, context, scope);
19
+ const aggregationResult = await datasource_toolkit_1.CollectionUtils.aggregateRelation(this.collection, parentId, this.relationName, filter, new datasource_toolkit_1.Aggregation({ operation: 'Count' }));
20
+ context.response.body = { count: aggregationResult?.[0]?.value ?? 0 };
21
+ }
22
+ }
23
+ exports.default = CountRelatedRoute;
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY291bnQtcmVsYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hZ2VudC9yb3V0ZXMvYWNjZXNzL2NvdW50LXJlbGF0ZWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx3RUFBK0U7QUFJL0UsZ0dBQXNFO0FBQ3RFLHdEQUFxQztBQUNyQyx1RUFBOEM7QUFFOUMsTUFBcUIsaUJBQWtCLFNBQVEsd0JBQWE7SUFDMUQsV0FBVyxDQUFDLE1BQWM7UUFDeEIsTUFBTSxDQUFDLEdBQUcsQ0FDUixJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSw0QkFBNEIsSUFBSSxDQUFDLFlBQVksUUFBUSxFQUM3RSxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUNuQyxDQUFDO0lBQ0osQ0FBQztJQUVNLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxPQUFnQjtRQUM5QyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFL0UsTUFBTSxRQUFRLEdBQUcsWUFBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ25GLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN4RixNQUFNLE1BQU0sR0FBRyxnQ0FBb0IsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLGlCQUFpQixFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUVsRixNQUFNLGlCQUFpQixHQUFHLE1BQU0sb0NBQWUsQ0FBQyxpQkFBaUIsQ0FDL0QsSUFBSSxDQUFDLFVBQVUsRUFDZixRQUFRLEVBQ1IsSUFBSSxDQUFDLFlBQVksRUFDakIsTUFBTSxFQUNOLElBQUksZ0NBQVcsQ0FBQyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUN4QyxDQUFDO1FBRUYsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEdBQUcsRUFBRSxLQUFLLEVBQUUsaUJBQWlCLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLElBQUksQ0FBQyxFQUFFLENBQUM7SUFDeEUsQ0FBQztDQUNGO0FBekJELG9DQXlCQyJ9
@@ -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 CountRoute extends CollectionRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleCount(context: Context): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=count.d.ts.map
@@ -0,0 +1,24 @@
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 context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
9
+ class CountRoute extends collection_route_1.default {
10
+ setupRoutes(router) {
11
+ router.get(`/${this.collection.name}/count`, this.handleCount.bind(this));
12
+ }
13
+ async handleCount(context) {
14
+ await this.services.permissions.can(context, `browse:${this.collection.name}`);
15
+ const scope = await this.services.permissions.getScope(this.collection, context);
16
+ const filter = context_filter_factory_1.default.build(this.collection, context, scope);
17
+ const aggregation = new datasource_toolkit_1.Aggregation({ operation: 'Count' });
18
+ const aggregationResult = await this.collection.aggregate(filter, aggregation);
19
+ const count = aggregationResult?.[0]?.value ?? 0;
20
+ context.response.body = { count };
21
+ }
22
+ }
23
+ exports.default = CountRoute;
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY291bnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYWdlbnQvcm91dGVzL2FjY2Vzcy9jb3VudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHdFQUE4RDtBQUk5RCwyRUFBa0Q7QUFDbEQsZ0dBQXNFO0FBRXRFLE1BQXFCLFVBQVcsU0FBUSwwQkFBZTtJQUNyRCxXQUFXLENBQUMsTUFBYztRQUN4QixNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLFFBQVEsRUFBRSxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzVFLENBQUM7SUFFTSxLQUFLLENBQUMsV0FBVyxDQUFDLE9BQWdCO1FBQ3ZDLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxVQUFVLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUUvRSxNQUFNLEtBQUssR0FBRyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ2pGLE1BQU0sTUFBTSxHQUFHLGdDQUFvQixDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUUzRSxNQUFNLFdBQVcsR0FBRyxJQUFJLGdDQUFXLENBQUMsRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztRQUM1RCxNQUFNLGlCQUFpQixHQUFHLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLFdBQVcsQ0FBQyxDQUFDO1FBQy9FLE1BQU0sS0FBSyxHQUFHLGlCQUFpQixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxJQUFJLENBQUMsQ0FBQztRQUVqRCxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksR0FBRyxFQUFFLEtBQUssRUFBRSxDQUFDO0lBQ3BDLENBQUM7Q0FDRjtBQWpCRCw2QkFpQkMifQ==
@@ -0,0 +1,9 @@
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 CsvRelatedRoute extends RelationRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleRelatedCsv(context: Context): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=csv-related.d.ts.map
@@ -0,0 +1,33 @@
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 stream_1 = require("stream");
8
+ const context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
9
+ const csv_generator_1 = __importDefault(require("../../utils/csv-generator"));
10
+ const csv_route_context_1 = __importDefault(require("../../utils/csv-route-context"));
11
+ const id_1 = __importDefault(require("../../utils/id"));
12
+ const query_string_1 = __importDefault(require("../../utils/query-string"));
13
+ const relation_route_1 = __importDefault(require("../relation-route"));
14
+ class CsvRelatedRoute extends relation_route_1.default {
15
+ setupRoutes(router) {
16
+ router.get(`/${this.collection.name}/:parentId/relationships/${this.relationName}.csv`, this.handleRelatedCsv.bind(this));
17
+ }
18
+ async handleRelatedCsv(context) {
19
+ await this.services.permissions.can(context, `browse:${this.collection.name}`);
20
+ await this.services.permissions.can(context, `export:${this.collection.name}`);
21
+ const { header } = context.request.query;
22
+ csv_route_context_1.default.buildResponse(context);
23
+ const projection = query_string_1.default.parseProjection(this.foreignCollection, context);
24
+ const scope = await this.services.permissions.getScope(this.foreignCollection, context);
25
+ const filter = context_filter_factory_1.default.buildPaginated(this.foreignCollection, context, scope);
26
+ const parentId = id_1.default.unpackId(this.collection.schema, context.params.parentId);
27
+ const list = async (paginatedFilter, projectionParam) => datasource_toolkit_1.CollectionUtils.listRelation(this.collection, parentId, this.relationName, paginatedFilter, projectionParam);
28
+ const gen = csv_generator_1.default.generate(projection, header, filter, this.foreignCollection, list);
29
+ context.response.body = stream_1.Readable.from(gen);
30
+ }
31
+ }
32
+ exports.default = CsvRelatedRoute;
33
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3N2LXJlbGF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvYWdlbnQvcm91dGVzL2FjY2Vzcy9jc3YtcmVsYXRlZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUFBLHdFQUErRjtBQUkvRixtQ0FBa0M7QUFDbEMsZ0dBQXNFO0FBQ3RFLDhFQUFxRDtBQUNyRCxzRkFBNEQ7QUFDNUQsd0RBQXFDO0FBQ3JDLDRFQUF5RDtBQUN6RCx1RUFBOEM7QUFFOUMsTUFBcUIsZUFBZ0IsU0FBUSx3QkFBYTtJQUN4RCxXQUFXLENBQUMsTUFBYztRQUN4QixNQUFNLENBQUMsR0FBRyxDQUNSLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLDRCQUE0QixJQUFJLENBQUMsWUFBWSxNQUFNLEVBQzNFLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQ2pDLENBQUM7SUFDSixDQUFDO0lBRUQsS0FBSyxDQUFDLGdCQUFnQixDQUFDLE9BQWdCO1FBQ3JDLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxVQUFVLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUMvRSxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFL0UsTUFBTSxFQUFFLE1BQU0sRUFBRSxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBK0IsQ0FBQztRQUNuRSwyQkFBZSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUV2QyxNQUFNLFVBQVUsR0FBRyxzQkFBaUIsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLGlCQUFpQixFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3RGLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxpQkFBaUIsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN4RixNQUFNLE1BQU0sR0FBRyxnQ0FBb0IsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLGlCQUFpQixFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUMzRixNQUFNLFFBQVEsR0FBRyxZQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFbkYsTUFBTSxJQUFJLEdBQUcsS0FBSyxFQUFFLGVBQWdDLEVBQUUsZUFBMkIsRUFBRSxFQUFFLENBQ25GLG9DQUFlLENBQUMsWUFBWSxDQUMxQixJQUFJLENBQUMsVUFBVSxFQUNmLFFBQVEsRUFDUixJQUFJLENBQUMsWUFBWSxFQUNqQixlQUFlLEVBQ2YsZUFBZSxDQUNoQixDQUFDO1FBRUosTUFBTSxHQUFHLEdBQUcsdUJBQVksQ0FBQyxRQUFRLENBQUMsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLGlCQUFpQixFQUFFLElBQUksQ0FBQyxDQUFDO1FBQzVGLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxHQUFHLGlCQUFRLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzdDLENBQUM7Q0FDRjtBQWhDRCxrQ0FnQ0MifQ==
@@ -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 CsvRoute extends CollectionRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleCsv(context: Context): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=csv.d.ts.map
@@ -0,0 +1,30 @@
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 stream_1 = require("stream");
7
+ const collection_route_1 = __importDefault(require("../collection-route"));
8
+ const context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
9
+ const csv_generator_1 = __importDefault(require("../../utils/csv-generator"));
10
+ const csv_route_context_1 = __importDefault(require("../../utils/csv-route-context"));
11
+ const query_string_1 = __importDefault(require("../../utils/query-string"));
12
+ class CsvRoute extends collection_route_1.default {
13
+ setupRoutes(router) {
14
+ router.get(`/${this.collection.name}.csv`, this.handleCsv.bind(this));
15
+ }
16
+ async handleCsv(context) {
17
+ await this.services.permissions.can(context, `read:${this.collection.name}`);
18
+ await this.services.permissions.can(context, `export:${this.collection.name}`);
19
+ const { header } = context.request.query;
20
+ csv_route_context_1.default.buildResponse(context);
21
+ const projection = query_string_1.default.parseProjection(this.collection, context);
22
+ const scope = await this.services.permissions.getScope(this.collection, context);
23
+ const filter = context_filter_factory_1.default.buildPaginated(this.collection, context, scope);
24
+ const list = this.collection.list.bind(this.collection);
25
+ const gen = csv_generator_1.default.generate(projection, header, filter, this.collection, list);
26
+ context.response.body = stream_1.Readable.from(gen);
27
+ }
28
+ }
29
+ exports.default = CsvRoute;
30
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3N2LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FnZW50L3JvdXRlcy9hY2Nlc3MvY3N2LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBR0EsbUNBQWtDO0FBQ2xDLDJFQUFrRDtBQUNsRCxnR0FBc0U7QUFDdEUsOEVBQXFEO0FBQ3JELHNGQUE0RDtBQUM1RCw0RUFBeUQ7QUFFekQsTUFBcUIsUUFBUyxTQUFRLDBCQUFlO0lBQ25ELFdBQVcsQ0FBQyxNQUFjO1FBQ3hCLE1BQU0sQ0FBQyxHQUFHLENBQUMsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksTUFBTSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDeEUsQ0FBQztJQUVELEtBQUssQ0FBQyxTQUFTLENBQUMsT0FBZ0I7UUFDOUIsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsT0FBTyxFQUFFLFFBQVEsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBQzdFLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxVQUFVLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUUvRSxNQUFNLEVBQUUsTUFBTSxFQUFFLEdBQUcsT0FBTyxDQUFDLE9BQU8sQ0FBQyxLQUErQixDQUFDO1FBQ25FLDJCQUFlLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBRXZDLE1BQU0sVUFBVSxHQUFHLHNCQUFpQixDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQy9FLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDakYsTUFBTSxNQUFNLEdBQUcsZ0NBQW9CLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRXBGLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDeEQsTUFBTSxHQUFHLEdBQUcsdUJBQVksQ0FBQyxRQUFRLENBQUMsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNyRixPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksR0FBRyxpQkFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM3QyxDQUFDO0NBQ0Y7QUFwQkQsMkJBb0JDIn0=
@@ -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 GetRoute extends CollectionRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleGet(context: Context): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=get.d.ts.map
@@ -0,0 +1,28 @@
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
+ class GetRoute extends collection_route_1.default {
11
+ setupRoutes(router) {
12
+ router.get(`/${this.collection.name}/:id`, this.handleGet.bind(this));
13
+ }
14
+ async handleGet(context) {
15
+ await this.services.permissions.can(context, `read:${this.collection.name}`);
16
+ const id = id_1.default.unpackId(this.collection.schema, context.params.id);
17
+ const filter = new datasource_toolkit_1.PaginatedFilter({
18
+ conditionTree: datasource_toolkit_1.ConditionTreeFactory.intersect(datasource_toolkit_1.ConditionTreeFactory.matchIds(this.collection.schema, [id]), await this.services.permissions.getScope(this.collection, context)),
19
+ });
20
+ const records = await this.collection.list(filter, datasource_toolkit_1.ProjectionFactory.all(this.collection));
21
+ if (!records.length) {
22
+ context.throw(types_1.HttpCode.NotFound, 'Record does not exists');
23
+ }
24
+ context.response.body = this.services.serializer.serialize(this.collection, records[0]);
25
+ }
26
+ }
27
+ exports.default = GetRoute;
28
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2V0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FnZW50L3JvdXRlcy9hY2Nlc3MvZ2V0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBSXlDO0FBSXpDLHVDQUF1QztBQUN2QywyRUFBa0Q7QUFDbEQsd0RBQXFDO0FBRXJDLE1BQXFCLFFBQVMsU0FBUSwwQkFBZTtJQUNuRCxXQUFXLENBQUMsTUFBYztRQUN4QixNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLE1BQU0sRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQ3hFLENBQUM7SUFFTSxLQUFLLENBQUMsU0FBUyxDQUFDLE9BQWdCO1FBQ3JDLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxRQUFRLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUU3RSxNQUFNLEVBQUUsR0FBRyxZQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDdkUsTUFBTSxNQUFNLEdBQUcsSUFBSSxvQ0FBZSxDQUFDO1lBQ2pDLGFBQWEsRUFBRSx5Q0FBb0IsQ0FBQyxTQUFTLENBQzNDLHlDQUFvQixDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQzNELE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsT0FBTyxDQUFDLENBQ25FO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsc0NBQWlCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO1FBRTNGLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFO1lBQ25CLE9BQU8sQ0FBQyxLQUFLLENBQUMsZ0JBQVEsQ0FBQyxRQUFRLEVBQUUsd0JBQXdCLENBQUMsQ0FBQztTQUM1RDtRQUVELE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzFGLENBQUM7Q0FDRjtBQXhCRCwyQkF3QkMifQ==
@@ -0,0 +1,9 @@
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 ListRelatedRoute extends RelationRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleListRelated(context: Context): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=list-related.d.ts.map
@@ -0,0 +1,26 @@
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 context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
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 ListRelatedRoute extends relation_route_1.default {
12
+ setupRoutes(router) {
13
+ router.get(`/${this.collection.name}/:parentId/relationships/${this.relationName}`, this.handleListRelated.bind(this));
14
+ }
15
+ async handleListRelated(context) {
16
+ await this.services.permissions.can(context, `browse:${this.collection.name}`);
17
+ const parentId = id_1.default.unpackId(this.collection.schema, context.params.parentId);
18
+ const scope = await this.services.permissions.getScope(this.foreignCollection, context);
19
+ const paginatedFilter = context_filter_factory_1.default.buildPaginated(this.foreignCollection, context, scope);
20
+ const projection = query_string_1.default.parseProjectionWithPks(this.foreignCollection, context);
21
+ const records = await datasource_toolkit_1.CollectionUtils.listRelation(this.collection, parentId, this.relationName, paginatedFilter, projection);
22
+ context.response.body = this.services.serializer.serializeWithSearchMetadata(this.foreignCollection, records, paginatedFilter.search);
23
+ }
24
+ }
25
+ exports.default = ListRelatedRoute;
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlzdC1yZWxhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2FnZW50L3JvdXRlcy9hY2Nlc3MvbGlzdC1yZWxhdGVkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsd0VBQWtFO0FBSWxFLGdHQUFzRTtBQUN0RSx3REFBcUM7QUFDckMsNEVBQXlEO0FBQ3pELHVFQUE4QztBQUU5QyxNQUFxQixnQkFBaUIsU0FBUSx3QkFBYTtJQUN6RCxXQUFXLENBQUMsTUFBYztRQUN4QixNQUFNLENBQUMsR0FBRyxDQUNSLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLDRCQUE0QixJQUFJLENBQUMsWUFBWSxFQUFFLEVBQ3ZFLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQ2xDLENBQUM7SUFDSixDQUFDO0lBRU0sS0FBSyxDQUFDLGlCQUFpQixDQUFDLE9BQWdCO1FBQzdDLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxVQUFVLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQztRQUUvRSxNQUFNLFFBQVEsR0FBRyxZQUFPLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDbkYsTUFBTSxLQUFLLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLGlCQUFpQixFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3hGLE1BQU0sZUFBZSxHQUFHLGdDQUFvQixDQUFDLGNBQWMsQ0FDekQsSUFBSSxDQUFDLGlCQUFpQixFQUN0QixPQUFPLEVBQ1AsS0FBSyxDQUNOLENBQUM7UUFFRixNQUFNLFVBQVUsR0FBRyxzQkFBaUIsQ0FBQyxzQkFBc0IsQ0FBQyxJQUFJLENBQUMsaUJBQWlCLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFN0YsTUFBTSxPQUFPLEdBQUcsTUFBTSxvQ0FBZSxDQUFDLFlBQVksQ0FDaEQsSUFBSSxDQUFDLFVBQVUsRUFDZixRQUFRLEVBQ1IsSUFBSSxDQUFDLFlBQVksRUFDakIsZUFBZSxFQUNmLFVBQVUsQ0FDWCxDQUFDO1FBRUYsT0FBTyxDQUFDLFFBQVEsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxVQUFVLENBQUMsMkJBQTJCLENBQzFFLElBQUksQ0FBQyxpQkFBaUIsRUFDdEIsT0FBTyxFQUNQLGVBQWUsQ0FBQyxNQUFNLENBQ3ZCLENBQUM7SUFDSixDQUFDO0NBQ0Y7QUFuQ0QsbUNBbUNDIn0=
@@ -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 ListRoute extends CollectionRoute {
6
+ setupRoutes(router: Router): void;
7
+ handleList(context: Context): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1,23 @@
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 collection_route_1 = __importDefault(require("../collection-route"));
7
+ const context_filter_factory_1 = __importDefault(require("../../utils/context-filter-factory"));
8
+ const query_string_1 = __importDefault(require("../../utils/query-string"));
9
+ class ListRoute extends collection_route_1.default {
10
+ setupRoutes(router) {
11
+ router.get(`/${this.collection.name}`, this.handleList.bind(this));
12
+ }
13
+ async handleList(context) {
14
+ await this.services.permissions.can(context, `browse:${this.collection.name}`);
15
+ const scope = await this.services.permissions.getScope(this.collection, context);
16
+ const paginatedFilter = context_filter_factory_1.default.buildPaginated(this.collection, context, scope);
17
+ const projection = query_string_1.default.parseProjectionWithPks(this.collection, context);
18
+ const records = await this.collection.list(paginatedFilter, projection);
19
+ context.response.body = this.services.serializer.serializeWithSearchMetadata(this.collection, records, paginatedFilter.search);
20
+ }
21
+ }
22
+ exports.default = ListRoute;
23
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9hZ2VudC9yb3V0ZXMvYWNjZXNzL2xpc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFHQSwyRUFBa0Q7QUFDbEQsZ0dBQXNFO0FBQ3RFLDRFQUF5RDtBQUV6RCxNQUFxQixTQUFVLFNBQVEsMEJBQWU7SUFDcEQsV0FBVyxDQUFDLE1BQWM7UUFDeEIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxFQUFFLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNyRSxDQUFDO0lBRU0sS0FBSyxDQUFDLFVBQVUsQ0FBQyxPQUFnQjtRQUN0QyxNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFFL0UsTUFBTSxLQUFLLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUNqRixNQUFNLGVBQWUsR0FBRyxnQ0FBb0IsQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDN0YsTUFBTSxVQUFVLEdBQUcsc0JBQWlCLENBQUMsc0JBQXNCLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN0RixNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLGVBQWUsRUFBRSxVQUFVLENBQUMsQ0FBQztRQUN4RSxPQUFPLENBQUMsUUFBUSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQywyQkFBMkIsQ0FDMUUsSUFBSSxDQUFDLFVBQVUsRUFDZixPQUFPLEVBQ1AsZUFBZSxDQUFDLE1BQU0sQ0FDdkIsQ0FBQztJQUNKLENBQUM7Q0FDRjtBQWxCRCw0QkFrQkMifQ==
@@ -0,0 +1,14 @@
1
+ /// <reference types="koa__router" />
2
+ import Router from '@koa/router';
3
+ import { AgentOptionsWithDefaults, RouteType } from '../types';
4
+ import { ForestAdminHttpDriverServices } from '../services';
5
+ export default abstract class BaseRoute {
6
+ protected readonly services: ForestAdminHttpDriverServices;
7
+ protected readonly options: AgentOptionsWithDefaults;
8
+ abstract get type(): RouteType;
9
+ constructor(services: ForestAdminHttpDriverServices, options: AgentOptionsWithDefaults);
10
+ bootstrap(): Promise<void>;
11
+ tearDown(): Promise<void>;
12
+ abstract setupRoutes(router: Router): void;
13
+ }
14
+ //# sourceMappingURL=base-route.d.ts.map
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class BaseRoute {
4
+ constructor(services, options) {
5
+ this.services = services;
6
+ this.options = options;
7
+ }
8
+ async bootstrap() {
9
+ // Do nothing by default
10
+ }
11
+ async tearDown() {
12
+ // Do nothing by default
13
+ }
14
+ }
15
+ exports.default = BaseRoute;
16
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZS1yb3V0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hZ2VudC9yb3V0ZXMvYmFzZS1yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUtBLE1BQThCLFNBQVM7SUFNckMsWUFBWSxRQUF1QyxFQUFFLE9BQWlDO1FBQ3BGLElBQUksQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO1FBQ3pCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO0lBQ3pCLENBQUM7SUFFRCxLQUFLLENBQUMsU0FBUztRQUNiLHdCQUF3QjtJQUMxQixDQUFDO0lBRUQsS0FBSyxDQUFDLFFBQVE7UUFDWix3QkFBd0I7SUFDMUIsQ0FBQztDQUdGO0FBcEJELDRCQW9CQyJ9
@@ -0,0 +1,12 @@
1
+ import { Collection, DataSource } from '@forestadmin/datasource-toolkit';
2
+ import { AgentOptionsWithDefaults, RouteType } from '../types';
3
+ import { ForestAdminHttpDriverServices } from '../services';
4
+ import BaseRoute from './base-route';
5
+ export default abstract class CollectionRoute extends BaseRoute {
6
+ type: RouteType;
7
+ private readonly collectionName;
8
+ protected readonly dataSource: DataSource;
9
+ protected get collection(): Collection;
10
+ constructor(services: ForestAdminHttpDriverServices, options: AgentOptionsWithDefaults, dataSource: DataSource, collectionName: string);
11
+ }
12
+ //# sourceMappingURL=collection-route.d.ts.map
@@ -0,0 +1,20 @@
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 types_1 = require("../types");
7
+ const base_route_1 = __importDefault(require("./base-route"));
8
+ class CollectionRoute extends base_route_1.default {
9
+ constructor(services, options, dataSource, collectionName) {
10
+ super(services, options);
11
+ this.type = types_1.RouteType.PrivateRoute;
12
+ this.collectionName = collectionName;
13
+ this.dataSource = dataSource;
14
+ }
15
+ get collection() {
16
+ return this.dataSource.getCollection(this.collectionName);
17
+ }
18
+ }
19
+ exports.default = CollectionRoute;
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29sbGVjdGlvbi1yb3V0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9hZ2VudC9yb3V0ZXMvY29sbGVjdGlvbi1yb3V0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUVBLG9DQUErRDtBQUUvRCw4REFBcUM7QUFFckMsTUFBOEIsZUFBZ0IsU0FBUSxvQkFBUztJQVU3RCxZQUNFLFFBQXVDLEVBQ3ZDLE9BQWlDLEVBQ2pDLFVBQXNCLEVBQ3RCLGNBQXNCO1FBRXRCLEtBQUssQ0FBQyxRQUFRLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFmM0IsU0FBSSxHQUFHLGlCQUFTLENBQUMsWUFBWSxDQUFDO1FBZ0I1QixJQUFJLENBQUMsY0FBYyxHQUFHLGNBQWMsQ0FBQztRQUNyQyxJQUFJLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztJQUMvQixDQUFDO0lBYkQsSUFBYyxVQUFVO1FBQ3RCLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxDQUFDO0lBQzVELENBQUM7Q0FZRjtBQXBCRCxrQ0FvQkMifQ==