@forestadmin/datasource-mongoose 1.0.0-beta.9 → 1.0.0

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 (35) hide show
  1. package/dist/collection.d.ts +11 -8
  2. package/dist/collection.js +124 -15
  3. package/dist/datasource.d.ts +6 -3
  4. package/dist/datasource.js +29 -12
  5. package/dist/index.d.ts +2 -1
  6. package/dist/index.js +3 -3
  7. package/dist/mongoose/schema.d.ts +21 -0
  8. package/dist/mongoose/schema.js +89 -0
  9. package/dist/types.d.ts +4 -0
  10. package/dist/types.js +3 -0
  11. package/dist/utils/helpers.d.ts +51 -0
  12. package/dist/utils/helpers.js +109 -0
  13. package/dist/utils/pipeline/filter.d.ts +18 -0
  14. package/dist/utils/pipeline/filter.js +160 -0
  15. package/dist/utils/pipeline/group.d.ts +15 -0
  16. package/dist/utils/pipeline/group.js +72 -0
  17. package/dist/utils/pipeline/lookup.d.ts +12 -0
  18. package/dist/utils/pipeline/lookup.js +49 -0
  19. package/dist/utils/pipeline/projection.d.ts +7 -0
  20. package/dist/utils/pipeline/projection.js +18 -0
  21. package/dist/utils/pipeline/reparent.d.ts +13 -0
  22. package/dist/utils/pipeline/reparent.js +71 -0
  23. package/dist/utils/pipeline/virtual-fields.d.ts +21 -0
  24. package/dist/utils/pipeline/virtual-fields.js +65 -0
  25. package/dist/utils/schema/fields.d.ts +18 -0
  26. package/dist/utils/schema/fields.js +110 -0
  27. package/dist/utils/{filter-operator-builder.d.ts → schema/filter-operators.d.ts} +2 -2
  28. package/dist/utils/schema/filter-operators.js +52 -0
  29. package/dist/utils/schema/relations.d.ts +19 -0
  30. package/dist/utils/schema/relations.js +75 -0
  31. package/package.json +4 -3
  32. package/CHANGELOG.md +0 -91
  33. package/dist/utils/filter-operator-builder.js +0 -57
  34. package/dist/utils/schema-fields-generator.d.ts +0 -13
  35. package/dist/utils/schema-fields-generator.js +0 -142
@@ -0,0 +1,110 @@
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 mongoose_1 = require("mongoose");
7
+ const schema_1 = __importDefault(require("../../mongoose/schema"));
8
+ const helpers_1 = require("../helpers");
9
+ const filter_operators_1 = __importDefault(require("./filter-operators"));
10
+ /** Generate forest admin schema from mongoose schema */
11
+ class FieldsGenerator {
12
+ static buildFieldsSchema(model, prefix = null, skips = []) {
13
+ const ourSchema = {};
14
+ const childSchema = schema_1.default.fromModel(model).getSubSchema(prefix, true);
15
+ // Add columns and many to one relations
16
+ for (const [name, field] of Object.entries(childSchema.fields)) {
17
+ if (name !== 'parent' && !skips.includes(name)) {
18
+ ourSchema[name] = this.buildColumnSchema(field);
19
+ if (field instanceof mongoose_1.SchemaType && field.options.ref)
20
+ ourSchema[`${name}__manyToOne`] = this.buildManyToOne(field.options.ref, name);
21
+ }
22
+ }
23
+ // When a prefix is used add pk + fk + many to one relation to the parent.
24
+ if (prefix?.length) {
25
+ const parentPrefix = prefix.includes('.')
26
+ ? prefix.substring(0, prefix.lastIndexOf('.'))
27
+ : null;
28
+ ourSchema._id = this.buildVirtualPrimaryKey();
29
+ ourSchema._pid = {
30
+ ...this.buildColumnSchema(childSchema.fields.parent._id),
31
+ isPrimaryKey: false,
32
+ validation: [{ operator: 'Present' }],
33
+ };
34
+ ourSchema.parent = this.buildManyToOne((0, helpers_1.escape)(parentPrefix ? `${model.modelName}.${parentPrefix}` : model.modelName), '_pid');
35
+ }
36
+ return ourSchema;
37
+ }
38
+ /** Fake primary key that will be used when we're flattening collections */
39
+ static buildVirtualPrimaryKey() {
40
+ return {
41
+ type: 'Column',
42
+ columnType: 'String',
43
+ filterOperators: filter_operators_1.default.getSupportedOperators('String'),
44
+ isPrimaryKey: true,
45
+ isReadOnly: true,
46
+ isSortable: true,
47
+ };
48
+ }
49
+ static buildManyToOne(collection, foreignKey) {
50
+ return {
51
+ type: 'ManyToOne',
52
+ foreignCollection: collection,
53
+ foreignKey,
54
+ foreignKeyTarget: '_id',
55
+ };
56
+ }
57
+ /** Build ColumnSchema from CleanSchema */
58
+ static buildColumnSchema(field) {
59
+ const columnType = this.getColumnType(field);
60
+ const schema = {
61
+ columnType,
62
+ filterOperators: filter_operators_1.default.getSupportedOperators(columnType),
63
+ defaultValue: field.options?.default,
64
+ isPrimaryKey: field.path === '_id',
65
+ isReadOnly: !!field.options?.immutable,
66
+ isSortable: !(columnType instanceof Object || columnType === 'Json'),
67
+ type: 'Column',
68
+ validation: field.isRequired ? [{ operator: 'Present' }] : null,
69
+ };
70
+ if (columnType === 'Enum') {
71
+ schema.enumValues = this.getEnumValues(field);
72
+ }
73
+ return schema;
74
+ }
75
+ /** Compute column type from CleanSchema */
76
+ static getColumnType(field) {
77
+ const columnType = this.getColumnTypeRec(field);
78
+ // Enum fields are promoted to enum instead of string _only_ if they are at the root of the
79
+ // record.
80
+ if (columnType === 'String') {
81
+ const enumValues = this.getEnumValues(field);
82
+ if (enumValues && enumValues.every(v => typeof v === 'string')) {
83
+ return 'Enum';
84
+ }
85
+ }
86
+ return columnType;
87
+ }
88
+ /** Build ColumnType from CleanSchema recursively */
89
+ static getColumnTypeRec(field) {
90
+ if (field instanceof mongoose_1.SchemaType) {
91
+ if (['String', 'Number', 'Date', 'Boolean'].includes(field.instance)) {
92
+ return field.instance;
93
+ }
94
+ if (['ObjectID', 'Buffer', 'Decimal128'].includes(field.instance)) {
95
+ return 'String';
96
+ }
97
+ return 'Json';
98
+ }
99
+ if (field['[]']) {
100
+ return [this.getColumnTypeRec(field['[]'])];
101
+ }
102
+ return Object.entries(field).reduce((memo, [name, subSchema]) => ({ ...memo, [name]: this.getColumnTypeRec(subSchema) }), {});
103
+ }
104
+ /** Get enum validator from field definition */
105
+ static getEnumValues(field) {
106
+ return field.options?.enum instanceof Array ? field.options.enum : field.options?.enum?.values;
107
+ }
108
+ }
109
+ exports.default = FieldsGenerator;
110
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmllbGRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3V0aWxzL3NjaGVtYS9maWVsZHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFVQSx1Q0FBNkM7QUFDN0MsbUVBQWlGO0FBRWpGLHdDQUFvQztBQUNwQywwRUFBMEQ7QUFFMUQsd0RBQXdEO0FBQ3hELE1BQXFCLGVBQWU7SUFDbEMsTUFBTSxDQUFDLGlCQUFpQixDQUN0QixLQUF3QixFQUN4QixTQUFpQixJQUFJLEVBQ3JCLFFBQWtCLEVBQUU7UUFFcEIsTUFBTSxTQUFTLEdBQStCLEVBQUUsQ0FBQztRQUNqRCxNQUFNLFdBQVcsR0FBRyxnQkFBYyxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxZQUFZLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBRS9FLHdDQUF3QztRQUN4QyxLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsTUFBTSxDQUFDLEVBQUU7WUFDOUQsSUFBSSxJQUFJLEtBQUssUUFBUSxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRTtnQkFDOUMsU0FBUyxDQUFDLElBQUksQ0FBQyxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDaEQsSUFBSSxLQUFLLFlBQVkscUJBQVUsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUc7b0JBQ2xELFNBQVMsQ0FBQyxHQUFHLElBQUksYUFBYSxDQUFDLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxJQUFJLENBQUMsQ0FBQzthQUNsRjtTQUNGO1FBRUQsMEVBQTBFO1FBQzFFLElBQUksTUFBTSxFQUFFLE1BQU0sRUFBRTtZQUNsQixNQUFNLFlBQVksR0FBRyxNQUFNLENBQUMsUUFBUSxD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
@@ -1,9 +1,9 @@
1
1
  import { ColumnType, Operator } from '@forestadmin/datasource-toolkit';
2
- export default class FilterOperatorBuilder {
2
+ export default class FilterOperatorsGenerator {
3
3
  static readonly defaultOperators: Partial<Operator[]>;
4
4
  static readonly inOperators: Partial<Operator[]>;
5
5
  static readonly stringOperators: Partial<Operator[]>;
6
6
  static readonly comparisonOperators: Partial<Operator[]>;
7
7
  static getSupportedOperators(type: ColumnType): Set<Operator>;
8
8
  }
9
- //# sourceMappingURL=filter-operator-builder.d.ts.map
9
+ //# sourceMappingURL=filter-operators.d.ts.map
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ class FilterOperatorsGenerator {
4
+ static getSupportedOperators(type) {
5
+ if (!(type instanceof Array) && type instanceof Object) {
6
+ return new Set(FilterOperatorsGenerator.defaultOperators);
7
+ }
8
+ switch (type) {
9
+ case 'Boolean':
10
+ return new Set(FilterOperatorsGenerator.defaultOperators);
11
+ case 'Date':
12
+ case 'Dateonly':
13
+ return new Set([
14
+ ...FilterOperatorsGenerator.defaultOperators,
15
+ ...FilterOperatorsGenerator.inOperators,
16
+ ...FilterOperatorsGenerator.comparisonOperators,
17
+ ]);
18
+ case 'Enum':
19
+ return new Set([
20
+ ...FilterOperatorsGenerator.defaultOperators,
21
+ ...FilterOperatorsGenerator.inOperators,
22
+ ]);
23
+ case 'Number':
24
+ return new Set([
25
+ ...FilterOperatorsGenerator.defaultOperators,
26
+ ...FilterOperatorsGenerator.inOperators,
27
+ ...FilterOperatorsGenerator.comparisonOperators,
28
+ ]);
29
+ case 'String':
30
+ return new Set([
31
+ ...FilterOperatorsGenerator.defaultOperators,
32
+ ...FilterOperatorsGenerator.inOperators,
33
+ ...FilterOperatorsGenerator.stringOperators,
34
+ ]);
35
+ case 'Uuid':
36
+ return new Set([
37
+ ...FilterOperatorsGenerator.defaultOperators,
38
+ ...FilterOperatorsGenerator.stringOperators,
39
+ ]);
40
+ case 'Json':
41
+ return new Set(FilterOperatorsGenerator.defaultOperators);
42
+ default:
43
+ return new Set();
44
+ }
45
+ }
46
+ }
47
+ exports.default = FilterOperatorsGenerator;
48
+ FilterOperatorsGenerator.defaultOperators = ['Equal', 'NotEqual', 'Present'];
49
+ FilterOperatorsGenerator.inOperators = ['In', 'NotIn'];
50
+ FilterOperatorsGenerator.stringOperators = ['Like', 'ILike', 'NotContains'];
51
+ FilterOperatorsGenerator.comparisonOperators = ['GreaterThan', 'LessThan'];
52
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsdGVyLW9wZXJhdG9ycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy91dGlscy9zY2hlbWEvZmlsdGVyLW9wZXJhdG9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUVBLE1BQXFCLHdCQUF3QjtJQU0zQyxNQUFNLENBQUMscUJBQXFCLENBQUMsSUFBZ0I7UUFDM0MsSUFBSSxDQUFDLENBQUMsSUFBSSxZQUFZLEtBQUssQ0FBQyxJQUFJLElBQUksWUFBWSxNQUFNLEVBQUU7WUFDdEQsT0FBTyxJQUFJLEdBQUcsQ0FBVyx3QkFBd0IsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1NBQ3JFO1FBRUQsUUFBUSxJQUFJLEVBQUU7WUFDWixLQUFLLFNBQVM7Z0JBQ1osT0FBTyxJQUFJLEdBQUcsQ0FBVyx3QkFBd0IsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO1lBQ3RFLEtBQUssTUFBTSxDQUFDO1lBQ1osS0FBSyxVQUFVO2dCQUNiLE9BQU8sSUFBSSxHQUFHLENBQVc7b0JBQ3ZCLEdBQUcsd0JBQXdCLENBQUMsZ0JBQWdCO29CQUM1QyxHQUFHLHdCQUF3QixDQUFDLFdBQVc7b0JBQ3ZDLEdBQUcsd0JBQXdCLENBQUMsbUJBQW1CO2lCQUNoRCxDQUFDLENBQUM7WUFDTCxLQUFLLE1BQU07Z0JBQ1QsT0FBTyxJQUFJLEdBQUcsQ0FBVztvQkFDdkIsR0FBRyx3QkFBd0IsQ0FBQyxnQkFBZ0I7b0JBQzVDLEdBQUcsd0JBQXdCLENBQUMsV0FBVztpQkFDeEMsQ0FBQyxDQUFDO1lBQ0wsS0FBSyxRQUFRO2dCQUNYLE9BQU8sSUFBSSxHQUFHLENBQVc7b0JBQ3ZCLEdBQUcsd0JBQXdCLENBQUMsZ0JBQWdCO29CQUM1QyxHQUFHLHdCQUF3QixDQUFDLFdBQVc7b0JBQ3ZDLEdBQUcsd0JBQXdCLENBQUMsbUJBQW1CO2lCQUNoRCxDQUFDLENBQUM7WUFDTCxLQUFLLFFBQVE7Z0JBQ1gsT0FBTyxJQUFJLEdBQUcsQ0FBVztvQkFDdkIsR0FBRyx3QkFBd0IsQ0FBQyxnQkFBZ0I7b0JBQzVDLEdBQUcsd0JBQXdCLENBQUMsV0FBVztvQkFDdkMsR0FBRyx3QkFBd0IsQ0FBQyxlQUFlO2lCQUM1QyxDQUFDLENBQUM7WUFDTCxLQUFLLE1BQU07Z0JBQ1QsT0FBTyxJQUFJLEdBQUcsQ0FBVztvQkFDdkIsR0FBRyx3QkFBd0IsQ0FBQyxnQkFBZ0I7b0JBQzVDLEdBQUcsd0JBQXdCLENBQUMsZUFBZTtpQkFDNUMsQ0FBQyxDQUFDO1lBQ0wsS0FBSyxNQUFNO2dCQUNULE9BQU8sSUFBSSxHQUFHLENBQVcsd0JBQXdCLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztZQUN0RTtnQkFDRSxPQUFPLElBQUksR0FBRyxFQUFZLENBQUM7U0FDOUI7SUFDSCxDQUFDOztBQWhESCwyQ0FpREM7QUFoRGlCLHlDQUFnQixHQUF3QixDQUFDLE9BQU8sRUFBRSxVQUFVLEVBQUUsU0FBUyxDQUFDLENBQUM7QUFDekUsb0NBQVcsR0FBd0IsQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7QUFDbkQsd0NBQWUsR0FBd0IsQ0FBQyxNQUFNLEVBQUUsT0FBTyxFQUFFLGFBQWEsQ0FBQyxDQUFDO0FBQ3hFLDRDQUFtQixHQUF3QixDQUFDLGFBQWEsRUFBRSxVQUFVLENBQUMsQ0FBQyJ9
@@ -0,0 +1,19 @@
1
+ import MongooseCollection from '../../collection';
2
+ /** Generate all relations which are not explicitly written in the mongoose schema using `ref` */
3
+ export default class RelationGenerator {
4
+ /**
5
+ * Scan collections for many to one relations, and inject all the other relations in the schemas
6
+ * (one to one, one to many, many to many)
7
+ */
8
+ static addImplicitRelations(collections: MongooseCollection[]): void;
9
+ /**
10
+ * Given any many to one relation, generated while parsing mongoose schema, generate the
11
+ * inverse relationship on the foreignCollection.
12
+ *
13
+ * /!\ The inverse can be a OneToOne, or a ManyToOne
14
+ */
15
+ private static addManyToOneInverse;
16
+ /** Generate many to many from two many to one */
17
+ private static addManyToMany;
18
+ }
19
+ //# sourceMappingURL=relations.d.ts.map
@@ -0,0 +1,75 @@
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 helpers_1 = require("../helpers");
7
+ const schema_1 = __importDefault(require("../../mongoose/schema"));
8
+ /** Generate all relations which are not explicitly written in the mongoose schema using `ref` */
9
+ class RelationGenerator {
10
+ /**
11
+ * Scan collections for many to one relations, and inject all the other relations in the schemas
12
+ * (one to one, one to many, many to many)
13
+ */
14
+ static addImplicitRelations(collections) {
15
+ for (const collection of collections) {
16
+ const manyToOnes = Object.entries(collection.schema.fields).filter(([, f]) => f.type === 'ManyToOne');
17
+ // Create one-to-many and one-to-one
18
+ for (const [name, field] of manyToOnes) {
19
+ this.addManyToOneInverse(collection, name, field);
20
+ }
21
+ // @fixme this will break if _id is both a foreignkey and a pk
22
+ // Create many to many (5 fields == _id + 2 relations + 2 foreignKeys)
23
+ if (manyToOnes.length === 2 && Object.keys(collection.schema.fields).length === 5) {
24
+ this.addManyToMany(collection, manyToOnes[0][1], manyToOnes[1][1]);
25
+ this.addManyToMany(collection, manyToOnes[1][1], manyToOnes[0][1]);
26
+ }
27
+ }
28
+ }
29
+ /**
30
+ * Given any many to one relation, generated while parsing mongoose schema, generate the
31
+ * inverse relationship on the foreignCollection.
32
+ *
33
+ * /!\ The inverse can be a OneToOne, or a ManyToOne
34
+ */
35
+ static addManyToOneInverse(collection, name, schema) {
36
+ let type;
37
+ let inverseName;
38
+ if (name === 'parent') {
39
+ // Create inverse of 'parent' relationship so that the relation name matches the actual name
40
+ // of the data which is stored in the database.
41
+ const childSchema = schema_1.default.fromModel(collection.model).getSubSchema(collection.prefix, true);
42
+ inverseName = (0, helpers_1.escape)(collection.prefix.substring(collection.prefix.lastIndexOf('.') + 1));
43
+ type = childSchema.fields.parent[inverseName]['[]'] ? 'OneToMany' : 'OneToOne';
44
+ }
45
+ else {
46
+ // Native ManyToOne relationship (there is an actual foreign key in the document, this is
47
+ // not an embedded document that we're faking as a relation).
48
+ inverseName = (0, helpers_1.escape)(`${collection.name}_${name}__inverse`);
49
+ type = 'OneToMany';
50
+ }
51
+ const otherCollection = collection.dataSource.getCollection(schema.foreignCollection);
52
+ otherCollection.schema.fields[inverseName] = {
53
+ type,
54
+ foreignCollection: collection.name,
55
+ originKey: schema.foreignKey,
56
+ originKeyTarget: schema.foreignKeyTarget,
57
+ };
58
+ }
59
+ /** Generate many to many from two many to one */
60
+ static addManyToMany(throughCollection, originRelation, foreignRelation) {
61
+ const origin = throughCollection.dataSource.getCollection(originRelation.foreignCollection);
62
+ const relationName = (0, helpers_1.escape)(`${foreignRelation.foreignCollection}_through_${throughCollection.name}`);
63
+ origin.schema.fields[relationName] = {
64
+ type: 'ManyToMany',
65
+ throughCollection: throughCollection.name,
66
+ foreignCollection: foreignRelation.foreignCollection,
67
+ foreignKey: foreignRelation.foreignKey,
68
+ foreignKeyTarget: foreignRelation.foreignKeyTarget,
69
+ originKey: originRelation.foreignKey,
70
+ originKeyTarget: originRelation.foreignKeyTarget,
71
+ };
72
+ }
73
+ }
74
+ exports.default = RelationGenerator;
75
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVsYXRpb25zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3V0aWxzL3NjaGVtYS9yZWxhdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFFQSx3Q0FBb0M7QUFFcEMsbUVBQW1EO0FBRW5ELGlHQUFpRztBQUNqRyxNQUFxQixpQkFBaUI7SUFDcEM7OztPQUdHO0lBQ0gsTUFBTSxDQUFDLG9CQUFvQixDQUFDLFdBQWlDO1FBQzNELEtBQUssTUFBTSxVQUFVLElBQUksV0FBVyxFQUFFO1lBQ3BDLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLENBQ2hFLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxLQUFLLFdBQVcsQ0FDSCxDQUFDO1lBRWpDLG9DQUFvQztZQUNwQyxLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLElBQUksVUFBVSxFQUFFO2dCQUN0QyxJQUFJLENBQUMsbUJBQW1CLENBQUMsVUFBVSxFQUFFLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQzthQUNuRDtZQUVELDhEQUE4RDtZQUM5RCxzRUFBc0U7WUFDdEUsSUFBSSxVQUFVLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtnQkFDakYsSUFBSSxDQUFDLGFBQWEsQ0FBQyxVQUFVLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUNuRSxJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsRUFBRSxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FB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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forestadmin/datasource-mongoose",
3
- "version": "1.0.0-beta.9",
3
+ "version": "1.0.0",
4
4
  "main": "dist/index.js",
5
5
  "license": "GPL-3.0",
6
6
  "publishConfig": {
@@ -16,8 +16,9 @@
16
16
  "dist/**/*.d.ts"
17
17
  ],
18
18
  "dependencies": {
19
- "@forestadmin/datasource-toolkit": "1.0.0-beta.23",
20
- "mongoose": "^6.3.2"
19
+ "@forestadmin/datasource-toolkit": "1.0.0",
20
+ "luxon": "^2.3.0",
21
+ "mongoose": "6.6.3"
21
22
  },
22
23
  "peerDependencies": {},
23
24
  "scripts": {
package/CHANGELOG.md DELETED
@@ -1,91 +0,0 @@
1
- # @forestadmin/datasource-mongoose [1.0.0-beta.9](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/datasource-mongoose@1.0.0-beta.8...@forestadmin/datasource-mongoose@1.0.0-beta.9) (2022-06-14)
2
-
3
-
4
-
5
-
6
-
7
- ### Dependencies
8
-
9
- * **@forestadmin/datasource-toolkit:** upgraded to 1.0.0-beta.23
10
-
11
- # @forestadmin/datasource-mongoose [1.0.0-beta.8](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/datasource-mongoose@1.0.0-beta.7...@forestadmin/datasource-mongoose@1.0.0-beta.8) (2022-06-09)
12
-
13
-
14
-
15
-
16
-
17
- ### Dependencies
18
-
19
- * **@forestadmin/datasource-toolkit:** upgraded to 1.0.0-beta.22
20
-
21
- # @forestadmin/datasource-mongoose [1.0.0-beta.7](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/datasource-mongoose@1.0.0-beta.6...@forestadmin/datasource-mongoose@1.0.0-beta.7) (2022-06-01)
22
-
23
-
24
-
25
-
26
-
27
- ### Dependencies
28
-
29
- * **@forestadmin/datasource-toolkit:** upgraded to 1.0.0-beta.21
30
-
31
- # @forestadmin/datasource-mongoose [1.0.0-beta.6](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/datasource-mongoose@1.0.0-beta.5...@forestadmin/datasource-mongoose@1.0.0-beta.6) (2022-05-31)
32
-
33
-
34
- ### Features
35
-
36
- * make count an optional feature ([#327](https://github.com/ForestAdmin/agent-nodejs/issues/327)) ([b6f688c](https://github.com/ForestAdmin/agent-nodejs/commit/b6f688ca5f84aa29740761ff848c4beca5ee61d6))
37
-
38
-
39
-
40
-
41
-
42
- ### Dependencies
43
-
44
- * **@forestadmin/datasource-toolkit:** upgraded to 1.0.0-beta.20
45
-
46
- # @forestadmin/datasource-mongoose [1.0.0-beta.5](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/datasource-mongoose@1.0.0-beta.4...@forestadmin/datasource-mongoose@1.0.0-beta.5) (2022-05-25)
47
-
48
-
49
-
50
-
51
-
52
- ### Dependencies
53
-
54
- * **@forestadmin/datasource-toolkit:** upgraded to 1.0.0-beta.19
55
-
56
- # @forestadmin/datasource-mongoose [1.0.0-beta.4](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/datasource-mongoose@1.0.0-beta.3...@forestadmin/datasource-mongoose@1.0.0-beta.4) (2022-05-24)
57
-
58
-
59
-
60
-
61
-
62
- ### Dependencies
63
-
64
- * **@forestadmin/datasource-toolkit:** upgraded to 1.0.0-beta.18
65
-
66
- # @forestadmin/datasource-mongoose [1.0.0-beta.3](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/datasource-mongoose@1.0.0-beta.2...@forestadmin/datasource-mongoose@1.0.0-beta.3) (2022-05-24)
67
-
68
-
69
-
70
-
71
-
72
- ### Dependencies
73
-
74
- * **@forestadmin/datasource-toolkit:** upgraded to 1.0.0-beta.17
75
-
76
- # @forestadmin/datasource-mongoose [1.0.0-beta.2](https://github.com/ForestAdmin/agent-nodejs/compare/@forestadmin/datasource-mongoose@1.0.0-beta.1...@forestadmin/datasource-mongoose@1.0.0-beta.2) (2022-05-23)
77
-
78
-
79
-
80
-
81
-
82
- ### Dependencies
83
-
84
- * **@forestadmin/datasource-toolkit:** upgraded to 1.0.0-beta.17
85
-
86
- # @forestadmin/datasource-mongoose 1.0.0-beta.1 (2022-05-17)
87
-
88
-
89
- ### Features
90
-
91
- * **mongoose:** add schema generator ([#303](https://github.com/ForestAdmin/agent-nodejs/issues/303)) ([55fa26a](https://github.com/ForestAdmin/agent-nodejs/commit/55fa26a3d1c975c35bdab6a20655573ecaceb31e))
@@ -1,57 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- class FilterOperatorBuilder {
4
- static getSupportedOperators(type) {
5
- if (!(type instanceof Array) && type instanceof Object) {
6
- return new Set(FilterOperatorBuilder.defaultOperators);
7
- }
8
- switch (type) {
9
- case 'Boolean':
10
- return new Set(FilterOperatorBuilder.defaultOperators);
11
- case 'Date':
12
- case 'Dateonly':
13
- return new Set([
14
- ...FilterOperatorBuilder.defaultOperators,
15
- ...FilterOperatorBuilder.inOperators,
16
- ...FilterOperatorBuilder.comparisonOperators,
17
- ]);
18
- case 'Enum':
19
- return new Set([
20
- ...FilterOperatorBuilder.defaultOperators,
21
- ...FilterOperatorBuilder.inOperators,
22
- ]);
23
- case 'Number':
24
- return new Set([
25
- ...FilterOperatorBuilder.defaultOperators,
26
- ...FilterOperatorBuilder.inOperators,
27
- ...FilterOperatorBuilder.comparisonOperators,
28
- ]);
29
- case 'String':
30
- return new Set([
31
- ...FilterOperatorBuilder.defaultOperators,
32
- ...FilterOperatorBuilder.inOperators,
33
- ...FilterOperatorBuilder.stringOperators,
34
- ]);
35
- case 'Uuid':
36
- return new Set([
37
- ...FilterOperatorBuilder.defaultOperators,
38
- ...FilterOperatorBuilder.stringOperators,
39
- ]);
40
- case 'Json':
41
- return new Set(FilterOperatorBuilder.defaultOperators);
42
- default:
43
- return new Set();
44
- }
45
- }
46
- }
47
- exports.default = FilterOperatorBuilder;
48
- FilterOperatorBuilder.defaultOperators = ['Equal', 'NotEqual', 'Present'];
49
- FilterOperatorBuilder.inOperators = ['In', 'NotIn'];
50
- FilterOperatorBuilder.stringOperators = [
51
- 'Like',
52
- 'NotContains',
53
- 'LongerThan',
54
- 'ShorterThan',
55
- ];
56
- FilterOperatorBuilder.comparisonOperators = ['GreaterThan', 'LessThan'];
57
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsdGVyLW9wZXJhdG9yLWJ1aWxkZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvZmlsdGVyLW9wZXJhdG9yLWJ1aWxkZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFFQSxNQUFxQixxQkFBcUI7SUFZeEMsTUFBTSxDQUFDLHFCQUFxQixDQUFDLElBQWdCO1FBQzNDLElBQUksQ0FBQyxDQUFDLElBQUksWUFBWSxLQUFLLENBQUMsSUFBSSxJQUFJLFlBQVksTUFBTSxFQUFFO1lBQ3RELE9BQU8sSUFBSSxHQUFHLENBQVcscUJBQXFCLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztTQUNsRTtRQUVELFFBQVEsSUFBSSxFQUFFO1lBQ1osS0FBSyxTQUFTO2dCQUNaLE9BQU8sSUFBSSxHQUFHLENBQVcscUJBQXFCLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztZQUNuRSxLQUFLLE1BQU0sQ0FBQztZQUNaLEtBQUssVUFBVTtnQkFDYixPQUFPLElBQUksR0FBRyxDQUFXO29CQUN2QixHQUFHLHFCQUFxQixDQUFDLGdCQUFnQjtvQkFDekMsR0FBRyxxQkFBcUIsQ0FBQyxXQUFXO29CQUNwQyxHQUFHLHFCQUFxQixDQUFDLG1CQUFtQjtpQkFDN0MsQ0FBQyxDQUFDO1lBQ0wsS0FBSyxNQUFNO2dCQUNULE9BQU8sSUFBSSxHQUFHLENBQVc7b0JBQ3ZCLEdBQUcscUJBQXFCLENBQUMsZ0JBQWdCO29CQUN6QyxHQUFHLHFCQUFxQixDQUFDLFdBQVc7aUJBQ3JDLENBQUMsQ0FBQztZQUNMLEtBQUssUUFBUTtnQkFDWCxPQUFPLElBQUksR0FBRyxDQUFXO29CQUN2QixHQUFHLHFCQUFxQixDQUFDLGdCQUFnQjtvQkFDekMsR0FBRyxxQkFBcUIsQ0FBQyxXQUFXO29CQUNwQyxHQUFHLHFCQUFxQixDQUFDLG1CQUFtQjtpQkFDN0MsQ0FBQyxDQUFDO1lBQ0wsS0FBSyxRQUFRO2dCQUNYLE9BQU8sSUFBSSxHQUFHLENBQVc7b0JBQ3ZCLEdBQUcscUJBQXFCLENBQUMsZ0JBQWdCO29CQUN6QyxHQUFHLHFCQUFxQixDQUFDLFdBQVc7b0JBQ3BDLEdBQUcscUJBQXFCLENBQUMsZUFBZTtpQkFDekMsQ0FBQyxDQUFDO1lBQ0wsS0FBSyxNQUFNO2dCQUNULE9BQU8sSUFBSSxHQUFHLENBQVc7b0JBQ3ZCLEdBQUcscUJBQXFCLENBQUMsZ0JBQWdCO29CQUN6QyxHQUFHLHFCQUFxQixDQUFDLGVBQWU7aUJBQ3pDLENBQUMsQ0FBQztZQUNMLEtBQUssTUFBTTtnQkFDVCxPQUFPLElBQUksR0FBRyxDQUFXLHFCQUFxQixDQUFDLGdCQUFnQixDQUFDLENBQUM7WUFDbkU7Z0JBQ0UsT0FBTyxJQUFJLEdBQUcsRUFBWSxDQUFDO1NBQzlCO0lBQ0gsQ0FBQzs7QUF0REgsd0NBdURDO0FBdERpQixzQ0FBZ0IsR0FBd0IsQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0FBQ3pFLGlDQUFXLEdBQXdCLENBQUMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0FBQ25ELHFDQUFlLEdBQXdCO0lBQ3JELE1BQU07SUFDTixhQUFhO0lBQ2IsWUFBWTtJQUNaLGFBQWE7Q0FDZCxDQUFDO0FBRWMseUNBQW1CLEdBQXdCLENBQUMsYUFBYSxFQUFFLFVBQVUsQ0FBQyxDQUFDIn0=
@@ -1,13 +0,0 @@
1
- import { CollectionSchema, RecordData } from '@forestadmin/datasource-toolkit';
2
- import { Model } from 'mongoose';
3
- import MongooseCollection from '../collection';
4
- export default class SchemaFieldsGenerator {
5
- static addInverseRelationships(collections: MongooseCollection[]): void;
6
- static buildFieldsSchema(model: Model<RecordData>): CollectionSchema['fields'];
7
- private static getColumnType;
8
- private static buildColumnSchema;
9
- private static getEnumValues;
10
- private static getColumnTypeFromNested;
11
- private static getColumnTypeFromNestedPath;
12
- }
13
- //# sourceMappingURL=schema-fields-generator.d.ts.map
@@ -1,142 +0,0 @@
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 filter_operator_builder_1 = __importDefault(require("./filter-operator-builder"));
7
- class SchemaFieldsGenerator {
8
- static addInverseRelationships(collections) {
9
- collections.forEach(collection => {
10
- Object.values(collection.schema.fields).forEach(fieldSchema => {
11
- if (fieldSchema.type === 'ManyToOne') {
12
- const foreignCollection = collections.find(c => c.name === fieldSchema.foreignCollection);
13
- if (!foreignCollection) {
14
- throw new Error(`The collection '${fieldSchema.foreignCollection}' does not exist`);
15
- }
16
- const field = `${foreignCollection.name}__${fieldSchema.foreignKey}__oneToMany`;
17
- foreignCollection.schema.fields[field] = {
18
- foreignCollection: collection.name,
19
- originKey: fieldSchema.foreignKey,
20
- originKeyTarget: '_id',
21
- type: 'OneToMany',
22
- };
23
- }
24
- });
25
- });
26
- }
27
- static buildFieldsSchema(model) {
28
- const schemaFields = {};
29
- Object.entries(model.schema.paths).forEach(([fieldName, field]) => {
30
- const mixedFieldPattern = '$*';
31
- const privateFieldPattern = '__';
32
- if (fieldName.startsWith(privateFieldPattern) || fieldName.includes(mixedFieldPattern)) {
33
- return;
34
- }
35
- if (field.options.ref) {
36
- schemaFields[`${fieldName}_manyToOne`] = {
37
- type: 'ManyToOne',
38
- foreignCollection: field.options.ref,
39
- foreignKey: field.path,
40
- foreignKeyTarget: '_id',
41
- };
42
- schemaFields[fieldName] = SchemaFieldsGenerator.buildColumnSchema(field, 'String');
43
- }
44
- schemaFields[field.path.split('.').shift()] = SchemaFieldsGenerator.buildColumnSchema(field, SchemaFieldsGenerator.getColumnType(field.instance, field));
45
- });
46
- return schemaFields;
47
- }
48
- static getColumnType(instance, field) {
49
- if (field.path.includes('.')) {
50
- const fieldPath = field.path.split('.');
51
- fieldPath.shift();
52
- field.path = fieldPath[fieldPath.length - 1];
53
- return SchemaFieldsGenerator.getColumnTypeFromNestedPath(fieldPath, field);
54
- }
55
- const potentialEnumValues = this.getEnumValues(field);
56
- if (potentialEnumValues) {
57
- if (potentialEnumValues.some(value => !(typeof value === 'string'))) {
58
- throw new Error('Enum support only String values');
59
- }
60
- return 'Enum';
61
- }
62
- switch (instance) {
63
- case 'Array':
64
- return [
65
- SchemaFieldsGenerator.getColumnType(field.schema ? 'Embedded' : field.caster.instance, field.schema ? field : field.caster),
66
- ];
67
- case 'String':
68
- case 'ObjectID':
69
- case 'Buffer':
70
- case 'Decimal128':
71
- return 'String';
72
- case 'Number':
73
- return 'Number';
74
- case 'Date':
75
- return 'Date';
76
- case 'Boolean':
77
- return 'Boolean';
78
- case 'Map':
79
- case 'Mixed':
80
- return 'Json';
81
- case 'Embedded':
82
- default:
83
- return SchemaFieldsGenerator.getColumnTypeFromNested(field);
84
- }
85
- }
86
- static buildColumnSchema(field, columnType) {
87
- return {
88
- columnType,
89
- filterOperators: filter_operator_builder_1.default.getSupportedOperators(columnType),
90
- defaultValue: field.options?.default,
91
- enumValues: this.getEnumValues(field),
92
- isPrimaryKey: field.path === '_id',
93
- isReadOnly: !!field.options?.immutable,
94
- isSortable: !(columnType instanceof Object || columnType === 'Json'),
95
- type: 'Column',
96
- validation: field.isRequired ? [{ operator: 'Present' }] : null,
97
- };
98
- }
99
- static getEnumValues(field) {
100
- return field.options?.enum instanceof Array ? field.options.enum : field.options?.enum?.values;
101
- }
102
- static getColumnTypeFromNested(field) {
103
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
104
- // @ts-ignore
105
- const { singleNestedPaths } = field.schema;
106
- const paths = Object.keys(singleNestedPaths).length > 0 ? singleNestedPaths : field.schema.paths;
107
- return Object.entries(paths).reduce((columnType, [fieldPath, fieldSchema]) => {
108
- return SchemaFieldsGenerator.getColumnTypeFromNestedPath(fieldPath.split('.'), fieldSchema, columnType);
109
- }, {});
110
- }
111
- static getColumnTypeFromNestedPath(fieldPath, field, columnType = {}) {
112
- let previousPath;
113
- fieldPath.forEach((fieldName, index) => {
114
- if (fieldName === '_id') {
115
- return;
116
- }
117
- if (index !== fieldPath.length - 1) {
118
- if (previousPath) {
119
- if (!previousPath[fieldName]) {
120
- previousPath[fieldName] = {};
121
- }
122
- previousPath = previousPath[fieldName];
123
- }
124
- else {
125
- if (!columnType[fieldName]) {
126
- columnType[fieldName] = {};
127
- }
128
- previousPath = columnType[fieldName];
129
- }
130
- }
131
- else {
132
- if (!previousPath) {
133
- previousPath = columnType;
134
- }
135
- previousPath[fieldName] = SchemaFieldsGenerator.getColumnType(field.instance, field);
136
- }
137
- });
138
- return columnType;
139
- }
140
- }
141
- exports.default = SchemaFieldsGenerator;
142
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NoZW1hLWZpZWxkcy1nZW5lcmF0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvdXRpbHMvc2NoZW1hLWZpZWxkcy1nZW5lcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFVQSx3RkFBOEQ7QUFHOUQsTUFBcUIscUJBQXFCO0lBQ3hDLE1BQU0sQ0FBQyx1QkFBdUIsQ0FBQyxXQUFpQztRQUM5RCxXQUFXLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxFQUFFO1lBQy9CLE1BQU0sQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLEVBQUU7Z0JBQzVELElBQUksV0FBVyxDQUFDLElBQUksS0FBSyxXQUFXLEVBQUU7b0JBQ3BDLE1BQU0saUJBQWlCLEdBQUcsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssV0FBVyxDQUFDLGlCQUFpQixDQUFDLENBQUM7b0JBRTFGLElBQUksQ0FBQyxpQkFBaUIsRUFBRTt3QkFDdEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxtQkFBbUIsV0FBVyxDQUFDLGlCQUFpQixrQkFBa0IsQ0FBQyxDQUFDO3FCQUNyRjtvQkFFRCxNQUFNLEtBQUssR0FBRyxHQUFHLGlCQUFpQixDQUFDLElBQUksS0FBSyxXQUFXLENBQUMsVUFBVSxhQUFhLENBQUM7b0JBQ2hGLGlCQUFpQixDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEdBQUc7d0JBQ3ZDLGlCQUFpQixFQUFFLFVBQVUsQ0FBQyxJQUFJO3dCQUNsQyxTQUFTLEVBQUUsV0FBVyxDQUFDLFVBQVU7d0JBQ2pDLGVBQWUsRUFBRSxLQUFLO3dCQUN0QixJQUFJLEVBQUUsV0FBVztxQkFDbEIsQ0FBQztpQkFDSDtZQUNILENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQyxDQUFDLENBQUM7SUFDTCxD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