From ba24cbef5e7b379525359bc5b9736e92fa295388 Mon Sep 17 00:00:00 2001 From: remoove <67414956+remoove@users.noreply.github.com> Date: Thu, 18 Feb 2021 12:41:23 +0300 Subject: [PATCH 1/5] add selection fields now, if you set {select: false} option in mongoose schema, it would be displayed in the adminbro table --- src/resource.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/resource.ts b/src/resource.ts index 99688aa..4c745e3 100644 --- a/src/resource.ts +++ b/src/resource.ts @@ -55,6 +55,10 @@ class Resource extends BaseResource { id() { return this.MongooseModel.modelName } + + get selectFields(){ + return Object.keys(this.MongooseModel.schema.paths).join(' '); + } properties() { return Object.entries(this.MongooseModel.schema.paths).map(([, path], position) => ( @@ -77,7 +81,7 @@ class Resource extends BaseResource { } const mongooseObjects = await this.MongooseModel .find(convertFilter(filters), {}, { - skip: offset, limit, sort: sortingParam, + skip: offset, limit, sort: sortingParam, select: this.selectFields }) return mongooseObjects.map(mongooseObject => new BaseRecord( Resource.stringifyId(mongooseObject), this, @@ -85,7 +89,7 @@ class Resource extends BaseResource { } async findOne(id:string) { - const mongooseObject = await this.MongooseModel.findById(id) + const mongooseObject = await this.MongooseModel.findById(id).select(this.selectFields) return new BaseRecord(Resource.stringifyId(mongooseObject), this) } @@ -93,6 +97,7 @@ class Resource extends BaseResource { const mongooseObjects = await this.MongooseModel.find( { _id: ids }, {}, + {select: this.selectFields} ) return mongooseObjects.map(mongooseObject => ( new BaseRecord(Resource.stringifyId(mongooseObject), this) From 31934cf020f40cb4fa8b3eda23e167526cb0b29a Mon Sep 17 00:00:00 2001 From: remoove <67414956+remoove@users.noreply.github.com> Date: Thu, 18 Feb 2021 13:00:36 +0300 Subject: [PATCH 2/5] fix displaing NumberDecimal You should set 'get' option in mongoose schema: {get: (v)=>v ? Number(v) : v} --- src/resource.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/resource.ts b/src/resource.ts index 4c745e3..f4e6d64 100644 --- a/src/resource.ts +++ b/src/resource.ts @@ -71,7 +71,7 @@ class Resource extends BaseResource { } async count(filters = null) { - return this.MongooseModel.count(convertFilter(filters)) + return this.MongooseModel.countDocuments(convertFilter(filters)) } async find(filters = {}, { limit = 20, offset = 0, sort = {} }: FindOptions) { @@ -164,7 +164,7 @@ class Resource extends BaseResource { // raw object it changes _id field not to a string but to an object. // stringify/parse is a path found here: https://github.com/Automattic/mongoose/issues/2790 // @todo We can somehow speed this up - const strinigified = JSON.stringify(mongooseObj) + const strinigified = JSON.stringify('toObject' in mongooseObj ? mongooseObj.toObject({getters: true, virtuals: true}): mongooseObj) return JSON.parse(strinigified) } From 7e917339bfe2a46593bb7c75c739073e1612df00 Mon Sep 17 00:00:00 2001 From: remoove <67414956+remoove@users.noreply.github.com> Date: Thu, 18 Feb 2021 13:44:11 +0300 Subject: [PATCH 3/5] build --- .gitignore | 3 +- lib/index.d.ts | 3 + lib/index.js | 12 + lib/index.js.map | 1 + lib/src/database.d.ts | 8 + lib/src/database.js | 21 ++ lib/src/database.js.map | 1 + lib/src/index.d.ts | 8 + lib/src/index.js | 17 ++ lib/src/index.js.map | 1 + lib/src/property.d.ts | 43 ++++ lib/src/property.js | 112 ++++++++++ lib/src/property.js.map | 1 + lib/src/resource.d.ts | 53 +++++ lib/src/resource.js | 209 ++++++++++++++++++ lib/src/resource.js.map | 1 + lib/src/utils/convert-filter.d.ts | 7 + lib/src/utils/convert-filter.js | 57 +++++ lib/src/utils/convert-filter.js.map | 1 + lib/src/utils/create-cast-error.d.ts | 1 + lib/src/utils/create-cast-error.js | 19 ++ lib/src/utils/create-cast-error.js.map | 1 + lib/src/utils/create-duplicate-error.d.ts | 4 + lib/src/utils/create-duplicate-error.js | 22 ++ lib/src/utils/create-duplicate-error.js.map | 1 + lib/src/utils/create-validation-error.d.ts | 1 + lib/src/utils/create-validation-error.js | 19 ++ lib/src/utils/create-validation-error.js.map | 1 + lib/src/utils/errors.d.ts | 6 + lib/src/utils/errors.js | 12 + lib/src/utils/errors.js.map | 1 + lib/src/utils/filter.types.d.ts | 8 + lib/src/utils/filter.types.js | 3 + lib/src/utils/filter.types.js.map | 1 + lib/test/database.spec.d.ts | 1 + lib/test/database.spec.js | 19 ++ lib/test/database.spec.js.map | 1 + lib/test/errors/create-cast-error.spec.d.ts | 1 + lib/test/errors/create-cast-error.spec.js | 20 ++ lib/test/errors/create-cast-error.spec.js.map | 1 + .../errors/create-validation-error.spec.d.ts | 1 + .../errors/create-validation-error.spec.js | 32 +++ .../create-validation-error.spec.js.map | 1 + lib/test/fixtures/duplicate-error.d.ts | 0 lib/test/fixtures/duplicate-error.js | 8 + lib/test/fixtures/duplicate-error.js.map | 1 + .../fixtures/mongoose-cast-array-error.d.ts | 9 + .../fixtures/mongoose-cast-array-error.js | 13 ++ .../fixtures/mongoose-cast-array-error.js.map | 1 + lib/test/fixtures/mongoose-cast-error.d.ts | 24 ++ lib/test/fixtures/mongoose-cast-error.js | 28 +++ lib/test/fixtures/mongoose-cast-error.js.map | 1 + .../mongoose-nested-validation-error.d.ts | 46 ++++ .../mongoose-nested-validation-error.js | 50 +++++ .../mongoose-nested-validation-error.js.map | 1 + .../fixtures/mongoose-validation-error.d.ts | 35 +++ .../fixtures/mongoose-validation-error.js | 39 ++++ .../fixtures/mongoose-validation-error.js.map | 1 + lib/test/fixtures/valid-user-record.d.ts | 27 +++ lib/test/fixtures/valid-user-record.js | 29 +++ lib/test/fixtures/valid-user-record.js.map | 1 + lib/test/property.spec.d.ts | 1 + lib/test/property.spec.js | 84 +++++++ lib/test/property.spec.js.map | 1 + lib/test/resource/constructor.d.ts | 1 + lib/test/resource/constructor.js | 16 ++ lib/test/resource/constructor.js.map | 1 + lib/test/resource/count.spec.d.ts | 1 + lib/test/resource/count.spec.js | 29 +++ lib/test/resource/count.spec.js.map | 1 + lib/test/resource/create.spec.d.ts | 1 + lib/test/resource/create.spec.js | 79 +++++++ lib/test/resource/create.spec.js.map | 1 + lib/test/resource/delete.spec.d.ts | 1 + lib/test/resource/delete.spec.js | 19 ++ lib/test/resource/delete.spec.js.map | 1 + lib/test/resource/find.spec.d.ts | 1 + lib/test/resource/find.spec.js | 24 ++ lib/test/resource/find.spec.js.map | 1 + lib/test/resource/name.spec.d.ts | 1 + lib/test/resource/name.spec.js | 14 ++ lib/test/resource/name.spec.js.map | 1 + lib/test/resource/parseParams.spec.d.ts | 1 + lib/test/resource/parseParams.spec.js | 20 ++ lib/test/resource/parseParams.spec.js.map | 1 + lib/test/resource/position.spec.d.ts | 1 + lib/test/resource/position.spec.js | 14 ++ lib/test/resource/position.spec.js.map | 1 + lib/test/resource/properties.spec.d.ts | 1 + lib/test/resource/properties.spec.js | 39 ++++ lib/test/resource/properties.spec.js.map | 1 + lib/test/resource/property.spec.d.ts | 1 + lib/test/resource/property.spec.js | 23 ++ lib/test/resource/property.spec.js.map | 1 + lib/test/resource/update.spec.d.ts | 1 + lib/test/resource/update.spec.js | 18 ++ lib/test/resource/update.spec.js.map | 1 + lib/test/utils/beforeEach.d.ts | 1 + lib/test/utils/beforeEach.js | 20 ++ lib/test/utils/beforeEach.js.map | 1 + lib/test/utils/models.d.ts | 1 + lib/test/utils/models.js | 51 +++++ lib/test/utils/models.js.map | 1 + lib/test/utils/teardown.d.ts | 2 + lib/test/utils/teardown.js | 14 ++ lib/test/utils/teardown.js.map | 1 + 106 files changed, 1543 insertions(+), 2 deletions(-) create mode 100644 lib/index.d.ts create mode 100644 lib/index.js create mode 100644 lib/index.js.map create mode 100644 lib/src/database.d.ts create mode 100644 lib/src/database.js create mode 100644 lib/src/database.js.map create mode 100644 lib/src/index.d.ts create mode 100644 lib/src/index.js create mode 100644 lib/src/index.js.map create mode 100644 lib/src/property.d.ts create mode 100644 lib/src/property.js create mode 100644 lib/src/property.js.map create mode 100644 lib/src/resource.d.ts create mode 100644 lib/src/resource.js create mode 100644 lib/src/resource.js.map create mode 100644 lib/src/utils/convert-filter.d.ts create mode 100644 lib/src/utils/convert-filter.js create mode 100644 lib/src/utils/convert-filter.js.map create mode 100644 lib/src/utils/create-cast-error.d.ts create mode 100644 lib/src/utils/create-cast-error.js create mode 100644 lib/src/utils/create-cast-error.js.map create mode 100644 lib/src/utils/create-duplicate-error.d.ts create mode 100644 lib/src/utils/create-duplicate-error.js create mode 100644 lib/src/utils/create-duplicate-error.js.map create mode 100644 lib/src/utils/create-validation-error.d.ts create mode 100644 lib/src/utils/create-validation-error.js create mode 100644 lib/src/utils/create-validation-error.js.map create mode 100644 lib/src/utils/errors.d.ts create mode 100644 lib/src/utils/errors.js create mode 100644 lib/src/utils/errors.js.map create mode 100644 lib/src/utils/filter.types.d.ts create mode 100644 lib/src/utils/filter.types.js create mode 100644 lib/src/utils/filter.types.js.map create mode 100644 lib/test/database.spec.d.ts create mode 100644 lib/test/database.spec.js create mode 100644 lib/test/database.spec.js.map create mode 100644 lib/test/errors/create-cast-error.spec.d.ts create mode 100644 lib/test/errors/create-cast-error.spec.js create mode 100644 lib/test/errors/create-cast-error.spec.js.map create mode 100644 lib/test/errors/create-validation-error.spec.d.ts create mode 100644 lib/test/errors/create-validation-error.spec.js create mode 100644 lib/test/errors/create-validation-error.spec.js.map create mode 100644 lib/test/fixtures/duplicate-error.d.ts create mode 100644 lib/test/fixtures/duplicate-error.js create mode 100644 lib/test/fixtures/duplicate-error.js.map create mode 100644 lib/test/fixtures/mongoose-cast-array-error.d.ts create mode 100644 lib/test/fixtures/mongoose-cast-array-error.js create mode 100644 lib/test/fixtures/mongoose-cast-array-error.js.map create mode 100644 lib/test/fixtures/mongoose-cast-error.d.ts create mode 100644 lib/test/fixtures/mongoose-cast-error.js create mode 100644 lib/test/fixtures/mongoose-cast-error.js.map create mode 100644 lib/test/fixtures/mongoose-nested-validation-error.d.ts create mode 100644 lib/test/fixtures/mongoose-nested-validation-error.js create mode 100644 lib/test/fixtures/mongoose-nested-validation-error.js.map create mode 100644 lib/test/fixtures/mongoose-validation-error.d.ts create mode 100644 lib/test/fixtures/mongoose-validation-error.js create mode 100644 lib/test/fixtures/mongoose-validation-error.js.map create mode 100644 lib/test/fixtures/valid-user-record.d.ts create mode 100644 lib/test/fixtures/valid-user-record.js create mode 100644 lib/test/fixtures/valid-user-record.js.map create mode 100644 lib/test/property.spec.d.ts create mode 100644 lib/test/property.spec.js create mode 100644 lib/test/property.spec.js.map create mode 100644 lib/test/resource/constructor.d.ts create mode 100644 lib/test/resource/constructor.js create mode 100644 lib/test/resource/constructor.js.map create mode 100644 lib/test/resource/count.spec.d.ts create mode 100644 lib/test/resource/count.spec.js create mode 100644 lib/test/resource/count.spec.js.map create mode 100644 lib/test/resource/create.spec.d.ts create mode 100644 lib/test/resource/create.spec.js create mode 100644 lib/test/resource/create.spec.js.map create mode 100644 lib/test/resource/delete.spec.d.ts create mode 100644 lib/test/resource/delete.spec.js create mode 100644 lib/test/resource/delete.spec.js.map create mode 100644 lib/test/resource/find.spec.d.ts create mode 100644 lib/test/resource/find.spec.js create mode 100644 lib/test/resource/find.spec.js.map create mode 100644 lib/test/resource/name.spec.d.ts create mode 100644 lib/test/resource/name.spec.js create mode 100644 lib/test/resource/name.spec.js.map create mode 100644 lib/test/resource/parseParams.spec.d.ts create mode 100644 lib/test/resource/parseParams.spec.js create mode 100644 lib/test/resource/parseParams.spec.js.map create mode 100644 lib/test/resource/position.spec.d.ts create mode 100644 lib/test/resource/position.spec.js create mode 100644 lib/test/resource/position.spec.js.map create mode 100644 lib/test/resource/properties.spec.d.ts create mode 100644 lib/test/resource/properties.spec.js create mode 100644 lib/test/resource/properties.spec.js.map create mode 100644 lib/test/resource/property.spec.d.ts create mode 100644 lib/test/resource/property.spec.js create mode 100644 lib/test/resource/property.spec.js.map create mode 100644 lib/test/resource/update.spec.d.ts create mode 100644 lib/test/resource/update.spec.js create mode 100644 lib/test/resource/update.spec.js.map create mode 100644 lib/test/utils/beforeEach.d.ts create mode 100644 lib/test/utils/beforeEach.js create mode 100644 lib/test/utils/beforeEach.js.map create mode 100644 lib/test/utils/models.d.ts create mode 100644 lib/test/utils/models.js create mode 100644 lib/test/utils/models.js.map create mode 100644 lib/test/utils/teardown.d.ts create mode 100644 lib/test/utils/teardown.js create mode 100644 lib/test/utils/teardown.js.map diff --git a/.gitignore b/.gitignore index 98bdd26..1a331da 100644 --- a/.gitignore +++ b/.gitignore @@ -117,5 +117,4 @@ dist .DS_store -# build files -/lib \ No newline at end of file +# build files \ No newline at end of file diff --git a/lib/index.d.ts b/lib/index.d.ts new file mode 100644 index 0000000..dee5c96 --- /dev/null +++ b/lib/index.d.ts @@ -0,0 +1,3 @@ +import Database from './src/database'; +import Resource from './src/resource'; +export { Database, Resource }; diff --git a/lib/index.js b/lib/index.js new file mode 100644 index 0000000..229dcd4 --- /dev/null +++ b/lib/index.js @@ -0,0 +1,12 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Resource = exports.Database = void 0; +const database_1 = __importDefault(require("./src/database")); +exports.Database = database_1.default; +const resource_1 = __importDefault(require("./src/resource")); +exports.Resource = resource_1.default; +module.exports = { Database: database_1.default, Resource: resource_1.default }; +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/index.js.map b/lib/index.js.map new file mode 100644 index 0000000..995d5b7 --- /dev/null +++ b/lib/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";;;;;;AAAA,8DAAqC;AAI5B,mBAJF,kBAAQ,CAIE;AAHjB,8DAAqC;AAGlB,mBAHZ,kBAAQ,CAGY;AAD3B,MAAM,CAAC,OAAO,GAAG,EAAE,QAAQ,EAAR,kBAAQ,EAAE,QAAQ,EAAR,kBAAQ,EAAE,CAAA"} \ No newline at end of file diff --git a/lib/src/database.d.ts b/lib/src/database.d.ts new file mode 100644 index 0000000..cb36ba3 --- /dev/null +++ b/lib/src/database.d.ts @@ -0,0 +1,8 @@ +import { BaseDatabase } from 'admin-bro'; +declare class Database extends BaseDatabase { + private readonly connection; + constructor(connection: any); + static isAdapterFor(connection: any): boolean; + resources(): any; +} +export default Database; diff --git a/lib/src/database.js b/lib/src/database.js new file mode 100644 index 0000000..6354768 --- /dev/null +++ b/lib/src/database.js @@ -0,0 +1,21 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const admin_bro_1 = require("admin-bro"); +const resource_1 = __importDefault(require("./resource")); +class Database extends admin_bro_1.BaseDatabase { + constructor(connection) { + super(connection); + this.connection = connection; + } + static isAdapterFor(connection) { + return connection.constructor.name === 'Mongoose'; + } + resources() { + return this.connection.modelNames().map(name => (new resource_1.default(this.connection.model(name)))); + } +} +exports.default = Database; +//# sourceMappingURL=database.js.map \ No newline at end of file diff --git a/lib/src/database.js.map b/lib/src/database.js.map new file mode 100644 index 0000000..105fd4e --- /dev/null +++ b/lib/src/database.js.map @@ -0,0 +1 @@ +{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/database.ts"],"names":[],"mappings":";;;;;AAAA,yCAAwC;AAGxC,0DAAiC;AAEjC,MAAM,QAAS,SAAQ,wBAAY;IAGjC,YAAY,UAAU;QACpB,KAAK,CAAC,UAAU,CAAC,CAAA;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IAC9B,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,UAAU;QAC5B,OAAO,UAAU,CAAC,WAAW,CAAC,IAAI,KAAK,UAAU,CAAA;IACnD,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAC9C,IAAI,kBAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAC1C,CAAC,CAAA;IACJ,CAAC;CACF;AAED,kBAAe,QAAQ,CAAA"} \ No newline at end of file diff --git a/lib/src/index.d.ts b/lib/src/index.d.ts new file mode 100644 index 0000000..1732264 --- /dev/null +++ b/lib/src/index.d.ts @@ -0,0 +1,8 @@ +/** + * @module @admin-bro/mongoose + * @subcategory Adapters + * @section modules + * @load ./index.doc.md + */ +export { default as Resource } from './resource'; +export { default as Database } from './database'; diff --git a/lib/src/index.js b/lib/src/index.js new file mode 100644 index 0000000..16f72a4 --- /dev/null +++ b/lib/src/index.js @@ -0,0 +1,17 @@ +"use strict"; +/** + * @module @admin-bro/mongoose + * @subcategory Adapters + * @section modules + * @load ./index.doc.md + */ +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Database = exports.Resource = void 0; +var resource_1 = require("./resource"); +Object.defineProperty(exports, "Resource", { enumerable: true, get: function () { return __importDefault(resource_1).default; } }); +var database_1 = require("./database"); +Object.defineProperty(exports, "Database", { enumerable: true, get: function () { return __importDefault(database_1).default; } }); +//# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/lib/src/index.js.map b/lib/src/index.js.map new file mode 100644 index 0000000..c279451 --- /dev/null +++ b/lib/src/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;AAEH,uCAAgD;AAAvC,qHAAA,OAAO,OAAY;AAC5B,uCAAgD;AAAvC,qHAAA,OAAO,OAAY"} \ No newline at end of file diff --git a/lib/src/property.d.ts b/lib/src/property.d.ts new file mode 100644 index 0000000..8ffcc93 --- /dev/null +++ b/lib/src/property.d.ts @@ -0,0 +1,43 @@ +import { BaseProperty } from 'admin-bro'; +declare class Property extends BaseProperty { + mongoosePath: any; + /** + * Crates an object from mongoose schema path + * + * @param {SchemaString} path + * @param {String[]} path.enumValues + * @param {String} path.regExp + * @param {String} path.path + * @param {String} path.instance + * @param {Object[]} path.validators + * @param {Object[]} path.setters + * @param {Object[]} path.getters + * @param {Object} path.options + * @param {Object} path._index + * @param {number} position + * + * @private + * + * @example + * + * const schema = new mongoose.Schema({ + * email: String, + * }) + * + * property = new Property(schema.paths.email)) + */ + constructor(path: any, position?: number); + instanceToType(mongooseInstance: any): "string" | "number" | "boolean" | "datetime" | "mixed" | "reference" | "float"; + name(): any; + isEditable(): boolean; + reference(): any; + isVisible(): boolean; + isId(): boolean; + availableValues(): any; + isArray(): boolean; + subProperties(): Property[]; + type(): "string" | "number" | "boolean" | "datetime" | "mixed" | "reference" | "float"; + isSortable(): boolean; + isRequired(): boolean; +} +export default Property; diff --git a/lib/src/property.js b/lib/src/property.js new file mode 100644 index 0000000..635808e --- /dev/null +++ b/lib/src/property.js @@ -0,0 +1,112 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const admin_bro_1 = require("admin-bro"); +const ID_PROPERTY = '_id'; +const VERSION_KEY_PROPERTY = '__v'; +class Property extends admin_bro_1.BaseProperty { + /** + * Crates an object from mongoose schema path + * + * @param {SchemaString} path + * @param {String[]} path.enumValues + * @param {String} path.regExp + * @param {String} path.path + * @param {String} path.instance + * @param {Object[]} path.validators + * @param {Object[]} path.setters + * @param {Object[]} path.getters + * @param {Object} path.options + * @param {Object} path._index + * @param {number} position + * + * @private + * + * @example + * + * const schema = new mongoose.Schema({ + * email: String, + * }) + * + * property = new Property(schema.paths.email)) + */ + constructor(path, position = 0) { + super({ path: path.path, position }); + this.mongoosePath = path; + } + instanceToType(mongooseInstance) { + switch (mongooseInstance) { + case 'String': + return 'string'; + case 'Boolean': + return 'boolean'; + case 'Number': + return 'number'; + case 'Date': + return 'datetime'; + case 'Embedded': + return 'mixed'; + case 'ObjectID': + if (this.reference()) { + return 'reference'; + } + return 'string'; + case 'Decimal128': + return 'float'; + default: + return 'string'; + } + } + name() { + return this.mongoosePath.path; + } + isEditable() { + return this.name() !== VERSION_KEY_PROPERTY && this.name() !== ID_PROPERTY; + } + reference() { + if (this.isArray()) { + return this.mongoosePath.caster.options && this.mongoosePath.caster.options.ref; + } + return this.mongoosePath.options && this.mongoosePath.options.ref; + } + isVisible() { + return this.name() !== VERSION_KEY_PROPERTY; + } + isId() { + return this.name() === ID_PROPERTY; + } + availableValues() { + var _a; + return ((_a = this.mongoosePath.enumValues) === null || _a === void 0 ? void 0 : _a.length) ? this.mongoosePath.enumValues : null; + } + isArray() { + return this.mongoosePath.instance === 'Array'; + } + subProperties() { + if (this.type() === 'mixed') { + const subPaths = Object.values(this.mongoosePath.caster.schema.paths); + return subPaths.map(p => new Property(p)); + } + return []; + } + type() { + if (this.isArray()) { + let { instance } = this.mongoosePath.caster; + // For array of embedded schemas mongoose returns null for caster.instance + // That is why we have to check if caster has a schema + if (!instance && this.mongoosePath.caster.schema) { + instance = 'Embedded'; + } + return this.instanceToType(instance); + } + return this.instanceToType(this.mongoosePath.instance); + } + isSortable() { + return this.type() !== 'mixed' && !this.isArray(); + } + isRequired() { + var _a, _b; + return !!((_b = (_a = this.mongoosePath.validators) === null || _a === void 0 ? void 0 : _a.find) === null || _b === void 0 ? void 0 : _b.call(_a, validator => validator.type === 'required')); + } +} +exports.default = Property; +//# sourceMappingURL=property.js.map \ No newline at end of file diff --git a/lib/src/property.js.map b/lib/src/property.js.map new file mode 100644 index 0000000..03fb448 --- /dev/null +++ b/lib/src/property.js.map @@ -0,0 +1 @@ +{"version":3,"file":"property.js","sourceRoot":"","sources":["../../src/property.ts"],"names":[],"mappings":";;AAAA,yCAAwC;AAExC,MAAM,WAAW,GAAG,KAAK,CAAA;AACzB,MAAM,oBAAoB,GAAG,KAAK,CAAA;AAElC,MAAM,QAAS,SAAQ,wBAAY;IAI/B;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACH,YAAY,IAAI,EAAE,QAAQ,GAAG,CAAC;QAC5B,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;QACpC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAA;IAC1B,CAAC;IAED,cAAc,CAAC,gBAAgB;QAC7B,QAAQ,gBAAgB,EAAE;YAC1B,KAAK,QAAQ;gBACX,OAAO,QAAQ,CAAA;YACjB,KAAK,SAAS;gBACZ,OAAO,SAAS,CAAA;YAClB,KAAK,QAAQ;gBACX,OAAO,QAAQ,CAAA;YACjB,KAAK,MAAM;gBACT,OAAO,UAAU,CAAA;YACnB,KAAK,UAAU;gBACb,OAAO,OAAO,CAAA;YAChB,KAAK,UAAU;gBACb,IAAI,IAAI,CAAC,SAAS,EAAE,EAAE;oBACpB,OAAO,WAAW,CAAA;iBACnB;gBACD,OAAO,QAAQ,CAAA;YACjB,KAAK,YAAY;gBACf,OAAO,OAAO,CAAA;YAChB;gBACE,OAAO,QAAQ,CAAA;SAChB;IACH,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,YAAY,CAAC,IAAI,CAAA;IAC/B,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,oBAAoB,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,WAAW,CAAA;IAC5E,CAAC;IAED,SAAS;QACP,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;YAClB,OAAO,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAA;SAChF;QACD,OAAO,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAA;IACnE,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,oBAAoB,CAAA;IAC7C,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,WAAW,CAAA;IACpC,CAAC;IAED,eAAe;;QACb,OAAO,OAAA,IAAI,CAAC,YAAY,CAAC,UAAU,0CAAE,MAAM,EAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAA;IACnF,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,YAAY,CAAC,QAAQ,KAAK,OAAO,CAAA;IAC/C,CAAC;IAED,aAAa;QACX,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,OAAO,EAAE;YAC3B,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;YACrE,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAA;SAC1C;QACD,OAAO,EAAE,CAAA;IACX,CAAC;IAED,IAAI;QACF,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE;YAClB,IAAI,EAAE,QAAQ,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC,MAAM,CAAA;YAC3C,0EAA0E;YAC1E,sDAAsD;YACtD,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE;gBAChD,QAAQ,GAAG,UAAU,CAAA;aACtB;YACD,OAAO,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAA;SACrC;QACD,OAAO,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAA;IACxD,CAAC;IAED,UAAU;QACR,OAAO,IAAI,CAAC,IAAI,EAAE,KAAK,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAA;IACnD,CAAC;IAED,UAAU;;QACR,OAAO,CAAC,cAAC,IAAI,CAAC,YAAY,CAAC,UAAU,0CAAE,IAAI,mDAAG,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,UAAU,EAAC,CAAA;IAC3F,CAAC;CACJ;AAED,kBAAe,QAAQ,CAAA"} \ No newline at end of file diff --git a/lib/src/resource.d.ts b/lib/src/resource.d.ts new file mode 100644 index 0000000..2c1dce2 --- /dev/null +++ b/lib/src/resource.d.ts @@ -0,0 +1,53 @@ +import { BaseResource } from 'admin-bro'; +import mongoose from 'mongoose'; +import { FindOptions } from './utils/filter.types'; +import Property from './property'; +/** + * Adapter for mongoose resource + * @private + */ +declare class Resource extends BaseResource { + private readonly dbType; + /** + * @typedef {Object} MongooseModel + * @private + * @see https://mongoosejs.com/docs/models.html + */ + readonly MongooseModel: mongoose.Model; + /** + * Initialize the class with the Resource name + * @param {MongooseModel} MongooseModel Class which subclass mongoose.Model + * @memberof Resource + */ + constructor(MongooseModel: any); + static isAdapterFor(MoongooseModel: any): boolean; + databaseName(): any; + databaseType(): string; + name(): any; + id(): any; + get selectFields(): string; + properties(): Property[]; + property(name: string): Property; + count(filters?: any): Promise; + find(filters: {}, { limit, offset, sort }: FindOptions): Promise; + findOne(id: string): Promise; + findMany(ids: string[]): Promise; + build(params: any): any; + create(params: any): Promise; + update(id: any, params: any): Promise; + delete(id: any): Promise; + static stringifyId(mongooseObj: any): any; + /** + * Check all params against values they hold. In case of wrong value it corrects it. + * + * What it does exactly: + * - changes all empty strings to `null`s for the ObjectID properties. + * - changes all empty strings to [] for array fields + * + * @param {Object} params received from AdminBro form + * + * @return {Object} converted params + */ + parseParams(params: any): any; +} +export default Resource; diff --git a/lib/src/resource.js b/lib/src/resource.js new file mode 100644 index 0000000..d1865ce --- /dev/null +++ b/lib/src/resource.js @@ -0,0 +1,209 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const admin_bro_1 = require("admin-bro"); +const lodash_1 = require("lodash"); +const property_1 = __importDefault(require("./property")); +const convert_filter_1 = require("./utils/convert-filter"); +const create_validation_error_1 = require("./utils/create-validation-error"); +const create_duplicate_error_1 = require("./utils/create-duplicate-error"); +const create_cast_error_1 = require("./utils/create-cast-error"); +const errors_1 = __importDefault(require("./utils/errors")); +const { MONGOOSE_CAST_ERROR, MONGOOSE_DUPLICATE_ERROR_CODE, MONGOOSE_VALIDATION_ERROR } = errors_1.default; +/** + * Adapter for mongoose resource + * @private + */ +class Resource extends admin_bro_1.BaseResource { + /** + * Initialize the class with the Resource name + * @param {MongooseModel} MongooseModel Class which subclass mongoose.Model + * @memberof Resource + */ + constructor(MongooseModel) { + super(MongooseModel); + this.dbType = 'mongodb'; + this.MongooseModel = MongooseModel; + } + static isAdapterFor(MoongooseModel) { + return lodash_1.get(MoongooseModel, 'base.constructor.name') === 'Mongoose'; + } + databaseName() { + return this.MongooseModel.db.name; + } + databaseType() { + return this.dbType; + } + name() { + return this.MongooseModel.modelName; + } + id() { + return this.MongooseModel.modelName; + } + get selectFields() { + return Object.keys(this.MongooseModel.schema.paths).join(' '); + } + properties() { + return Object.entries(this.MongooseModel.schema.paths).map(([, path], position) => (new property_1.default(path, position))); + } + property(name) { + var _a; + return (_a = this.properties().find(property => property.path() === name)) !== null && _a !== void 0 ? _a : null; + } + async count(filters = null) { + return this.MongooseModel.countDocuments(convert_filter_1.convertFilter(filters)); + } + async find(filters = {}, { limit = 20, offset = 0, sort = {} }) { + const { direction, sortBy } = sort; + const sortingParam = { + [sortBy]: direction, + }; + const mongooseObjects = await this.MongooseModel + .find(convert_filter_1.convertFilter(filters), {}, { + skip: offset, limit, sort: sortingParam, select: this.selectFields + }); + return mongooseObjects.map(mongooseObject => new admin_bro_1.BaseRecord(Resource.stringifyId(mongooseObject), this)); + } + async findOne(id) { + const mongooseObject = await this.MongooseModel.findById(id).select(this.selectFields); + return new admin_bro_1.BaseRecord(Resource.stringifyId(mongooseObject), this); + } + async findMany(ids) { + const mongooseObjects = await this.MongooseModel.find({ _id: ids }, {}, { select: this.selectFields }); + return mongooseObjects.map(mongooseObject => (new admin_bro_1.BaseRecord(Resource.stringifyId(mongooseObject), this))); + } + build(params) { + return new admin_bro_1.BaseRecord(Resource.stringifyId(params), this); + } + async create(params) { + const parsedParams = this.parseParams(params); + let mongooseDocument = new this.MongooseModel(parsedParams); + try { + mongooseDocument = await mongooseDocument.save(); + } + catch (error) { + if (error.name === MONGOOSE_VALIDATION_ERROR) { + throw create_validation_error_1.createValidationError(error); + } + if (error.code === MONGOOSE_DUPLICATE_ERROR_CODE) { + throw create_duplicate_error_1.createDuplicateError(error, mongooseDocument.toJSON()); + } + throw error; + } + return Resource.stringifyId(mongooseDocument.toObject()); + } + async update(id, params) { + const parsedParams = this.parseParams(params); + const unflattedParams = admin_bro_1.flat.unflatten(parsedParams); + try { + const mongooseObject = await this.MongooseModel.findOneAndUpdate({ + _id: id, + }, { + $set: unflattedParams, + }, { + new: true, + runValidators: true, + }); + return Resource.stringifyId(mongooseObject.toObject()); + } + catch (error) { + if (error.name === MONGOOSE_VALIDATION_ERROR) { + throw create_validation_error_1.createValidationError(error); + } + if (error.code === MONGOOSE_DUPLICATE_ERROR_CODE) { + throw create_duplicate_error_1.createDuplicateError(error, unflattedParams); + } + // In update cast errors are not wrapped into a validation errors (as it happens in create). + // that is why we have to have a different way of handling them - check out tests to see + // example error + if (error.name === MONGOOSE_CAST_ERROR) { + throw create_cast_error_1.createCastError(error); + } + throw error; + } + } + async delete(id) { + return this.MongooseModel.findOneAndRemove({ _id: id }); + } + static stringifyId(mongooseObj) { + // By default Id field is an ObjectID and when we change entire mongoose model to + // raw object it changes _id field not to a string but to an object. + // stringify/parse is a path found here: https://github.com/Automattic/mongoose/issues/2790 + // @todo We can somehow speed this up + const strinigified = JSON.stringify('toObject' in mongooseObj ? mongooseObj.toObject({ getters: true, virtuals: true }) : mongooseObj); + return JSON.parse(strinigified); + } + /** + * Check all params against values they hold. In case of wrong value it corrects it. + * + * What it does exactly: + * - changes all empty strings to `null`s for the ObjectID properties. + * - changes all empty strings to [] for array fields + * + * @param {Object} params received from AdminBro form + * + * @return {Object} converted params + */ + parseParams(params) { + const parsedParams = { ...params }; + // this function handles ObjectIDs and Arrays recursively + const handleProperty = (prefix = '') => (property) => { + const { path, schema, instance, } = property; + // mongoose doesn't supply us with the same path as we're using in our data + // so we need to improvise + const fullPath = [prefix, path].filter(Boolean).join('.'); + const value = parsedParams[fullPath]; + // this handles missing ObjectIDs + if (instance === 'ObjectID') { + if (value === '') { + parsedParams[fullPath] = null; + } + else if (value) { + // this works similar as this.stringifyId + parsedParams[fullPath] = value.toString(); + } + } + // this handles empty Arrays or recurse into all properties of a filled Array + if (instance === 'Array') { + if (value === '') { + parsedParams[fullPath] = []; + } + else if (schema && schema.paths) { // we only want arrays of objects (with sub-paths) + const subProperties = Object.values(schema.paths); + // eslint-disable-next-line no-plusplus, no-constant-condition + for (let i = 0; true; i++) { // loop over every item + const newPrefix = `${fullPath}.${i}`; + if (parsedParams[newPrefix] === '') { + // this means we have an empty object here + parsedParams[newPrefix] = {}; + } + else if (!Object.keys(parsedParams).some(key => key.startsWith(newPrefix))) { + // we're past the last index of this array + break; + } + else { + // recurse into the object + subProperties.forEach(handleProperty(newPrefix)); + } + } + } + } + // this handles all properties of an object + if (instance === 'Embedded') { + if (parsedParams[fullPath] === '') { + parsedParams[fullPath] = {}; + } + else { + const subProperties = Object.values(schema.paths); + subProperties.forEach(handleProperty(fullPath)); + } + } + }; + this.properties().forEach(({ mongoosePath }) => handleProperty()(mongoosePath)); + return parsedParams; + } +} +exports.default = Resource; +//# sourceMappingURL=resource.js.map \ No newline at end of file diff --git a/lib/src/resource.js.map b/lib/src/resource.js.map new file mode 100644 index 0000000..6439dbb --- /dev/null +++ b/lib/src/resource.js.map @@ -0,0 +1 @@ +{"version":3,"file":"resource.js","sourceRoot":"","sources":["../../src/resource.ts"],"names":[],"mappings":";;;;;AAAA,yCAA0D;AAE1D,mCAA4B;AAE5B,0DAAiC;AACjC,2DAAsD;AACtD,6EAAuE;AACvE,2EAAqE;AACrE,iEAA2D;AAE3D,4DAAmC;AAEnC,MAAM,EAAE,mBAAmB,EAAE,6BAA6B,EAAE,yBAAyB,EAAE,GAAG,gBAAM,CAAA;AAEhG;;;GAGG;AACH,MAAM,QAAS,SAAQ,wBAAY;IAU/B;;;;OAIG;IACH,YAAY,aAAa;QACvB,KAAK,CAAC,aAAa,CAAC,CAAA;QAfL,WAAM,GAAW,SAAS,CAAC;QAgB1C,IAAI,CAAC,aAAa,GAAG,aAAa,CAAA;IACpC,CAAC;IAED,MAAM,CAAC,YAAY,CAAC,cAAc;QAChC,OAAO,YAAG,CAAC,cAAc,EAAE,uBAAuB,CAAC,KAAK,UAAU,CAAA;IACpE,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,aAAa,CAAC,EAAE,CAAC,IAAI,CAAA;IACnC,CAAC;IAED,YAAY;QACV,OAAO,IAAI,CAAC,MAAM,CAAA;IACpB,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAA;IACrC,CAAC;IAED,EAAE;QACA,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAA;IACrC,CAAC;IAED,IAAI,YAAY;QACd,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChE,CAAC;IAED,UAAU;QACR,OAAO,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,EAAE,EAAE,CAAC,CACjF,IAAI,kBAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAC7B,CAAC,CAAA;IACJ,CAAC;IAED,QAAQ,CAAC,IAAW;;QAClB,aAAO,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,KAAK,IAAI,CAAC,mCAAI,IAAI,CAAA;IAC7E,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI;QACxB,OAAO,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,8BAAa,CAAC,OAAO,CAAC,CAAC,CAAA;IAClE,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAO,GAAG,EAAE,EAAE,EAAE,KAAK,GAAG,EAAE,EAAE,MAAM,GAAG,CAAC,EAAE,IAAI,GAAG,EAAE,EAAe;QACzE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI,CAAA;QAClC,MAAM,YAAY,GAAG;YACnB,CAAC,MAAM,CAAC,EAAE,SAAS;SACpB,CAAA;QACD,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,aAAa;aAC7C,IAAI,CAAC,8BAAa,CAAC,OAAO,CAAC,EAAE,EAAE,EAAE;YAChC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY;SACnE,CAAC,CAAA;QACJ,OAAO,eAAe,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,sBAAU,CACzD,QAAQ,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE,IAAI,CAC3C,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,EAAS;QACrB,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QACtF,OAAO,IAAI,sBAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,CAAA;IACnE,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,GAAa;QAC1B,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,IAAI,CACnD,EAAE,GAAG,EAAE,GAAG,EAAE,EACZ,EAAE,EACF,EAAC,MAAM,EAAE,IAAI,CAAC,YAAY,EAAC,CAC5B,CAAA;QACD,OAAO,eAAe,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,CAAC,CAC3C,IAAI,sBAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,cAAc,CAAC,EAAE,IAAI,CAAC,CAC3D,CAAC,CAAA;IACJ,CAAC;IAED,KAAK,CAAC,MAAM;QACV,OAAO,IAAI,sBAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAA;IAC3D,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,MAAM;QACjB,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;QAC7C,IAAI,gBAAgB,GAAG,IAAI,IAAI,CAAC,aAAa,CAAC,YAAY,CAAC,CAAA;QAC3D,IAAI;YACF,gBAAgB,GAAG,MAAM,gBAAgB,CAAC,IAAI,EAAE,CAAA;SACjD;QAAC,OAAO,KAAK,EAAE;YACd,IAAI,KAAK,CAAC,IAAI,KAAK,yBAAyB,EAAE;gBAC5C,MAAM,+CAAqB,CAAC,KAAK,CAAC,CAAA;aACnC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,6BAA6B,EAAE;gBAChD,MAAM,6CAAoB,CAAC,KAAK,EAAE,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAA;aAC7D;YACD,MAAM,KAAK,CAAA;SACZ;QACD,OAAO,QAAQ,CAAC,WAAW,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC,CAAA;IAC1D,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,MAAM;QACrB,MAAM,YAAY,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;QAC7C,MAAM,eAAe,GAAG,gBAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAA;QACpD,IAAI;YACF,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC;gBAC/D,GAAG,EAAE,EAAE;aACR,EAAE;gBACD,IAAI,EAAE,eAAe;aACtB,EAAE;gBACD,GAAG,EAAE,IAAI;gBACT,aAAa,EAAE,IAAI;aACpB,CAAC,CAAA;YACF,OAAO,QAAQ,CAAC,WAAW,CAAC,cAAc,CAAC,QAAQ,EAAE,CAAC,CAAA;SACvD;QAAC,OAAO,KAAK,EAAE;YACd,IAAI,KAAK,CAAC,IAAI,KAAK,yBAAyB,EAAE;gBAC5C,MAAM,+CAAqB,CAAC,KAAK,CAAC,CAAA;aACnC;YACD,IAAI,KAAK,CAAC,IAAI,KAAK,6BAA6B,EAAE;gBAChD,MAAM,6CAAoB,CAAC,KAAK,EAAE,eAAe,CAAC,CAAA;aACnD;YACD,4FAA4F;YAC5F,wFAAwF;YACxF,gBAAgB;YAChB,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,EAAE;gBACtC,MAAM,mCAAe,CAAC,KAAK,CAAC,CAAA;aAC7B;YACD,MAAM,KAAK,CAAA;SACZ;IACH,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,EAAE;QACb,OAAO,IAAI,CAAC,aAAa,CAAC,gBAAgB,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAA;IACzD,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,WAAW;QAC5B,iFAAiF;QACjF,oEAAoE;QACpE,2FAA2F;QAC3F,qCAAqC;QACrC,MAAM,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,IAAI,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAC,CAAC,CAAA,CAAC,CAAC,WAAW,CAAC,CAAA;QACnI,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;IACjC,CAAC;IAED;;;;;;;;;;OAUG;IACH,WAAW,CAAC,MAAM;QAChB,MAAM,YAAY,GAAG,EAAE,GAAG,MAAM,EAAE,CAAA;QAElC,yDAAyD;QACzD,MAAM,cAAc,GAAG,CAAC,MAAM,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,EAAE,EAAE;YACnD,MAAM,EACJ,IAAI,EACJ,MAAM,EACN,QAAQ,GACT,GAAG,QAAQ,CAAA;YACZ,2EAA2E;YAC3E,0BAA0B;YAC1B,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YACzD,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;YAEpC,iCAAiC;YACjC,IAAI,QAAQ,KAAK,UAAU,EAAE;gBAC3B,IAAI,KAAK,KAAK,EAAE,EAAE;oBAChB,YAAY,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAA;iBAC9B;qBAAM,IAAI,KAAK,EAAE;oBAClB,yCAAyC;oBACvC,YAAY,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAA;iBAC1C;aACF;YAED,6EAA6E;YAC7E,IAAI,QAAQ,KAAK,OAAO,EAAE;gBACxB,IAAI,KAAK,KAAK,EAAE,EAAE;oBAChB,YAAY,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAA;iBAC5B;qBAAM,IAAI,MAAM,IAAI,MAAM,CAAC,KAAK,EAAE,EAAE,kDAAkD;oBACrF,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBACjD,8DAA8D;oBAC9D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,uBAAuB;wBAClD,MAAM,SAAS,GAAG,GAAG,QAAQ,IAAI,CAAC,EAAE,CAAA;wBACpC,IAAI,YAAY,CAAC,SAAS,CAAC,KAAK,EAAE,EAAE;4BACpC,0CAA0C;4BACxC,YAAY,CAAC,SAAS,CAAC,GAAG,EAAE,CAAA;yBAC7B;6BAAM,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,EAAE;4BAC9E,0CAA0C;4BACxC,MAAK;yBACN;6BAAM;4BACP,0BAA0B;4BACxB,aAAa,CAAC,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CAAA;yBACjD;qBACF;iBACF;aACF;YAED,2CAA2C;YAC3C,IAAI,QAAQ,KAAK,UAAU,EAAE;gBAC3B,IAAI,YAAY,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE;oBACjC,YAAY,CAAC,QAAQ,CAAC,GAAG,EAAE,CAAA;iBAC5B;qBAAM;oBACL,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;oBACjD,aAAa,CAAC,OAAO,CAAC,cAAc,CAAC,QAAQ,CAAC,CAAC,CAAA;iBAChD;aACF;QACH,CAAC,CAAA;QAED,IAAI,CAAC,UAAU,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,cAAc,EAAE,CAAC,YAAY,CAAC,CAAC,CAAA;QAE/E,OAAO,YAAY,CAAA;IACrB,CAAC;CACJ;AAED,kBAAe,QAAQ,CAAA"} \ No newline at end of file diff --git a/lib/src/utils/convert-filter.d.ts b/lib/src/utils/convert-filter.d.ts new file mode 100644 index 0000000..b1e0baa --- /dev/null +++ b/lib/src/utils/convert-filter.d.ts @@ -0,0 +1,7 @@ +/** + * Changes AdminBro's {@link Filter} to an object acceptible by a mongoose query. + * + * @param {Filter} filter + * @private + */ +export declare const convertFilter: (filter: any) => any; diff --git a/lib/src/utils/convert-filter.js b/lib/src/utils/convert-filter.js new file mode 100644 index 0000000..cf0bf82 --- /dev/null +++ b/lib/src/utils/convert-filter.js @@ -0,0 +1,57 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.convertFilter = void 0; +const escape_regexp_1 = __importDefault(require("escape-regexp")); +const mongoose_1 = __importDefault(require("mongoose")); +/** + * Changes AdminBro's {@link Filter} to an object acceptible by a mongoose query. + * + * @param {Filter} filter + * @private + */ +const convertFilter = (filter) => { + if (!filter) { + return {}; + } + return filter.reduce((memo, filterProperty) => { + const { property, value } = filterProperty; + switch (property.type()) { + case 'string': + return { + [property.name()]: { $regex: escape_regexp_1.default(value), $options: 'i' }, + ...memo, + }; + case 'date': + case 'datetime': + if (value.from || value.to) { + return { + [property.name()]: { + ...value.from && { $gte: value.from }, + ...value.to && { $lte: value.to }, + }, + ...memo, + }; + } + break; + case 'id': + if (mongoose_1.default.Types.ObjectId.isValid(value)) { + return { + [property.name()]: value, + ...memo, + }; + } + return {}; + default: + break; + } + return { + [property.name()]: value, + ...memo, + }; + }, {}); +}; +exports.convertFilter = convertFilter; +//# sourceMappingURL=convert-filter.js.map \ No newline at end of file diff --git a/lib/src/utils/convert-filter.js.map b/lib/src/utils/convert-filter.js.map new file mode 100644 index 0000000..3c68be3 --- /dev/null +++ b/lib/src/utils/convert-filter.js.map @@ -0,0 +1 @@ +{"version":3,"file":"convert-filter.js","sourceRoot":"","sources":["../../../src/utils/convert-filter.ts"],"names":[],"mappings":";;;;;;AAAA,kEAAkC;AAClC,wDAA+B;AAE/B;;;;;GAKG;AACI,MAAM,aAAa,GAAG,CAAC,MAAM,EAAE,EAAE;IACtC,IAAI,CAAC,MAAM,EAAE;QACX,OAAO,EAAE,CAAA;KACV;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE;QAC5C,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,cAAc,CAAA;QAC1C,QAAQ,QAAQ,CAAC,IAAI,EAAE,EAAE;YACzB,KAAK,QAAQ;gBACX,OAAO;oBACL,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,uBAAM,CAAC,KAAK,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE;oBAC3D,GAAG,IAAI;iBACR,CAAA;YACH,KAAK,MAAM,CAAC;YACZ,KAAK,UAAU;gBACb,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,EAAE,EAAE;oBAC1B,OAAO;wBACL,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE;4BACjB,GAAG,KAAK,CAAC,IAAI,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE;4BACrC,GAAG,KAAK,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;yBAClC;wBACD,GAAG,IAAI;qBACR,CAAA;iBACF;gBACD,MAAK;YACP,KAAK,IAAI;gBACP,IAAI,kBAAQ,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;oBAC1C,OAAO;wBACL,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK;wBACxB,GAAG,IAAI;qBACR,CAAA;iBACF;gBACD,OAAO,EAAE,CAAA;YACX;gBACE,MAAK;SACN;QACD,OAAO;YACL,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,EAAE,KAAK;YACxB,GAAG,IAAI;SACR,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;AACR,CAAC,CAAA;AAxCY,QAAA,aAAa,iBAwCzB"} \ No newline at end of file diff --git a/lib/src/utils/create-cast-error.d.ts b/lib/src/utils/create-cast-error.d.ts new file mode 100644 index 0000000..32c1728 --- /dev/null +++ b/lib/src/utils/create-cast-error.d.ts @@ -0,0 +1 @@ +export declare const createCastError: (originalError: any) => any; diff --git a/lib/src/utils/create-cast-error.js b/lib/src/utils/create-cast-error.js new file mode 100644 index 0000000..dbeb938 --- /dev/null +++ b/lib/src/utils/create-cast-error.js @@ -0,0 +1,19 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createCastError = void 0; +const admin_bro_1 = require("admin-bro"); +const createCastError = (originalError) => { + // cas error has only the nested path. So when an actual path is 'parents.age' + // originalError will have just a 'age'. That is why we are finding first param + // with the same value as the error has and path ending the same like path in + // originalError or ending with path with array notation: "${path}.0" + const errors = { + [originalError.path]: { + message: originalError.message, + type: originalError.kind || originalError.name, + }, + }; + return new admin_bro_1.ValidationError(errors); +}; +exports.createCastError = createCastError; +//# sourceMappingURL=create-cast-error.js.map \ No newline at end of file diff --git a/lib/src/utils/create-cast-error.js.map b/lib/src/utils/create-cast-error.js.map new file mode 100644 index 0000000..1d8a2d7 --- /dev/null +++ b/lib/src/utils/create-cast-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"create-cast-error.js","sourceRoot":"","sources":["../../../src/utils/create-cast-error.ts"],"names":[],"mappings":";;;AAAA,yCAA2C;AAGpC,MAAM,eAAe,GAAG,CAAC,aAAa,EAAmB,EAAE;IAChE,8EAA8E;IAC9E,+EAA+E;IAC/E,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,MAAM,GAAG;QACb,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE;YACpB,OAAO,EAAE,aAAa,CAAC,OAAO;YAC9B,IAAI,EAAE,aAAa,CAAC,IAAI,IAAI,aAAa,CAAC,IAAI;SAC/C;KACF,CAAA;IACD,OAAO,IAAI,2BAAe,CAAC,MAAM,CAAC,CAAA;AACpC,CAAC,CAAA;AAZY,QAAA,eAAe,mBAY3B"} \ No newline at end of file diff --git a/lib/src/utils/create-duplicate-error.d.ts b/lib/src/utils/create-duplicate-error.d.ts new file mode 100644 index 0000000..599cdc7 --- /dev/null +++ b/lib/src/utils/create-duplicate-error.d.ts @@ -0,0 +1,4 @@ +export declare const createDuplicateError: ({ keyValue: duplicateEntry, errmsg }: { + keyValue: any; + errmsg: any; +}, document: any) => any; diff --git a/lib/src/utils/create-duplicate-error.js b/lib/src/utils/create-duplicate-error.js new file mode 100644 index 0000000..2b94914 --- /dev/null +++ b/lib/src/utils/create-duplicate-error.js @@ -0,0 +1,22 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createDuplicateError = void 0; +const admin_bro_1 = require("admin-bro"); +const createDuplicateMessage = message => ({ + type: 'duplicate', + message, +}); +const createDuplicateError = ({ keyValue: duplicateEntry, errmsg }, document) => { + if (!duplicateEntry) { + const duplicatedKey = Object.keys(document).find(key => errmsg.includes(key)); + return new admin_bro_1.ValidationError({ + [duplicatedKey]: createDuplicateMessage(`Record with that ${duplicatedKey} already exists`), + }); + } + const [[keyName]] = Object.entries(duplicateEntry); + return new admin_bro_1.ValidationError({ + [keyName]: createDuplicateMessage(`Record with that ${keyName} already exists`), + }); +}; +exports.createDuplicateError = createDuplicateError; +//# sourceMappingURL=create-duplicate-error.js.map \ No newline at end of file diff --git a/lib/src/utils/create-duplicate-error.js.map b/lib/src/utils/create-duplicate-error.js.map new file mode 100644 index 0000000..0f15f26 --- /dev/null +++ b/lib/src/utils/create-duplicate-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"create-duplicate-error.js","sourceRoot":"","sources":["../../../src/utils/create-duplicate-error.ts"],"names":[],"mappings":";;;AAAA,yCAA2C;AAE3C,MAAM,sBAAsB,GAAG,OAAO,CAAC,EAAE,CAAC,CAAC;IACzC,IAAI,EAAE,WAAW;IACjB,OAAO;CACR,CAAC,CAAA;AAEK,MAAM,oBAAoB,GAAG,CAClC,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,QAAQ,EAC7B,EAAE;IACnB,IAAI,CAAC,cAAc,EAAE;QACnB,MAAM,aAAa,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAA;QAE7E,OAAO,IAAI,2BAAe,CAAC;YACzB,CAAC,aAAa,CAAC,EAAE,sBAAsB,CAAC,oBAAoB,aAAa,iBAAiB,CAAC;SAC5F,CAAC,CAAA;KACH;IAED,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;IAElD,OAAO,IAAI,2BAAe,CAAC;QACzB,CAAC,OAAO,CAAC,EAAE,sBAAsB,CAAC,oBAAoB,OAAO,iBAAiB,CAAC;KAChF,CAAC,CAAA;AACJ,CAAC,CAAA;AAhBY,QAAA,oBAAoB,wBAgBhC"} \ No newline at end of file diff --git a/lib/src/utils/create-validation-error.d.ts b/lib/src/utils/create-validation-error.d.ts new file mode 100644 index 0000000..d9c4d3c --- /dev/null +++ b/lib/src/utils/create-validation-error.d.ts @@ -0,0 +1 @@ +export declare const createValidationError: (originalError: any) => any; diff --git a/lib/src/utils/create-validation-error.js b/lib/src/utils/create-validation-error.js new file mode 100644 index 0000000..20a1faa --- /dev/null +++ b/lib/src/utils/create-validation-error.js @@ -0,0 +1,19 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.createValidationError = void 0; +const admin_bro_1 = require("admin-bro"); +const createValidationError = (originalError) => { + const errors = Object.keys(originalError.errors).reduce((memo, key) => { + const { message, kind, name } = originalError.errors[key]; + return { + ...memo, + [key]: { + message, + type: kind || name, + }, + }; + }, {}); + return new admin_bro_1.ValidationError(errors); +}; +exports.createValidationError = createValidationError; +//# sourceMappingURL=create-validation-error.js.map \ No newline at end of file diff --git a/lib/src/utils/create-validation-error.js.map b/lib/src/utils/create-validation-error.js.map new file mode 100644 index 0000000..b3f868c --- /dev/null +++ b/lib/src/utils/create-validation-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"create-validation-error.js","sourceRoot":"","sources":["../../../src/utils/create-validation-error.ts"],"names":[],"mappings":";;;AAAA,yCAA2C;AAEpC,MAAM,qBAAqB,GAAG,CAAC,aAAa,EAAmB,EAAE;IACtE,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE;QACpE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,aAAa,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QACzD,OAAO;YACL,GAAG,IAAI;YACP,CAAC,GAAG,CAAC,EAAE;gBACL,OAAO;gBACP,IAAI,EAAE,IAAI,IAAI,IAAI;aACnB;SACF,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IACN,OAAO,IAAI,2BAAe,CAAC,MAAM,CAAC,CAAA;AACpC,CAAC,CAAA;AAZY,QAAA,qBAAqB,yBAYjC"} \ No newline at end of file diff --git a/lib/src/utils/errors.d.ts b/lib/src/utils/errors.d.ts new file mode 100644 index 0000000..6265f3d --- /dev/null +++ b/lib/src/utils/errors.d.ts @@ -0,0 +1,6 @@ +declare const _default: { + MONGOOSE_VALIDATION_ERROR: string; + MONGOOSE_CAST_ERROR: string; + MONGOOSE_DUPLICATE_ERROR_CODE: number; +}; +export default _default; diff --git a/lib/src/utils/errors.js b/lib/src/utils/errors.js new file mode 100644 index 0000000..3f5b6ed --- /dev/null +++ b/lib/src/utils/errors.js @@ -0,0 +1,12 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = { + // Error thrown by mongoose in case of validation error + MONGOOSE_VALIDATION_ERROR: 'ValidationError', + // Error thrown by mongoose in case of casting error (writing string to Number field) + MONGOOSE_CAST_ERROR: 'CastError', + // Error thrown by mongoose in case of inserting duplicate record + // with some property marked as `unique` + MONGOOSE_DUPLICATE_ERROR_CODE: 11000, +}; +//# sourceMappingURL=errors.js.map \ No newline at end of file diff --git a/lib/src/utils/errors.js.map b/lib/src/utils/errors.js.map new file mode 100644 index 0000000..e709685 --- /dev/null +++ b/lib/src/utils/errors.js.map @@ -0,0 +1 @@ +{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/utils/errors.ts"],"names":[],"mappings":";;AACA,kBAAe;IACb,uDAAuD;IACvD,yBAAyB,EAAE,iBAAiB;IAE5C,qFAAqF;IACrF,mBAAmB,EAAE,WAAW;IAEhC,iEAAiE;IACjE,wCAAwC;IACxC,6BAA6B,EAAE,KAAK;CACrC,CAAA"} \ No newline at end of file diff --git a/lib/src/utils/filter.types.d.ts b/lib/src/utils/filter.types.d.ts new file mode 100644 index 0000000..4bbfb36 --- /dev/null +++ b/lib/src/utils/filter.types.d.ts @@ -0,0 +1,8 @@ +export declare type FindOptions = { + limit?: number; + offset?: number; + sort?: { + sortBy?: string; + direction?: 'asc' | 'desc'; + }; +}; diff --git a/lib/src/utils/filter.types.js b/lib/src/utils/filter.types.js new file mode 100644 index 0000000..ba00d51 --- /dev/null +++ b/lib/src/utils/filter.types.js @@ -0,0 +1,3 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//# sourceMappingURL=filter.types.js.map \ No newline at end of file diff --git a/lib/src/utils/filter.types.js.map b/lib/src/utils/filter.types.js.map new file mode 100644 index 0000000..c0358d8 --- /dev/null +++ b/lib/src/utils/filter.types.js.map @@ -0,0 +1 @@ +{"version":3,"file":"filter.types.js","sourceRoot":"","sources":["../../../src/utils/filter.types.ts"],"names":[],"mappings":""} \ No newline at end of file diff --git a/lib/test/database.spec.d.ts b/lib/test/database.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/database.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/database.spec.js b/lib/test/database.spec.js new file mode 100644 index 0000000..494836d --- /dev/null +++ b/lib/test/database.spec.js @@ -0,0 +1,19 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const mongoose_1 = __importDefault(require("mongoose")); +const database_1 = __importDefault(require("../src/database")); +describe('Database', () => { + describe('#resources', () => { + let resources; + beforeEach(() => { + resources = new database_1.default(mongoose_1.default.connection).resources(); + }); + it('return all resources', () => { + expect(resources.length).toEqual(3); + }); + }); +}); +//# sourceMappingURL=database.spec.js.map \ No newline at end of file diff --git a/lib/test/database.spec.js.map b/lib/test/database.spec.js.map new file mode 100644 index 0000000..b6014bc --- /dev/null +++ b/lib/test/database.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"database.spec.js","sourceRoot":"","sources":["../../test/database.spec.ts"],"names":[],"mappings":";;;;;AAAA,wDAA+B;AAC/B,+DAA8C;AAG9C,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;QAC1B,IAAI,SAAqB,CAAA;QAEzB,UAAU,CAAC,GAAG,EAAE;YACd,SAAS,GAAG,IAAI,kBAAgB,CAAC,kBAAQ,CAAC,UAAU,CAAC,CAAC,SAAS,EAAE,CAAA;QACnE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;YAC9B,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QACrC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/errors/create-cast-error.spec.d.ts b/lib/test/errors/create-cast-error.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/errors/create-cast-error.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/errors/create-cast-error.spec.js b/lib/test/errors/create-cast-error.spec.js new file mode 100644 index 0000000..4f1ba1e --- /dev/null +++ b/lib/test/errors/create-cast-error.spec.js @@ -0,0 +1,20 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const create_cast_error_1 = require("../../src/utils/create-cast-error"); +const mongoose_cast_error_1 = require("../fixtures/mongoose-cast-error"); +const mongoose_cast_array_error_1 = require("../fixtures/mongoose-cast-array-error"); +describe('createCastError', () => { + describe('throwin cast error on update after one key has error', () => { + it('has error for nested "parent.age" (errorKey) field', () => { + const error = create_cast_error_1.createCastError(mongoose_cast_error_1.SAMPLE_CAST_ERROR); + expect(error.propertyErrors.age.type).toEqual('Number'); + }); + }); + describe('throwing cast error on update when one array field has error', () => { + it('throws an error for root field', () => { + const error = create_cast_error_1.createCastError(mongoose_cast_array_error_1.SAMPLE_CAST_ARRAY_ERROR); + expect(error.propertyErrors.authors.type).toEqual('ObjectId'); + }); + }); +}); +//# sourceMappingURL=create-cast-error.spec.js.map \ No newline at end of file diff --git a/lib/test/errors/create-cast-error.spec.js.map b/lib/test/errors/create-cast-error.spec.js.map new file mode 100644 index 0000000..2819540 --- /dev/null +++ b/lib/test/errors/create-cast-error.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"create-cast-error.spec.js","sourceRoot":"","sources":["../../../test/errors/create-cast-error.spec.ts"],"names":[],"mappings":";;AAAA,yEAAmE;AACnE,yEAAmE;AACnE,qFAA+E;AAE/E,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,QAAQ,CAAC,sDAAsD,EAAE,GAAG,EAAE;QACpE,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC5D,MAAM,KAAK,GAAG,mCAAe,CAAC,uCAAiB,CAAC,CAAA;YAEhD,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QACzD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,8DAA8D,EAAE,GAAG,EAAE;QAC5E,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;YACxC,MAAM,KAAK,GAAG,mCAAe,CAAC,mDAAuB,CAAC,CAAA;YAEtD,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;QAC/D,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/errors/create-validation-error.spec.d.ts b/lib/test/errors/create-validation-error.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/errors/create-validation-error.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/errors/create-validation-error.spec.js b/lib/test/errors/create-validation-error.spec.js new file mode 100644 index 0000000..388d950 --- /dev/null +++ b/lib/test/errors/create-validation-error.spec.js @@ -0,0 +1,32 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const create_validation_error_1 = require("../../src/utils/create-validation-error"); +const mongoose_validation_error_1 = require("../fixtures/mongoose-validation-error"); +const mongoose_nested_validation_error_1 = require("../fixtures/mongoose-nested-validation-error"); +describe('#createValidationError', () => { + describe('regular error', () => { + it('has errors', () => { + const error = create_validation_error_1.createValidationError(mongoose_validation_error_1.SAMPLE_VALIDATION_ERROR); + expect(Object.keys(error.propertyErrors).length).toEqual(2); + }); + it('has error for email', () => { + const error = create_validation_error_1.createValidationError(mongoose_validation_error_1.SAMPLE_VALIDATION_ERROR); + expect(error.propertyErrors.email.type).toEqual('required'); + }); + }); + describe('error for nested field', () => { + it('2 errors, one for root field and one for an actual nested field', () => { + const error = create_validation_error_1.createValidationError(mongoose_nested_validation_error_1.SAMPLE_NESTED_VALIDATION_ERROR); + expect(Object.keys(error.propertyErrors).length).toEqual(2); + }); + it('has error for nested "parent.age" field', () => { + const error = create_validation_error_1.createValidationError(mongoose_nested_validation_error_1.SAMPLE_NESTED_VALIDATION_ERROR); + expect(error.propertyErrors['parent.age'].type).toEqual('Number'); + }); + it('has error for "parent" field', () => { + const error = create_validation_error_1.createValidationError(mongoose_nested_validation_error_1.SAMPLE_NESTED_VALIDATION_ERROR); + expect(error.propertyErrors.parent.type).toEqual('ValidationError'); + }); + }); +}); +//# sourceMappingURL=create-validation-error.spec.js.map \ No newline at end of file diff --git a/lib/test/errors/create-validation-error.spec.js.map b/lib/test/errors/create-validation-error.spec.js.map new file mode 100644 index 0000000..7d32ede --- /dev/null +++ b/lib/test/errors/create-validation-error.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"create-validation-error.spec.js","sourceRoot":"","sources":["../../../test/errors/create-validation-error.spec.ts"],"names":[],"mappings":";;AAAA,qFAA+E;AAC/E,qFAA+E;AAC/E,mGAA6F;AAE7F,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;IACtC,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC7B,EAAE,CAAC,YAAY,EAAE,GAAG,EAAE;YACpB,MAAM,KAAK,GAAG,+CAAqB,CAAC,mDAAuB,CAAC,CAAA;YAE5D,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAC7D,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,qBAAqB,EAAE,GAAG,EAAE;YAC7B,MAAM,KAAK,GAAG,+CAAqB,CAAC,mDAAuB,CAAC,CAAA;YAE5D,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;QAC7D,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,QAAQ,CAAC,wBAAwB,EAAE,GAAG,EAAE;QACtC,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YACzE,MAAM,KAAK,GAAG,+CAAqB,CAAC,iEAA8B,CAAC,CAAA;YAEnE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;QAC7D,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;YACjD,MAAM,KAAK,GAAG,+CAAqB,CAAC,iEAA8B,CAAC,CAAA;YAEnE,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;QACnE,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;YACtC,MAAM,KAAK,GAAG,+CAAqB,CAAC,iEAA8B,CAAC,CAAA;YAEnE,MAAM,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;QACrE,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/fixtures/duplicate-error.d.ts b/lib/test/fixtures/duplicate-error.d.ts new file mode 100644 index 0000000..e69de29 diff --git a/lib/test/fixtures/duplicate-error.js b/lib/test/fixtures/duplicate-error.js new file mode 100644 index 0000000..4f6e3e1 --- /dev/null +++ b/lib/test/fixtures/duplicate-error.js @@ -0,0 +1,8 @@ +module.exports = { + driver: true, + name: 'MongoError', + index: 0, + code: 11000, + errmsg: 'insertDocument :: caused by :: 11000 E11000 duplicate key error index: admin-bro-mongoose.pesels.$pesel_1 dup key: { : "1" }', +}; +//# sourceMappingURL=duplicate-error.js.map \ No newline at end of file diff --git a/lib/test/fixtures/duplicate-error.js.map b/lib/test/fixtures/duplicate-error.js.map new file mode 100644 index 0000000..f478813 --- /dev/null +++ b/lib/test/fixtures/duplicate-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"duplicate-error.js","sourceRoot":"","sources":["../../../test/fixtures/duplicate-error.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,OAAO,GAAG;IACf,MAAM,EAAE,IAAI;IACZ,IAAI,EAAE,YAAY;IAClB,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,KAAK;IACX,MAAM,EAAE,+HAA+H;CACxI,CAAA"} \ No newline at end of file diff --git a/lib/test/fixtures/mongoose-cast-array-error.d.ts b/lib/test/fixtures/mongoose-cast-array-error.d.ts new file mode 100644 index 0000000..23c7af5 --- /dev/null +++ b/lib/test/fixtures/mongoose-cast-array-error.d.ts @@ -0,0 +1,9 @@ +export declare const SAMPLE_CAST_ARRAY_ERROR: { + stringValue: string; + kind: string; + value: string; + path: string; + reason: {}; + message: string; + name: string; +}; diff --git a/lib/test/fixtures/mongoose-cast-array-error.js b/lib/test/fixtures/mongoose-cast-array-error.js new file mode 100644 index 0000000..aed14d8 --- /dev/null +++ b/lib/test/fixtures/mongoose-cast-array-error.js @@ -0,0 +1,13 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SAMPLE_CAST_ARRAY_ERROR = void 0; +exports.SAMPLE_CAST_ARRAY_ERROR = { + stringValue: '""', + kind: 'ObjectId', + value: '', + path: 'authors', + reason: {}, + message: 'Cast to ObjectId failed for value "" at path "authors"', + name: 'CastError', +}; +//# sourceMappingURL=mongoose-cast-array-error.js.map \ No newline at end of file diff --git a/lib/test/fixtures/mongoose-cast-array-error.js.map b/lib/test/fixtures/mongoose-cast-array-error.js.map new file mode 100644 index 0000000..26cf647 --- /dev/null +++ b/lib/test/fixtures/mongoose-cast-array-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mongoose-cast-array-error.js","sourceRoot":"","sources":["../../../test/fixtures/mongoose-cast-array-error.ts"],"names":[],"mappings":";;;AAAa,QAAA,uBAAuB,GAAG;IACrC,WAAW,EAAE,IAAI;IACjB,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,SAAS;IACf,MAAM,EAAE,EAEP;IACD,OAAO,EAAE,wDAAwD;IACjE,IAAI,EAAE,WAAW;CAClB,CAAA"} \ No newline at end of file diff --git a/lib/test/fixtures/mongoose-cast-error.d.ts b/lib/test/fixtures/mongoose-cast-error.d.ts new file mode 100644 index 0000000..be5b9ca --- /dev/null +++ b/lib/test/fixtures/mongoose-cast-error.d.ts @@ -0,0 +1,24 @@ +export declare const SAMPLE_CAST_ERROR: { + stringValue: string; + kind: string; + value: string; + path: string; + reason: { + stringValue: string; + kind: string; + value: string; + path: string; + reason: { + generatedMessage: boolean; + name: string; + code: string; + actual: boolean; + expected: boolean; + operator: string; + }; + message: string; + name: string; + }; + message: string; + name: string; +}; diff --git a/lib/test/fixtures/mongoose-cast-error.js b/lib/test/fixtures/mongoose-cast-error.js new file mode 100644 index 0000000..8c92725 --- /dev/null +++ b/lib/test/fixtures/mongoose-cast-error.js @@ -0,0 +1,28 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SAMPLE_CAST_ERROR = void 0; +exports.SAMPLE_CAST_ERROR = { + stringValue: '"asdasd"', + kind: 'Number', + value: 'asdasd', + path: 'age', + reason: { + stringValue: '"asdasd"', + kind: 'number', + value: 'asdasd', + path: 'age', + reason: { + generatedMessage: true, + name: 'AssertionError [ERR_ASSERTION]', + code: 'ERR_ASSERTION', + actual: false, + expected: true, + operator: '==', + }, + message: 'Cast to number failed for value "asdasd" at path "age"', + name: 'CastError', + }, + message: 'Cast to Number failed for value "asdasd" at path "age"', + name: 'CastError', +}; +//# sourceMappingURL=mongoose-cast-error.js.map \ No newline at end of file diff --git a/lib/test/fixtures/mongoose-cast-error.js.map b/lib/test/fixtures/mongoose-cast-error.js.map new file mode 100644 index 0000000..d34d9e6 --- /dev/null +++ b/lib/test/fixtures/mongoose-cast-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mongoose-cast-error.js","sourceRoot":"","sources":["../../../test/fixtures/mongoose-cast-error.ts"],"names":[],"mappings":";;;AAAa,QAAA,iBAAiB,GAAG;IAC/B,WAAW,EAAE,UAAU;IACvB,IAAI,EAAE,QAAQ;IACd,KAAK,EAAE,QAAQ;IACf,IAAI,EAAE,KAAK;IACX,MAAM,EAAE;QACN,WAAW,EAAE,UAAU;QACvB,IAAI,EAAE,QAAQ;QACd,KAAK,EAAE,QAAQ;QACf,IAAI,EAAE,KAAK;QACX,MAAM,EAAE;YACN,gBAAgB,EAAE,IAAI;YACtB,IAAI,EAAE,gCAAgC;YACtC,IAAI,EAAE,eAAe;YACrB,MAAM,EAAE,KAAK;YACb,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,IAAI;SACf;QACD,OAAO,EAAE,wDAAwD;QACjE,IAAI,EAAE,WAAW;KAClB;IACD,OAAO,EAAE,wDAAwD;IACjE,IAAI,EAAE,WAAW;CAClB,CAAA"} \ No newline at end of file diff --git a/lib/test/fixtures/mongoose-nested-validation-error.d.ts b/lib/test/fixtures/mongoose-nested-validation-error.d.ts new file mode 100644 index 0000000..6729627 --- /dev/null +++ b/lib/test/fixtures/mongoose-nested-validation-error.d.ts @@ -0,0 +1,46 @@ +export declare const SAMPLE_NESTED_VALIDATION_ERROR: { + errors: { + 'parent.age': { + message: string; + name: string; + stringValue: string; + kind: string; + value: string; + path: string; + reason: { + message: string; + name: string; + stringValue: string; + kind: string; + value: string; + path: string; + }; + }; + parent: { + errors: { + age: { + message: string; + name: string; + stringValue: string; + kind: string; + value: string; + path: string; + reason: { + message: string; + name: string; + stringValue: string; + kind: string; + value: string; + path: string; + }; + }; + }; + _message: string; + message: string; + name: string; + }; + }; + _message: string; + message: string; + name: string; +}; diff --git a/lib/test/fixtures/mongoose-nested-validation-error.js b/lib/test/fixtures/mongoose-nested-validation-error.js new file mode 100644 index 0000000..a571d68 --- /dev/null +++ b/lib/test/fixtures/mongoose-nested-validation-error.js @@ -0,0 +1,50 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SAMPLE_NESTED_VALIDATION_ERROR = void 0; +exports.SAMPLE_NESTED_VALIDATION_ERROR = { + errors: { + 'parent.age': { + message: 'Cast to Number failed for value "not a number" at path "age"', + name: 'CastError', + stringValue: '"not a number"', + kind: 'Number', + value: 'not a number', + path: 'age', + reason: { + message: 'Cast to number failed for value "not a number" at path "age"', + name: 'CastError', + stringValue: '"not a number"', + kind: 'number', + value: 'not a number', + path: 'age', + }, + }, + parent: { + errors: { + age: { + message: 'Cast to Number failed for value "not a number" at path "age"', + name: 'CastError', + stringValue: '"not a number"', + kind: 'Number', + value: 'not a number', + path: 'age', + reason: { + message: 'Cast to number failed for value "not a number" at path "age"', + name: 'CastError', + stringValue: '"not a number"', + kind: 'number', + value: 'not a number', + path: 'age', + }, + }, + }, + _message: 'Validation failed', + message: 'Validation failed: age: Cast to Number failed for value "not a number" at path "age"', + name: 'ValidationError', + }, + }, + _message: 'User validation failed', + message: 'User validation failed: parent.age: Cast to Number failed for value "not a number" at path "age", parent: Validation failed: age: Cast to Number failed for value "not a number" at path "age"', + name: 'ValidationError', +}; +//# sourceMappingURL=mongoose-nested-validation-error.js.map \ No newline at end of file diff --git a/lib/test/fixtures/mongoose-nested-validation-error.js.map b/lib/test/fixtures/mongoose-nested-validation-error.js.map new file mode 100644 index 0000000..cdea6c6 --- /dev/null +++ b/lib/test/fixtures/mongoose-nested-validation-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mongoose-nested-validation-error.js","sourceRoot":"","sources":["../../../test/fixtures/mongoose-nested-validation-error.ts"],"names":[],"mappings":";;;AAAa,QAAA,8BAA8B,GAAG;IAC5C,MAAM,EAAE;QACN,YAAY,EAAE;YACZ,OAAO,EAAE,8DAA8D;YACvE,IAAI,EAAE,WAAW;YACjB,WAAW,EAAE,gBAAgB;YAC7B,IAAI,EAAE,QAAQ;YACd,KAAK,EAAE,cAAc;YACrB,IAAI,EAAE,KAAK;YACX,MAAM,EAAE;gBACN,OAAO,EAAE,8DAA8D;gBACvE,IAAI,EAAE,WAAW;gBACjB,WAAW,EAAE,gBAAgB;gBAC7B,IAAI,EAAE,QAAQ;gBACd,KAAK,EAAE,cAAc;gBACrB,IAAI,EAAE,KAAK;aACZ;SACF;QACD,MAAM,EAAE;YACN,MAAM,EAAE;gBACN,GAAG,EAAE;oBACH,OAAO,EAAE,8DAA8D;oBACvE,IAAI,EAAE,WAAW;oBACjB,WAAW,EAAE,gBAAgB;oBAC7B,IAAI,EAAE,QAAQ;oBACd,KAAK,EAAE,cAAc;oBACrB,IAAI,EAAE,KAAK;oBACX,MAAM,EAAE;wBACN,OAAO,EAAE,8DAA8D;wBACvE,IAAI,EAAE,WAAW;wBACjB,WAAW,EAAE,gBAAgB;wBAC7B,IAAI,EAAE,QAAQ;wBACd,KAAK,EAAE,cAAc;wBACrB,IAAI,EAAE,KAAK;qBACZ;iBACF;aACF;YACD,QAAQ,EAAE,mBAAmB;YAC7B,OAAO,EAAE,sFAAsF;YAC/F,IAAI,EAAE,iBAAiB;SACxB;KACF;IACD,QAAQ,EAAE,wBAAwB;IAClC,OAAO,EAAE,gMAAgM;IACzM,IAAI,EAAE,iBAAiB;CACxB,CAAA"} \ No newline at end of file diff --git a/lib/test/fixtures/mongoose-validation-error.d.ts b/lib/test/fixtures/mongoose-validation-error.d.ts new file mode 100644 index 0000000..dad9e1c --- /dev/null +++ b/lib/test/fixtures/mongoose-validation-error.d.ts @@ -0,0 +1,35 @@ +export declare const SAMPLE_VALIDATION_ERROR: { + _message: string; + errors: { + email: { + $isValidatorError: boolean; + kind: string; + message: string; + name: string; + path: string; + properties: { + message: string; + path: string; + type: string; + value: string; + }; + value: string; + }; + passwordHash: { + $isValidatorError: boolean; + kind: string; + message: string; + name: string; + path: string; + properties: { + message: string; + path: string; + type: string; + value: string; + }; + value: string; + }; + }; + message: string; + name: string; +}; diff --git a/lib/test/fixtures/mongoose-validation-error.js b/lib/test/fixtures/mongoose-validation-error.js new file mode 100644 index 0000000..c221e33 --- /dev/null +++ b/lib/test/fixtures/mongoose-validation-error.js @@ -0,0 +1,39 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.SAMPLE_VALIDATION_ERROR = void 0; +exports.SAMPLE_VALIDATION_ERROR = { + _message: 'User validation failed', + errors: { + email: { + $isValidatorError: true, + kind: 'required', + message: 'Path `email` is required.', + name: 'ValidatorError', + path: 'email', + properties: { + message: 'Path `email` is required.', + path: 'email', + type: 'required', + value: '', + }, + value: '', + }, + passwordHash: { + $isValidatorError: true, + kind: 'required', + message: 'Path `passwordHash` is required.', + name: 'ValidatorError', + path: 'passwordHash', + properties: { + message: 'Path `passwordHash` is required.', + path: 'passwordHash', + type: 'required', + value: '', + }, + value: '', + }, + }, + message: 'User validation failed: email: Path `email` is required., passwordHash: Path `passwordHash` is required.', + name: 'ValidationError', +}; +//# sourceMappingURL=mongoose-validation-error.js.map \ No newline at end of file diff --git a/lib/test/fixtures/mongoose-validation-error.js.map b/lib/test/fixtures/mongoose-validation-error.js.map new file mode 100644 index 0000000..e8a942d --- /dev/null +++ b/lib/test/fixtures/mongoose-validation-error.js.map @@ -0,0 +1 @@ +{"version":3,"file":"mongoose-validation-error.js","sourceRoot":"","sources":["../../../test/fixtures/mongoose-validation-error.ts"],"names":[],"mappings":";;;AAAa,QAAA,uBAAuB,GAAG;IACrC,QAAQ,EAAE,wBAAwB;IAClC,MAAM,EAAE;QACN,KAAK,EAAE;YACL,iBAAiB,EAAE,IAAI;YACvB,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,2BAA2B;YACpC,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,OAAO;YACb,UAAU,EAAE;gBACV,OAAO,EAAE,2BAA2B;gBACpC,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,EAAE;aACV;YACD,KAAK,EAAE,EAAE;SACV;QACD,YAAY,EAAE;YACZ,iBAAiB,EAAE,IAAI;YACvB,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,kCAAkC;YAC3C,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,cAAc;YACpB,UAAU,EAAE;gBACV,OAAO,EAAE,kCAAkC;gBAC3C,IAAI,EAAE,cAAc;gBACpB,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,EAAE;aACV;YACD,KAAK,EAAE,EAAE;SACV;KACF;IACD,OAAO,EAAE,0GAA0G;IACnH,IAAI,EAAE,iBAAiB;CACxB,CAAA"} \ No newline at end of file diff --git a/lib/test/fixtures/valid-user-record.d.ts b/lib/test/fixtures/valid-user-record.d.ts new file mode 100644 index 0000000..d0e01f3 --- /dev/null +++ b/lib/test/fixtures/valid-user-record.d.ts @@ -0,0 +1,27 @@ +declare const _default: { + email: string; + passwordHash: string; + 'genre.type': string; + 'genre.enum': string; + 'arrayed.0': string; + 'arrayed.1': string; + 'parent.name': string; + 'parent.surname': string; + 'parent.age': number; + 'parent.nestedArray.0.someProperty': number; + 'parent.nestedArray.1.someProperty': number; + 'parent.nestedObject.someProperty': number; + 'family.0.name': string; + 'family.0.surname': string; + 'family.0.age': number; + 'family.0.nestedArray.0.someProperty': number; + 'family.0.nestedArray.1.someProperty': number; + 'family.0.nestedObject.someProperty': number; + 'family.1.name': string; + 'family.1.surname': string; + 'family.1.age': number; + 'family.1.nestedArray.0.someProperty': number; + 'family.1.nestedArray.1.someProperty': number; + 'family.1.nestedObject.someProperty': number; +}; +export default _default; diff --git a/lib/test/fixtures/valid-user-record.js b/lib/test/fixtures/valid-user-record.js new file mode 100644 index 0000000..b1770c8 --- /dev/null +++ b/lib/test/fixtures/valid-user-record.js @@ -0,0 +1,29 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.default = { + email: 'john@doe.com', + passwordHash: 'somesecretpasswordhash', + 'genre.type': 'some type', + 'genre.enum': 'male', + 'arrayed.0': 'first', + 'arrayed.1': 'second', + 'parent.name': 'name', + 'parent.surname': 'surname', + 'parent.age': 12, + 'parent.nestedArray.0.someProperty': 12, + 'parent.nestedArray.1.someProperty': 12, + 'parent.nestedObject.someProperty': 12, + 'family.0.name': 'some string', + 'family.0.surname': 'some string', + 'family.0.age': 13, + 'family.0.nestedArray.0.someProperty': 12, + 'family.0.nestedArray.1.someProperty': 12, + 'family.0.nestedObject.someProperty': 12, + 'family.1.name': 'some string', + 'family.1.surname': 'some string', + 'family.1.age': 14, + 'family.1.nestedArray.0.someProperty': 12, + 'family.1.nestedArray.1.someProperty': 12, + 'family.1.nestedObject.someProperty': 12, +}; +//# sourceMappingURL=valid-user-record.js.map \ No newline at end of file diff --git a/lib/test/fixtures/valid-user-record.js.map b/lib/test/fixtures/valid-user-record.js.map new file mode 100644 index 0000000..0749f8c --- /dev/null +++ b/lib/test/fixtures/valid-user-record.js.map @@ -0,0 +1 @@ +{"version":3,"file":"valid-user-record.js","sourceRoot":"","sources":["../../../test/fixtures/valid-user-record.ts"],"names":[],"mappings":";;AAAA,kBAAe;IACb,KAAK,EAAE,cAAc;IACrB,YAAY,EAAE,wBAAwB;IACtC,YAAY,EAAE,WAAW;IACzB,YAAY,EAAE,MAAM;IACpB,WAAW,EAAE,OAAO;IACpB,WAAW,EAAE,QAAQ;IACrB,aAAa,EAAE,MAAM;IACrB,gBAAgB,EAAE,SAAS;IAC3B,YAAY,EAAE,EAAE;IAChB,mCAAmC,EAAE,EAAE;IACvC,mCAAmC,EAAE,EAAE;IACvC,kCAAkC,EAAE,EAAE;IACtC,eAAe,EAAE,aAAa;IAC9B,kBAAkB,EAAE,aAAa;IACjC,cAAc,EAAE,EAAE;IAClB,qCAAqC,EAAE,EAAE;IACzC,qCAAqC,EAAE,EAAE;IACzC,oCAAoC,EAAE,EAAE;IACxC,eAAe,EAAE,aAAa;IAC9B,kBAAkB,EAAE,aAAa;IACjC,cAAc,EAAE,EAAE;IAClB,qCAAqC,EAAE,EAAE;IACzC,qCAAqC,EAAE,EAAE;IACzC,oCAAoC,EAAE,EAAE;CACzC,CAAA"} \ No newline at end of file diff --git a/lib/test/property.spec.d.ts b/lib/test/property.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/property.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/property.spec.js b/lib/test/property.spec.js new file mode 100644 index 0000000..b0ba065 --- /dev/null +++ b/lib/test/property.spec.js @@ -0,0 +1,84 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const models_1 = require("./utils/models"); +const property_1 = __importDefault(require("../src/property")); +describe('Property', () => { + describe('#availableValues', () => { + it('returns null for all standard (Non enum) values', () => { + const property = new property_1.default(models_1.User.schema.paths.email); + expect(property.availableValues()).toEqual(null); + }); + it('returns array of values for the enum field', () => { + const property = new property_1.default(models_1.User.schema.paths.genre); + expect(property.availableValues()).toEqual(['male', 'female']); + }); + }); + describe('#isArray', () => { + it('returns false for regular (not arrayed) property', () => { + const property = new property_1.default(models_1.User.schema.paths.email); + expect(property.isArray()).toEqual(false); + }); + it('returns true for array property', () => { + const property = new property_1.default(models_1.User.schema.paths.arrayed); + expect(property.isArray()).toEqual(true); + }); + }); + describe('#type', () => { + it('returns string type for string property', () => { + const property = new property_1.default(models_1.User.schema.paths.email); + expect(property.type()).toEqual('string'); + }); + it('returns string when property is an array of strings', () => { + const property = new property_1.default(models_1.User.schema.paths.arrayed); + expect(property.type()).toEqual('string'); + }); + it('returns mixed when prooperty is an array of embeded schemas', () => { + const property = new property_1.default(models_1.User.schema.paths.family); + expect(property.type()).toEqual('mixed'); + }); + }); + describe('#reference', () => { + it('returns undefined when property without a reference is given', () => { + const property = new property_1.default(models_1.User.schema.paths.email); + expect(property.reference()).toEqual(undefined); + }); + it('returns reference to User when field with it is given', () => { + const property = new property_1.default(models_1.Article.schema.paths.createdBy); + expect(property.reference()).toEqual('User'); + }); + it('returns reference to User when field is an array fields with references', () => { + const property = new property_1.default(models_1.Article.schema.paths.owners); + expect(property.reference()).toEqual('User'); + }); + }); + describe('#subProperties', () => { + it('returns empty array for regular (not mixed) property', () => { + const property = new property_1.default(models_1.User.schema.paths.email); + expect(property.subProperties()).toEqual([]); + }); + it('returns an array of all subproperties when nested schema is given', () => { + const property = new property_1.default(models_1.User.schema.paths.parent); + const subProperties = property.subProperties(); + expect(subProperties.length).toEqual(6); + }); + it('returns an array of all subproperties when array of nested schema is given', () => { + const property = new property_1.default(models_1.User.schema.paths.family); + const subProperties = property.subProperties(); + expect(subProperties.length).toEqual(6); + }); + }); + describe('#isRequired', () => { + it('returns true for required property', () => { + const property = new property_1.default(models_1.User.schema.paths.email); + expect(property.isRequired()).toEqual(true); + }); + it('returns string when property is an array of strings', () => { + const property = new property_1.default(models_1.User.schema.paths.genre); + expect(property.isRequired()).toEqual(false); + }); + }); +}); +//# sourceMappingURL=property.spec.js.map \ No newline at end of file diff --git a/lib/test/property.spec.js.map b/lib/test/property.spec.js.map new file mode 100644 index 0000000..9fab1a5 --- /dev/null +++ b/lib/test/property.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"property.spec.js","sourceRoot":"","sources":["../../test/property.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/test/resource/constructor.d.ts b/lib/test/resource/constructor.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/resource/constructor.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/resource/constructor.js b/lib/test/resource/constructor.js new file mode 100644 index 0000000..f7139f0 --- /dev/null +++ b/lib/test/resource/constructor.js @@ -0,0 +1,16 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const resource_1 = __importDefault(require("../../src/resource")); +const models_1 = require("../utils/models"); +describe('Resource', () => { + describe('#constructor', () => { + it('stores original model', () => { + const userResource = new resource_1.default(models_1.User); + expect(userResource.MongooseModel).toEqual(models_1.User); + }); + }); +}); +//# sourceMappingURL=constructor.js.map \ No newline at end of file diff --git a/lib/test/resource/constructor.js.map b/lib/test/resource/constructor.js.map new file mode 100644 index 0000000..d01cda4 --- /dev/null +++ b/lib/test/resource/constructor.js.map @@ -0,0 +1 @@ +{"version":3,"file":"constructor.js","sourceRoot":"","sources":["../../../test/resource/constructor.ts"],"names":[],"mappings":";;;;;AAAA,kEAAyC;AACzC,4CAAsC;AAGtC,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACxB,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,uBAAuB,EAAE,GAAG,EAAE;YAC/B,MAAM,YAAY,GAAG,IAAI,kBAAQ,CAAC,aAAI,CAAC,CAAA;YACvC,MAAM,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,OAAO,CAAC,aAAI,CAAC,CAAA;QAClD,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/resource/count.spec.d.ts b/lib/test/resource/count.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/resource/count.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/resource/count.spec.js b/lib/test/resource/count.spec.js new file mode 100644 index 0000000..f558acb --- /dev/null +++ b/lib/test/resource/count.spec.js @@ -0,0 +1,29 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const admin_bro_1 = require("admin-bro"); +const factory_girl_1 = require("factory-girl"); +const resource_1 = __importDefault(require("../../src/resource")); +const models_1 = require("../utils/models"); +describe('Resource #count', () => { + let resource; + beforeEach(() => { + resource = new resource_1.default(models_1.User); + }); + it('returns given count without filters', async () => { + const NUMBER_OF_RECORDS = 12; + await factory_girl_1.factory.createMany('user', NUMBER_OF_RECORDS); + const countedRecords = await resource.count(new admin_bro_1.Filter({}, resource)); + expect(countedRecords).toEqual(NUMBER_OF_RECORDS); + }); + it('returns given count for given filters', async () => { + const filterOutAllRecords = new admin_bro_1.Filter({ + email: 'some-not-existing-email', + }, resource); + const counterRecords = await resource.count(filterOutAllRecords); + expect(counterRecords).toEqual(0); + }); +}); +//# sourceMappingURL=count.spec.js.map \ No newline at end of file diff --git a/lib/test/resource/count.spec.js.map b/lib/test/resource/count.spec.js.map new file mode 100644 index 0000000..88f4c9f --- /dev/null +++ b/lib/test/resource/count.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"count.spec.js","sourceRoot":"","sources":["../../../test/resource/count.spec.ts"],"names":[],"mappings":";;;;;AAAA,yCAAkC;AAClC,+CAAsC;AACtC,kEAAyC;AACzC,4CAAsC;AAGtC,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC/B,IAAI,QAAQ,CAAA;IAEZ,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,GAAG,IAAI,kBAAQ,CAAC,aAAI,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,iBAAiB,GAAG,EAAE,CAAA;QAC5B,MAAM,sBAAO,CAAC,UAAU,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;QAEnD,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,IAAI,kBAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC,CAAA;QAErE,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,uCAAuC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,mBAAmB,GAAG,IAAI,kBAAM,CAAC;YACrC,KAAK,EAAE,yBAAyB;SACjC,EAAE,QAAQ,CAAC,CAAA;QAEZ,MAAM,cAAc,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,mBAAmB,CAAC,CAAA;QAEhE,MAAM,CAAC,cAAc,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IACnC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/resource/create.spec.d.ts b/lib/test/resource/create.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/resource/create.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/resource/create.spec.js b/lib/test/resource/create.spec.js new file mode 100644 index 0000000..a76286e --- /dev/null +++ b/lib/test/resource/create.spec.js @@ -0,0 +1,79 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const admin_bro_1 = require("admin-bro"); +const factory_girl_1 = require("factory-girl"); +const resource_1 = __importDefault(require("../../src/resource")); +const valid_user_record_1 = __importDefault(require("../fixtures/valid-user-record")); +const models_1 = require("../utils/models"); +describe('Resource #create', () => { + it('creates new record with valid parameters', async () => { + const resource = new resource_1.default(models_1.User); + const record = await resource.create(valid_user_record_1.default); + expect(await resource.count()).toEqual(1); + expect(record).toBeInstanceOf(Object); + }); + it('throws validation error for record with invalid parameters', async () => { + const resource = new resource_1.default(models_1.User); + await expect(() => resource.create({ email: '', passwordHash: '' })).rejects.toThrow(admin_bro_1.ValidationError); + }); + it('throws validation error for record with cast errors in nested schema', async () => { + const resource = new resource_1.default(models_1.User); + try { + await resource.create({ + email: 'a@a.pl', + passwordHash: 'asdasdasd', + 'parent.age': 'not a number', + }); + throw new Error('Should throw validation error'); + } + catch (error) { + expect(error).toBeInstanceOf(admin_bro_1.ValidationError); + expect(error.propertyErrors['parent.age'].type).toEqual('Number'); + expect(error.propertyErrors.parent.type).toEqual('ValidationError'); + } + }); + it('throws duplicate error for record with unique field', async () => { + const peselResource = new resource_1.default(models_1.Pesel); + try { + await peselResource.create({ pesel: '1' }); + await peselResource.create({ pesel: '1' }); + } + catch (error) { + expect(error).toBeInstanceOf(admin_bro_1.ValidationError); + expect(error.propertyErrors.pesel.type).toEqual('duplicate'); + } + }); + it('creates resource with id field passed as an empty string', async () => { + const resource = new resource_1.default(models_1.Article); + await resource.create({ content: 'some content', createdBy: '' }); + const recordsCount = await resource.count(); + expect(recordsCount).toEqual(1); + }); + it('creates new resource for record with reference', async () => { + const resource = new resource_1.default(models_1.Article); + const userRecords = await factory_girl_1.factory.createMany('user', 1); + const createdRecord = await resource.create({ content: '', createdBy: userRecords[0]._id }); + expect(createdRecord.createdBy.toString()).toEqual(userRecords[0]._id.toString()); + }); + it('creates new object for record with nested array', async () => { + const resource = new resource_1.default(models_1.User); + await factory_girl_1.factory.createMany('user', 1); + const countBefore = await resource.count(); + await resource.create({ + email: 'john@doe.com', + passwordHash: 'somesecretpasswordhash', + 'parent.name': 'name', + 'parent.nestedArray': '', + 'parent.nestedObject': '', + 'family.0.name': 'some string', + 'family.0.nestedArray.0': '', + 'family.1': '', + }); + const countAfter = await resource.count(); + expect(countAfter - countBefore).toEqual(1); + }); +}); +//# sourceMappingURL=create.spec.js.map \ No newline at end of file diff --git a/lib/test/resource/create.spec.js.map b/lib/test/resource/create.spec.js.map new file mode 100644 index 0000000..a647346 --- /dev/null +++ b/lib/test/resource/create.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"create.spec.js","sourceRoot":"","sources":["../../../test/resource/create.spec.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/test/resource/delete.spec.d.ts b/lib/test/resource/delete.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/resource/delete.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/resource/delete.spec.js b/lib/test/resource/delete.spec.js new file mode 100644 index 0000000..2ca2214 --- /dev/null +++ b/lib/test/resource/delete.spec.js @@ -0,0 +1,19 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const factory_girl_1 = require("factory-girl"); +const resource_1 = __importDefault(require("../../src/resource")); +const models_1 = require("../utils/models"); +describe('Resource #delete', () => { + it('removes the item from the database', async () => { + const resource = new resource_1.default(models_1.User); + const records = await factory_girl_1.factory.createMany('user', 12); + const initialNumberOfRecords = await models_1.User.countDocuments(); + const idOfItemToDelete = records[0]._id; + await resource.delete(idOfItemToDelete); + expect(await models_1.User.countDocuments()).toEqual(initialNumberOfRecords - 1); + }); +}); +//# sourceMappingURL=delete.spec.js.map \ No newline at end of file diff --git a/lib/test/resource/delete.spec.js.map b/lib/test/resource/delete.spec.js.map new file mode 100644 index 0000000..51fa28b --- /dev/null +++ b/lib/test/resource/delete.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"delete.spec.js","sourceRoot":"","sources":["../../../test/resource/delete.spec.ts"],"names":[],"mappings":";;;;;AAAA,+CAAsC;AACtC,kEAAyC;AACzC,4CAAsC;AAEtC,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,QAAQ,GAAG,IAAI,kBAAQ,CAAC,aAAI,CAAC,CAAA;QACnC,MAAM,OAAO,GAAG,MAAM,sBAAO,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QACpD,MAAM,sBAAsB,GAAG,MAAM,aAAI,CAAC,cAAc,EAAE,CAAA;QAC1D,MAAM,gBAAgB,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;QAEvC,MAAM,QAAQ,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAA;QAEvC,MAAM,CAAC,MAAM,aAAI,CAAC,cAAc,EAAE,CAAC,CAAC,OAAO,CAAC,sBAAsB,GAAG,CAAC,CAAC,CAAA;IACzE,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/resource/find.spec.d.ts b/lib/test/resource/find.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/resource/find.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/resource/find.spec.js b/lib/test/resource/find.spec.js new file mode 100644 index 0000000..aae81f1 --- /dev/null +++ b/lib/test/resource/find.spec.js @@ -0,0 +1,24 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const admin_bro_1 = require("admin-bro"); +const factory_girl_1 = require("factory-girl"); +const resource_1 = __importDefault(require("../../src/resource")); +const models_1 = require("../utils/models"); +describe('Resource #find', () => { + it('returns first n items', async () => { + await factory_girl_1.factory.createMany('user', 10); + const resource = new resource_1.default(models_1.User); + const limit = 5; + const offset = 0; + const returnedItems = await resource.find(new admin_bro_1.Filter({}, models_1.User), { + limit, + offset, + }); + expect(returnedItems.length).toEqual(limit); + expect(returnedItems[0]).toBeInstanceOf(admin_bro_1.BaseRecord); + }); +}); +//# sourceMappingURL=find.spec.js.map \ No newline at end of file diff --git a/lib/test/resource/find.spec.js.map b/lib/test/resource/find.spec.js.map new file mode 100644 index 0000000..1a47b3e --- /dev/null +++ b/lib/test/resource/find.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"find.spec.js","sourceRoot":"","sources":["../../../test/resource/find.spec.ts"],"names":[],"mappings":";;;;;AAAA,yCAA8C;AAC9C,+CAAsC;AACtC,kEAAyC;AACzC,4CAAsC;AAEtC,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,uBAAuB,EAAE,KAAK,IAAI,EAAE;QACrC,MAAM,sBAAO,CAAC,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;QACpC,MAAM,QAAQ,GAAG,IAAI,kBAAQ,CAAC,aAAI,CAAC,CAAA;QACnC,MAAM,KAAK,GAAG,CAAC,CAAA;QACf,MAAM,MAAM,GAAG,CAAC,CAAA;QAEhB,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,kBAAM,CAAC,EAAE,EAAE,aAAI,CAAC,EAAE;YAC9D,KAAK;YACL,MAAM;SACP,CAAC,CAAA;QAEF,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC3C,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,sBAAU,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/resource/name.spec.d.ts b/lib/test/resource/name.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/resource/name.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/resource/name.spec.js b/lib/test/resource/name.spec.js new file mode 100644 index 0000000..e8a18fb --- /dev/null +++ b/lib/test/resource/name.spec.js @@ -0,0 +1,14 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const resource_1 = __importDefault(require("../../src/resource")); +const models_1 = require("../utils/models"); +describe('Resource #name', () => { + it('returns name of the model', () => { + const resource = new resource_1.default(models_1.User); + expect(resource.name()).toEqual('User'); + }); +}); +//# sourceMappingURL=name.spec.js.map \ No newline at end of file diff --git a/lib/test/resource/name.spec.js.map b/lib/test/resource/name.spec.js.map new file mode 100644 index 0000000..e45b371 --- /dev/null +++ b/lib/test/resource/name.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"name.spec.js","sourceRoot":"","sources":["../../../test/resource/name.spec.ts"],"names":[],"mappings":";;;;;AAAA,kEAAyC;AACzC,4CAAsC;AAEtC,QAAQ,CAAC,gBAAgB,EAAE,GAAG,EAAE;IAC9B,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,QAAQ,GAAG,IAAI,kBAAQ,CAAC,aAAI,CAAC,CAAA;QAEnC,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAA;IACzC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/resource/parseParams.spec.d.ts b/lib/test/resource/parseParams.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/resource/parseParams.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/resource/parseParams.spec.js b/lib/test/resource/parseParams.spec.js new file mode 100644 index 0000000..171ec0d --- /dev/null +++ b/lib/test/resource/parseParams.spec.js @@ -0,0 +1,20 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const resource_1 = __importDefault(require("../../src/resource")); +const models_1 = require("../utils/models"); +describe('Resource #parseParams', () => { + let resource; + beforeEach(() => { + resource = new resource_1.default(models_1.User); + }); + it('converts empty strings to nulls for ObjectIDs', () => { + expect(resource.parseParams({ _id: '' })).toHaveProperty('_id', null); + }); + it('converts empty strings to [] for arrays', () => { + expect(resource.parseParams({ family: '' })).toHaveProperty('family', []); + }); +}); +//# sourceMappingURL=parseParams.spec.js.map \ No newline at end of file diff --git a/lib/test/resource/parseParams.spec.js.map b/lib/test/resource/parseParams.spec.js.map new file mode 100644 index 0000000..b551bb1 --- /dev/null +++ b/lib/test/resource/parseParams.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"parseParams.spec.js","sourceRoot":"","sources":["../../../test/resource/parseParams.spec.ts"],"names":[],"mappings":";;;;;AAAA,kEAAyC;AACzC,4CAAsC;AAGtC,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,IAAI,QAAQ,CAAA;IAEZ,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,GAAG,IAAI,kBAAQ,CAAC,aAAI,CAAC,CAAA;IAC/B,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;IACvE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAA;IAC3E,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/resource/position.spec.d.ts b/lib/test/resource/position.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/resource/position.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/resource/position.spec.js b/lib/test/resource/position.spec.js new file mode 100644 index 0000000..9997c37 --- /dev/null +++ b/lib/test/resource/position.spec.js @@ -0,0 +1,14 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const resource_1 = __importDefault(require("../../src/resource")); +const models_1 = require("../utils/models"); +describe('Resource #position', () => { + it('returns position of a parent field', () => { + const property = new resource_1.default(models_1.User).property('parent'); + expect(property.position()).toEqual(4); + }); +}); +//# sourceMappingURL=position.spec.js.map \ No newline at end of file diff --git a/lib/test/resource/position.spec.js.map b/lib/test/resource/position.spec.js.map new file mode 100644 index 0000000..58f051b --- /dev/null +++ b/lib/test/resource/position.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"position.spec.js","sourceRoot":"","sources":["../../../test/resource/position.spec.ts"],"names":[],"mappings":";;;;;AAAA,kEAAyC;AACzC,4CAAsC;AAGtC,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,QAAQ,GAAG,IAAI,kBAAQ,CAAC,aAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;QAEtD,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/resource/properties.spec.d.ts b/lib/test/resource/properties.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/resource/properties.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/resource/properties.spec.js b/lib/test/resource/properties.spec.js new file mode 100644 index 0000000..76eef98 --- /dev/null +++ b/lib/test/resource/properties.spec.js @@ -0,0 +1,39 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const mongoose_1 = __importDefault(require("mongoose")); +const resource_1 = __importDefault(require("../../src/resource")); +const models_1 = require("../utils/models"); +const property_1 = __importDefault(require("../../src/property")); +describe('Resource #properties', () => { + let resource; + let returnedProperties; + beforeEach(() => { + resource = new resource_1.default(models_1.User); + returnedProperties = resource.properties(); + }); + it('returns correct amount of properties', () => { + // 8 because of implicit _id and __v properties + expect(returnedProperties.length).toEqual(8); + }); + it('sets the position of properties', () => { + expect(returnedProperties.map(p => p.position())).toEqual([0, 1, 2, 3, 4, 5, 6, 7]); + }); + it('returns instances of Property class', async () => { + expect(returnedProperties[0]).toBeInstanceOf(property_1.default); + }); + it('returns all fields for nested properties', () => { + const Nested = mongoose_1.default.model('Nested', new mongoose_1.default.Schema({ + field: { + subfield: String, + anotherSubField: String, + }, + })); + const nestedResource = new resource_1.default(Nested); + const propertiesOfNestedResource = nestedResource.properties(); + expect(propertiesOfNestedResource.length).toEqual(4); + }); +}); +//# sourceMappingURL=properties.spec.js.map \ No newline at end of file diff --git a/lib/test/resource/properties.spec.js.map b/lib/test/resource/properties.spec.js.map new file mode 100644 index 0000000..d660e77 --- /dev/null +++ b/lib/test/resource/properties.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"properties.spec.js","sourceRoot":"","sources":["../../../test/resource/properties.spec.ts"],"names":[],"mappings":";;;;;AAAA,wDAA+B;AAC/B,kEAAyC;AACzC,4CAAsC;AACtC,kEAAyC;AAEzC,QAAQ,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACpC,IAAI,QAAQ,CAAA;IACZ,IAAI,kBAAkB,CAAA;IAEtB,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,GAAG,IAAI,kBAAQ,CAAC,aAAI,CAAC,CAAA;QAC7B,kBAAkB,GAAG,QAAQ,CAAC,UAAU,EAAE,CAAA;IAC5C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,+CAA+C;QAC/C,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC9C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;IACrF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,kBAAQ,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;IAGF,EAAE,CAAC,0CAA0C,EAAE,GAAG,EAAE;QAClD,MAAM,MAAM,GAAG,kBAAQ,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,kBAAQ,CAAC,MAAM,CAAC;YAC1D,KAAK,EAAE;gBACL,QAAQ,EAAE,MAAM;gBAChB,eAAe,EAAE,MAAM;aACxB;SACF,CAAC,CAAC,CAAA;QACH,MAAM,cAAc,GAAG,IAAI,kBAAQ,CAAC,MAAM,CAAC,CAAA;QAE3C,MAAM,0BAA0B,GAAG,cAAc,CAAC,UAAU,EAAE,CAAA;QAE9D,MAAM,CAAC,0BAA0B,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IACtD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/resource/property.spec.d.ts b/lib/test/resource/property.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/resource/property.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/resource/property.spec.js b/lib/test/resource/property.spec.js new file mode 100644 index 0000000..d516ad4 --- /dev/null +++ b/lib/test/resource/property.spec.js @@ -0,0 +1,23 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const resource_1 = __importDefault(require("../../src/resource")); +const models_1 = require("../utils/models"); +const property_1 = __importDefault(require("../../src/property")); +describe('Resource #property', () => { + let resource; + let returnedProperty; + beforeEach(() => { + resource = new resource_1.default(models_1.User); + returnedProperty = resource.property('email'); + }); + it('returns selected property for an email', () => { + expect(returnedProperty.name()).toEqual('email'); + }); + it('returns instance of Property class', () => { + expect(returnedProperty).toBeInstanceOf(property_1.default); + }); +}); +//# sourceMappingURL=property.spec.js.map \ No newline at end of file diff --git a/lib/test/resource/property.spec.js.map b/lib/test/resource/property.spec.js.map new file mode 100644 index 0000000..47f6027 --- /dev/null +++ b/lib/test/resource/property.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"property.spec.js","sourceRoot":"","sources":["../../../test/resource/property.spec.ts"],"names":[],"mappings":";;;;;AAAA,kEAAyC;AACzC,4CAAsC;AACtC,kEAAyC;AAEzC,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,IAAI,QAAQ,CAAA;IACZ,IAAI,gBAAgB,CAAA;IAEpB,UAAU,CAAC,GAAG,EAAE;QACd,QAAQ,GAAG,IAAI,kBAAQ,CAAC,aAAI,CAAC,CAAA;QAC7B,gBAAgB,GAAG,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAA;IAClD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,oCAAoC,EAAE,GAAG,EAAE;QAC5C,MAAM,CAAC,gBAAgB,CAAC,CAAC,cAAc,CAAC,kBAAQ,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/resource/update.spec.d.ts b/lib/test/resource/update.spec.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/resource/update.spec.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/resource/update.spec.js b/lib/test/resource/update.spec.js new file mode 100644 index 0000000..97255d2 --- /dev/null +++ b/lib/test/resource/update.spec.js @@ -0,0 +1,18 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const resource_1 = __importDefault(require("../../src/resource")); +const models_1 = require("../utils/models"); +describe('Resource #update', () => { + it('changes record and returns updated', async () => { + const resource = new resource_1.default(models_1.Article); + const initialRecord = await resource.create({ + content: 'Test content', + }); + const updatedRecord = await resource.update(initialRecord._id, { content: 'Updated content' }); + expect(updatedRecord.content).toEqual('Updated content'); + }); +}); +//# sourceMappingURL=update.spec.js.map \ No newline at end of file diff --git a/lib/test/resource/update.spec.js.map b/lib/test/resource/update.spec.js.map new file mode 100644 index 0000000..a7db004 --- /dev/null +++ b/lib/test/resource/update.spec.js.map @@ -0,0 +1 @@ +{"version":3,"file":"update.spec.js","sourceRoot":"","sources":["../../../test/resource/update.spec.ts"],"names":[],"mappings":";;;;;AAAA,kEAAyC;AACzC,4CAAyC;AAEzC,QAAQ,CAAC,kBAAkB,EAAE,GAAG,EAAE;IAChC,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;QAClD,MAAM,QAAQ,GAAG,IAAI,kBAAQ,CAAC,gBAAO,CAAC,CAAA;QACtC,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YAC1C,OAAO,EAAE,cAAc;SACxB,CAAC,CAAA;QAEF,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,MAAM,CACzC,aAAa,CAAC,GAAG,EACjB,EAAE,OAAO,EAAE,iBAAiB,EAAE,CAC/B,CAAA;QAED,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAC1D,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/utils/beforeEach.d.ts b/lib/test/utils/beforeEach.d.ts new file mode 100644 index 0000000..cb0ff5c --- /dev/null +++ b/lib/test/utils/beforeEach.d.ts @@ -0,0 +1 @@ +export {}; diff --git a/lib/test/utils/beforeEach.js b/lib/test/utils/beforeEach.js new file mode 100644 index 0000000..8c94fb8 --- /dev/null +++ b/lib/test/utils/beforeEach.js @@ -0,0 +1,20 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const mongoose_1 = __importDefault(require("mongoose")); +const models_1 = require("./models"); +const dropAllCollections = async () => { + await mongoose_1.default.connect('mongodb://localhost/e2e_test', { + useNewUrlParser: true, + useUnifiedTopology: true, + }); + await Promise.all([ + models_1.Pesel.deleteMany({}), + models_1.User.deleteMany({}), + models_1.Article.deleteMany({}), + ]); +}; +beforeEach(dropAllCollections); +//# sourceMappingURL=beforeEach.js.map \ No newline at end of file diff --git a/lib/test/utils/beforeEach.js.map b/lib/test/utils/beforeEach.js.map new file mode 100644 index 0000000..e10581c --- /dev/null +++ b/lib/test/utils/beforeEach.js.map @@ -0,0 +1 @@ +{"version":3,"file":"beforeEach.js","sourceRoot":"","sources":["../../../test/utils/beforeEach.ts"],"names":[],"mappings":";;;;;AAAA,wDAA+B;AAC/B,qCAA+C;AAE/C,MAAM,kBAAkB,GAAG,KAAK,IAAmB,EAAE;IACnD,MAAM,kBAAQ,CAAC,OAAO,CAAC,8BAA8B,EAAE;QACrD,eAAe,EAAE,IAAI;QACrB,kBAAkB,EAAE,IAAI;KACzB,CAAC,CAAA;IACF,MAAM,OAAO,CAAC,GAAG,CAAC;QAChB,cAAK,CAAC,UAAU,CAAC,EAAE,CAAC;QACpB,aAAI,CAAC,UAAU,CAAC,EAAE,CAAC;QACnB,gBAAO,CAAC,UAAU,CAAC,EAAE,CAAC;KACvB,CAAC,CAAA;AACJ,CAAC,CAAA;AACD,UAAU,CAAC,kBAAkB,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/utils/models.d.ts b/lib/test/utils/models.d.ts new file mode 100644 index 0000000..30b698b --- /dev/null +++ b/lib/test/utils/models.d.ts @@ -0,0 +1 @@ +export declare const User: any, Article: any, Pesel: any; diff --git a/lib/test/utils/models.js b/lib/test/utils/models.js new file mode 100644 index 0000000..7403fd8 --- /dev/null +++ b/lib/test/utils/models.js @@ -0,0 +1,51 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.Pesel = exports.Article = exports.User = void 0; +const mongoose_1 = __importDefault(require("mongoose")); +const factory_girl_1 = require("factory-girl"); +const globalAny = global; +// @ts-ignore +const NestedObject = new mongoose_1.default.Schema({ + someProperty: Number, +}); +// @ts-ignore +const SubType = new mongoose_1.default.Schema({ + name: String, + surname: String, + age: Number, + nestedArray: [NestedObject], + nestedObject: NestedObject, +}); +globalAny.User = mongoose_1.default.model('User', new mongoose_1.default.Schema({ + email: { type: String, required: true }, + passwordHash: { type: String, required: true }, + genre: { type: String, enum: ['male', 'female'] }, + arrayed: [String], + parent: SubType, + family: [SubType], +})); +globalAny.Pesel = mongoose_1.default.model('Pesel', new mongoose_1.default.Schema({ + pesel: { + type: String, unique: true, required: true, sparse: true, + }, +})); +globalAny.Article = mongoose_1.default.model('Article', new mongoose_1.default.Schema({ + content: String, + owners: [{ + type: mongoose_1.default.Schema.Types.ObjectId, + ref: 'User', + }], + createdBy: { + type: mongoose_1.default.Schema.Types.ObjectId, + ref: 'User', + }, +})); +exports.User = globalAny.User, exports.Article = globalAny.Article, exports.Pesel = globalAny.Pesel; +factory_girl_1.factory.define('user', exports.User, { + email: factory_girl_1.factory.sequence('User.email', n => `john@doe${n}.com`), + passwordHash: 'somehashedpassword', +}); +//# sourceMappingURL=models.js.map \ No newline at end of file diff --git a/lib/test/utils/models.js.map b/lib/test/utils/models.js.map new file mode 100644 index 0000000..ebc2f66 --- /dev/null +++ b/lib/test/utils/models.js.map @@ -0,0 +1 @@ +{"version":3,"file":"models.js","sourceRoot":"","sources":["../../../test/utils/models.ts"],"names":[],"mappings":";;;;;;AAAA,wDAA+B;AAC/B,+CAAsC;AAGtC,MAAM,SAAS,GAAG,MAAa,CAAA;AAE/B,aAAa;AACb,MAAM,YAAY,GAAG,IAAI,kBAAQ,CAAC,MAAM,CAAC;IACvC,YAAY,EAAE,MAAM;CACrB,CAAC,CAAA;AAEF,aAAa;AACb,MAAM,OAAO,GAAG,IAAI,kBAAQ,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,MAAM;IACf,GAAG,EAAE,MAAM;IACX,WAAW,EAAE,CAAC,YAAY,CAAC;IAC3B,YAAY,EAAE,YAAY;CAC3B,CAAC,CAAA;AAEF,SAAS,CAAC,IAAI,GAAG,kBAAQ,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,kBAAQ,CAAC,MAAM,CAAC;IAC1D,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IACvC,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;IAC9C,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;IACjD,OAAO,EAAE,CAAC,MAAM,CAAC;IACjB,MAAM,EAAE,OAAO;IACf,MAAM,EAAE,CAAC,OAAO,CAAC;CAClB,CAAC,CAAC,CAAA;AAEH,SAAS,CAAC,KAAK,GAAG,kBAAQ,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI,kBAAQ,CAAC,MAAM,CAAC;IAC5D,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI;KACzD;CACF,CAAC,CAAC,CAAA;AAEH,SAAS,CAAC,OAAO,GAAG,kBAAQ,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,kBAAQ,CAAC,MAAM,CAAC;IAChE,OAAO,EAAE,MAAM;IACf,MAAM,EAAE,CAAC;YACP,IAAI,EAAE,kBAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ;YACpC,GAAG,EAAE,MAAM;SACZ,CAAC;IACF,SAAS,EAAE;QACT,IAAI,EAAE,kBAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ;QACpC,GAAG,EAAE,MAAM;KACZ;CACF,CAAC,CAAC,CAAA;AAEY,YAAI,GAA0D,SAAS,OAAjE,eAAO,GAAiD,SAAS,UAAxD,aAAK,GAA0C,SAAS,OAAA;AAEtF,sBAAO,CAAC,MAAM,CAAC,MAAM,EAAE,YAAI,EAAE;IAC3B,KAAK,EAAE,sBAAO,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC;IAC9D,YAAY,EAAE,oBAAoB;CACnC,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/test/utils/teardown.d.ts b/lib/test/utils/teardown.d.ts new file mode 100644 index 0000000..c93604e --- /dev/null +++ b/lib/test/utils/teardown.d.ts @@ -0,0 +1,2 @@ +declare const teardownE2ETests: () => Promise; +export default teardownE2ETests; diff --git a/lib/test/utils/teardown.js b/lib/test/utils/teardown.js new file mode 100644 index 0000000..b753d7a --- /dev/null +++ b/lib/test/utils/teardown.js @@ -0,0 +1,14 @@ +"use strict"; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const mongoose_1 = __importDefault(require("mongoose")); +const teardownE2ETests = async () => { + await Promise.all(mongoose_1.default.connections.map(connection => connection.close(true))); + await mongoose_1.default.connection.close(); + await mongoose_1.default.disconnect(); + process.exit(); +}; +exports.default = teardownE2ETests; +//# sourceMappingURL=teardown.js.map \ No newline at end of file diff --git a/lib/test/utils/teardown.js.map b/lib/test/utils/teardown.js.map new file mode 100644 index 0000000..d4f45e1 --- /dev/null +++ b/lib/test/utils/teardown.js.map @@ -0,0 +1 @@ +{"version":3,"file":"teardown.js","sourceRoot":"","sources":["../../../test/utils/teardown.ts"],"names":[],"mappings":";;;;;AAAA,wDAA+B;AAE/B,MAAM,gBAAgB,GAAG,KAAK,IAAmB,EAAE;IACjD,MAAM,OAAO,CAAC,GAAG,CACf,kBAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAC/D,CAAA;IACD,MAAM,kBAAQ,CAAC,UAAU,CAAC,KAAK,EAAE,CAAA;IACjC,MAAM,kBAAQ,CAAC,UAAU,EAAE,CAAA;IAC3B,OAAO,CAAC,IAAI,EAAE,CAAA;AAChB,CAAC,CAAA;AAED,kBAAe,gBAAgB,CAAA"} \ No newline at end of file From 2e84f4c825b83c0c31df1d90f119885d119370a5 Mon Sep 17 00:00:00 2001 From: remoove <67414956+remoove@users.noreply.github.com> Date: Mon, 10 May 2021 13:09:01 +0300 Subject: [PATCH 4/5] fixes --- .idea/workspace.xml | 243 ++++++++++++++++++++++++++++++++++++++++++++ lib/src/resource.js | 4 +- src/resource.ts | 4 +- 3 files changed, 247 insertions(+), 4 deletions(-) create mode 100644 .idea/workspace.xml diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..68bbe58 --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,243 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -217,6 +110,7 @@ @@ -233,6 +127,7 @@ +