From 863e37d4e2019fa7c1371209ae9c4ef1c75c27c7 Mon Sep 17 00:00:00 2001 From: Matt Schnee Date: Wed, 22 Apr 2020 18:48:41 -0700 Subject: [PATCH 1/2] feat: mongoose extension --- extensions/mongoose/.npmrc | 1 + extensions/mongoose/LICENSE | 27 + extensions/mongoose/README.md | 160 ++++ extensions/mongoose/index.d.ts | 6 + extensions/mongoose/index.js | 6 + extensions/mongoose/index.ts | 6 + extensions/mongoose/package-lock.json | 865 ++++++++++++++++++ extensions/mongoose/package.json | 64 ++ .../src/__tests__/acceptance/README.md | 1 + .../src/__tests__/integration/MySequence.ts | 40 + .../src/__tests__/integration/application.ts | 64 ++ .../__tests__/integration/rest-server.test.ts | 46 + .../integration/schemas/event.schema.ts | 26 + .../__tests__/integration/schemas/index.ts | 43 + .../integration/schemas/login-event.schema.ts | 18 + .../integration/schemas/user.schema.ts | 18 + .../__tests__/integration/user.controller.ts | 74 ++ .../mongoose/src/__tests__/unit/README.md | 1 + extensions/mongoose/src/component.ts | 138 +++ extensions/mongoose/src/index.ts | 8 + extensions/mongoose/src/keys.ts | 16 + extensions/mongoose/src/types.ts | 49 + extensions/mongoose/tsconfig.build.json | 9 + 23 files changed, 1686 insertions(+) create mode 100644 extensions/mongoose/.npmrc create mode 100644 extensions/mongoose/LICENSE create mode 100644 extensions/mongoose/README.md create mode 100644 extensions/mongoose/index.d.ts create mode 100644 extensions/mongoose/index.js create mode 100644 extensions/mongoose/index.ts create mode 100644 extensions/mongoose/package-lock.json create mode 100644 extensions/mongoose/package.json create mode 100644 extensions/mongoose/src/__tests__/acceptance/README.md create mode 100644 extensions/mongoose/src/__tests__/integration/MySequence.ts create mode 100644 extensions/mongoose/src/__tests__/integration/application.ts create mode 100644 extensions/mongoose/src/__tests__/integration/rest-server.test.ts create mode 100644 extensions/mongoose/src/__tests__/integration/schemas/event.schema.ts create mode 100644 extensions/mongoose/src/__tests__/integration/schemas/index.ts create mode 100644 extensions/mongoose/src/__tests__/integration/schemas/login-event.schema.ts create mode 100644 extensions/mongoose/src/__tests__/integration/schemas/user.schema.ts create mode 100644 extensions/mongoose/src/__tests__/integration/user.controller.ts create mode 100644 extensions/mongoose/src/__tests__/unit/README.md create mode 100644 extensions/mongoose/src/component.ts create mode 100644 extensions/mongoose/src/index.ts create mode 100644 extensions/mongoose/src/keys.ts create mode 100644 extensions/mongoose/src/types.ts create mode 100644 extensions/mongoose/tsconfig.build.json diff --git a/extensions/mongoose/.npmrc b/extensions/mongoose/.npmrc new file mode 100644 index 000000000000..cafe685a112d --- /dev/null +++ b/extensions/mongoose/.npmrc @@ -0,0 +1 @@ +package-lock=true diff --git a/extensions/mongoose/LICENSE b/extensions/mongoose/LICENSE new file mode 100644 index 000000000000..3cb4e65cf6fa --- /dev/null +++ b/extensions/mongoose/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) IBM Corp. 2020. +Node module: @loopback/mongoose +This project is licensed under the MIT License, full text below. + +-------- + +MIT License + +MIT License Copyright (c) IBM Corp. 2020 + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/extensions/mongoose/README.md b/extensions/mongoose/README.md new file mode 100644 index 000000000000..a82a385e22b1 --- /dev/null +++ b/extensions/mongoose/README.md @@ -0,0 +1,160 @@ +# @loopback/mongoose + +## Stability: ⚠️Experimental⚠️ + +> Experimental packages provide early access to advanced or experimental +> functionality to get community feedback. Such modules are published to npm +> using `0.x.y` versions. Their APIs and functionality may be subject to +> breaking changes in future releases. + +[![LoopBack]()](http://loopback.io/) + +## ⚠️Warnings⚠️ + +As of `0.0.1` of this extension, the type definitions of `@types/mongoose` are +several signifigant minor versions out of date: it supports mongoose `5.7.12`, +and the latest stable version of mongoose is `5.9.10` + +## Using your existing Mongoose Schemas in Loopback + +Using mongoose to devine your mongodb schemas is relatively straightforward, +though at this early stage it's still a number of steps: + +- Import the component, and it's binding: + `import {LoopbackMongooseComponent, MongooseBindings} from '@loopback/mongoose'` + +- Register your configuration (see below) + ```ts + this.configure(MongooseBindings.COMPONENT).to(configuration); + ``` +- Add the component to your application + ```ts + this.component(LoopbackMongooseComponent); + ``` +- Finally, `@inject` your Entity Models for use + ```ts + public async MyService(@inject('loopback-mongoose-component.model.ModelName') ModelName) { + const result = await ModelName.findOne({}); + } + ``` + +## Configuration + +There are three pieces of information that the Mongoose Component needs in order +to create a connection to your database and set up the mongoose models: + +- the `uri` of the connection +- an array of Schemas +- optionally, an array of Discriminator Schemas + +The configuration looks like the following: + +```ts + this.configure(MongooseBindings.COMPONENT).to({ + uri: 'mongodb://localhost:27017', + connectionOptions: {} // anything valid to mongoose.createConnection(), + schemas: [ + { + bindingKey: 'my-custom.binding.key', + schema: myImportedSchema, + name: 'MyModel' + } + ], + discriminators: [ + { + bindingKey: 'my-custom.discriminator.binding.key', + modelKey: 'my-custom.binding.key', + schema: myImportedDiscriminatorSchema, + value: 'MyModelDiscriminator' + } + ] + }) +``` + +For multiple connections, pass an array instead of an object: + +```ts +this.configure(MongooseBindings.COMPONENT).to([ + { + uri: 'mongodb://localhost:27017', + schemas: [...] + }, + { + uri: 'mongodb://127.0.0.12:27017', + schemas: [...] + } +]) +``` + +Remember, models are **always** scoped to a single connection. See the +[Mongoose Documentation for Multiple Connections](https://mongoosejs.com/docs/connections.html#multiple_connections) +for more information. + +### uri + +This is a valid mongodb connection uri string. See the +[MongoDB Documentation](https://docs.mongodb.com/manual/reference/connection-string/) +for more information. + +### connectionOptions + +_(optional)_ + +Optionally, these are options that can be passed to the mongoose +`createConnection` function. See the +[Mongoose Documentation](https://mongoosejs.com/docs/api.html#mongoose_Mongoose-createConnection) +for more details. + +### Schemas + +The Mongoose Component will create the schemas for you. Each item in this array +contains the information necessary to so do: + +**schema** The schema class itself, created from `new mongoose.Schema({})` + +**name** The model name passed to `connection.model(name, schema)` + +**bindingKey** **optional** Optionally, you can create your own binding key. The +default binding key will be `loopback-mongoose-extensions.model.${name}`. If you +have multiple connections, the binding key will include the connection index: +`loopback-mongoose-extension.connection.0.model.${name}` + +Using the same binding key for a model on multiple connections is not supported, +and doing so will throw an `InvalidArgumentException`. + +## Discriminators + +Creating discriminators requires having already created a model to create the +discriminator from. The configuration to do so requires the bindingKey for the +original model, as well as the binding key for the new model, as well as the +name of the discriminator. + +**schema** + +The schema class itself, created from `new mongoose.Schema({})` + +**name** + +The model name passed to `model.discriminator(name, schema)` + +**modelKey** + +This must be the same binding key used for the discriminator base model. + +**bindingKey** _(optional)_ + +Optionally, you can create your own binding key. The default binding key will be +`loopback-mongoose-extensions.model.${name}`. If you have multiple connections, +the binding key will include the connection index: +`loopback-mongoose-extension.connection.0.model.${name}` + +**value** **(optional)** + +The string stored in the `discriminatorKey` property. See the +[mongoose documentation for discriminators](https://mongoosejs.com/docs/api.html#model_Model.discriminator). + +# Using the Mongoose Extension + +There is a full REST server used for +[integration tests](./src/__tests__/integration), which contains an example of +how to set up and use mongoose models and discriminators. diff --git a/extensions/mongoose/index.d.ts b/extensions/mongoose/index.d.ts new file mode 100644 index 000000000000..dbbc9b978a40 --- /dev/null +++ b/extensions/mongoose/index.d.ts @@ -0,0 +1,6 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/mongoose +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +export * from './dist'; diff --git a/extensions/mongoose/index.js b/extensions/mongoose/index.js new file mode 100644 index 000000000000..f47461c2fc94 --- /dev/null +++ b/extensions/mongoose/index.js @@ -0,0 +1,6 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/mongoose +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +module.exports = require('./dist'); diff --git a/extensions/mongoose/index.ts b/extensions/mongoose/index.ts new file mode 100644 index 000000000000..a079f49fe880 --- /dev/null +++ b/extensions/mongoose/index.ts @@ -0,0 +1,6 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/mongoose +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +export * from './src'; diff --git a/extensions/mongoose/package-lock.json b/extensions/mongoose/package-lock.json new file mode 100644 index 000000000000..415c9b6ba98e --- /dev/null +++ b/extensions/mongoose/package-lock.json @@ -0,0 +1,865 @@ +{ + "name": "@loopback/mongoose", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/bson": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.2.tgz", + "integrity": "sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cross-spawn": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/cross-spawn/-/cross-spawn-6.0.1.tgz", + "integrity": "sha512-MtN1pDYdI6D6QFDzy39Q+6c9rl2o/xN7aWGe6oZuzqq5N6+YuwFsWiEAv3dNzvzN9YzU+itpN8lBzFpphQKLAw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/debug": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", + "dev": true + }, + "@types/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@types/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-EGlKlgMhnLt/cM4DbUSafFdrkeJoC9Mvnj0PUCU7tFmTjMjNRT957kXCx0wYm3JuEq4o4ZsS5vG+NlkM2DMd2A==", + "dev": true + }, + "@types/find-cache-dir": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@types/find-cache-dir/-/find-cache-dir-3.2.0.tgz", + "integrity": "sha512-+JeT9qb2Jwzw72WdjU+TSvD5O1QRPWCeRpDJV+guiIq+2hwR0DFGw+nZNbTFjMIVe6Bf4GgAKeB/6Ytx6+MbeQ==", + "dev": true + }, + "@types/find-package-json": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/find-package-json/-/find-package-json-1.1.1.tgz", + "integrity": "sha512-XMCocYkg6VUpkbOQMKa3M5cgc3MvU/LJKQwd3VUJrWZbLr2ARUggupsCAF8DxjEEIuSO6HlnH+vl+XV4bgVeEQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/get-port": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/get-port/-/get-port-4.2.0.tgz", + "integrity": "sha512-Iv2FAb5RnIk/eFO2CTu8k+0VMmIR15pKbcqRWi+s3ydW+aKXlN2yemP92SrO++ERyJx+p6Ie1ggbLBMbU1SjiQ==", + "dev": true, + "requires": { + "get-port": "*" + } + }, + "@types/lockfile": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/lockfile/-/lockfile-1.0.1.tgz", + "integrity": "sha512-65WZedEm4AnOsBDdsapJJG42MhROu3n4aSSiu87JXF/pSdlubxZxp3S1yz3kTfkJ2KBPud4CpjoHVAptOm9Zmw==", + "dev": true + }, + "@types/md5-file": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/md5-file/-/md5-file-4.0.1.tgz", + "integrity": "sha512-uK6vlo/LJp6iNWinpSzZwMe8Auzs0UYxesm7OGfQS3oz6PJciHtrKcqVOGk4wjYKawrl234vwNWvHyXH1ZzRyQ==", + "dev": true + }, + "@types/mkdirp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@types/mkdirp/-/mkdirp-1.0.0.tgz", + "integrity": "sha512-ONFY9//bCEr3DWKON3iDv/Q8LXnhaYYaNDeFSN0AtO5o4sLf9F0pstJKKKjQhXE0kJEeHs8eR6SAsROhhc2Csw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/mongodb": { + "version": "3.5.9", + "resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.5.9.tgz", + "integrity": "sha512-YEs/yBGkxpp9QxSB6gZInV7+S74pryqdfxEUJnlXDsFTtLmnDJA9iHnGEsxgrWm9gl2f4BDTwKe6lzTNB25oHg==", + "dev": true, + "requires": { + "@types/bson": "*", + "@types/node": "*" + } + }, + "@types/mongoose": { + "version": "5.7.12", + "resolved": "https://registry.npmjs.org/@types/mongoose/-/mongoose-5.7.12.tgz", + "integrity": "sha512-yzLJk3cdSwuMXaIacUCWUb8m960YcgnID7S4ZPOOgzT39aSC46670TuunN+ajDio7OUcGG4mGg8eOGs2Z6VmrA==", + "dev": true, + "requires": { + "@types/mongodb": "*", + "@types/node": "*" + } + }, + "@types/node": { + "version": "10.17.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.20.tgz", + "integrity": "sha512-XgDgo6W10SeGEAM0k7FosJpvLCynOTYns4Xk3J5HGrA+UI/bKZ30PGMzOP5Lh2zs4259I71FSYLAtjnx3qhObw==", + "dev": true + }, + "@types/tmp": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@types/tmp/-/tmp-0.1.0.tgz", + "integrity": "sha512-6IwZ9HzWbCq6XoQWhxLpDjuADodH/MKXRUIDFudvgjcVdjFknvmR+DNsoUeer4XPrEnrZs04Jj+kfV9pFsrhmA==", + "dev": true + }, + "@types/uuid": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-7.0.0.tgz", + "integrity": "sha512-RiX1I0lK9WFLFqy2xOxke396f0wKIzk5sAll0tL4J4XDYJXURI7JOs96XQb3nP+2gEpQ/LutBb66jgiT5oQshQ==", + "dev": true + }, + "agent-base": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.0.tgz", + "integrity": "sha512-j1Q7cSCqN+AwrmDd+pzgqc0/NpC655x2bUf5ZjRIO77DcNBFmh+OgRNzF6OKdCC9RSCb19fGd99+bhXFdkRNqw==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "bl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz", + "integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "bson": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.4.tgz", + "integrity": "sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q==" + }, + "buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cross-spawn": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz", + "integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=", + "dev": true + }, + "denque": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", + "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "find-cache-dir": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz", + "integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + } + }, + "find-package-json": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/find-package-json/-/find-package-json-1.2.0.tgz", + "integrity": "sha512-+SOGcLGYDJHtyqHd87ysBhmaeQ95oWspDKnMXBrnQ9Eq4OkLNqejgoaD8xVWu6GPa0B6roa6KinCMEMcVeqONw==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "kareem": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz", + "integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw==" + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "lockfile": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.4.tgz", + "integrity": "sha512-cvbTwETRfsFh4nHsL1eGWapU1XFi5Ot9E85sWAwia7Y7EgB7vfqcZhTKZ+l7hCGxSPoushMv5GKhT5PdLv03WA==", + "dev": true, + "requires": { + "signal-exit": "^3.0.2" + } + }, + "make-dir": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.2.tgz", + "integrity": "sha512-rYKABKutXa6vXTXhoV18cBE7PaewPXHe/Bdq4v+ZLMhxbWApkFFplT0LcbMW+6BbjnQXzZ/sAvSE/JdguApG5w==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "md5-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/md5-file/-/md5-file-4.0.0.tgz", + "integrity": "sha512-UC0qFwyAjn4YdPpKaDNw6gNxRf7Mcx7jC1UGCY4boCzgvU2Aoc1mOGzTtrjjLKhM5ivsnhoKpQVxKPp+1j1qwg==", + "dev": true + }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "mongodb": { + "version": "3.5.6", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.6.tgz", + "integrity": "sha512-sh3q3GLDLT4QmoDLamxtAECwC3RGjq+oNuK1ENV8+tnipIavss6sMYt77hpygqlMOCt0Sla5cl7H4SKCVBCGEg==", + "requires": { + "bl": "^2.2.0", + "bson": "^1.1.4", + "denque": "^1.4.1", + "require_optional": "^1.0.1", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + } + }, + "mongodb-memory-server": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/mongodb-memory-server/-/mongodb-memory-server-6.5.2.tgz", + "integrity": "sha512-PUCiWcHGwyqQiZF3J4iCy1DXqPjoNtehV2qMFJ26rhNBFzmc5SW+9/FUQwGNLge5/Lm1dEwcraJD5PUe8m9Kdg==", + "dev": true, + "requires": { + "mongodb-memory-server-core": "6.5.2" + } + }, + "mongodb-memory-server-core": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/mongodb-memory-server-core/-/mongodb-memory-server-core-6.5.2.tgz", + "integrity": "sha512-Cs1wB+GrL2KconDD2emk6ptU1OqdYia11I7fw5sOqnEWc8stTQ4rtptbRcLmHyTcTgRYC/fsQQvzbbd7DBf4DQ==", + "dev": true, + "requires": { + "@types/cross-spawn": "^6.0.1", + "@types/debug": "^4.1.5", + "@types/dedent": "^0.7.0", + "@types/find-cache-dir": "^3.2.0", + "@types/find-package-json": "^1.1.1", + "@types/get-port": "^4.0.1", + "@types/lockfile": "^1.0.1", + "@types/md5-file": "^4.0.1", + "@types/mkdirp": "^1.0.0", + "@types/tmp": "0.1.0", + "@types/uuid": "7.0.0", + "camelcase": "^5.3.1", + "cross-spawn": "^7.0.1", + "debug": "^4.1.1", + "dedent": "^0.7.0", + "find-cache-dir": "3.3.1", + "find-package-json": "^1.2.0", + "get-port": "5.1.1", + "https-proxy-agent": "5.0.0", + "lockfile": "^1.0.4", + "md5-file": "^4.0.0", + "mkdirp": "^1.0.3", + "mongodb": "^3.5.4", + "tar-stream": "^2.1.1", + "tmp": "^0.1.0", + "uuid": "^7.0.2", + "yauzl": "^2.10.0" + } + }, + "mongoose": { + "version": "5.9.10", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.9.10.tgz", + "integrity": "sha512-w1HNukfJzzDLfcI1f79h2Wj4ogVbf+X8hRkyFgqlcjK7OnDlAgahjDMIsT+mCS9jKojrMhjSsZIs9FiRPkLqMg==", + "requires": { + "bson": "^1.1.4", + "kareem": "2.3.1", + "mongodb": "3.5.6", + "mongoose-legacy-pluralize": "1.0.2", + "mpath": "0.7.0", + "mquery": "3.2.2", + "ms": "2.1.2", + "regexp-clone": "1.0.0", + "safe-buffer": "5.1.2", + "sift": "7.0.1", + "sliced": "1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "mongoose-legacy-pluralize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", + "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" + }, + "mpath": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.7.0.tgz", + "integrity": "sha512-Aiq04hILxhz1L+f7sjGyn7IxYzWm1zLNNXcfhDtx04kZ2Gk7uvFdgZ8ts1cWa/6d0TQmag2yR8zSGZUmp0tFNg==" + }, + "mquery": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz", + "integrity": "sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q==", + "requires": { + "bluebird": "3.5.1", + "debug": "3.1.0", + "regexp-clone": "^1.0.0", + "safe-buffer": "5.1.2", + "sliced": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "regexp-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", + "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==" + }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "requires": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "sift": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz", + "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.18.tgz", + "integrity": "sha512-9luZr/BZ2QeU6tO2uG8N2aZpVSli4TSAOAqFOyTO51AJcD9P99c0K1h6dD6r6qo5dyT44BR5exweOaLLeldTkQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + }, + "dependencies": { + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + } + } + }, + "tar-stream": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz", + "integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==", + "dev": true, + "requires": { + "bl": "^4.0.1", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "dependencies": { + "bl": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz", + "integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==", + "dev": true, + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "tmp": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.1.0.tgz", + "integrity": "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==", + "dev": true, + "requires": { + "rimraf": "^2.6.3" + } + }, + "tslib": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.11.1.tgz", + "integrity": "sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA==" + }, + "typescript": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz", + "integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz", + "integrity": "sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } +} diff --git a/extensions/mongoose/package.json b/extensions/mongoose/package.json new file mode 100644 index 000000000000..eee7d5be508a --- /dev/null +++ b/extensions/mongoose/package.json @@ -0,0 +1,64 @@ +{ + "name": "@loopback/mongoose", + "version": "0.0.1", + "description": "@loopback/mongoose", + "keywords": [ + "loopback-extension", + "loopback", + "mongoose", + "mongodb" + ], + "main": "index.js", + "engines": { + "node": ">=10" + }, + "scripts": { + "build": "lb-tsc", + "build:watch": "lb-tsc --watch", + "pretest": "npm run clean && npm run build", + "test": "lb-mocha --allow-console-logs \"dist/__tests__\"", + "test:dev": "lb-mocha --allow-console-logs dist/__tests__/**/*.js", + "clean": "lb-clean dist *.tsbuildinfo .eslintcache" + }, + "repository": { + "type": "git", + "url": "https://github.com/strongloop/loopback-next.git", + "directory": "extensions/mongoose" + }, + "author": "IBM Corp.", + "license": "MIT", + "files": [ + "README.md", + "index.js", + "index.d.ts", + "dist", + "src", + "!*/__tests__" + ], + "dependencies": { + "@loopback/core": "^2.3.0", + "mongoose": "^5.9.10", + "tslib": "^1.10.0" + }, + "devDependencies": { + "@loopback/boot": "^2.0.4", + "@loopback/build": "^5.0.1", + "@loopback/context": "^3.4.0", + "@loopback/openapi-v3": "^3.1.3", + "@loopback/repository": "^2.1.1", + "@loopback/rest": "^3.2.1", + "@loopback/service-proxy": "^2.0.4", + "@loopback/testlab": "^3.0.1", + "@types/mongodb": "^3.5.9", + "@types/mongoose": "^5.7.12", + "@types/node": "^10.17.19", + "get-port": "^5.1.1", + "mongodb-memory-server": "^6.5.2", + "source-map-support": "^0.5.16", + "typescript": "~3.8.3" + }, + "copyright.owner": "IBM Corp.", + "publishConfig": { + "access": "public" + } +} diff --git a/extensions/mongoose/src/__tests__/acceptance/README.md b/extensions/mongoose/src/__tests__/acceptance/README.md new file mode 100644 index 000000000000..5bb177829768 --- /dev/null +++ b/extensions/mongoose/src/__tests__/acceptance/README.md @@ -0,0 +1 @@ +# Acceptance tests diff --git a/extensions/mongoose/src/__tests__/integration/MySequence.ts b/extensions/mongoose/src/__tests__/integration/MySequence.ts new file mode 100644 index 000000000000..53579a866357 --- /dev/null +++ b/extensions/mongoose/src/__tests__/integration/MySequence.ts @@ -0,0 +1,40 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/typeorm +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {inject} from '@loopback/core'; +import { + FindRoute, + InvokeMethod, + ParseParams, + Reject, + RequestContext, + RestBindings, + Send, + SequenceHandler, +} from '@loopback/rest'; + +const SequenceActions = RestBindings.SequenceActions; + +export class MySequence implements SequenceHandler { + constructor( + @inject(SequenceActions.FIND_ROUTE) protected findRoute: FindRoute, + @inject(SequenceActions.PARSE_PARAMS) protected parseParams: ParseParams, + @inject(SequenceActions.INVOKE_METHOD) protected invoke: InvokeMethod, + @inject(SequenceActions.SEND) public send: Send, + @inject(SequenceActions.REJECT) public reject: Reject, + ) {} + + async handle(context: RequestContext) { + try { + const {request, response} = context; + const route = this.findRoute(request); + const args = await this.parseParams(request, route); + const result = await this.invoke(route, args); + this.send(response, result); + } catch (err) { + this.reject(context, err); + } + } +} diff --git a/extensions/mongoose/src/__tests__/integration/application.ts b/extensions/mongoose/src/__tests__/integration/application.ts new file mode 100644 index 000000000000..664574778986 --- /dev/null +++ b/extensions/mongoose/src/__tests__/integration/application.ts @@ -0,0 +1,64 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/typeorm +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {BootMixin} from '@loopback/boot'; +import {ApplicationConfig} from '@loopback/core'; +import {RestApplication} from '@loopback/rest'; +import {ServiceMixin} from '@loopback/service-proxy'; +import {LoopbackMongooseComponent, MongooseBindings} from '../../'; +import {MySequence} from './MySequence'; +import {BindingKeys, Schemas} from './schemas'; +import UserController from './user.controller'; + +export interface TestApplicationConfig extends ApplicationConfig { + mongoUri?: string; +} + +export class TestMongooseApplication extends BootMixin( + ServiceMixin(RestApplication), +) { + constructor(options: ApplicationConfig = {}) { + super(options); + + this.sequence(MySequence); + this.configureMongoose(options.mongoUri); + this.component(LoopbackMongooseComponent); + this.controller(UserController); + + this.projectRoot = __dirname; + } + + configureMongoose(uri: string) { + const schemas = [ + { + schema: Schemas.Event, + bindingKey: BindingKeys.Connection1.Event, + name: 'Event', + }, + { + schema: Schemas.User, + bindingKey: BindingKeys.Connection1.User, + name: 'User', + }, + ]; + const discriminators = [ + { + name: 'LoginEvent', + schema: Schemas.LoginEvent, + modelKey: BindingKeys.Connection1.Event, + bindingKey: BindingKeys.Connection1.LoginEvent, + }, + ]; + + this.configure(MongooseBindings.COMPONENT).to([ + { + uri, + connectionOptions: {userNewUrlParser: true}, + schemas, + discriminators, + }, + ]); + } +} diff --git a/extensions/mongoose/src/__tests__/integration/rest-server.test.ts b/extensions/mongoose/src/__tests__/integration/rest-server.test.ts new file mode 100644 index 000000000000..19b9d1d0b911 --- /dev/null +++ b/extensions/mongoose/src/__tests__/integration/rest-server.test.ts @@ -0,0 +1,46 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/typeorm +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {Client, createRestAppClient, expect} from '@loopback/testlab'; +import getPort from 'get-port'; +import {MongoMemoryServer} from 'mongodb-memory-server'; +import {TestMongooseApplication} from './application'; +describe('Mongoose Extension', () => { + let app: TestMongooseApplication; + let client: Client; + + const userData = { + firstName: 'TestName', + lastName: 'TestLastName', + }; + afterEach(async () => { + if (app) await app.stop(); + (app as unknown) = undefined; + }); + + beforeEach(async () => { + const server = new MongoMemoryServer(); + const connectionUrl = await server.getConnectionString(); + const port = await getPort(); + app = new TestMongooseApplication({ + mongoUri: connectionUrl, + rest: { + port, + }, + }); + await app.boot(); + await app.start(); + client = createRestAppClient(app); + }); + + it('Posting to /login should create a single event', async () => { + const loginRes = await client.post('/login').send(userData); + expect(loginRes.status).to.eql(204); + + const eventRes = await client.post('/find').send(userData); + expect(eventRes.status).to.eql(200); + expect(eventRes.body.length).to.eql(1); + }); +}); diff --git a/extensions/mongoose/src/__tests__/integration/schemas/event.schema.ts b/extensions/mongoose/src/__tests__/integration/schemas/event.schema.ts new file mode 100644 index 000000000000..84ae21f17a55 --- /dev/null +++ b/extensions/mongoose/src/__tests__/integration/schemas/event.schema.ts @@ -0,0 +1,26 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/typeorm +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {Document, Schema} from 'mongoose'; + +export interface EventInterface { + createdAt: Date; +} + +const eventSchema = new Schema( + { + createdAt: {type: Date}, + }, + { + discriminatorKey: 'eventType', + }, +); + +eventSchema.pre('save', function () { + // eslint-disable-next-line no-invalid-this + this.createdAt = new Date(); +}); + +export default eventSchema; diff --git a/extensions/mongoose/src/__tests__/integration/schemas/index.ts b/extensions/mongoose/src/__tests__/integration/schemas/index.ts new file mode 100644 index 000000000000..e63b1c2e58bd --- /dev/null +++ b/extensions/mongoose/src/__tests__/integration/schemas/index.ts @@ -0,0 +1,43 @@ +import {BindingKey} from '@loopback/core'; +import {Document, Model} from 'mongoose'; +import EventSchema, {EventInterface} from './event.schema'; +import LoginEventSchema, {LoginEventInterface} from './login-event.schema'; +import UserSchema, {UserInterface} from './user.schema'; + +export namespace Schemas { + export const Event = EventSchema; + export const LoginEvent = LoginEventSchema; + export const User = UserSchema; +} + +export namespace Models { + export type Event = Model; + export type LoginEvent = Model; + export type User = Model; +} + +export namespace BindingKeys { + export namespace Connection1 { + export const Event = BindingKey.create( + 'typegoose.models.conn1.Event', + ); + export const LoginEvent = BindingKey.create( + 'typegoose.models.conn1.LoginEvent', + ); + export const User = BindingKey.create( + 'typegoose.models.conn1.User', + ); + } + + export namespace Connection2 { + export const Event = BindingKey.create( + 'typegoose.models.conn2.Event', + ); + export const LoginEvent = BindingKey.create( + 'typegoose.models.conn2.LoginEvent', + ); + export const User = BindingKey.create( + 'typegoose.models.conn2.User', + ); + } +} diff --git a/extensions/mongoose/src/__tests__/integration/schemas/login-event.schema.ts b/extensions/mongoose/src/__tests__/integration/schemas/login-event.schema.ts new file mode 100644 index 000000000000..1c8a32a3a484 --- /dev/null +++ b/extensions/mongoose/src/__tests__/integration/schemas/login-event.schema.ts @@ -0,0 +1,18 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/typeorm +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {ObjectId} from 'mongodb'; +import {Document, Schema} from 'mongoose'; +import {UserInterface} from './user.schema'; + +export interface LoginEventInterface { + _user?: ObjectId | (Document & UserInterface); +} + +const loginEventSchema = new Schema({ + _user: {type: Schema.Types.ObjectId, ref: 'User'}, +}); + +export default loginEventSchema; diff --git a/extensions/mongoose/src/__tests__/integration/schemas/user.schema.ts b/extensions/mongoose/src/__tests__/integration/schemas/user.schema.ts new file mode 100644 index 000000000000..0188c1c8c3b9 --- /dev/null +++ b/extensions/mongoose/src/__tests__/integration/schemas/user.schema.ts @@ -0,0 +1,18 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/typeorm +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {Schema} from 'mongoose'; + +export interface UserInterface { + firstName: string; + lastName: string; +} + +const userSchema = new Schema({ + firstName: {type: String}, + lastName: {type: String}, +}); + +export default userSchema; diff --git a/extensions/mongoose/src/__tests__/integration/user.controller.ts b/extensions/mongoose/src/__tests__/integration/user.controller.ts new file mode 100644 index 000000000000..029def7baffb --- /dev/null +++ b/extensions/mongoose/src/__tests__/integration/user.controller.ts @@ -0,0 +1,74 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/typeorm +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {inject} from '@loopback/core'; +import {oas, post, requestBody} from '@loopback/openapi-v3'; +import {Model, model, property} from '@loopback/repository'; +import {BindingKeys, Models} from './schemas'; + +@model() +class LoginBody extends Model { + @property() + firstName: string; + + @property() + lastName: string; +} + +@model() +class LoginResponse extends Model { + constructor(d: Partial) { + super(d); + } + @property() + createdAt: Date; +} + +export default class UserController { + constructor( + @inject(BindingKeys.Connection1.User) private userModel: Models.User, + @inject(BindingKeys.Connection1.Event) private eventModel: Models.Event, + @inject(BindingKeys.Connection1.LoginEvent) + private loginEventModel: Models.LoginEvent, + ) {} + + @post('/login') + public async userLogin(@requestBody() body: LoginBody) { + let user = await this.userModel.findOne({ + firstName: body.firstName, + lastName: body.lastName, + }); + if (!user) { + user = await this.userModel.create({ + firstName: body.firstName, + lastName: body.lastName, + }); + } + + await this.loginEventModel.create({_user: user}); + } + + @post('/find') + @oas.response(200, [LoginResponse]) + public async findUserLogins(@requestBody() body: LoginBody) { + const user = await this.userModel.findOne({ + firstName: body.firstName, + lastName: body.lastName, + }); + + if (!user) { + return []; + } + const events = await this.eventModel.find({ + _user: user._id, + }); + + if (events) { + return events.map(e => new LoginResponse({createdAt: e.createdAt})); + } else { + return []; + } + } +} diff --git a/extensions/mongoose/src/__tests__/unit/README.md b/extensions/mongoose/src/__tests__/unit/README.md new file mode 100644 index 000000000000..a0291f0699f9 --- /dev/null +++ b/extensions/mongoose/src/__tests__/unit/README.md @@ -0,0 +1 @@ +# Unit tests diff --git a/extensions/mongoose/src/component.ts b/extensions/mongoose/src/component.ts new file mode 100644 index 000000000000..74f6a76340e8 --- /dev/null +++ b/extensions/mongoose/src/component.ts @@ -0,0 +1,138 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/typeorm +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import { + Application, + bind, + Binding, + BindingScope, + Component, + config, + ContextTags, + CoreBindings, + inject, + LifeCycleObserver, +} from '@loopback/core'; +import debugFactory from 'debug'; +import {Connection, createConnection, Model} from 'mongoose'; +import {MongooseBindings} from './keys'; +import {MongooseConfig, MongooseConnectionOptions} from './types'; + +const debug = debugFactory('loopback:typegoose'); + +@bind({ + tags: {[ContextTags.KEY]: MongooseBindings.COMPONENT}, + scope: BindingScope.SINGLETON, +}) +export class LoopbackMongooseComponent implements Component, LifeCycleObserver { + mongooseConnections: Connection[] = []; + bindings: Binding[] = []; + + constructor( + @inject(CoreBindings.APPLICATION_INSTANCE) + protected application: Application, + @config() + readonly typegooseConfig: MongooseConfig = [], + ) {} + + async start() { + /** + * You can have multiple connections and you can use schemas on different + * connections to create connection-model instances. + */ + let connectionOptions: MongooseConnectionOptions[]; + + if (Array.isArray(this.typegooseConfig)) { + connectionOptions = this.typegooseConfig; + } else { + connectionOptions = [this.typegooseConfig]; + } + + for (const connectionIndex in connectionOptions) { + const connectionConfig = connectionOptions[connectionIndex]; + const connection = await createConnection( + connectionConfig.uri, + connectionConfig.connectionOptions, + ); + // Add the connection to our array. We don't want to depend on + // mongoose as a singleton since we could have multiple applications + // or servers running, and the singleton would disconnect other + // services + this.mongooseConnections.push(connection); + + /** + * First, we turn the base schemas referenced by this connection into + * models, and bind them to the application context. + */ + for (const schemaConfig of connectionConfig.schemas ?? []) { + const model = connection.model( + schemaConfig.name, + schemaConfig.schema, + schemaConfig.collection, + ); + let binding = schemaConfig.bindingKey; + if (!binding) { + if (connectionOptions.length === 1) { + binding = `loopback-mongoose-extensions.model.${schemaConfig.name}`; + } else { + binding = `loopback-mongoose-extensions.connection.${connectionIndex}.model.${schemaConfig.name}`; + } + } + + const existing = await this.application.get(binding, {optional: true}); + if (existing) { + throw new Error(`binding key '${binding}' is already bound`); + } + debug(`binding ${binding}`); + + this.application + .bind(binding) + .to(model) + .inScope(BindingScope.SINGLETON); + } + + /** + * Now that we have models created, we can creeate any discriminators. + */ + for (const discriminatorConfig of connectionConfig.discriminators ?? []) { + const fromModel = (await this.application.get( + discriminatorConfig.modelKey, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + )) as Model; + const model = fromModel.discriminator( + discriminatorConfig.name, + discriminatorConfig.schema, + discriminatorConfig.value, + ); + + let binding = discriminatorConfig.bindingKey; + + if (!binding) { + if (connectionOptions.length === 1) { + binding = `loopback-mongoose-extensions.model.${discriminatorConfig.name}`; + } else { + binding = `loopback-mongoose-extensions.connection.${connectionIndex}.model.${discriminatorConfig.name}`; + } + } + + const existing = await this.application.get(binding, {optional: true}); + if (existing) { + throw new Error(`binding key '${binding}' is already bound`); + } + debug(`binding discriminator ${binding}`); + this.application + .bind(binding) + .to(model) + .inScope(BindingScope.SINGLETON); + } + } + } + + async stop() { + for (const connection of this.mongooseConnections) { + await connection.close(); + } + } +} diff --git a/extensions/mongoose/src/index.ts b/extensions/mongoose/src/index.ts new file mode 100644 index 000000000000..ec512d55c903 --- /dev/null +++ b/extensions/mongoose/src/index.ts @@ -0,0 +1,8 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/mongoose +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +export * from './component'; +export * from './keys'; +export * from './types'; diff --git a/extensions/mongoose/src/keys.ts b/extensions/mongoose/src/keys.ts new file mode 100644 index 000000000000..e7900fc3f9b9 --- /dev/null +++ b/extensions/mongoose/src/keys.ts @@ -0,0 +1,16 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/typeorm +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {BindingKey} from '@loopback/core'; +import {LoopbackMongooseComponent} from './component'; + +/** + * Binding keys used by this component. + */ +export namespace MongooseBindings { + export const COMPONENT = BindingKey.create( + 'components.LoopbackMongooseComponent', + ); +} diff --git a/extensions/mongoose/src/types.ts b/extensions/mongoose/src/types.ts new file mode 100644 index 000000000000..c30e42c83c23 --- /dev/null +++ b/extensions/mongoose/src/types.ts @@ -0,0 +1,49 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/typeorm +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {BindingKey} from '@loopback/core'; +import {ConnectionOptions, Document, Model, Schema} from 'mongoose'; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export interface MongooseSchema { + /** + * In the mongoose world, you interace directly with the models + * created from mongoose.model() + * + * These are bound to specific connections, which can be either a global + * connection or a specific connection. + * + * In either case, you need to create your own binding key for each + * connection that you have configured. + * + * Pass the Schema Class Constructor type in configuration, and when you + * @inject(YourModelBindingKey), you'll have the correct ReturnModelType + */ + name: string; + bindingKey?: string | BindingKey>; + schema: Schema; + collection?: string; +} + +export interface MongooseDiscriminator { + name: string; + modelKey: string | BindingKey>; + bindingKey?: string | BindingKey>; + schema: Schema; + value?: string; +} + +export interface MongooseConnectionOptions { + uri: string; + connectionOptions?: ConnectionOptions; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + schemas?: MongooseSchema[]; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + discriminators?: MongooseDiscriminator[]; +} + +export type MongooseConfig = + | MongooseConnectionOptions + | MongooseConnectionOptions[]; diff --git a/extensions/mongoose/tsconfig.build.json b/extensions/mongoose/tsconfig.build.json new file mode 100644 index 000000000000..c7b8e49eaca5 --- /dev/null +++ b/extensions/mongoose/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + "extends": "@loopback/build/config/tsconfig.common.json", + "compilerOptions": { + "outDir": "dist", + "rootDir": "src" + }, + "include": ["src"] +} From 1dc8fd365e9223de0a5f58438b2afa0cd5c2b197 Mon Sep 17 00:00:00 2001 From: Matt Schnee Date: Wed, 22 Apr 2020 19:22:31 -0700 Subject: [PATCH 2/2] fix: update headers --- extensions/mongoose/src/__tests__/integration/MySequence.ts | 2 +- extensions/mongoose/src/__tests__/integration/application.ts | 2 +- .../mongoose/src/__tests__/integration/rest-server.test.ts | 2 +- .../src/__tests__/integration/schemas/event.schema.ts | 2 +- .../mongoose/src/__tests__/integration/schemas/index.ts | 5 +++++ .../src/__tests__/integration/schemas/login-event.schema.ts | 2 +- .../src/__tests__/integration/schemas/user.schema.ts | 2 +- .../mongoose/src/__tests__/integration/user.controller.ts | 2 +- extensions/mongoose/src/component.ts | 2 +- extensions/mongoose/src/keys.ts | 2 +- extensions/mongoose/src/types.ts | 2 +- 11 files changed, 15 insertions(+), 10 deletions(-) diff --git a/extensions/mongoose/src/__tests__/integration/MySequence.ts b/extensions/mongoose/src/__tests__/integration/MySequence.ts index 53579a866357..927f91527e93 100644 --- a/extensions/mongoose/src/__tests__/integration/MySequence.ts +++ b/extensions/mongoose/src/__tests__/integration/MySequence.ts @@ -1,5 +1,5 @@ // Copyright IBM Corp. 2020. All Rights Reserved. -// Node module: @loopback/typeorm +// Node module: @loopback/mongoose // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT diff --git a/extensions/mongoose/src/__tests__/integration/application.ts b/extensions/mongoose/src/__tests__/integration/application.ts index 664574778986..b0fe34953e55 100644 --- a/extensions/mongoose/src/__tests__/integration/application.ts +++ b/extensions/mongoose/src/__tests__/integration/application.ts @@ -1,5 +1,5 @@ // Copyright IBM Corp. 2020. All Rights Reserved. -// Node module: @loopback/typeorm +// Node module: @loopback/mongoose // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT diff --git a/extensions/mongoose/src/__tests__/integration/rest-server.test.ts b/extensions/mongoose/src/__tests__/integration/rest-server.test.ts index 19b9d1d0b911..b1fce1029501 100644 --- a/extensions/mongoose/src/__tests__/integration/rest-server.test.ts +++ b/extensions/mongoose/src/__tests__/integration/rest-server.test.ts @@ -1,5 +1,5 @@ // Copyright IBM Corp. 2020. All Rights Reserved. -// Node module: @loopback/typeorm +// Node module: @loopback/mongoose // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT diff --git a/extensions/mongoose/src/__tests__/integration/schemas/event.schema.ts b/extensions/mongoose/src/__tests__/integration/schemas/event.schema.ts index 84ae21f17a55..3caf97017b20 100644 --- a/extensions/mongoose/src/__tests__/integration/schemas/event.schema.ts +++ b/extensions/mongoose/src/__tests__/integration/schemas/event.schema.ts @@ -1,5 +1,5 @@ // Copyright IBM Corp. 2020. All Rights Reserved. -// Node module: @loopback/typeorm +// Node module: @loopback/mongoose // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT diff --git a/extensions/mongoose/src/__tests__/integration/schemas/index.ts b/extensions/mongoose/src/__tests__/integration/schemas/index.ts index e63b1c2e58bd..ac57e319cb62 100644 --- a/extensions/mongoose/src/__tests__/integration/schemas/index.ts +++ b/extensions/mongoose/src/__tests__/integration/schemas/index.ts @@ -1,3 +1,8 @@ +// Copyright IBM Corp. 2020. All Rights Reserved. +// Node module: @loopback/mongoose +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + import {BindingKey} from '@loopback/core'; import {Document, Model} from 'mongoose'; import EventSchema, {EventInterface} from './event.schema'; diff --git a/extensions/mongoose/src/__tests__/integration/schemas/login-event.schema.ts b/extensions/mongoose/src/__tests__/integration/schemas/login-event.schema.ts index 1c8a32a3a484..574f56879685 100644 --- a/extensions/mongoose/src/__tests__/integration/schemas/login-event.schema.ts +++ b/extensions/mongoose/src/__tests__/integration/schemas/login-event.schema.ts @@ -1,5 +1,5 @@ // Copyright IBM Corp. 2020. All Rights Reserved. -// Node module: @loopback/typeorm +// Node module: @loopback/mongoose // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT diff --git a/extensions/mongoose/src/__tests__/integration/schemas/user.schema.ts b/extensions/mongoose/src/__tests__/integration/schemas/user.schema.ts index 0188c1c8c3b9..038689892481 100644 --- a/extensions/mongoose/src/__tests__/integration/schemas/user.schema.ts +++ b/extensions/mongoose/src/__tests__/integration/schemas/user.schema.ts @@ -1,5 +1,5 @@ // Copyright IBM Corp. 2020. All Rights Reserved. -// Node module: @loopback/typeorm +// Node module: @loopback/mongoose // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT diff --git a/extensions/mongoose/src/__tests__/integration/user.controller.ts b/extensions/mongoose/src/__tests__/integration/user.controller.ts index 029def7baffb..c5b22ab22fc6 100644 --- a/extensions/mongoose/src/__tests__/integration/user.controller.ts +++ b/extensions/mongoose/src/__tests__/integration/user.controller.ts @@ -1,5 +1,5 @@ // Copyright IBM Corp. 2020. All Rights Reserved. -// Node module: @loopback/typeorm +// Node module: @loopback/mongoose // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT diff --git a/extensions/mongoose/src/component.ts b/extensions/mongoose/src/component.ts index 74f6a76340e8..061b0adf9f8b 100644 --- a/extensions/mongoose/src/component.ts +++ b/extensions/mongoose/src/component.ts @@ -1,5 +1,5 @@ // Copyright IBM Corp. 2020. All Rights Reserved. -// Node module: @loopback/typeorm +// Node module: @loopback/mongoose // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT diff --git a/extensions/mongoose/src/keys.ts b/extensions/mongoose/src/keys.ts index e7900fc3f9b9..8344f4c1ea09 100644 --- a/extensions/mongoose/src/keys.ts +++ b/extensions/mongoose/src/keys.ts @@ -1,5 +1,5 @@ // Copyright IBM Corp. 2020. All Rights Reserved. -// Node module: @loopback/typeorm +// Node module: @loopback/mongoose // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT diff --git a/extensions/mongoose/src/types.ts b/extensions/mongoose/src/types.ts index c30e42c83c23..ab9dc6e12f1b 100644 --- a/extensions/mongoose/src/types.ts +++ b/extensions/mongoose/src/types.ts @@ -1,5 +1,5 @@ // Copyright IBM Corp. 2020. All Rights Reserved. -// Node module: @loopback/typeorm +// Node module: @loopback/mongoose // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT