diff --git a/README.md b/README.md index 3684796..488d050 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ const { Pagination } = require('@limit0/mongoose-graphql-pagination'); ``` Use the class constructor to configure the settings for the paginated query. -#### constructor(Model, { criteria = {}, pagination = {}, sort = {} }, options = {}) +#### constructor(Model, { criteria = {}, pagination = {}, sort = {}, projection }, options = {}) `Model`: The Mongoose model instance to query. _Required._ `criteria`: A query criteria object to apply to the paginated query. Can be any MongoDB query. For example: `{ deleted: false }` or `{ age: { $gt: 30 } }`. Optional. @@ -25,6 +25,8 @@ Use the class constructor to configure the settings for the paginated query. `sort`: Specifies the sort options. The `field` property specifies the field to sort by, and the order defines the direction. For example: `{ field: 'name', order: -1 }` would sort the edges by name, descending. By default the edges are sorted by ID, ascending. Optional. +`projection`: Specifies the fields to return from the database. For example: `{ field: 1 }` or `{ field: 0 }` would include or exclude the specified field, respectively. If left `undefined`, or as an empty object, all fields will be returned (which is the default behavior). Optional. + `options`: Specifies additional configuration options, such as default limit, max limit, sort collation, and sort created field. Complete example: diff --git a/src/pagination.js b/src/pagination.js index cc5f374..c909c92 100644 --- a/src/pagination.js +++ b/src/pagination.js @@ -17,9 +17,15 @@ class Pagination { * @param {object} params.sort The sort parameters * @param {string} params.sort.field The sort field name. * @param {string} params.sort.order The sort order. Either 1/-1 or asc/desc. + * @param {?object} params.projection The field projection (fields to return). * @param {object} options Additional sort and limit options. See the corresponding classes. */ - constructor(Model, { criteria = {}, pagination = {}, sort = {} } = {}, options = {}) { + constructor(Model, { + criteria = {}, + pagination = {}, + sort = {}, + projection, + } = {}, options = {}) { this.promises = {}; // Set the Model to use for querying. @@ -36,6 +42,9 @@ class Pagination { // Set the sort criteria. const { field, order } = sort; this.sort = new Sort(field, order, options.sort); + + // Set the projection. + this.projection = projection; } /** @@ -63,7 +72,7 @@ class Pagination { getEdges() { const run = async () => { const criteria = await this.getQueryCriteria(); - const docs = await this.Model.find(criteria) + const docs = await this.Model.find(criteria, this.projection) .sort(this.sort.value) .limit(this.first.value) .collation(this.sort.collation) diff --git a/test/docker-compose.yml b/test/docker-compose.yml index 1d5369d..f334d46 100644 --- a/test/docker-compose.yml +++ b/test/docker-compose.yml @@ -20,7 +20,7 @@ services: volumes: - mongodb:/data/db elasticsearch: - image: docker.elastic.co/elasticsearch/elasticsearch:6.2.4 + image: docker.elastic.co/elasticsearch/elasticsearch-oss:6.2.4 environment: - cluster.name=docker-cluster - bootstrap.memory_lock=true diff --git a/test/pagination.spec.js b/test/pagination.spec.js index 9e0da58..0bce735 100644 --- a/test/pagination.spec.js +++ b/test/pagination.spec.js @@ -227,6 +227,31 @@ describe('pagination', function() { sinon.assert.calledOnce(Pagination.prototype.getQueryCriteria); }); + it('should apply the projection', async function() { + const pagination = { first: 10 }; + const projection = { name: 1 }; + const paginated = new Pagination(Model, { pagination, projection }); + const r1 = await paginated.getEdges(); + r1.forEach((edge, i) => { + const { node } = edge; + expect(node.deleted).to.be.undefined; + expect(node.name).to.equal(data[i].name); + }); + }); + + [{}, undefined].forEach((projection) => { + it(`should return all fields when the projection is '${projection}'`, async function() { + const pagination = { first: 10 }; + const paginated = new Pagination(Model, { pagination, projection }); + const r1 = await paginated.getEdges(); + r1.forEach((edge, i) => { + const { node } = edge; + expect(node.deleted).to.equal(data[i].deleted); + expect(node.name).to.equal(data[i].name); + }); + }); + }); + }); describe('#findCursorModel', function() {