@forestadmin/datasource-customizer 1.0.0-alpha.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.
- package/LICENSE +674 -0
- package/README.md +0 -0
- package/dist/collection-customizer.d.ts +263 -0
- package/dist/collection-customizer.js +397 -0
- package/dist/context/agent-context.d.ts +11 -0
- package/dist/context/agent-context.js +20 -0
- package/dist/context/collection-context.d.ts +10 -0
- package/dist/context/collection-context.js +18 -0
- package/dist/context/relaxed-wrappers/collection.d.ts +112 -0
- package/dist/context/relaxed-wrappers/collection.js +161 -0
- package/dist/context/relaxed-wrappers/datasource.d.ts +15 -0
- package/dist/context/relaxed-wrappers/datasource.js +22 -0
- package/dist/datasource-customizer.d.ts +53 -0
- package/dist/datasource-customizer.js +89 -0
- package/dist/decorators/actions/collection.d.ts +18 -0
- package/dist/decorators/actions/collection.js +104 -0
- package/dist/decorators/actions/context/base.d.ts +28 -0
- package/dist/decorators/actions/context/base.js +105 -0
- package/dist/decorators/actions/context/single.d.ts +9 -0
- package/dist/decorators/actions/context/single.js +22 -0
- package/dist/decorators/actions/result-builder.d.ts +53 -0
- package/dist/decorators/actions/result-builder.js +81 -0
- package/dist/decorators/actions/types/actions.d.ts +18 -0
- package/dist/decorators/actions/types/actions.js +3 -0
- package/dist/decorators/actions/types/fields.d.ts +32 -0
- package/dist/decorators/actions/types/fields.js +3 -0
- package/dist/decorators/chart/datasource.d.ts +11 -0
- package/dist/decorators/chart/datasource.js +38 -0
- package/dist/decorators/chart/result-builder.d.ts +12 -0
- package/dist/decorators/chart/result-builder.js +48 -0
- package/dist/decorators/chart/types.d.ts +6 -0
- package/dist/decorators/chart/types.js +3 -0
- package/dist/decorators/collection-decorator.d.ts +21 -0
- package/dist/decorators/collection-decorator.js +57 -0
- package/dist/decorators/composite-datasource.d.ts +11 -0
- package/dist/decorators/composite-datasource.js +38 -0
- package/dist/decorators/computed/collection.d.ts +14 -0
- package/dist/decorators/computed/collection.js +69 -0
- package/dist/decorators/computed/helpers/compute-fields.d.ts +5 -0
- package/dist/decorators/computed/helpers/compute-fields.js +36 -0
- package/dist/decorators/computed/helpers/rewrite-projection.d.ts +4 -0
- package/dist/decorators/computed/helpers/rewrite-projection.js +22 -0
- package/dist/decorators/computed/types.d.ts +11 -0
- package/dist/decorators/computed/types.js +3 -0
- package/dist/decorators/computed/utils/deduplication.d.ts +2 -0
- package/dist/decorators/computed/utils/deduplication.js +28 -0
- package/dist/decorators/computed/utils/flattener.d.ts +6 -0
- package/dist/decorators/computed/utils/flattener.js +35 -0
- package/dist/decorators/datasource-decorator.d.ts +15 -0
- package/dist/decorators/datasource-decorator.js +27 -0
- package/dist/decorators/decorators-stack.d.ts +42 -0
- package/dist/decorators/decorators-stack.js +59 -0
- package/dist/decorators/empty/collection.d.ts +18 -0
- package/dist/decorators/empty/collection.js +85 -0
- package/dist/decorators/hook/collection.d.ts +13 -0
- package/dist/decorators/hook/collection.js +67 -0
- package/dist/decorators/hook/context/aggregate.d.ts +22 -0
- package/dist/decorators/hook/context/aggregate.js +46 -0
- package/dist/decorators/hook/context/create.d.ts +17 -0
- package/dist/decorators/hook/context/create.js +35 -0
- package/dist/decorators/hook/context/delete.d.ts +14 -0
- package/dist/decorators/hook/context/delete.js +28 -0
- package/dist/decorators/hook/context/hook.d.ts +26 -0
- package/dist/decorators/hook/context/hook.js +38 -0
- package/dist/decorators/hook/context/list.d.ts +20 -0
- package/dist/decorators/hook/context/list.js +42 -0
- package/dist/decorators/hook/context/update.d.ts +16 -0
- package/dist/decorators/hook/context/update.js +31 -0
- package/dist/decorators/hook/hook.d.ts +10 -0
- package/dist/decorators/hook/hook.js +30 -0
- package/dist/decorators/hook/types.d.ts +27 -0
- package/dist/decorators/hook/types.js +3 -0
- package/dist/decorators/operators-emulate/collection.d.ts +15 -0
- package/dist/decorators/operators-emulate/collection.js +99 -0
- package/dist/decorators/operators-emulate/types.d.ts +4 -0
- package/dist/decorators/operators-emulate/types.js +3 -0
- package/dist/decorators/operators-replace/collection.d.ts +10 -0
- package/dist/decorators/operators-replace/collection.js +35 -0
- package/dist/decorators/publication/collection.d.ts +14 -0
- package/dist/decorators/publication/collection.js +63 -0
- package/dist/decorators/relation/collection.d.ts +23 -0
- package/dist/decorators/relation/collection.js +190 -0
- package/dist/decorators/relation/types.d.ts +5 -0
- package/dist/decorators/relation/types.js +3 -0
- package/dist/decorators/rename-collection/collection.d.ts +15 -0
- package/dist/decorators/rename-collection/collection.js +50 -0
- package/dist/decorators/rename-collection/datasource.d.ts +11 -0
- package/dist/decorators/rename-collection/datasource.js +33 -0
- package/dist/decorators/rename-field/collection.d.ts +33 -0
- package/dist/decorators/rename-field/collection.js +149 -0
- package/dist/decorators/schema/collection.d.ts +13 -0
- package/dist/decorators/schema/collection.js +26 -0
- package/dist/decorators/search/collection.d.ts +14 -0
- package/dist/decorators/search/collection.js +105 -0
- package/dist/decorators/search/types.d.ts +4 -0
- package/dist/decorators/search/types.js +3 -0
- package/dist/decorators/segment/collection.d.ts +10 -0
- package/dist/decorators/segment/collection.js +43 -0
- package/dist/decorators/segment/types.d.ts +4 -0
- package/dist/decorators/segment/types.js +3 -0
- package/dist/decorators/sort-emulate/collection.d.ts +15 -0
- package/dist/decorators/sort-emulate/collection.js +97 -0
- package/dist/decorators/validation/collection.d.ts +20 -0
- package/dist/decorators/validation/collection.js +109 -0
- package/dist/decorators/write/collection.d.ts +26 -0
- package/dist/decorators/write/collection.js +214 -0
- package/dist/decorators/write/context.d.ts +9 -0
- package/dist/decorators/write/context.js +15 -0
- package/dist/decorators/write/types.d.ts +4 -0
- package/dist/decorators/write/types.js +3 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +27 -0
- package/dist/templates.d.ts +65 -0
- package/dist/templates.js +3 -0
- package/dist/types.d.ts +18 -0
- package/dist/types.js +3 -0
- package/dist/typing-generator.d.ts +19 -0
- package/dist/typing-generator.js +123 -0
- package/package.json +37 -0
|
@@ -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 datasource_1 = __importDefault(require("./relaxed-wrappers/datasource"));
|
|
7
|
+
class AgentCustomizationContext {
|
|
8
|
+
constructor(dataSource, caller) {
|
|
9
|
+
this.realDataSource = dataSource;
|
|
10
|
+
this._caller = caller;
|
|
11
|
+
}
|
|
12
|
+
get dataSource() {
|
|
13
|
+
return new datasource_1.default(this.realDataSource, this._caller);
|
|
14
|
+
}
|
|
15
|
+
get caller() {
|
|
16
|
+
return Object.freeze(this._caller);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.default = AgentCustomizationContext;
|
|
20
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWdlbnQtY29udGV4dC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb250ZXh0L2FnZW50LWNvbnRleHQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFFQSwrRUFBOEQ7QUFFOUQsTUFBcUIseUJBQXlCO0lBUTVDLFlBQVksVUFBc0IsRUFBRSxNQUFjO1FBQ2hELElBQUksQ0FBQyxjQUFjLEdBQUcsVUFBVSxDQUFDO1FBQ2pDLElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDO0lBQ3hCLENBQUM7SUFQRCxJQUFJLFVBQVU7UUFDWixPQUFPLElBQUksb0JBQWlCLENBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDckUsQ0FBQztJQU9ELElBQUksTUFBTTtRQUNSLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDckMsQ0FBQztDQUNGO0FBaEJELDRDQWdCQyJ9
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Caller, Collection } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
import { TCollectionName, TSchema } from '../templates';
|
|
3
|
+
import AgentCustomizationContext from './agent-context';
|
|
4
|
+
import RelaxedCollection from './relaxed-wrappers/collection';
|
|
5
|
+
export default class CollectionCustomizationContext<S extends TSchema = TSchema, N extends TCollectionName<S> = TCollectionName<S>> extends AgentCustomizationContext<S> {
|
|
6
|
+
protected realCollection: Collection;
|
|
7
|
+
get collection(): RelaxedCollection<S, N>;
|
|
8
|
+
constructor(collection: Collection, caller: Caller);
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=collection-context.d.ts.map
|
|
@@ -0,0 +1,18 @@
|
|
|
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 agent_context_1 = __importDefault(require("./agent-context"));
|
|
7
|
+
const collection_1 = __importDefault(require("./relaxed-wrappers/collection"));
|
|
8
|
+
class CollectionCustomizationContext extends agent_context_1.default {
|
|
9
|
+
constructor(collection, caller) {
|
|
10
|
+
super(collection.dataSource, caller);
|
|
11
|
+
this.realCollection = collection;
|
|
12
|
+
}
|
|
13
|
+
get collection() {
|
|
14
|
+
return new collection_1.default(this.realCollection, this.caller);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.default = CollectionCustomizationContext;
|
|
18
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29sbGVjdGlvbi1jb250ZXh0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2NvbnRleHQvY29sbGVjdGlvbi1jb250ZXh0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBRUEsb0VBQXdEO0FBQ3hELCtFQUE4RDtBQUU5RCxNQUFxQiw4QkFHbkIsU0FBUSx1QkFBNEI7SUFPcEMsWUFBWSxVQUFzQixFQUFFLE1BQWM7UUFDaEQsS0FBSyxDQUFDLFVBQVUsQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDckMsSUFBSSxDQUFDLGNBQWMsR0FBRyxVQUFVLENBQUM7SUFDbkMsQ0FBQztJQVBELElBQUksVUFBVTtRQUNaLE9BQU8sSUFBSSxvQkFBaUIsQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNqRSxDQUFDO0NBTUY7QUFkRCxpREFjQyJ9
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { ActionField, ActionResult, Caller, Collection, RecordData } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
import { TAggregateResult, TAggregation, TCollectionName, TFieldName, TFilter, TPaginatedFilter, TPartialSimpleRow, TRow, TSchema, TSimpleRow } from '../../templates';
|
|
3
|
+
/** Collection wrapper which accepts plain objects in all methods */
|
|
4
|
+
export default class RelaxedCollection<S extends TSchema = TSchema, N extends TCollectionName<S> = TCollectionName<S>> {
|
|
5
|
+
private collection;
|
|
6
|
+
private caller;
|
|
7
|
+
constructor(collection: Collection, caller: Caller);
|
|
8
|
+
/**
|
|
9
|
+
* Execute a given action
|
|
10
|
+
* @param name the name of the action
|
|
11
|
+
* @param formValues the values of the form, if the action rely on an action form
|
|
12
|
+
* @param filter the filter used to represent the selected records to use the action on
|
|
13
|
+
* @example
|
|
14
|
+
* .execute(
|
|
15
|
+
* 'Refund',
|
|
16
|
+
* { reason: 'Article is broken' },
|
|
17
|
+
* {
|
|
18
|
+
* conditionTree: {
|
|
19
|
+
* field: 'id',
|
|
20
|
+
* operator: 'Equal',
|
|
21
|
+
* value: 1
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* );
|
|
25
|
+
*/
|
|
26
|
+
execute(name: string, formValues: RecordData, filter?: TFilter<S, N>): Promise<ActionResult>;
|
|
27
|
+
getForm(name: string, formValues?: RecordData, filter?: TFilter<S, N>): Promise<ActionField[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Create a list of records
|
|
30
|
+
* @param data An array of records to create
|
|
31
|
+
* @example
|
|
32
|
+
* .create([
|
|
33
|
+
* { amountInEur: 150, description: 'Buy dvd' },
|
|
34
|
+
* { amountInEur: -100, description: 'Refund' },
|
|
35
|
+
* ]);
|
|
36
|
+
*/
|
|
37
|
+
create(data: TSimpleRow<S, N>[]): Promise<TSimpleRow<S, N>[]>;
|
|
38
|
+
/**
|
|
39
|
+
* List multiple records
|
|
40
|
+
* @param filter the filter used to select the records to list
|
|
41
|
+
* @param projection an array of fields name representing the data to select
|
|
42
|
+
* @example
|
|
43
|
+
* .list({
|
|
44
|
+
* conditionTree: {
|
|
45
|
+
* aggregator: 'And',
|
|
46
|
+
* conditions: [{
|
|
47
|
+
* field: 'amountInEur',
|
|
48
|
+
* operator: 'GreaterThan',
|
|
49
|
+
* value: 1000
|
|
50
|
+
* }, {
|
|
51
|
+
* field: 'description',
|
|
52
|
+
* operator: 'Contains',
|
|
53
|
+
* value: 'Refund',
|
|
54
|
+
* }],
|
|
55
|
+
* page: { limit: 10, skip: 0 },
|
|
56
|
+
* sort: [{ field: 'id', ascending: true }]
|
|
57
|
+
* }
|
|
58
|
+
* }, ['id', 'amountInEur', 'description']);
|
|
59
|
+
*/
|
|
60
|
+
list(filter: TPaginatedFilter<S, N>, projection: TFieldName<S, N>[]): Promise<TRow<S, N>[]>;
|
|
61
|
+
/**
|
|
62
|
+
* Update a list of records
|
|
63
|
+
* @param filter the filter that represent the list of records to update
|
|
64
|
+
* @param patch the patch to apply on the selected records
|
|
65
|
+
* @example
|
|
66
|
+
* .update({
|
|
67
|
+
* conditionTree: {
|
|
68
|
+
* field: 'isActive',
|
|
69
|
+
* operator: 'Equal',
|
|
70
|
+
* value: false
|
|
71
|
+
* },
|
|
72
|
+
* }, { isActive: true });
|
|
73
|
+
*/
|
|
74
|
+
update(filter: TFilter<S, N>, patch: TPartialSimpleRow<S, N>): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Delete a list of records
|
|
77
|
+
* @param filter the filter that represent the list of records to update
|
|
78
|
+
* @example
|
|
79
|
+
* .delete({
|
|
80
|
+
* conditionTree: {
|
|
81
|
+
* field: 'isBlocked',
|
|
82
|
+
* operator: 'Equal',
|
|
83
|
+
* value: false,
|
|
84
|
+
* },
|
|
85
|
+
* });
|
|
86
|
+
*/
|
|
87
|
+
delete(filter: TFilter<S, N>): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Aggregate a list of records
|
|
90
|
+
* @param filter the filter used to list the records to aggregate
|
|
91
|
+
* @param aggregation the aggregation to apply
|
|
92
|
+
* @param limit the maximum number of result to return
|
|
93
|
+
* @example
|
|
94
|
+
* .aggregate({
|
|
95
|
+
* conditionTree: {
|
|
96
|
+
* field: "user:company:id",
|
|
97
|
+
* operator: "In",
|
|
98
|
+
* value: records.map((r) => r.id),
|
|
99
|
+
* },
|
|
100
|
+
* }, {
|
|
101
|
+
* operation: "Sum",
|
|
102
|
+
* field: "amountInEur",
|
|
103
|
+
* groups: [{ field: "user:company:id" }],
|
|
104
|
+
* }, 10);
|
|
105
|
+
*/
|
|
106
|
+
aggregate(filter: TFilter<S, N>, aggregation: TAggregation<S, N>, limit?: number): Promise<TAggregateResult<S, N>[]>;
|
|
107
|
+
private buildFilter;
|
|
108
|
+
private buildPaginatedFilter;
|
|
109
|
+
private buildProjection;
|
|
110
|
+
private buildAggregation;
|
|
111
|
+
}
|
|
112
|
+
//# sourceMappingURL=collection.d.ts.map
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
4
|
+
/** Collection wrapper which accepts plain objects in all methods */
|
|
5
|
+
class RelaxedCollection {
|
|
6
|
+
constructor(collection, caller) {
|
|
7
|
+
this.collection = collection;
|
|
8
|
+
this.caller = caller;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Execute a given action
|
|
12
|
+
* @param name the name of the action
|
|
13
|
+
* @param formValues the values of the form, if the action rely on an action form
|
|
14
|
+
* @param filter the filter used to represent the selected records to use the action on
|
|
15
|
+
* @example
|
|
16
|
+
* .execute(
|
|
17
|
+
* 'Refund',
|
|
18
|
+
* { reason: 'Article is broken' },
|
|
19
|
+
* {
|
|
20
|
+
* conditionTree: {
|
|
21
|
+
* field: 'id',
|
|
22
|
+
* operator: 'Equal',
|
|
23
|
+
* value: 1
|
|
24
|
+
* }
|
|
25
|
+
* }
|
|
26
|
+
* );
|
|
27
|
+
*/
|
|
28
|
+
execute(name, formValues, filter) {
|
|
29
|
+
const filterInstance = this.buildFilter(filter);
|
|
30
|
+
return this.collection.execute(this.caller, name, formValues, filterInstance);
|
|
31
|
+
}
|
|
32
|
+
getForm(name, formValues, filter) {
|
|
33
|
+
const filterInstance = this.buildFilter(filter);
|
|
34
|
+
return this.collection.getForm(this.caller, name, formValues, filterInstance);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Create a list of records
|
|
38
|
+
* @param data An array of records to create
|
|
39
|
+
* @example
|
|
40
|
+
* .create([
|
|
41
|
+
* { amountInEur: 150, description: 'Buy dvd' },
|
|
42
|
+
* { amountInEur: -100, description: 'Refund' },
|
|
43
|
+
* ]);
|
|
44
|
+
*/
|
|
45
|
+
create(data) {
|
|
46
|
+
return this.collection.create(this.caller, data);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* List multiple records
|
|
50
|
+
* @param filter the filter used to select the records to list
|
|
51
|
+
* @param projection an array of fields name representing the data to select
|
|
52
|
+
* @example
|
|
53
|
+
* .list({
|
|
54
|
+
* conditionTree: {
|
|
55
|
+
* aggregator: 'And',
|
|
56
|
+
* conditions: [{
|
|
57
|
+
* field: 'amountInEur',
|
|
58
|
+
* operator: 'GreaterThan',
|
|
59
|
+
* value: 1000
|
|
60
|
+
* }, {
|
|
61
|
+
* field: 'description',
|
|
62
|
+
* operator: 'Contains',
|
|
63
|
+
* value: 'Refund',
|
|
64
|
+
* }],
|
|
65
|
+
* page: { limit: 10, skip: 0 },
|
|
66
|
+
* sort: [{ field: 'id', ascending: true }]
|
|
67
|
+
* }
|
|
68
|
+
* }, ['id', 'amountInEur', 'description']);
|
|
69
|
+
*/
|
|
70
|
+
list(filter, projection) {
|
|
71
|
+
const filterInstance = this.buildPaginatedFilter(filter);
|
|
72
|
+
const projectionInstance = this.buildProjection(projection);
|
|
73
|
+
const rows = this.collection.list(this.caller, filterInstance, projectionInstance);
|
|
74
|
+
return rows;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Update a list of records
|
|
78
|
+
* @param filter the filter that represent the list of records to update
|
|
79
|
+
* @param patch the patch to apply on the selected records
|
|
80
|
+
* @example
|
|
81
|
+
* .update({
|
|
82
|
+
* conditionTree: {
|
|
83
|
+
* field: 'isActive',
|
|
84
|
+
* operator: 'Equal',
|
|
85
|
+
* value: false
|
|
86
|
+
* },
|
|
87
|
+
* }, { isActive: true });
|
|
88
|
+
*/
|
|
89
|
+
update(filter, patch) {
|
|
90
|
+
const filterInstance = this.buildFilter(filter);
|
|
91
|
+
return this.collection.update(this.caller, filterInstance, patch);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Delete a list of records
|
|
95
|
+
* @param filter the filter that represent the list of records to update
|
|
96
|
+
* @example
|
|
97
|
+
* .delete({
|
|
98
|
+
* conditionTree: {
|
|
99
|
+
* field: 'isBlocked',
|
|
100
|
+
* operator: 'Equal',
|
|
101
|
+
* value: false,
|
|
102
|
+
* },
|
|
103
|
+
* });
|
|
104
|
+
*/
|
|
105
|
+
delete(filter) {
|
|
106
|
+
const filterInstance = this.buildFilter(filter);
|
|
107
|
+
return this.collection.delete(this.caller, filterInstance);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Aggregate a list of records
|
|
111
|
+
* @param filter the filter used to list the records to aggregate
|
|
112
|
+
* @param aggregation the aggregation to apply
|
|
113
|
+
* @param limit the maximum number of result to return
|
|
114
|
+
* @example
|
|
115
|
+
* .aggregate({
|
|
116
|
+
* conditionTree: {
|
|
117
|
+
* field: "user:company:id",
|
|
118
|
+
* operator: "In",
|
|
119
|
+
* value: records.map((r) => r.id),
|
|
120
|
+
* },
|
|
121
|
+
* }, {
|
|
122
|
+
* operation: "Sum",
|
|
123
|
+
* field: "amountInEur",
|
|
124
|
+
* groups: [{ field: "user:company:id" }],
|
|
125
|
+
* }, 10);
|
|
126
|
+
*/
|
|
127
|
+
async aggregate(filter, aggregation, limit) {
|
|
128
|
+
const filterInstance = this.buildFilter(filter);
|
|
129
|
+
const aggregationInstance = this.buildAggregation(aggregation);
|
|
130
|
+
const result = await this.collection.aggregate(this.caller, filterInstance, aggregationInstance, limit);
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
buildFilter(filter) {
|
|
134
|
+
return filter
|
|
135
|
+
? new datasource_toolkit_1.Filter({
|
|
136
|
+
...filter,
|
|
137
|
+
conditionTree: filter.conditionTree
|
|
138
|
+
? datasource_toolkit_1.ConditionTreeFactory.fromPlainObject(filter.conditionTree)
|
|
139
|
+
: undefined,
|
|
140
|
+
})
|
|
141
|
+
: null;
|
|
142
|
+
}
|
|
143
|
+
buildPaginatedFilter(filter) {
|
|
144
|
+
return new datasource_toolkit_1.PaginatedFilter({
|
|
145
|
+
...filter,
|
|
146
|
+
conditionTree: filter?.conditionTree
|
|
147
|
+
? datasource_toolkit_1.ConditionTreeFactory.fromPlainObject(filter.conditionTree)
|
|
148
|
+
: undefined,
|
|
149
|
+
sort: filter.sort ? new datasource_toolkit_1.Sort(...filter.sort) : undefined,
|
|
150
|
+
page: filter.page ? new datasource_toolkit_1.Page(filter.page.skip, filter.page.limit) : undefined,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
buildProjection(projection) {
|
|
154
|
+
return new datasource_toolkit_1.Projection(...projection);
|
|
155
|
+
}
|
|
156
|
+
buildAggregation(aggregation) {
|
|
157
|
+
return new datasource_toolkit_1.Aggregation(aggregation);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
exports.default = RelaxedCollection;
|
|
161
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29sbGVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb250ZXh0L3JlbGF4ZWQtd3JhcHBlcnMvY29sbGVjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHdFQWF5QztBQWN6QyxvRUFBb0U7QUFDcEUsTUFBcUIsaUJBQWlCO0lBT3BDLFlBQVksVUFBc0IsRUFBRSxNQUFjO1FBQ2hELElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO1FBQzdCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FpQkc7SUFDSCxPQUFPLENBQUMsSUFBWSxFQUFFLFVBQXNCLEVBQUUsTUFBc0I7UUFDbEUsTUFBTSxjQUFjLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUVoRCxPQUFPLElBQUksQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFFLFVBQVUsRUFBRSxjQUFjLENBQUMsQ0FBQztJQUNoRixDQUFDO0lBRUQsT0FBTyxDQUFDLElBQVksRUFBRSxVQUF1QixFQUFFLE1BQXNCO1FBQ25FLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFaEQsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxVQUFVLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDaEYsQ0FBQztJQUVEOzs7Ozs7OztPQVFHO0lBQ0gsTUFBTSxDQUFDLElBQXdCO1FBQzdCLE9BQU8sSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQWdDLENBQUM7SUFDbEYsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7T0FxQkc7SUFDSCxJQUFJ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
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Caller, DataSource } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
import { TCollectionName, TSchema } from '../../templates';
|
|
3
|
+
import RelaxedCollection from './collection';
|
|
4
|
+
/** DataSource wrapper which accepts plain objects in all methods */
|
|
5
|
+
export default class RelaxedDataSource<S extends TSchema = TSchema> {
|
|
6
|
+
private dataSource;
|
|
7
|
+
private caller;
|
|
8
|
+
constructor(dataSource: DataSource, caller: Caller);
|
|
9
|
+
/**
|
|
10
|
+
* Get a collection from a datasource
|
|
11
|
+
* @param name the name of the collection
|
|
12
|
+
*/
|
|
13
|
+
getCollection<N extends TCollectionName<S>>(name: N): RelaxedCollection<S, N>;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=datasource.d.ts.map
|
|
@@ -0,0 +1,22 @@
|
|
|
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_1 = __importDefault(require("./collection"));
|
|
7
|
+
/** DataSource wrapper which accepts plain objects in all methods */
|
|
8
|
+
class RelaxedDataSource {
|
|
9
|
+
constructor(dataSource, caller) {
|
|
10
|
+
this.dataSource = dataSource;
|
|
11
|
+
this.caller = caller;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Get a collection from a datasource
|
|
15
|
+
* @param name the name of the collection
|
|
16
|
+
*/
|
|
17
|
+
getCollection(name) {
|
|
18
|
+
return new collection_1.default(this.dataSource.getCollection(name), this.caller);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
exports.default = RelaxedDataSource;
|
|
22
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YXNvdXJjZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9jb250ZXh0L3JlbGF4ZWQtd3JhcHBlcnMvZGF0YXNvdXJjZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUVBLDhEQUE2QztBQUU3QyxvRUFBb0U7QUFDcEUsTUFBcUIsaUJBQWlCO0lBSXBDLFlBQVksVUFBc0IsRUFBRSxNQUFjO1FBQ2hELElBQUksQ0FBQyxVQUFVLEdBQUcsVUFBVSxDQUFDO1FBQzdCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQ3ZCLENBQUM7SUFFRDs7O09BR0c7SUFDSCxhQUFhLENBQStCLElBQU87UUFDakQsT0FBTyxJQUFJLG9CQUFpQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUNqRixDQUFDO0NBQ0Y7QUFoQkQsb0NBZ0JDIn0=
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DataSource, DataSourceFactory, Logger } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
import { ChartDefinition } from './decorators/chart/types';
|
|
3
|
+
import { DataSourceOptions } from './types';
|
|
4
|
+
import { TCollectionName, TSchema } from './templates';
|
|
5
|
+
import CollectionCustomizer from './collection-customizer';
|
|
6
|
+
/**
|
|
7
|
+
* Allow to create a new Forest Admin agent from scratch.
|
|
8
|
+
* Builds the application by composing and configuring all the collection decorators.
|
|
9
|
+
*
|
|
10
|
+
* Minimal code to add a datasource
|
|
11
|
+
* @example
|
|
12
|
+
* new AgentBuilder(options)
|
|
13
|
+
* .addDataSource(new SomeDataSource())
|
|
14
|
+
* .start();
|
|
15
|
+
*/
|
|
16
|
+
export default class DataSourceCustomizer<S extends TSchema = TSchema> {
|
|
17
|
+
private readonly compositeDataSource;
|
|
18
|
+
private readonly stack;
|
|
19
|
+
private customizations;
|
|
20
|
+
constructor();
|
|
21
|
+
/**
|
|
22
|
+
* Add a datasource
|
|
23
|
+
* @param factory the datasource to add
|
|
24
|
+
* @param options the options
|
|
25
|
+
*/
|
|
26
|
+
addDataSource(factory: DataSourceFactory, options?: DataSourceOptions): this;
|
|
27
|
+
/**
|
|
28
|
+
* Create a new API chart
|
|
29
|
+
* @param name name of the chart
|
|
30
|
+
* @param definition definition of the chart
|
|
31
|
+
* @example
|
|
32
|
+
* .addChart('numCustomers', {
|
|
33
|
+
* type: 'Value',
|
|
34
|
+
* render: (context, resultBuilder) => {
|
|
35
|
+
* return resultBuilder.value(123);
|
|
36
|
+
* }
|
|
37
|
+
* })
|
|
38
|
+
*/
|
|
39
|
+
addChart(name: string, definition: ChartDefinition<S>): this;
|
|
40
|
+
/**
|
|
41
|
+
* Allow to interact with a decorated collection
|
|
42
|
+
* @param name the name of the collection to manipulate
|
|
43
|
+
* @param handle a function that provide a
|
|
44
|
+
* collection builder on the given collection name
|
|
45
|
+
* @example
|
|
46
|
+
* .customizeCollection('books', books => books.renameField('xx', 'yy'))
|
|
47
|
+
*/
|
|
48
|
+
customizeCollection<N extends TCollectionName<S>>(name: N, handle: (collection: CollectionCustomizer<S, N>) => unknown): this;
|
|
49
|
+
getDataSource(logger: Logger): Promise<DataSource>;
|
|
50
|
+
getFactory(): DataSourceFactory;
|
|
51
|
+
updateTypesOnFileSystem(typingsPath: string, typingsMaxDepth: number): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=datasource-customizer.d.ts.map
|
|
@@ -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 collection_customizer_1 = __importDefault(require("./collection-customizer"));
|
|
7
|
+
const composite_datasource_1 = __importDefault(require("./decorators/composite-datasource"));
|
|
8
|
+
const decorators_stack_1 = __importDefault(require("./decorators/decorators-stack"));
|
|
9
|
+
const datasource_1 = __importDefault(require("./decorators/rename-collection/datasource"));
|
|
10
|
+
const typing_generator_1 = __importDefault(require("./typing-generator"));
|
|
11
|
+
/**
|
|
12
|
+
* Allow to create a new Forest Admin agent from scratch.
|
|
13
|
+
* Builds the application by composing and configuring all the collection decorators.
|
|
14
|
+
*
|
|
15
|
+
* Minimal code to add a datasource
|
|
16
|
+
* @example
|
|
17
|
+
* new AgentBuilder(options)
|
|
18
|
+
* .addDataSource(new SomeDataSource())
|
|
19
|
+
* .start();
|
|
20
|
+
*/
|
|
21
|
+
class DataSourceCustomizer {
|
|
22
|
+
constructor() {
|
|
23
|
+
this.customizations = [];
|
|
24
|
+
this.compositeDataSource = new composite_datasource_1.default();
|
|
25
|
+
this.stack = new decorators_stack_1.default(this.compositeDataSource);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Add a datasource
|
|
29
|
+
* @param factory the datasource to add
|
|
30
|
+
* @param options the options
|
|
31
|
+
*/
|
|
32
|
+
addDataSource(factory, options) {
|
|
33
|
+
this.customizations.push(async (logger) => {
|
|
34
|
+
const dataSource = await factory(logger);
|
|
35
|
+
const renamedDecorator = new datasource_1.default(dataSource);
|
|
36
|
+
renamedDecorator.renameCollections(options?.rename);
|
|
37
|
+
this.compositeDataSource.addDataSource(renamedDecorator);
|
|
38
|
+
});
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Create a new API chart
|
|
43
|
+
* @param name name of the chart
|
|
44
|
+
* @param definition definition of the chart
|
|
45
|
+
* @example
|
|
46
|
+
* .addChart('numCustomers', {
|
|
47
|
+
* type: 'Value',
|
|
48
|
+
* render: (context, resultBuilder) => {
|
|
49
|
+
* return resultBuilder.value(123);
|
|
50
|
+
* }
|
|
51
|
+
* })
|
|
52
|
+
*/
|
|
53
|
+
addChart(name, definition) {
|
|
54
|
+
this.customizations.push(async () => {
|
|
55
|
+
this.stack.chart.addChart(name, definition);
|
|
56
|
+
});
|
|
57
|
+
return this;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Allow to interact with a decorated collection
|
|
61
|
+
* @param name the name of the collection to manipulate
|
|
62
|
+
* @param handle a function that provide a
|
|
63
|
+
* collection builder on the given collection name
|
|
64
|
+
* @example
|
|
65
|
+
* .customizeCollection('books', books => books.renameField('xx', 'yy'))
|
|
66
|
+
*/
|
|
67
|
+
customizeCollection(name, handle) {
|
|
68
|
+
this.customizations.push(async () => {
|
|
69
|
+
if (this.stack.dataSource.getCollection(name)) {
|
|
70
|
+
handle(new collection_customizer_1.default(this.stack, name));
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
return this;
|
|
74
|
+
}
|
|
75
|
+
async getDataSource(logger) {
|
|
76
|
+
while (this.customizations.length) {
|
|
77
|
+
await this.customizations.shift()(logger); // eslint-disable-line no-await-in-loop
|
|
78
|
+
}
|
|
79
|
+
return this.stack.dataSource;
|
|
80
|
+
}
|
|
81
|
+
getFactory() {
|
|
82
|
+
return async (logger) => this.getDataSource(logger);
|
|
83
|
+
}
|
|
84
|
+
async updateTypesOnFileSystem(typingsPath, typingsMaxDepth) {
|
|
85
|
+
return typing_generator_1.default.updateTypesOnFileSystem(this.stack.hook, typingsPath, typingsMaxDepth);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
exports.default = DataSourceCustomizer;
|
|
89
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YXNvdXJjZS1jdXN0b21pemVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2RhdGFzb3VyY2UtY3VzdG9taXplci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQUtBLG9GQUEyRDtBQUMzRCw2RkFBb0U7QUFDcEUscUZBQTREO0FBQzVELDJGQUE0RjtBQUM1RiwwRUFBaUQ7QUFFakQ7Ozs7Ozs7OztHQVNHO0FBQ0gsTUFBcUIsb0JBQW9CO0lBS3ZDO1FBRlEsbUJBQWMsR0FBMEMsRUFBRSxDQUFDO1FBR2pFLElBQUksQ0FBQyxtQkFBbUIsR0FBRyxJQUFJLDhCQUFtQixFQUFjLENBQUM7UUFDakUsSUFBSSxDQUFDLEtBQUssR0FBRyxJQUFJLDBCQUFlLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFDN0QsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxhQUFhLENBQUMsT0FBMEIsRUFBRSxPQUEyQjtRQUNuRSxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUMsTUFBTSxFQUFDLEVBQUU7WUFDdEMsTUFBTSxVQUFVLEdBQUcsTUFBTSxPQUFPLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDekMsTUFBTSxnQkFBZ0IsR0FBRyxJQUFJLG9CQUFtQyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBQzdFLGdCQUFnQixDQUFDLGlCQUFpQixDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztZQUVwRCxJQUFJLENBQUMsbUJBQW1CLENBQUMsYUFBYSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDM0QsQ0FBQyxDQUFDLENBQUM7UUFFSCxPQUFPLElBQUksQ0FBQztJQUNkLENBQUM7SUFFRDs7Ozs7Ozs7Ozs7T0FXRztJQUNILFFBQVEsQ0FBQyxJQUFZLEVBQUUsVUFBOEI7UUFDbkQsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsS0FBSyxJQUFJLEVBQUU7WUFDbEMsSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQztRQUM5QyxDQUFDLENBQUMsQ0FBQztRQUVILE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSCxtQkFBbUIsQ0FDakIsSUFBTyxFQUNQLE1BQTJEO1FBRTNELElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLEtBQUssSUFBSSxFQUFFO1lBQ2xDLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFO2dCQUM3QyxNQUFNLENBQUMsSUFBSSwrQkFBb0IsQ0FBTyxJQUFJLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7YUFDMUQ7UUFDSCxDQUFDLENBQUMsQ0FBQztRQUVILE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELEtBQUssQ0FBQyxhQUFhLENBQUMsTUFBYztRQUNoQyxPQUFPLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFO1lBQ2pDLE1BQU0sSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLHVDQUF1QztTQUNuRjtRQUVELE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUM7SUFDL0IsQ0FBQztJQUVELFVBQVU7UUFDUixPQUFPLEtBQUssRUFBRSxNQUFjLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDOUQsQ0FBQztJQUVELEtBQUssQ0FBQyx1QkFBdUIsQ0FBQyxXQUFtQixFQUFFLGVBQXVCO1FBQ3hFLE9BQU8sMEJBQWUsQ0FBQyx1QkFBdUIsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxXQUFXLEVBQUUsZUFBZSxDQUFDLENBQUM7SUFDaEcsQ0FBQztDQUNGO0FBbkZELHVDQW1GQyJ9
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ActionField, ActionResult, Caller, CollectionSchema, Filter, RecordData } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
import { ActionDefinition } from './types/actions';
|
|
3
|
+
import CollectionDecorator from '../collection-decorator';
|
|
4
|
+
import DataSourceDecorator from '../datasource-decorator';
|
|
5
|
+
export default class ActionCollectionDecorator extends CollectionDecorator {
|
|
6
|
+
readonly dataSource: DataSourceDecorator<ActionCollectionDecorator>;
|
|
7
|
+
private actions;
|
|
8
|
+
addAction(name: string, action: ActionDefinition): void;
|
|
9
|
+
execute(caller: Caller, name: string, data: RecordData, filter: Filter): Promise<ActionResult>;
|
|
10
|
+
getForm(caller: Caller, name: string, data?: RecordData, filter?: Filter): Promise<ActionField[]>;
|
|
11
|
+
protected refineSchema(subSchema: CollectionSchema): CollectionSchema;
|
|
12
|
+
private getContext;
|
|
13
|
+
private dropDefaults;
|
|
14
|
+
private dropIfs;
|
|
15
|
+
private dropDeferred;
|
|
16
|
+
private evaluate;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=collection.d.ts.map
|
|
@@ -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 base_1 = __importDefault(require("./context/base"));
|
|
7
|
+
const single_1 = __importDefault(require("./context/single"));
|
|
8
|
+
const collection_decorator_1 = __importDefault(require("../collection-decorator"));
|
|
9
|
+
const result_builder_1 = __importDefault(require("./result-builder"));
|
|
10
|
+
class ActionCollectionDecorator extends collection_decorator_1.default {
|
|
11
|
+
constructor() {
|
|
12
|
+
super(...arguments);
|
|
13
|
+
this.actions = {};
|
|
14
|
+
}
|
|
15
|
+
addAction(name, action) {
|
|
16
|
+
this.actions[name] = action;
|
|
17
|
+
this.markSchemaAsDirty();
|
|
18
|
+
}
|
|
19
|
+
async execute(caller, name, data, filter) {
|
|
20
|
+
const action = this.actions[name];
|
|
21
|
+
if (!action)
|
|
22
|
+
return this.childCollection.execute(caller, name, data, filter);
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
+
const context = this.getContext(caller, action, data, filter);
|
|
25
|
+
const resultBuilder = new result_builder_1.default();
|
|
26
|
+
const result = await action.execute(context, resultBuilder);
|
|
27
|
+
return (result || {
|
|
28
|
+
type: 'Success',
|
|
29
|
+
invalidated: new Set(),
|
|
30
|
+
message: 'Success',
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
async getForm(caller, name, data, filter) {
|
|
34
|
+
const action = this.actions[name];
|
|
35
|
+
if (!action)
|
|
36
|
+
return this.childCollection.getForm(caller, name, data, filter);
|
|
37
|
+
if (!action.form)
|
|
38
|
+
return [];
|
|
39
|
+
const formValues = data ? { ...data } : {};
|
|
40
|
+
const used = new Set();
|
|
41
|
+
const context = this.getContext(caller, action, formValues, filter, used);
|
|
42
|
+
// Convert DynamicField to ActionField in successive steps.
|
|
43
|
+
let dynamicFields;
|
|
44
|
+
dynamicFields = action.form.map(c => ({ ...c }));
|
|
45
|
+
dynamicFields = await this.dropDefaults(context, dynamicFields, !data, formValues);
|
|
46
|
+
dynamicFields = await this.dropIfs(context, dynamicFields);
|
|
47
|
+
const fields = await this.dropDeferred(context, dynamicFields);
|
|
48
|
+
for (const field of fields) {
|
|
49
|
+
// customer did not define a handler to rewrite the previous value => reuse current one.
|
|
50
|
+
if (field.value === undefined)
|
|
51
|
+
field.value = formValues[field.label];
|
|
52
|
+
// fields that were accessed through the context.formValues.X getter should be watched.
|
|
53
|
+
field.watchChanges = used.has(field.label);
|
|
54
|
+
}
|
|
55
|
+
return fields;
|
|
56
|
+
}
|
|
57
|
+
refineSchema(subSchema) {
|
|
58
|
+
const newSchema = { ...subSchema, actions: { ...subSchema.actions } };
|
|
59
|
+
for (const [name, { form, scope, generateFile }] of Object.entries(this.actions)) {
|
|
60
|
+
// An action form can be send in the schema to avoid calling the load handler
|
|
61
|
+
// as long as there is nothing dynamic in it.
|
|
62
|
+
const isDynamic = form?.some(field => Object.values(field).some(value => typeof value === 'function'));
|
|
63
|
+
newSchema.actions[name] = { scope, generateFile: !!generateFile, staticForm: !isDynamic };
|
|
64
|
+
}
|
|
65
|
+
return newSchema;
|
|
66
|
+
}
|
|
67
|
+
getContext(caller, action, formValues, filter, used) {
|
|
68
|
+
return new {
|
|
69
|
+
Global: base_1.default,
|
|
70
|
+
Bulk: base_1.default,
|
|
71
|
+
Single: single_1.default,
|
|
72
|
+
}[action.scope](this, caller, formValues, filter, used);
|
|
73
|
+
}
|
|
74
|
+
async dropDefaults(context, fields, isFirstCall, data) {
|
|
75
|
+
if (isFirstCall) {
|
|
76
|
+
const defaults = await Promise.all(fields.map(field => this.evaluate(context, field.defaultValue)));
|
|
77
|
+
fields.forEach((field, index) => {
|
|
78
|
+
data[field.label] = defaults[index];
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
fields.forEach(field => delete field.defaultValue);
|
|
82
|
+
return fields;
|
|
83
|
+
}
|
|
84
|
+
async dropIfs(context, fields) {
|
|
85
|
+
// Remove fields which have falsy if
|
|
86
|
+
const ifValues = await Promise.all(fields.map(field => !field.if || this.evaluate(context, field.if)));
|
|
87
|
+
const newFields = fields.filter((_, index) => ifValues[index]);
|
|
88
|
+
newFields.forEach(field => delete field.if);
|
|
89
|
+
return newFields;
|
|
90
|
+
}
|
|
91
|
+
async dropDeferred(context, fields) {
|
|
92
|
+
const newFields = fields.map(async (field) => {
|
|
93
|
+
const keys = Object.keys(field);
|
|
94
|
+
const values = await Promise.all(Object.values(field).map(value => this.evaluate(context, value)));
|
|
95
|
+
return keys.reduce((memo, key, index) => ({ ...memo, [key]: values[index] }), {});
|
|
96
|
+
});
|
|
97
|
+
return Promise.all(newFields);
|
|
98
|
+
}
|
|
99
|
+
async evaluate(context, value) {
|
|
100
|
+
return typeof value === 'function' ? value(context) : value;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
exports.default = ActionCollectionDecorator;
|
|
104
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29sbGVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9kZWNvcmF0b3JzL2FjdGlvbnMvY29sbGVjdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7OztBQVlBLDBEQUEyQztBQUMzQyw4REFBbUQ7QUFDbkQsbUZBQTBEO0FBRTFELHNFQUE2QztBQUU3QyxNQUFxQix5QkFBMEIsU0FBUSw4QkFBbUI7SUFBMUU7O1FBR1UsWUFBTyxHQUFxQyxFQUFFLENBQUM7SUFtSnpELENBQUM7SUFqSkMsU0FBUyxDQUFDLElBQVksRUFBRSxNQUF3QjtRQUM5QyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU0sQ0FBQztRQUM1QixJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRVEsS0FBSyxDQUFDLE9BQU8sQ0FDcEIsTUFBYyxFQUNkLElBQVksRUFDWixJQUFnQixFQUNoQixNQUFjO1FBRWQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNsQyxJQUFJLENBQUMsTUFBTTtZQUFFLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFFN0UsOERBQThEO1FBQzlELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsTUFBTSxFQUFFLE1BQU0sRUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFRLENBQUM7UUFDckUsTUFBTSxhQUFhLEdBQUcsSUFBSSx3QkFBYSxFQUFFLENBQUM7UUFDMUMsTUFBTSxNQUFNLEdBQUcsTUFBTSxNQUFNLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxhQUFhLENBQUMsQ0FBQztRQUU1RCxPQUFPLENBQ0wsTUFBTSxJQUFJO1lBQ1IsSUFBSSxFQUFFLFNBQWtCO1lBQ3hCLFdBQVcsRUFBRSxJQUFJLEdB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
|