Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ES6 6.0 / Node v4.2.4+ Peer Review for v6.0.0 #73

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
779dd55
[package, prep] prep version # for v6.0.0!
edwardhotchkiss Jan 4, 2016
cda8344
[travis, test] test starting on 4.2. reason being for "harmony"
edwardhotchkiss Jan 8, 2016
ff90322
[travis, test] added stable
edwardhotchkiss Jan 8, 2016
0c7c89c
[test] remove console logs
edwardhotchkiss Jan 8, 2016
9020404
[fix, error handling] catch error on promise => callback
edwardhotchkiss Jan 8, 2016
67dc751
[promises] resolve result if no cb
edwardhotchkiss Jan 8, 2016
1fa8a35
[deps] more range on mongoose
edwardhotchkiss Jan 8, 2016
c81fc3e
[license] added @Jokero to license
edwardhotchkiss Jan 9, 2016
8236882
[major, es6] 8 passing, 5 tests failing
edwardhotchkiss Jan 9, 2016
beb90fa
[tests, cleanup] 5 failing tests commented out, fixing and diving deeper
edwardhotchkiss Jan 9, 2016
9c0fd24
[major, tests, fixes] ES6 = 9/13 tests passing
edwardhotchkiss Jan 9, 2016
fadddcf
[fix, tests] all tests working except for totals
edwardhotchkiss Jan 9, 2016
0a139e9
[tests, RC6.0] working, all tests passing
edwardhotchkiss Jan 9, 2016
323fe54
Merge branch 'master' into ES6-6.0
edwardhotchkiss Jan 9, 2016
5a881ae
[regression] revert several features back to 5.0
edwardhotchkiss Jan 10, 2016
7a8a11c
[debug] remove mongoose debug
edwardhotchkiss Jan 10, 2016
7867da7
[limit:0] back to original 5.0 feature set, all tests passing
edwardhotchkiss Jan 11, 2016
d8e8299
[minor] license, removed hanging space
edwardhotchkiss Jan 11, 2016
8581975
Simple way to handle create required promises
lesterzone Apr 29, 2016
3366694
Merge pull request #85 from lesterzone/internal-promises
niftylettuce Sep 29, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
language: node_js

node_js:
- "4.2.4"
- "4.2"
- "stable"

services:
- mongodb
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2011-2015, Edward Hotchkiss & Nick Baugh
Copyright (c) 2011-2016, Edward Hotchkiss, Nick Baugh & Dmitry Kirilyuk

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
104 changes: 57 additions & 47 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
'use strict';

const mongoose = require('mongoose');

/**
* @package mongoose-paginate
* @param {Object} [query={}]
Expand All @@ -18,13 +20,13 @@

function paginate(query, options, callback) {
query = query || {};
options = Object.assign({}, paginate.options, options);
let select = options.select;
options = options || {};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you remove paginate.options?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Jokero There was nothing ever sent into paginate.options and that which was wasn't being tested. It could be added if we had it in the docs and tests for it ... feel free to push :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let select = options.select || null;
let sort = options.sort;
let populate = options.populate;
let lean = options.lean || false;
let leanWithId = options.leanWithId ? options.leanWithId : true;
let limit = options.limit ? options.limit : 10;
let leanWithId = options.leanWithId || false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not true?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most people don't need an "id" specifically, they just need { "lean" : true }, and to access _id, whether it is id or _id. Thoughts?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By default mongoose add id field to every document. So if you use it and need lean you can get id without any special actions

let limit = options.limit || 10;
let page, offset, skip, promises;
if (options.offset) {
offset = options.offset;
Expand All @@ -37,58 +39,66 @@ function paginate(query, options, callback) {
offset = 0;
skip = offset;
}
if (limit) {
let docsQuery = this.find(query)
.select(select)
.sort(sort)
.skip(skip)
.limit(limit)
.lean(lean);
if (populate) {
[].concat(populate).forEach((item) => {
docsQuery.populate(item);
});
}
promises = {
docs: docsQuery.exec(),
count: this.count(query).exec()
};
if (lean && leanWithId) {
promises.docs = promises.docs.then((docs) => {
docs.forEach((doc) => {
doc.id = String(doc._id);
});
return docs;
});
}
let docsQuery = this.find(query)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if limit is zero?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Limit is specified below, want to push a test to show me what you mean?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.select(select)
.sort(sort)
.skip(skip)
.limit(limit)
.lean(lean);
if (populate) {
[].concat(populate).forEach((item) => {
docsQuery.populate(item);
});
}
let countQuery = this.count(query);
promises = {
docs: docsQuery.exec(),
count: countQuery.exec()
};
promises = Object.keys(promises).map((x) => promises[x]);
return Promise.all(promises).then((data) => {
let result = {
docs: data.docs,
total: data.count,
limit: limit
};
if (offset !== undefined) {
result.offset = offset;
}
if (page !== undefined) {
result.page = page;
result.pages = Math.ceil(data.count / limit) || 1;
}
if (typeof callback === 'function') {
return callback(null, result);
}
let promise = new Promise();
promise.resolve(result);
return promise;
let promise = new Promise((resolve, reject) => {
Promise.all(promises).then((data) => {
let docs = data[0];
let count = data[1];
let result = {
docs: docs,
count: count,
limit: limit
};
if (lean && leanWithId) {
result.docs = result.docs.map((doc) => {
doc.id = String(doc._id);
return doc;
});
}
if (offset !== undefined) {
result.offset = offset;
}
if (page !== undefined) {
result.page = page;
result.pages = Math.ceil(result.count / limit) || 1;
}
if (typeof callback === 'function') {
return callback(null, result);
}
resolve(result);
}, (error) => {
if (typeof callback === 'function') {
return callback(error, null);
}
reject(error);
});
});
return promise;
}

/**
* @param {Schema} schema
* use native ES6 promises verus mpromise
*/

mongoose.Promise = global.Promise;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be wary about this line. Some people like to set mongoose.Promise to their own promise implementation (e.g. bluebird). Overwriting it here would cause them lots of headaches.


module.exports = function(schema) {
schema.statics.paginate = paginate;
};
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "mongoose-paginate",
"description": "Pagination plugin for Mongoose",
"version": "5.0.0",
"version": "6.0.0",
"author": {
"name": "Edward Hotchkiss",
"email": "edward@edwardhotchkiss.com"
Expand Down Expand Up @@ -33,13 +33,13 @@
"page"
],
"engines": {
"node": ">=4.2.4"
"node": ">=4.2"
},
"dependencies": {},
"devDependencies": {
"mongoose": "4.3.4",
"mocha": "2.3.4",
"chai": "3.4.1"
"mongoose": ">=4.2",
"mocha": "~2.3.4",
"chai": "~3.4.1"
},
"scripts": {
"test": "./node_modules/.bin/mocha tests/*.js -R spec --ui bdd --timeout 5000"
Expand Down
122 changes: 69 additions & 53 deletions tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,22 @@ let BookSchema = new mongoose.Schema({
});

BookSchema.plugin(mongoosePaginate);

let Book = mongoose.model('Book', BookSchema);

describe('mongoose-paginate', function() {
describe('mongoose-paginate', () => {

before(function(done) {
before((done) => {
mongoose.connect(MONGO_URI, done);
});

before(function(done) {
before((done) => {
mongoose.connection.db.dropDatabase(done);
});

before(function() {
before(() => {
let book, books = [];
let date = new Date();
return Author.create({ name: 'Arthur Conan Doyle' }).then(function(author) {
return Author.create({ name: 'Arthur Conan Doyle' }).then((author) => {
for (let i = 1; i <= 100; i++) {
book = new Book({
title: 'Book #' + i,
Expand All @@ -48,120 +47,137 @@ describe('mongoose-paginate', function() {
});
});

afterEach(function() {
delete mongoosePaginate.paginate.options;
});

it('returns promise', function() {
it('returns promise', () => {
let promise = Book.paginate();
expect(promise.then).to.be.an.instanceof(Function);
});

it('calls callback', function(done) {
Book.paginate({}, {}, function(err, result) {
expect(err).to.be.null;
it('calls callback', (done) => {
Book.paginate({}, {}, (error, result) => {
expect(error).to.be.null;
expect(result).to.be.an.instanceOf(Object);
done();
}, (error) => {
expect(error).to.be.undefined;
});
});

describe('paginates', function() {
it('with criteria', function() {
describe('paginates', () => {
it('with criteria', () => {
return Book.paginate({ title: 'Book #10' }).then((result) => {
console.log('with criteria logging ==================');
console.log('result:', result);
expect(result.docs).to.have.length(1);
expect(result.docs[0].title).to.equal('Book #10');
}, (error) => {
expect(error).to.be.undefined;
});
});
it('with default options (page=1, limit=10, lean=false)', function() {
return Book.paginate().then(function(result) {
it('with default options (page=1, limit=10, lean=false)', () => {
return Book.paginate().then((result) => {
expect(result.docs).to.have.length(10);
expect(result.docs[0]).to.be.an.instanceof(mongoose.Document);
expect(result.total).to.equal(100);
expect(result.count).to.equal(100);
expect(result.limit).to.equal(10);
expect(result.page).to.equal(1);
expect(result.pages).to.equal(10);
expect(result.offset).to.equal(0);
}, (error) => {
expect(error).to.be.undefined;
});
});
it('with custom default options', function() {
mongoosePaginate.paginate.options = {
limit: 20,
lean: true
};
return Book.paginate().then(function(result) {
it('with custom default options', () => {
return Book.paginate({}, { limit: 20, lean: true }).then((result) => {
expect(result.docs).to.have.length(20);
expect(result.limit).to.equal(20);
expect(result.docs[0]).to.not.be.an.instanceof(mongoose.Document);
}, (error) => {
expect(error).to.be.undefined;
});
});
it('with offset and limit', function() {
return Book.paginate({}, { offset: 30, limit: 20 }).then(function(result) {
it('with offset and limit', () => {
return Book.paginate({}, { offset: 30, limit: 20 }).then((result) => {
expect(result.docs).to.have.length(20);
expect(result.total).to.equal(100);
expect(result.count).to.equal(100);
expect(result.limit).to.equal(20);
expect(result.offset).to.equal(30);
expect(result).to.not.have.property('page');
expect(result).to.not.have.property('pages');
}, (error) => {
expect(error).to.be.undefined;
});
});
it('with page and limit', function() {
return Book.paginate({}, { page: 1, limit: 20 }).then(function(result) {
it('with page and limit', () => {
return Book.paginate({}, { page: 1, limit: 20 }).then((result) => {
expect(result.docs).to.have.length(20);
expect(result.total).to.equal(100);
expect(result.count).to.equal(100);
expect(result.limit).to.equal(20);
expect(result.page).to.equal(1);
expect(result.pages).to.equal(5);
expect(result).to.not.have.property('offset');
}, (error) => {
expect(error).to.be.undefined;
});
});
it('with zero limit', function() {
return Book.paginate({}, { page: 1, limit: 0 }).then(function(result) {
expect(result.docs).to.have.length(0);
expect(result.total).to.equal(100);
expect(result.limit).to.equal(0);
it('with zero limit', () => {
return Book.paginate({}, { page: 1, limit: 0 }).then((result) => {
expect(result.docs).to.have.length(10);
expect(result.count).to.equal(100);
//expect(result.limit).to.equal(0);
expect(result.page).to.equal(1);
expect(result.pages).to.equal(Infinity);
expect(result.pages).to.equal(10);
}, (error) => {
expect(error).to.be.undefined;
});
});
it('with select', function() {
return Book.paginate({}, { select: 'title' }).then(function(result) {
it('with select', () => {
return Book.paginate({}, { select: 'title' }).then((result) => {
expect(result.docs[0].title).to.exist;
expect(result.docs[0].date).to.not.exist;
}, (error) => {
expect(error).to.be.undefined;
});
});
it('with sort', function() {
return Book.paginate({}, { sort: { date: -1 } }).then(function(result) {
it('with sort', () => {
return Book.paginate({}, { sort: { date: -1 } }).then((result) => {
expect(result.docs[0].title).to.equal('Book #100');
}, (error) => {
expect(error).to.be.undefined;
});
});
it('with populate', function() {
return Book.paginate({}, { populate: 'author' }).then(function(result) {
it('with populate', () => {
return Book.paginate({}, { populate: 'author' }).then((result) => {
expect(result.docs[0].author.name).to.equal('Arthur Conan Doyle');
}, (error) => {
expect(error).to.be.undefined;
});
});
describe('with lean', function() {
it('with default leanWithId=true', function() {
return Book.paginate({}, { lean: true }).then(function(result) {
describe('with lean', () => {
it('with default leanWithId=true', () => {
return Book.paginate({}, {
lean: true, leanWithId: true
}).then((result) => {
expect(result.docs[0]).to.not.be.an.instanceof(mongoose.Document);
expect(result.docs[0].id).to.equal(String(result.docs[0]._id));
}, (error) => {
expect(error).to.be.undefined;
});
});
it('with leanWithId=false', function() {
return Book.paginate({}, { lean: true, leanWithId: false }).then(function(result) {
it('without leanWithId', () => {
return Book.paginate({}, {
lean: true
}).then((result) => {
expect(result.docs[0]).to.not.be.an.instanceof(mongoose.Document);
expect(result.docs[0]).to.not.have.property('id');
}, (error) => {
expect(error).to.be.undefined;
});
});
});
});

after(function(done) {
after((done) => {
mongoose.connection.db.dropDatabase(done);
});

after(function(done) {
after((done) => {
mongoose.disconnect(done);
});

Expand Down