hapi-bookshelf-total-count

5.0.0 • Public • Published

Hapi Bookshelf Total Count

A Hapi plugin used with Bookshelf models to calculate the total number of records that match a query and appends it to the response. It can be used to calculate an absolute total count or a filtered total count.

Absolute Total Count

Appends the total_count of all instances of the model when the query contains include[]=total_count, regardless of query filter.

Register the Plugin

const Hapi = require('hapi');

const server = new Hapi.Server();

server.register([
  require('hapi-bookshelf-total-count')
], (err) => {

});

Configure the endpoint

const Bookshelf = require('bookshelf')(require('knex')(config));

const Book = Bookshelf.Model.extend({ tableName: 'books' });

server.route({
  method: 'GET',
  path: '/books',
  config: {
    plugins: {
      totalCount: { model: Book }
    },
    handler: (request, reply) => {
      return new Book().fetchAll()
      .then((books) => {
        reply({ data: books });
      });
    }
  }
});

Request

$ curl -g GET "https://YOUR_DOMAIN/books?include[]=total_count"

Response

{
  "data": [...],
  "total_count": 100
}

Filtered Total Count

Appends the total_count of a subset of model instances that match a query filter when the query contains include[]=total_count. In order to calculate a filtered total_count, you'll need to use this plugin in conjunction with hapi-query-filter and define a filter function on each model that will be filtered. The model's filter function is intended to be reused by the list endpoint.

Register the Plugin

const Hapi = require('hapi');

const server = new Hapi.Server();

server.register([
  require('hapi-bookshelf-total-count'),
  {
    register: require('hapi-query-filter'),
    options: { ignoredKeys: ['include'] }
  }
], (err) => {

});

Define a filter function on the model

// models/book.js

const Bookshelf = require('bookshelf')(require('knex')(config));

module.exports = Bookshelf.Model.extend({
  tableName: 'books'
  /**
   * @param {Object} filter - from request.query.filter
   * @param {Object} [credentials] - from request.auth.credentials
   * You may add any additional parameters after filter and credentials
   */
  filter: function (filter, credentials) {
    return this.query((qb) => {
      qb.where('deleted', false);

      if (filter.year) {
        qb.where('year', filter.year);
      }
    });
  }
});

Configure the endpoint

const Book = require('../models/book');

server.route({
  method: 'GET',
  path: '/books',
  config: {
    plugins: {
      queryFilter: { enabled: true },
      totalCount: { model: Book }
    },
    handler: (request, reply) => {
      return new Book().filter(request.query.filter, request.auth.credentials)
      .fetchAll()
      .then((books) => {
        reply({ data: books });
      });
    }
  }
});

Request

$ curl -g GET "https://YOUR_DOMAIN/books?year=1984&include[]=total_count"

Response

{
  "data": [...],
  "total_count": 20
}

Approximate Total Count

Appends the approximate_count which is a cached total count. Currently only Redis is supported as a cache. Both requests that fetch the total_count and approximate_count will prime the cache.

Register the Plugin

const Bluebird = require('bluebird');
const Hapi     = require('hapi');
const Redis    = require('redis');

Bluebird.promisifyAll(Redis.RedisClient.prototype);
Bluebird.promisifyAll(Redis.Multi.prototype);

const RedisClient = Redis.createClient({
  port: '6379',
  host: 'localhost'
});

const server = new Hapi.Server();

server.register([
  {
    register: require('hapi-bookshelf-total-count'),
    options: {
      redisClient: RedisClient,
      ttl: (count) => count / 10, // a function which returns the TTL to set for the cached approximate count
      uniqueKey: (request) => request.auth.credentials.api_key // an optional function to add additional uniqueness to the cache key
    }
  }
], (err) => {

});

Define a filter function on the model

// models/book.js

const Bookshelf = require('bookshelf')(require('knex')(config));

module.exports = Bookshelf.Model.extend({
  tableName: 'books'
  /**
   * @param {Object} filter - from request.query.filter
   * @param {Object} [credentials] - from request.auth.credentials
   * You may add any additional parameters after filter and credentials
   */
  filter: function (filter, credentials) {
    return this.query((qb) => {
      qb.where('deleted', false);

      if (filter.year) {
        qb.where('year', filter.year);
      }
    });
  }
});

Configure the endpoint

const Book = require('../models/book');

server.route({
  method: 'GET',
  path: '/books',
  config: {
    plugins: {
      queryFilter: { enabled: true },
      totalCount: { model: Book }
    },
    handler: (request, reply) => {
      return new Book().filter(request.query.filter, request.auth.credentials)
      .fetchAll()
      .then((books) => {
        reply({ data: books });
      });
    }
  }
});

include option - use this option to restrict counting to only the included items in the list

const Book = require('../models/book');

server.route({
  method: 'GET',
  path: '/books',
  config: {
    plugins: {
      queryFilter: { enabled: true },
      totalCount: { 
        include: ['approximate'],
        model: Book 
      }
    },
    handler: (request, reply) => {
      return new Book().filter(request.query.filter, request.auth.credentials)
      .fetchAll()
      .then((books) => {
        reply({ data: books });
      });
    }
  }
});

Request

$ curl -g GET "https://YOUR_DOMAIN/books?year=1984&include[]=approximate_count"

Response

{
  "data": [...],
  "approximate_count": 20
}

/hapi-bookshelf-total-count/

    Package Sidebar

    Install

    npm i hapi-bookshelf-total-count

    Weekly Downloads

    5

    Version

    5.0.0

    License

    MIT

    Unpacked Size

    31.8 kB

    Total Files

    26

    Last publish

    Collaborators

    • aperezlob
    • hpelletier
    • zrivest-lob
    • mananshah78424
    • rromit.lob
    • joemeers82
    • vikita.bhandari
    • matthew.burke
    • jarrod-lob
    • klaus.opreschko.lob
    • pkamatlob
    • philthelobster
    • ngnasr1123_lob
    • jayteelob
    • erik.forsman-lob
    • jkleung11
    • tanya.sah
    • hunteryoakum
    • rdimouro7373
    • lobstertroy
    • joshnkoy
    • haroutrs
    • kjones_lob
    • eamon-barisone
    • nathanielwaldschmidtlob
    • zach.reed
    • kencrim
    • jorgelob
    • nick-place-lob
    • andrew.guterres
    • juan.frissdekereki
    • mmorgan-lob
    • vmangwani
    • sachinlob
    • nick.perri
    • siddharthpant92
    • bethqiang
    • kplob
    • samkitsheth95
    • erin-doyle
    • meussdorffer
    • shannamurry
    • amaan_lob
    • team.platform.lob.com
    • elijah-lob
    • barnabygo
    • james.cho
    • douglaje
    • lob-owner
    • graeme.lowe.lob