From e761fcf18266417979960aba4f1301e7cb884219 Mon Sep 17 00:00:00 2001 From: manuel-di-iorio Date: Sun, 14 Jul 2019 09:41:47 +0200 Subject: [PATCH] V2.0 --- .gitignore | 4 +- .npmignore | 2 + LICENSE | 42 +++--- README.md | 140 ++++++++++---------- index.test.js | 346 +++++++++++++++++++++++++------------------------- package.json | 10 +- 6 files changed, 278 insertions(+), 266 deletions(-) create mode 100644 .npmignore diff --git a/.gitignore b/.gitignore index 4976080..40b878d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1 @@ -node_modules -npm-debug.log -.idea/ \ No newline at end of file +node_modules/ \ No newline at end of file diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..de625be --- /dev/null +++ b/.npmignore @@ -0,0 +1,2 @@ +node_modules +npm-debug.log \ No newline at end of file diff --git a/LICENSE b/LICENSE index eb209d4..e79a015 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -The MIT License (MIT) - -Copyright (c) 2016-2017 Manuel Di Iorio - -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 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. +The MIT License (MIT) + +Copyright (c) 2016-2019 Manuel Di Iorio + +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 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/README.md b/README.md index 6c024a7..d482a6d 100644 --- a/README.md +++ b/README.md @@ -1,64 +1,76 @@ -# Mongoose FindOrCreate() -## Extend the mongoose schemas with a findOrCreate() plugin. Essentially, if a document is not found, will be atomically created or (if specified) updated - -### Install it with: - - npm i find-or-create - or - git clone https://github.com/manuel-di-iorio/find-or-create.git - -### **Examples**: - -```javascript -yourSchema.statics.findOrCreate = require("find-or-create"); -YourModel = mongoose.model("yourSchema", yourSchema); - -YourModel.findOrCreate({_id: myID}, {apples: 2}, (err, result) => { - if (err) return console.error(err); - console.log(result.doc); // the document itself - console.log(result.isNew); // if the document has just been created -}); -``` - -Example upserting the document and using the promise return: - -```javascript -Model.findOrCreate({_id: myID, apples: 2}, {apples: 5}, {upsert: true}) -.then((result) => { - console.log(result.doc); - console.log(result.isNew); -}) -.catch(console.error); -``` - - ---- -## API: - -```javascript -MongooseModel.findOrCreate(query, doc, [options, callback]); -``` -If you don't specify a callback, it will be returned a promise. - ---- - -- **doc** is the document that will be inserted if the document based on your **query** is not found, otherwise the record will be updated with the new document (if upsert is enabled). - -- **options** is an optional object that will be passed to the underlying mongoose 'findOrCreate' method. - - You can find the possible options here: http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate - - Set `{upsert: true}` to update the document when it already exists, otherwhise it will be only inserted when not found - - ---- -## Test with - -```bash -npm test -``` - ---- -## License - -MIT +# FindOrCreate v2.0 for Mongoose +### Extend the mongoose schemas with a findOrCreate() plugin. Essentially, if a document is not found, will be atomically created or (if specified) updated + +### Install it with: + + npm i find-or-create + +### **Examples**: + +```javascript +yourSchema.statics.findOrCreate = require("find-or-create"); +YourModel = mongoose.model("yourSchema", yourSchema); + +YourModel.findOrCreate({_id: myID}, {apples: 2}, (err, result) => { + if (err) return console.error(err); + console.log(result.doc); // the document itself + console.log(result.isNew); // if the document has just been created +}); +``` + +Example upserting the document and using the promise return: + +```javascript +Model.findOrCreate({_id: myID, apples: 2}, {apples: 5}, {upsert: true}) +.then((result) => { + console.log(result.doc); + console.log(result.isNew); +}) +.catch(console.error); +``` + +## Note: + +As of Mongoose v5, to use this module you need to set the global option `useFindAndModify` to _false_, otherwise a warning will be logged. + +Example: +``` +mongoose.connect(uri, { useFindAndModify: false }); +``` + +## Upgrading to Mongoose 5: + +The latest v2.0 of this plugin is compatible with Mongoose 5.x. +If you need retro-compatibility with Mongoose 4.x, please install the version 1.1 of this module. + + +--- +## API: + +```javascript +MongooseModel.findOrCreate(query, doc, [options, callback]); +``` +If you don't specify a callback, it will be returned a promise. + +--- + +- **doc** is the document that will be inserted if the document based on your **query** is not found, otherwise the record will be updated with the new document (if upsert is enabled). + +- **options** is an optional object that will be passed to the underlying mongoose 'findOrCreate' method. + + You can find the possible options here: http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate + + Set `{upsert: true}` to update the document when it already exists, otherwhise it will be only inserted when not found + + +--- +## Test with + +```bash +npm test +``` + +--- +## License + +MIT diff --git a/index.test.js b/index.test.js index e0fe523..7de6916 100644 --- a/index.test.js +++ b/index.test.js @@ -1,173 +1,173 @@ -const findOrCreate = require('.'); -const assert = require('assert'); -const mongoose = require('mongoose'); -mongoose.Promise = global.Promise; - -const db = process.env.db || "mongodb://localhost:27017/findOrCreateTest"; - -/* Defining the Test model */ -const schema = mongoose.Schema({ - name: String, - age: Number -}); - -schema.statics.findOrCreate = findOrCreate; -const TestModel = mongoose.model("Test", schema); - -// Connect to the database before everything -before(function(done) { - mongoose.connection - .on('error', done) - .once('open', done); - - mongoose.connect(db); -}); - -// Clear the test collection before each new test and add a new test record -beforeEach(function(done) { - TestModel.remove({}, () => { - TestModel.create({name: "Conan", age: 28}, done); - }); -}); - -// Start the tests -describe("Basic tests", function() { - it('should does not throw an expection, when callback and options are not provided', function(done) { - TestModel.findOrCreate({}, null).exec(done); - }); - - it('should catch an error when an incorrect number of arguments are passed', function(done) { - assert.throws(function() { - TestModel.findOrCreate(); - }, Error); - - assert.throws(function() { - TestModel.findOrCreate({}); - }, Error); - - done() - }); - - it('should catch a promise error when an issue happens with the query', function(done) { - TestModel.findOrCreate({"$thisOperatorDoesNotExists": true}, null) - .catch((err) => done(null)); - }); -}); - -/* No upserting tests */ -describe("Find or create without upserting", function() { - it('should returns the document found, using the callback style', function(done) { - const doc = {name: "Conan"}; - - TestModel.findOrCreate(doc, null, (err, result) => { - assert.ifError(err); - assert(result.doc); - assert.strictEqual(result.isNew, false); - done(); - }); - }); - - it('should returns the document found, using the promise return', function(done) { - const doc = {name: "Conan"}; - - TestModel.findOrCreate(doc, null) - .catch(assert.ifError) - .then((result) => { - assert(result.doc); - assert.strictEqual(result.isNew, false); - done(); - }); - }); - - it('should returns the document found, using the exec() method', function(done) { - const doc = {name: "Conan"}; - - TestModel.findOrCreate(doc, null) - .exec((err, result) => { - assert.ifError(err); - assert(result.doc); - assert.strictEqual(result.isNew, false); - done(); - }); - }); - - it('should returns the document found, only selecting the "age" field', function(done) { - const doc = {name: "Conan"}; - - TestModel.findOrCreate(doc, null, {fields: "age"}, (err, result) => { - assert.ifError(err); - assert.ifError(result.doc.name); - assert.strictEqual(result.isNew, false); - done(); - }); - }); - - it('should returns the new created document', function(done) { - const doc = {name: "Barbarus"}; - - TestModel.findOrCreate(doc, doc, (err, result) => { - assert.ifError(err); - assert.equal(result.doc.name, "Barbarus"); - assert.strictEqual(result.isNew, true); - done(); - }); - }); -}); - - -/* Upserting tests */ -describe("Find or create with upserting", function() { - it('should returns the document found and updated', function(done) { - const query = {name: "Conan"}; - const doc = {name: "Marcus"}; - - TestModel.findOrCreate(query, doc, {upsert: true}, (err, result) => { - assert.ifError(err); - assert.equal(result.doc.name, "Marcus"); - assert.strictEqual(result.isNew, false); - done(); - }); - }); - - it('should creates a new document', function(done) { - const doc = {name: "Marcus"}; - - TestModel.findOrCreate(doc, doc, {upsert: true}, (err, result) => { - assert.ifError(err); - assert(result.doc); - assert.strictEqual(result.isNew, true); - done(); - }); - }); - - it('should creates a new document and use the query projection option', function(done) { - const doc = {name: "Marcus", age: 17}; - const options = { - upsert: true, - fields: "age" - }; - - TestModel.findOrCreate(doc, doc, options, (err, result) => { - assert.ifError(err); - assert.ifError(result.doc.name); - assert.strictEqual(result.isNew, true); - done(); - }); - }); - - it('should updates a document, but returning the old record', function(done) { - const query = {name: "Conan"}; - const doc = {name: "Marcus"}; - const options = { - upsert: true, - new: false - }; - - TestModel.findOrCreate(query, doc, options, (err, result) => { - assert.ifError(err); - assert.equal(result.doc.name, "Conan"); - assert.strictEqual(result.isNew, false); - done(); - }); - }); -}); +const findOrCreate = require('.'); +const assert = require('assert'); +const mongoose = require('mongoose'); +mongoose.Promise = global.Promise; + +const db = process.env.db || "mongodb://localhost:27017/findOrCreateTest"; + +/* Defining the Test model */ +const schema = mongoose.Schema({ + name: String, + age: Number +}); + +schema.statics.findOrCreate = findOrCreate; +const TestModel = mongoose.model("Test", schema); + +// Connect to the database before everything +before(function (done) { + mongoose.connection + .on('error', done) + .once('open', done); + + mongoose.connect(db, { useNewUrlParser: true, useFindAndModify: false }); +}); + +// Clear the test collection before each new test and add a new test record +beforeEach(function (done) { + TestModel.deleteMany({}, () => { + TestModel.create({ name: "Conan", age: 28 }, done); + }); +}); + +// Start the tests +describe("Basic tests", function () { + it('should does not throw an expection, when callback and options are not provided', function (done) { + TestModel.findOrCreate({}, null).exec(done); + }); + + it('should catch an error when an incorrect number of arguments are passed', function (done) { + assert.throws(function () { + TestModel.findOrCreate(); + }, Error); + + assert.throws(function () { + TestModel.findOrCreate({}); + }, Error); + + done() + }); + + it('should catch a promise error when an issue happens with the query', function (done) { + TestModel.findOrCreate({ "$thisOperatorDoesNotExists": true }, null) + .catch((err) => done(null)); + }); +}); + +/* No upserting tests */ +describe("Find or create without upserting", function () { + it('should returns the document found, using the callback style', function (done) { + const doc = { name: "Conan" }; + + TestModel.findOrCreate(doc, null, (err, result) => { + assert.ifError(err); + assert(result.doc); + assert.strictEqual(result.isNew, false); + done(); + }); + }); + + it('should returns the document found, using the promise return', function (done) { + const doc = { name: "Conan" }; + + TestModel.findOrCreate(doc, null) + .catch(assert.ifError) + .then((result) => { + assert(result.doc); + assert.strictEqual(result.isNew, false); + done(); + }); + }); + + it('should returns the document found, using the exec() method', function (done) { + const doc = { name: "Conan" }; + + TestModel.findOrCreate(doc, null) + .exec((err, result) => { + assert.ifError(err); + assert(result.doc); + assert.strictEqual(result.isNew, false); + done(); + }); + }); + + it('should returns the document found, only selecting the "age" field', function (done) { + const doc = { name: "Conan" }; + + TestModel.findOrCreate(doc, null, { fields: "age" }, (err, result) => { + assert.ifError(err); + assert.ifError(result.doc.name); + assert.strictEqual(result.isNew, false); + done(); + }); + }); + + it('should returns the new created document', function (done) { + const doc = { name: "Barbarus" }; + + TestModel.findOrCreate(doc, doc, (err, result) => { + assert.ifError(err); + assert.equal(result.doc.name, "Barbarus"); + assert.strictEqual(result.isNew, true); + done(); + }); + }); +}); + + +/* Upserting tests */ +describe("Find or create with upserting", function () { + it('should returns the document found and updated', function (done) { + const query = { name: "Conan" }; + const doc = { name: "Marcus" }; + + TestModel.findOrCreate(query, doc, { upsert: true }, (err, result) => { + assert.ifError(err); + assert.equal(result.doc.name, "Marcus"); + assert.strictEqual(result.isNew, false); + done(); + }); + }); + + it('should creates a new document', function (done) { + const doc = { name: "Marcus" }; + + TestModel.findOrCreate(doc, doc, { upsert: true }, (err, result) => { + assert.ifError(err); + assert(result.doc); + assert.strictEqual(result.isNew, true); + done(); + }); + }); + + it('should creates a new document and use the query projection option', function (done) { + const doc = { name: "Marcus", age: 17 }; + const options = { + upsert: true, + fields: "age" + }; + + TestModel.findOrCreate(doc, doc, options, (err, result) => { + assert.ifError(err); + assert.ifError(result.doc.name); + assert.strictEqual(result.isNew, true); + done(); + }); + }); + + it('should updates a document, but returning the old record', function (done) { + const query = { name: "Conan" }; + const doc = { name: "Marcus" }; + const options = { + upsert: true, + new: false + }; + + TestModel.findOrCreate(query, doc, options, (err, result) => { + assert.ifError(err); + assert.equal(result.doc.name, "Conan"); + assert.strictEqual(result.isNew, false); + done(); + }); + }); +}); diff --git a/package.json b/package.json index a64e93f..3ecbf9e 100644 --- a/package.json +++ b/package.json @@ -8,8 +8,8 @@ "dependencies": {}, "description": "Moongose find or create schema plugin", "devDependencies": { - "mocha": "3.2.0", - "mongoose": "4.8.1" + "mocha": "^3.2.0", + "mongoose": "^5.6.4" }, "keywords": [ "mongoose", @@ -22,8 +22,8 @@ "main": "index.js", "maintainers": [ { - "name": "xeryan", - "email": "xeryan@gmail.com" + "name": "manuel-di-iorio", + "email": "manuel.diiorio.mail@gmail.com" } ], "name": "find-or-create", @@ -34,5 +34,5 @@ "scripts": { "test": "node_modules/.bin/mocha index.test" }, - "version": "1.1.0" + "version": "2.0.0" }