@forestadmin/plugin-flattener 1.0.0 → 1.0.2
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/dist/flatten-column/customization.d.ts +11 -0
- package/dist/flatten-column/customization.js +78 -0
- package/dist/flatten-column/helpers.d.ts +43 -0
- package/dist/flatten-column/helpers.js +90 -0
- package/dist/flatten-column/index.d.ts +22 -0
- package/dist/flatten-column/index.js +65 -0
- package/dist/flatten-relation/helpers.d.ts +5 -0
- package/dist/flatten-relation/helpers.js +27 -0
- package/dist/flatten-relation/index.d.ts +19 -0
- package/dist/flatten-relation/index.js +33 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +5 -5
- package/package.json +5 -5
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CollectionCustomizer, HookBeforeCreateContext, HookBeforeUpdateContext } from '@forestadmin/datasource-customizer';
|
|
2
|
+
import { ColumnSchema, ColumnType } from '@forestadmin/datasource-toolkit';
|
|
3
|
+
export declare function makeField(columnName: string, path: string, schema: ColumnSchema): {
|
|
4
|
+
columnType: ColumnType;
|
|
5
|
+
dependencies: string[];
|
|
6
|
+
getValues: (records: any) => any;
|
|
7
|
+
};
|
|
8
|
+
export declare function makeWriteHandler(path: string): () => never;
|
|
9
|
+
export declare function makeCreateHook(paths: string[]): (context: HookBeforeCreateContext) => Promise<void>;
|
|
10
|
+
export declare function makeUpdateHook(collection: CollectionCustomizer, columnName: string, paths: string[]): (context: HookBeforeUpdateContext) => Promise<void>;
|
|
11
|
+
//# sourceMappingURL=customization.d.ts.map
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.makeUpdateHook = exports.makeCreateHook = exports.makeWriteHandler = exports.makeField = void 0;
|
|
7
|
+
const datasource_toolkit_1 = require("@forestadmin/datasource-toolkit");
|
|
8
|
+
const object_hash_1 = __importDefault(require("object-hash"));
|
|
9
|
+
const helpers_1 = require("./helpers");
|
|
10
|
+
function makeField(columnName, path, schema) {
|
|
11
|
+
const columnType = (0, helpers_1.getValue)({ [columnName]: schema.columnType }, path);
|
|
12
|
+
if (!columnType)
|
|
13
|
+
throw new Error(`Cannot add field '${path}' (dependency not found).`);
|
|
14
|
+
return {
|
|
15
|
+
columnType,
|
|
16
|
+
dependencies: [columnName],
|
|
17
|
+
getValues: records => records.map(r => (0, helpers_1.getValue)(r, path)),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
exports.makeField = makeField;
|
|
21
|
+
function makeWriteHandler(path) {
|
|
22
|
+
// We're ignoring this line in coverage because it's not callable: we're adding a write handler
|
|
23
|
+
// only so that the field is marked as writable, but all the writes are handled by the hooks.
|
|
24
|
+
// istanbul ignore next
|
|
25
|
+
return () => {
|
|
26
|
+
throw new Error(`Cannot write on computed field '${path}'. Did you inhibit BeforeHooks?`);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
exports.makeWriteHandler = makeWriteHandler;
|
|
30
|
+
function makeCreateHook(paths) {
|
|
31
|
+
return async (context) => {
|
|
32
|
+
for (const record of context.data) {
|
|
33
|
+
(0, helpers_1.unflattenPathsInPlace)(paths, record);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
exports.makeCreateHook = makeCreateHook;
|
|
38
|
+
function makeUpdateHook(collection, columnName, paths) {
|
|
39
|
+
return async (context) => {
|
|
40
|
+
(0, helpers_1.unflattenPathsInPlace)(paths, context.patch);
|
|
41
|
+
// We're not updating the nested column, so we don't have anything to do.
|
|
42
|
+
if (!context.patch[columnName])
|
|
43
|
+
return;
|
|
44
|
+
// List the records that we're updating, and group them by the patch that we'll need to apply
|
|
45
|
+
const projection = [...datasource_toolkit_1.SchemaUtils.getPrimaryKeys(collection.schema), columnName];
|
|
46
|
+
const records = await context.collection.list(context.filter, projection);
|
|
47
|
+
const recordsByPatch = new Map();
|
|
48
|
+
for (const record of records) {
|
|
49
|
+
const patchForThatRecord = { [columnName]: record[columnName] };
|
|
50
|
+
(0, helpers_1.deepUpdateInPlace)(patchForThatRecord, { [columnName]: context.patch[columnName] });
|
|
51
|
+
const hash = (0, object_hash_1.default)(patchForThatRecord);
|
|
52
|
+
if (!recordsByPatch.has(hash))
|
|
53
|
+
recordsByPatch.set(hash, { matches: [], patch: patchForThatRecord });
|
|
54
|
+
recordsByPatch.get(hash).matches.push(record);
|
|
55
|
+
}
|
|
56
|
+
if (recordsByPatch.size === 1) {
|
|
57
|
+
// All records have the same patch!
|
|
58
|
+
// That happened either because we got only one record, or because we got lucky.
|
|
59
|
+
// In any case, we don't need to perform separate requests.
|
|
60
|
+
const { patch } = recordsByPatch.values().next().value;
|
|
61
|
+
context.patch[columnName] = patch[columnName];
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
// Different patches need to be applied to different groups of records.
|
|
65
|
+
// We need to perform separate requests.
|
|
66
|
+
const promises = [...recordsByPatch.values()].map(({ matches, patch }) => {
|
|
67
|
+
const conditionTree = datasource_toolkit_1.ConditionTreeFactory.matchRecords(collection.schema, matches);
|
|
68
|
+
const filter = { conditionTree: conditionTree };
|
|
69
|
+
return context.collection.update(filter, patch);
|
|
70
|
+
});
|
|
71
|
+
await Promise.all(promises);
|
|
72
|
+
// Tell child decorators that we've already handled the update.
|
|
73
|
+
delete context.patch[columnName];
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
exports.makeUpdateHook = makeUpdateHook;
|
|
78
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY3VzdG9taXphdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mbGF0dGVuLWNvbHVtbi9jdXN0b21pemF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQU9BLHdFQUt5QztBQUN6Qyw4REFBcUM7QUFFckMsdUNBQStFO0FBRS9FLFNBQWdCLFNBQVMsQ0FBQyxVQUFrQixFQUFFLElBQVksRUFBRSxNQUFvQjtJQUM5RSxNQUFNLFVBQVUsR0FBRyxJQUFBLGtCQUFRLEVBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxVQUFVLEVBQUUsRUFBRSxJQUFJLENBQWUsQ0FBQztJQUNyRixJQUFJLENBQUMsVUFBVTtRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMscUJBQXFCLElBQUksMkJBQTJCLENBQUMsQ0FBQztJQUV2RixPQUFPO1FBQ0wsVUFBVTtRQUNWLFlBQVksRUFBRSxDQUFDLFVBQVUsQ0FBQztRQUMxQixTQUFTLEVBQUUsT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBQSxrQkFBUSxFQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQztLQUMxRCxDQUFDO0FBQ0osQ0FBQztBQVRELDhCQVNDO0FBRUQsU0FBZ0IsZ0JBQWdCLENBQUMsSUFBWTtJQUMzQywrRkFBK0Y7SUFDL0YsNkZBQTZGO0lBRTdGLHVCQUF1QjtJQUN2QixPQUFPLEdBQUcsRUFBRTtRQUNWLE1BQU0sSUFBSSxLQUFLLENBQUMsbUNBQW1DLElBQUksaUNBQWlDLENBQUMsQ0FBQztJQUM1RixDQUFDLENBQUM7QUFDSixDQUFDO0FBUkQsNENBUUM7QUFFRCxTQUFnQixjQUFjLENBQUMsS0FBZTtJQUM1QyxPQUFPLEtBQUssRUFBRSxPQUFnQyxFQUFFLEVBQUU7UUFDaEQsS0FBSyxNQUFNLE1BQU0sSUFBSSxPQUFPLENBQUMsSUFBSSxFQUFFO1lBQ2pDLElB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
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ColumnType, RecordData } from '@forestadmin/datasource-toolkit';
|
|
2
|
+
/**
|
|
3
|
+
* Given the name of a column, its type and the maximum allowed depth, compute the list of paths
|
|
4
|
+
* that can be flattened.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* listPaths('address', { streetName: 'String' }, 2)
|
|
8
|
+
* // => ['address@@@streetName']
|
|
9
|
+
*/
|
|
10
|
+
export declare function listPaths(columnName: string, type: ColumnType, level: number): string[];
|
|
11
|
+
/**
|
|
12
|
+
* Convert string which are provided in the options.include and options.exclude to a valid path.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* includeStrToPath('country:name', 'address') // => 'address@@@country@@@name'
|
|
16
|
+
*/
|
|
17
|
+
export declare function includeStrToPath(columnName: string, include: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Recursively update the first object with the values of the second one.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* deepUpdateInPlace({ a: 1, b: 2 }, { b: 3, c: 4 })
|
|
23
|
+
* // => { a: 1, b: 3, c: 4 }
|
|
24
|
+
*/
|
|
25
|
+
export declare function deepUpdateInPlace(memo: RecordData, newData: RecordData): void;
|
|
26
|
+
/**
|
|
27
|
+
* Get a flattened value from a record.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* getValue({ address: { streetName: 'rue de la paix' } }, 'address@@@streetName')
|
|
31
|
+
* // => 'rue de la paix'
|
|
32
|
+
*/
|
|
33
|
+
export declare function getValue(object: unknown, path: string): unknown;
|
|
34
|
+
/**
|
|
35
|
+
* Given a list of flattened paths, unflatten them in place in the given object.
|
|
36
|
+
* The values of the flattened paths are deleted from the object in place.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* unflattenPathsInPlace(['address@@@streetName'], { 'address@@@streetName': 'rue de la paix' })
|
|
40
|
+
* // => { address: { streetName: 'rue de la paix' } }
|
|
41
|
+
*/
|
|
42
|
+
export declare function unflattenPathsInPlace(paths: string[], patch: RecordData): void;
|
|
43
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.unflattenPathsInPlace = exports.getValue = exports.deepUpdateInPlace = exports.includeStrToPath = exports.listPaths = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Given the name of a column, its type and the maximum allowed depth, compute the list of paths
|
|
6
|
+
* that can be flattened.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* listPaths('address', { streetName: 'String' }, 2)
|
|
10
|
+
* // => ['address@@@streetName']
|
|
11
|
+
*/
|
|
12
|
+
function listPaths(columnName, type, level) {
|
|
13
|
+
return level <= 0 || typeof type !== 'object'
|
|
14
|
+
? [columnName]
|
|
15
|
+
: Object.keys(type)
|
|
16
|
+
.map(key => listPaths(`${columnName}@@@${key}`, type[key], level - 1))
|
|
17
|
+
.flat();
|
|
18
|
+
}
|
|
19
|
+
exports.listPaths = listPaths;
|
|
20
|
+
/**
|
|
21
|
+
* Convert string which are provided in the options.include and options.exclude to a valid path.
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* includeStrToPath('country:name', 'address') // => 'address@@@country@@@name'
|
|
25
|
+
*/
|
|
26
|
+
function includeStrToPath(columnName, include) {
|
|
27
|
+
return `${columnName}@@@${include.replace(/[.:]/g, '@@@')}`;
|
|
28
|
+
}
|
|
29
|
+
exports.includeStrToPath = includeStrToPath;
|
|
30
|
+
/**
|
|
31
|
+
* Recursively update the first object with the values of the second one.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* deepUpdateInPlace({ a: 1, b: 2 }, { b: 3, c: 4 })
|
|
35
|
+
* // => { a: 1, b: 3, c: 4 }
|
|
36
|
+
*/
|
|
37
|
+
function deepUpdateInPlace(memo, newData) {
|
|
38
|
+
for (const [key, value] of Object.entries(newData)) {
|
|
39
|
+
const isObject = value && typeof value === 'object' && Object.getPrototypeOf(value) === Object.prototype;
|
|
40
|
+
if (isObject) {
|
|
41
|
+
memo[key] ?? (memo[key] = {});
|
|
42
|
+
deepUpdateInPlace(memo[key], value);
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
memo[key] = value;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.deepUpdateInPlace = deepUpdateInPlace;
|
|
50
|
+
/**
|
|
51
|
+
* Get a flattened value from a record.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* getValue({ address: { streetName: 'rue de la paix' } }, 'address@@@streetName')
|
|
55
|
+
* // => 'rue de la paix'
|
|
56
|
+
*/
|
|
57
|
+
function getValue(object, path) {
|
|
58
|
+
const parts = path.split('@@@');
|
|
59
|
+
return parts.length === 1
|
|
60
|
+
? object[parts[0]]
|
|
61
|
+
: getValue(object[parts[0]], parts.slice(1).join('@@@'));
|
|
62
|
+
}
|
|
63
|
+
exports.getValue = getValue;
|
|
64
|
+
/**
|
|
65
|
+
* Given a list of flattened paths, unflatten them in place in the given object.
|
|
66
|
+
* The values of the flattened paths are deleted from the object in place.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* unflattenPathsInPlace(['address@@@streetName'], { 'address@@@streetName': 'rue de la paix' })
|
|
70
|
+
* // => { address: { streetName: 'rue de la paix' } }
|
|
71
|
+
*/
|
|
72
|
+
function unflattenPathsInPlace(paths, patch) {
|
|
73
|
+
const keysToRewrite = paths.filter(p => patch[p] !== undefined);
|
|
74
|
+
for (const key of keysToRewrite) {
|
|
75
|
+
let subExternalPatch = patch;
|
|
76
|
+
const parts = key.split('@@@');
|
|
77
|
+
for (const [index, part] of parts.entries()) {
|
|
78
|
+
if (index === parts.length - 1) {
|
|
79
|
+
subExternalPatch[part] = patch[key];
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
subExternalPatch[part] ?? (subExternalPatch[part] = {});
|
|
83
|
+
subExternalPatch = subExternalPatch[part];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
delete patch[key];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
exports.unflattenPathsInPlace = unflattenPathsInPlace;
|
|
90
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mbGF0dGVuLWNvbHVtbi9oZWxwZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBOzs7Ozs7O0dBT0c7QUFDSCxTQUFnQixTQUFTLENBQUMsVUFBa0IsRUFBRSxJQUFnQixFQUFFLEtBQWE7SUFDM0UsT0FBTyxLQUFLLElBQUksQ0FBQyxJQUFJLE9BQU8sSUFBSSxLQUFLLFFBQVE7UUFDM0MsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDO1FBQ2QsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO2FBQ2QsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLEdBQUcsVUFBVSxNQUFNLEdBQUcsRUFBRSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxLQUFLLEdBQUcsQ0FBQyxDQUFDLENBQUM7YUFDckUsSUFBSSxFQUFFLENBQUM7QUFDaEIsQ0FBQztBQU5ELDhCQU1DO0FBRUQ7Ozs7O0dBS0c7QUFDSCxTQUFnQixnQkFBZ0IsQ0FBQyxVQUFrQixFQUFFLE9BQWU7SUFDbEUsT0FBTyxHQUFHLFVBQVUsTUFBTSxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDO0FBQzlELENBQUM7QUFGRCw0Q0FFQztBQUVEOzs7Ozs7R0FNRztBQUNILFNBQWdCLGlCQUFpQixDQUFDLElBQWdCLEVBQUUsT0FBbUI7SUFDckUsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUU7UUFDbEQsTUFBTSxRQUFRLEdBQ1osS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxLQUFLLE1BQU0sQ0FBQyxTQUFTLENBQUM7UUFFMUYsSUFBSSxRQUFRLEVBQUU7WUFDWixJQUFJLENBQUMsR0FBRyxNQUFSLElBQUksQ0FBQyxHQUFHLElBQU0sRUFBRSxFQUFDO1lBQ2pCLGlCQUFpQixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztTQUNyQzthQUFNO1lBQ0wsSUFBSSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQztTQUNuQjtLQUNGO0FBQ0gsQ0FBQztBQVpELDhDQVlDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsU0FBZ0IsUUFBUSxDQUFDLE1BQWUsRUFBRSxJQUFZO0lBQ3BELE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7SUFFaEMsT0FBTyxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUM7UUFDdkIsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDbEIsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUM3RCxDQUFDO0FBTkQsNEJBTUM7QUFFRDs7Ozs7OztHQU9HO0FBQ0gsU0FBZ0IscUJBQXFCLENBQUMsS0FBZSxFQUFFLEtBQWlCO0lBQ3RFLE1BQU0sYUFBYSxHQUFHLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEtBQUssU0FBUyxDQUFDLENBQUM7SUFFaEUsS0FBSyxNQUFNLEdBQUcsSUFBSSxhQUFhLEVBQUU7UUFDL0IsSUFBSSxnQkFBZ0IsR0FBRyxLQUFLLENBQUM7UUFDN0IsTUFBTSxLQUFLLEdBQUcsR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUUvQixLQUFLLE1BQU0sQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLElBQUksS0FBSyxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQzNDLElBQUksS0FBSyxLQUFLLEtBQUssQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO2dCQUM5QixnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7YUFDckM7aUJBQU07Z0JBQ0wsZ0JBQWdCLENBQUMsSUFBSSxNQUFyQixnQkFBZ0IsQ0FBQyxJQUFJLElBQU0sRUFBRSxFQUFDO2dCQUM5QixnQkFBZ0IsR0FBRyxnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsQ0FBQzthQUMzQztTQUNGO1FBRUQsT0FBTyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7S0FDbkI7QUFDSCxDQUFDO0FBbEJELHNEQWtCQyJ9
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CollectionCustomizer, DataSourceCustomizer } from '@forestadmin/datasource-customizer';
|
|
2
|
+
export declare type FlattenColumnOptions = {
|
|
3
|
+
columnName: string;
|
|
4
|
+
include?: string[];
|
|
5
|
+
exclude?: string[];
|
|
6
|
+
level?: number;
|
|
7
|
+
readonly?: boolean;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Flatten a column which have a composite type
|
|
11
|
+
*
|
|
12
|
+
* @param dataSource The dataSource customizer provided by the agent.
|
|
13
|
+
* @param collection The collection customizer instance provided by the agent.
|
|
14
|
+
* @param options The options of the plugin.
|
|
15
|
+
* @param options.columnName The name of the column to import.
|
|
16
|
+
* @param options.include The list of fields to import.
|
|
17
|
+
* @param options.exclude The list of fields to exclude.
|
|
18
|
+
* @param options.level The maximum level of nested fields to import.
|
|
19
|
+
* @param options.readonly Should the imported fields be read-only?
|
|
20
|
+
*/
|
|
21
|
+
export default function flattenColumn(dataSource: DataSourceCustomizer, collection: CollectionCustomizer, options?: FlattenColumnOptions): Promise<void>;
|
|
22
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const customization_1 = require("./customization");
|
|
4
|
+
const helpers_1 = require("./helpers");
|
|
5
|
+
function optionsToPaths(collection, options) {
|
|
6
|
+
const { columnName, include, exclude, level } = options;
|
|
7
|
+
const errorMessage = `'${collection.name}.${columnName}' cannot be flattened`;
|
|
8
|
+
const schema = collection.schema.fields[options.columnName];
|
|
9
|
+
if (!schema)
|
|
10
|
+
throw new Error(`${errorMessage}' (not found).`);
|
|
11
|
+
if (schema.type !== 'Column')
|
|
12
|
+
throw new Error(`${errorMessage}' (not a column).`);
|
|
13
|
+
if (typeof schema.columnType === 'string')
|
|
14
|
+
throw new Error(`${errorMessage}' (primitive).`);
|
|
15
|
+
if (Array.isArray(schema.columnType))
|
|
16
|
+
throw new Error(`${errorMessage}' (array).`);
|
|
17
|
+
let paths = include?.map(p => (0, helpers_1.includeStrToPath)(columnName, p));
|
|
18
|
+
if (!paths?.length) {
|
|
19
|
+
if (level < 1)
|
|
20
|
+
throw new Error('options.level must be greater than 0.');
|
|
21
|
+
paths = (0, helpers_1.listPaths)(columnName, schema.columnType, level ?? 1);
|
|
22
|
+
}
|
|
23
|
+
paths = paths.filter(path => !exclude?.find(p => path === (0, helpers_1.includeStrToPath)(columnName, p)));
|
|
24
|
+
if (!paths.length)
|
|
25
|
+
throw new Error(`${errorMessage}' (no fields match level/include/exclude).`);
|
|
26
|
+
return paths;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Flatten a column which have a composite type
|
|
30
|
+
*
|
|
31
|
+
* @param dataSource The dataSource customizer provided by the agent.
|
|
32
|
+
* @param collection The collection customizer instance provided by the agent.
|
|
33
|
+
* @param options The options of the plugin.
|
|
34
|
+
* @param options.columnName The name of the column to import.
|
|
35
|
+
* @param options.include The list of fields to import.
|
|
36
|
+
* @param options.exclude The list of fields to exclude.
|
|
37
|
+
* @param options.level The maximum level of nested fields to import.
|
|
38
|
+
* @param options.readonly Should the imported fields be read-only?
|
|
39
|
+
*/
|
|
40
|
+
async function flattenColumn(dataSource, collection, options) {
|
|
41
|
+
if (!options || !options.columnName)
|
|
42
|
+
throw new Error('options.columnName is required.');
|
|
43
|
+
if (!collection)
|
|
44
|
+
throw new Error('This plugin can only be called when customizing collections.');
|
|
45
|
+
const paths = optionsToPaths(collection, options);
|
|
46
|
+
const schema = collection.schema.fields[options.columnName];
|
|
47
|
+
// Add fields that reads the value from the deeply nested column
|
|
48
|
+
for (const path of paths) {
|
|
49
|
+
collection.addField(path, (0, customization_1.makeField)(options.columnName, path, schema));
|
|
50
|
+
}
|
|
51
|
+
// Implement write
|
|
52
|
+
if (!schema.isReadOnly && !options.readonly) {
|
|
53
|
+
// Add hooks to intercept the creation and update of the column (replaceFieldWriting would not
|
|
54
|
+
// work because it is called once per field, and we need to intercept the whole patch).
|
|
55
|
+
collection.addHook('Before', 'Create', (0, customization_1.makeCreateHook)(paths));
|
|
56
|
+
collection.addHook('Before', 'Update', (0, customization_1.makeUpdateHook)(collection, options.columnName, paths));
|
|
57
|
+
// They will never get called because the hooks will modify the patch, but we need them
|
|
58
|
+
// so that the field is flagged as writable.
|
|
59
|
+
for (const path of paths) {
|
|
60
|
+
collection.replaceFieldWriting(path, (0, customization_1.makeWriteHandler)(path));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
exports.default = flattenColumn;
|
|
65
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmxhdHRlbi1jb2x1bW4vaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFPQSxtREFBOEY7QUFDOUYsdUNBQXdEO0FBVXhELFNBQVMsY0FBYyxDQUFDLFVBQWdDLEVBQUUsT0FBNkI7SUFDckYsTUFBTSxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLEtBQUssRUFBRSxHQUFHLE9BQU8sQ0FBQztJQUN4RCxNQUFNLFlBQVksR0FBRyxJQUFJLFVBQVUsQ0FBQyxJQUFJLElBQUksVUFBVSx1QkFBdUIsQ0FBQztJQUM5RSxNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLENBQUM7SUFFNUQsSUFBSSxDQUFDLE1BQU07UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLEdBQUcsWUFBWSxnQkFBZ0IsQ0FBQyxDQUFDO0lBQzlELElBQUksTUFBTSxDQUFDLElBQUksS0FBSyxRQUFRO1FBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLFlBQVksbUJBQW1CLENBQUMsQ0FBQztJQUNsRixJQUFJLE9BQU8sTUFBTSxDQUFDLFVBQVUsS0FBSyxRQUFRO1FBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLFlBQVksZ0JBQWdCLENBQUMsQ0FBQztJQUM1RixJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQztRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsR0FBRyxZQUFZLFlBQVksQ0FBQyxDQUFDO0lBRW5GLElBQUksS0FBSyxHQUFHLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxJQUFBLDBCQUFnQixFQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRS9ELElBQUksQ0FBQyxLQUFLLEVBQUUsTUFBTSxFQUFFO1FBQ2xCLElBQUksS0FBSyxHQUFHLENBQUM7WUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLHVDQUF1QyxDQUFDLENBQUM7UUFDeEUsS0FBSyxHQUFHLElBQUEsbUJBQVMsRUFBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLFVBQVUsRUFBRSxLQUFLLElBQUksQ0FBQyxDQUFDLENBQUM7S0FDOUQ7SUFFRCxLQUFLLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLElBQUksS0FBSyxJQUFBLDBCQUFnQixFQUFDLFVBQVUsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFNUYsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNO1FBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxHQUFHLFlBQVksNENBQTRDLENBQUMsQ0FBQztJQUVoRyxPQUFPLEtBQUssQ0FBQztBQUNmLENBQUM7QUFFRDs7Ozs7Ozs7Ozs7R0FXRztBQUNZLEtBQUssVUFBVSxhQUFhLENBQ3pDLFVBQWdDLEVBQ2hDLFVBQWdDLEVBQ2hDLE9BQThCO0lBRTlCLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVTtRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsaUNBQWlDLENBQUMsQ0FBQztJQUN4RixJQUFJLENBQUMsVUFBVTtRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsOERBQThELENBQUMsQ0FBQztJQUVqRyxNQUFNLEtBQUssR0FBRyxjQUFjLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ2xELE1BQU0sTUFBTSxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQWlCLENBQUM7SUFFNUUsZ0VBQWdFO0lBQ2hFLEtBQUssTUFBTSxJQUFJLElBQUksS0FBSyxFQUFFO1FBQ3hCLFVBQVUsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLElBQUEseUJBQVMsRUFBQyxPQUFPLENBQUMsVUFBVSxFQUFFLElBQUksRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDO0tBQ3hFO0lBRUQsa0JBQWtCO0lBQ2xCLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRTtRQUMzQyw4RkFBOEY7UUFDOUYsdUZBQXVGO1FBQ3ZGLFVBQVUsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLFFBQVEsRUFBRSxJQUFBLDhCQUFjLEVBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUM5RCxVQUFVLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsSUFBQSw4QkFBYyxFQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFFOUYsdUZBQXVGO1FBQ3ZGLDRDQUE0QztRQUM1QyxLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRTtZQUN4QixVQUFVLENBQUMsbUJBQW1CLENBQUMsSUFBSSxFQUFFLElBQUEsZ0NBQWdCLEVBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztTQUM5RDtLQUNGO0FBQ0gsQ0FBQztBQTdCRCxnQ0E2QkMifQ==
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CollectionCustomizer, DataSourceCustomizer } from '@forestadmin/datasource-customizer';
|
|
2
|
+
import type { CollectionSchema, RelationSchema } from '@forestadmin/datasource-toolkit';
|
|
3
|
+
export declare function getColumns(schema: CollectionSchema): string[];
|
|
4
|
+
export declare function getRelation(relationName: string, dataSource: DataSourceCustomizer, collection: CollectionCustomizer): RelationSchema;
|
|
5
|
+
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getRelation = exports.getColumns = void 0;
|
|
4
|
+
function getColumns(schema) {
|
|
5
|
+
return Object.keys(schema.fields).filter(name => schema.fields[name].type === 'Column');
|
|
6
|
+
}
|
|
7
|
+
exports.getColumns = getColumns;
|
|
8
|
+
function getRelation(relationName, dataSource, collection) {
|
|
9
|
+
const [field, ...nested] = relationName.split(':');
|
|
10
|
+
const relation = collection.schema.fields[field];
|
|
11
|
+
if (relation?.type !== 'ManyToOne' && relation?.type !== 'OneToOne') {
|
|
12
|
+
const name = `'${collection.name}.${relationName}'`;
|
|
13
|
+
let message;
|
|
14
|
+
if (!relation)
|
|
15
|
+
message = `Relation ${name} not found`;
|
|
16
|
+
else if (relation.type === 'Column')
|
|
17
|
+
message = `${name} is a column, not a relation`;
|
|
18
|
+
else
|
|
19
|
+
message = `${name} is not a ManyToOne or OneToOne relation`;
|
|
20
|
+
throw new Error(message);
|
|
21
|
+
}
|
|
22
|
+
return nested.length > 0
|
|
23
|
+
? getRelation(nested.join(':'), dataSource, dataSource.getCollection(relation.foreignCollection))
|
|
24
|
+
: relation;
|
|
25
|
+
}
|
|
26
|
+
exports.getRelation = getRelation;
|
|
27
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9mbGF0dGVuLXJlbGF0aW9uL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBTUEsU0FBZ0IsVUFBVSxDQUFDLE1BQXdCO0lBQ2pELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFDLENBQUM7QUFDMUYsQ0FBQztBQUZELGdDQUVDO0FBRUQsU0FBZ0IsV0FBVyxDQUN6QixZQUFvQixFQUNwQixVQUFnQyxFQUNoQyxVQUFnQztJQUVoQyxNQUFNLENBQUMsS0FBSyxFQUFFLEdBQUcsTUFBTSxDQUFDLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuRCxNQUFNLFFBQVEsR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUVqRCxJQUFJLFFBQVEsRUFBRSxJQUFJLEtBQUssV0FBVyxJQUFJLFFBQVEsRUFBRSxJQUFJLEtBQUssVUFBVSxFQUFFO1FBQ25FLE1BQU0sSUFBSSxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksSUFBSSxZQUFZLEdBQUcsQ0FBQztRQUVwRCxJQUFJLE9BQWUsQ0FBQztRQUNwQixJQUFJLENBQUMsUUFBUTtZQUFFLE9BQU8sR0FBRyxZQUFZLElBQUksWUFBWSxDQUFDO2FBQ2pELElBQUksUUFBUSxDQUFDLElBQUksS0FBSyxRQUFRO1lBQUUsT0FBTyxHQUFHLEdBQUcsSUFBSSw4QkFBOEIsQ0FBQzs7WUFDaEYsT0FBTyxHQUFHLEdBQUcsSUFBSSwwQ0FBMEMsQ0FBQztRQUVqRSxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0tBQzFCO0lBRUQsT0FBTyxNQUFNLENBQUMsTUFBTSxHQUFHLENBQUM7UUFDdEIsQ0FBQyxDQUFDLFdBQVcsQ0FDVCxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUNoQixVQUFVLEVBQ1YsVUFBVSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUMsQ0FDckQ7UUFDSCxDQUFDLENBQUMsUUFBUSxDQUFDO0FBQ2YsQ0FBQztBQTFCRCxrQ0EwQkMifQ==
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CollectionCustomizer, DataSourceCustomizer } from '@forestadmin/datasource-customizer';
|
|
2
|
+
/**
|
|
3
|
+
* Import all fields of a relation in the current collection.
|
|
4
|
+
*
|
|
5
|
+
* @param dataSource The dataSource customizer provided by the agent.
|
|
6
|
+
* @param collection The collection customizer instance provided by the agent.
|
|
7
|
+
* @param options The options of the plugin.
|
|
8
|
+
* @param options.relationName The name of the relation to import.
|
|
9
|
+
* @param options.include The list of fields to import.
|
|
10
|
+
* @param options.exclude The list of fields to exclude.
|
|
11
|
+
* @param options.readonly Should the imported fields be read-only?
|
|
12
|
+
*/
|
|
13
|
+
export default function flattenRelation(dataSource: DataSourceCustomizer, collection: CollectionCustomizer, options?: {
|
|
14
|
+
relationName: string;
|
|
15
|
+
include?: string[];
|
|
16
|
+
exclude?: string[];
|
|
17
|
+
readonly?: boolean;
|
|
18
|
+
}): Promise<void>;
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const helpers_1 = require("./helpers");
|
|
4
|
+
/**
|
|
5
|
+
* Import all fields of a relation in the current collection.
|
|
6
|
+
*
|
|
7
|
+
* @param dataSource The dataSource customizer provided by the agent.
|
|
8
|
+
* @param collection The collection customizer instance provided by the agent.
|
|
9
|
+
* @param options The options of the plugin.
|
|
10
|
+
* @param options.relationName The name of the relation to import.
|
|
11
|
+
* @param options.include The list of fields to import.
|
|
12
|
+
* @param options.exclude The list of fields to exclude.
|
|
13
|
+
* @param options.readonly Should the imported fields be read-only?
|
|
14
|
+
*/
|
|
15
|
+
async function flattenRelation(dataSource, collection, options) {
|
|
16
|
+
if (!options || !options.relationName)
|
|
17
|
+
throw new Error('options.relationName is required.');
|
|
18
|
+
if (!collection)
|
|
19
|
+
throw new Error('This plugin can only be called when customizing collections.');
|
|
20
|
+
const { relationName, include, exclude, readonly } = options;
|
|
21
|
+
const relation = (0, helpers_1.getRelation)(relationName, dataSource, collection);
|
|
22
|
+
const foreignCollection = dataSource.getCollection(relation.foreignCollection);
|
|
23
|
+
const columns = new Set(include?.length > 0 ? include : (0, helpers_1.getColumns)(foreignCollection.schema));
|
|
24
|
+
exclude?.forEach(column => columns.delete(column));
|
|
25
|
+
for (const column of columns) {
|
|
26
|
+
const path = `${relationName}:${column}`;
|
|
27
|
+
const alias = path.replace(/:/g, '@@@');
|
|
28
|
+
collection.importField(alias, { path, readonly });
|
|
29
|
+
}
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
exports.default = flattenRelation;
|
|
33
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvZmxhdHRlbi1yZWxhdGlvbi9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUtBLHVDQUFvRDtBQUVwRDs7Ozs7Ozs7OztHQVVHO0FBQ1ksS0FBSyxVQUFVLGVBQWUsQ0FDM0MsVUFBZ0MsRUFDaEMsVUFBZ0MsRUFDaEMsT0FLQztJQUVELElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWTtRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsbUNBQW1DLENBQUMsQ0FBQztJQUM1RixJQUFJLENBQUMsVUFBVTtRQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsOERBQThELENBQUMsQ0FBQztJQUVqRyxNQUFNLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEdBQUcsT0FBTyxDQUFDO0lBQzdELE1BQU0sUUFBUSxHQUFHLElBQUEscUJBQVcsRUFBQyxZQUFZLEVBQUUsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQ25FLE1BQU0saUJBQWlCLEdBQUcsVUFBVSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUUvRSxNQUFNLE9BQU8sR0FBRyxJQUFJLEdBQUcsQ0FBQyxPQUFPLEVBQUUsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxJQUFBLG9CQUFVLEVBQUMsaUJBQWlCLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztJQUM5RixPQUFPLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO0lBRW5ELEtBQUssTUFBTSxNQUFNLElBQUksT0FBTyxFQUFFO1FBQzVCLE1BQU0sSUFBSSxHQUFHLEdBQUcsWUFBWSxJQUFJLE1BQU0sRUFBRSxDQUFDO1FBQ3pDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBRXhDLFVBQVUsQ0FBQyxXQUFXLENBQUMsS0FBSyxFQUFFLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxDQUFDLENBQUM7S0FDbkQ7SUFFRCxPQUFPLElBQUksQ0FBQztBQUNkLENBQUM7QUE1QkQsa0NBNEJDIn0=
|
package/dist/index.d.ts
ADDED
package/dist/index.js
CHANGED
|
@@ -4,8 +4,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.flattenColumn = exports.flattenRelation = void 0;
|
|
7
|
-
var
|
|
8
|
-
Object.defineProperty(exports, "flattenRelation", { enumerable: true, get: function () { return __importDefault(
|
|
9
|
-
var
|
|
10
|
-
Object.defineProperty(exports, "flattenColumn", { enumerable: true, get: function () { return __importDefault(
|
|
11
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
7
|
+
var index_1 = require("./flatten-relation/index");
|
|
8
|
+
Object.defineProperty(exports, "flattenRelation", { enumerable: true, get: function () { return __importDefault(index_1).default; } });
|
|
9
|
+
var index_2 = require("./flatten-column/index");
|
|
10
|
+
Object.defineProperty(exports, "flattenColumn", { enumerable: true, get: function () { return __importDefault(index_2).default; } });
|
|
11
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUEsa0RBQXNFO0FBQTdELHlIQUFBLE9BQU8sT0FBbUI7QUFDbkMsZ0RBQWtFO0FBQXpELHVIQUFBLE9BQU8sT0FBaUIifQ==
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@forestadmin/plugin-flattener",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
4
4
|
"description": "A plugin that allows to flatten columns and relations in Forest Admin",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"license": "GPL-3.0",
|
|
7
7
|
"files": [
|
|
8
|
-
"dist
|
|
9
|
-
"dist
|
|
8
|
+
"dist/**/*.js",
|
|
9
|
+
"dist/**/*.d.ts"
|
|
10
10
|
],
|
|
11
11
|
"publishConfig": {
|
|
12
12
|
"access": "public"
|
|
@@ -24,11 +24,11 @@
|
|
|
24
24
|
"test": "jest"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@forestadmin/datasource-customizer": "1.5.
|
|
27
|
+
"@forestadmin/datasource-customizer": "1.5.1",
|
|
28
28
|
"@types/object-hash": "^3.0.1"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@forestadmin/datasource-toolkit": "1.1.
|
|
31
|
+
"@forestadmin/datasource-toolkit": "1.1.2",
|
|
32
32
|
"object-hash": "^3.0.0"
|
|
33
33
|
}
|
|
34
34
|
}
|