-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
335e27a
commit 6d229b8
Showing
6 changed files
with
352 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,172 @@ | ||
# basic-node-paginator | ||
A basic, lightweight and independent paginator for the popular 'mysql' node module. | ||
This is an easily integratable paginator for the popular [mysql](https://www.npmjs.com/package/mysql) node module. | ||
|
||
The generated links are by default compatible with the [Bootstrap CSS framework](http://getbootstrap.com/). | ||
|
||
The CSS classes applied to the links can be overridden. | ||
|
||
Custom queries with joins, special clauses, aggregates etc can also be provided. | ||
|
||
|
||
If your MySQL version or configuration causes problems with SQL_CALC_FOUND_ROWS / FOUND_ROWS(), | ||
then please install version 1.2.5. | ||
|
||
Otherwise, you can install version 1.2.2 and expect better performance. | ||
|
||
## Table of Contents | ||
|
||
- [Install](#install) | ||
- [Setup](#setup) | ||
- [State](#state) | ||
- [Example](#example) | ||
|
||
|
||
## Install | ||
|
||
```sh | ||
$ npm install basic-node-paginator | ||
``` | ||
|
||
## Setup | ||
|
||
Here is an example of a mysql configuration you may be using. | ||
Make sure to export the get() method that returns the connection pool: | ||
```js | ||
// db.js | ||
|
||
var mysql = require('mysql'); | ||
var PRODUCTION_DB = 'productiondb'; | ||
var TEST_DB = 'testdb' | ||
|
||
exports.MODE_TEST = 'mode_test' | ||
exports.MODE_PRODUCTION = 'mode_production' | ||
|
||
var state = { | ||
pool: null, | ||
mode: null, | ||
} | ||
|
||
exports.connect = function (mode, done) | ||
{ | ||
state.pool = mysql.createPool({ | ||
host: 'localhost', | ||
user: 'root', | ||
password: '@#$1!%%', | ||
database: mode === exports.MODE_PRODUCTION ? PRODUCTION_DB : TEST_DB | ||
}) | ||
|
||
state.mode = mode | ||
done() | ||
} | ||
|
||
exports.get = function () | ||
{ | ||
return state.pool | ||
} | ||
``` | ||
|
||
This is the paging module that will export a paginator object. The createPaginator() factory method | ||
initializes the state of the paginator object it returns. | ||
|
||
```js | ||
// paging.js | ||
|
||
var db = require('./db'); | ||
var paginator = require('basic-node-paginator'); | ||
|
||
var MyPaginator = paginator.createPaginator({ | ||
dbConn: db, | ||
pageParam: '/' | ||
}); | ||
|
||
exports.MyPaginator = MyPaginator; | ||
``` | ||
|
||
|
||
The paginator object exposes a few methods: | ||
|
||
* `configureInstance(obj)` : Meant to change the state of the paginator. | ||
|
||
* `getPage(page_num, success, error)` | ||
|
||
|
||
## State | ||
|
||
The state of the paginator includes: | ||
|
||
* `pageSize`: The number of records to be displayed per page. The default is 25. | ||
|
||
* `tableName`: The table from where to retrieve the records. | ||
|
||
* `customQuery`: A user-defined MySQL query that will be used instead of `table_name` if provided. Example: | ||
|
||
`SELECT users.name, posts.text FROM users INNER JOIN posts on users.id = posts.user_id` | ||
|
||
Note: You can use [Squel.js](https://hiddentao.github.io/squel/) to generate queries. | ||
|
||
* `linksClasses`: The space-separated classes applied to the ul element of the links. The default is 'pagination'. | ||
|
||
* `inactiveClasses`: The space-separated classes applied to the inactive pages' li elements within the list. | ||
|
||
* `activeClasses`: The space-separated classes applied to the current page's li element within the list. The default is 'active'. | ||
|
||
* `dbConn`: The config module which exports a get() method returning the mysql pool object. | ||
|
||
* `baseUrl`: This is the base url that all the generated links will point to. | ||
|
||
* `pageParam`: The name of the paramater that will be appended to the base url in the links. | ||
This will contain the page number to be requested. | ||
It can be set to '/' for cleaner page urls like: | ||
|
||
```txt | ||
/admin/users/1 | ||
``` | ||
|
||
as opposed to something like: | ||
|
||
```txt | ||
/admin/users/?page=1 | ||
``` | ||
|
||
|
||
## Example | ||
|
||
This is what the route may look like: | ||
|
||
```txt | ||
/admin/users/:page? | ||
``` | ||
|
||
Here is a method that may serve the request to this route. | ||
|
||
```js | ||
var paginator = require('./paging'); | ||
|
||
var page_num = req.params.page ? req.params.page : 1; | ||
|
||
paginator.MyPaginator.configureInstance({ | ||
pageSize: 5, | ||
tableName : 'users', | ||
baseUrl: '/admin/users' | ||
}); | ||
|
||
paginator.MyPaginator.getPage(page_num, | ||
function (obj) { | ||
|
||
return res.render('users', {users: obj.records, links: obj.links}); | ||
|
||
}, function (err) { | ||
|
||
return res.render('error'); | ||
}); | ||
``` | ||
|
||
And in your users.jade file: | ||
|
||
```jade | ||
row.text-center !{links} | ||
each user in users | ||
<!-- Display users in a table or something. --> | ||
``` | ||
|
||
Note: This can be easily done with some other templating engine as well. Jade is used only for demonstration. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
function getUrl(base, param) | ||
{ | ||
if(param == '/') { | ||
|
||
return base.slice(-1) == '/' ? base : base + '/'; | ||
} | ||
else { | ||
return base.slice(-1) == '/' ? base + '?' + param + '=' : base + '/?' + param + '='; | ||
} | ||
} | ||
|
||
|
||
exports.getLinks = function (_pageNum, numOfPages, recordCount, baseUrl, pagingParam, linksClasses, activeClasses, inactiveClasses) | ||
{ | ||
var links = "<ul class='" + linksClasses + "'>"; | ||
var url = getUrl(baseUrl, pagingParam); | ||
|
||
for(var i = 1; i <= numOfPages; ++i) { | ||
|
||
if(i == _pageNum) { | ||
links += "<li class='"+activeClasses+"'><span>" + i + "</span></li>"; | ||
} | ||
else { | ||
links += "<li class='"+inactiveClasses+"'><a href='"+ url + i +"'>" + i + "</a></li>"; | ||
} | ||
} | ||
|
||
links += "</ul>"; | ||
return links; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
exports.getTotalCount = function getTotalCount(_db_connection, _table_name, custom_query, done) | ||
{ | ||
var query = custom_query ? "SELECT COUNT(*) as cn FROM (" + custom_query + ") _t_" : | ||
"SELECT COUNT(*) as cn FROM " + _table_name; | ||
|
||
_db_connection.get().query(query, | ||
function (err, cnt) { | ||
if (err) { return done(err, null); } | ||
else { | ||
return done(null, cnt[0].cn); | ||
} | ||
}) | ||
} | ||
|
||
|
||
exports.getRecords = function getRecords(_pageNum, _db_connection, _table_name, _records_per_page, custom_query, callback) | ||
{ | ||
var query = custom_query ? custom_query + " LIMIT ?, ?" : "SELECT * FROM " + _table_name + " LIMIT ?, ?"; | ||
|
||
_db_connection.get().query(query, [_records_per_page * (_pageNum-1), _records_per_page], | ||
function (err, rows) { | ||
if (err) { | ||
return callback(err, null); | ||
} | ||
else { | ||
return callback(null, rows); | ||
} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
exports.isAlphaOrParen = function (str) { | ||
|
||
return /[a-z]/i.test(str) || str == '/'; | ||
} | ||
|
||
|
||
exports.isPositiveInt = function(_num) { | ||
|
||
return (parseInt(_num, 10) > 0); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
var validator = require('./helpers/validators'); | ||
var links = require('./helpers/links'); | ||
var runner = require('./helpers/runner'); | ||
|
||
|
||
function Paginator(obj) { | ||
|
||
if(! validator.isAlphaOrParen(obj.pageParam)) | ||
throw new Error("Invalid page parameter."); | ||
|
||
if(! obj.hasOwnProperty('dbConn')) | ||
throw new Error("Database connection not provided."); | ||
|
||
this.db_connection = obj.dbConn; | ||
this.table_name = obj.hasOwnProperty('tableName') ? obj.tableName : null; | ||
this.records_per_page = obj.hasOwnProperty('pageSize') ? obj.pageSize : 25; | ||
this.base_url = obj.hasOwnProperty('baseUrl') ? obj.baseUrl : null; | ||
this.paging_param_name = obj.hasOwnProperty('pageParam') ? obj.pageParam : null; | ||
|
||
this.link_ul_classes = obj.hasOwnProperty('linksClasses') ? obj.linksClasses : 'pagination'; | ||
this.link_inactive_li_classes = obj.hasOwnProperty('inactiveClasses') ? obj.inactiveClasses : ''; | ||
this.link_active_li_classes = obj.hasOwnProperty('activeClasses') ? obj.activeClasses : 'active'; | ||
|
||
this.custom_query = obj.customQuery ? obj.customQuery : null; | ||
} | ||
|
||
|
||
Paginator.prototype.configureInstance = function configureInstance(obj) { | ||
|
||
if(obj.hasOwnProperty('pageSize') && ! validator.isPositiveInt(obj.pageSize)) | ||
throw new Error("Invalid page size."); | ||
|
||
this.base_url = obj.hasOwnProperty('baseUrl') ? obj.baseUrl : this.base_url; | ||
this.table_name = obj.hasOwnProperty('tableName') ? obj.tableName : this.table_name; | ||
this.records_per_page = obj.hasOwnProperty('pageSize') ? obj.pageSize : this.records_per_page; | ||
this.db_connection = obj.hasOwnProperty('dbConn') ? obj.dbConn : this.db_connection; | ||
this.paging_param_name = obj.hasOwnProperty('pageParam') ? obj.pageParam : this.paging_param_name; | ||
|
||
this.link_ul_classes = obj.hasOwnProperty('linksClasses') ? obj.linksClasses : 'pagination'; | ||
this.link_inactive_li_classes = obj.hasOwnProperty('inactiveClasses') ? obj.inactiveClasses : ''; | ||
this.link_active_li_classes = obj.hasOwnProperty('activeClasses') ? obj.activeClasses : 'active'; | ||
|
||
this.custom_query = obj.customQuery ? obj.customQuery : null; | ||
}; | ||
|
||
|
||
Paginator.prototype.getPage = function getPage(_pageNum, success, error) { | ||
|
||
if(! this.db_connection || (! this.table_name && ! this.custom_query) || | ||
! this.records_per_page || ! _pageNum || ! this.base_url || ! validator.isPositiveInt(_pageNum)) | ||
{ | ||
return error("Invalid configuration or parameters found."); | ||
} | ||
|
||
var self = this; | ||
|
||
runner.getRecords(_pageNum, this.db_connection, this.table_name, this.records_per_page, this.custom_query, | ||
function(err, result) { | ||
|
||
if(err || result.length == 0) { | ||
return error(err); | ||
} | ||
|
||
runner.getTotalCount(self.db_connection, self.table_name, self.custom_query, | ||
function(_err, recordCount) { | ||
|
||
if(_err || recordCount == 0) { | ||
return error(err); | ||
} | ||
|
||
links_html = | ||
links.getLinks(_pageNum, Math.ceil(recordCount / self.records_per_page), recordCount, | ||
self.base_url, self.paging_param_name, self.link_ul_classes, self.link_active_li_classes, self.link_inactive_li_classes); | ||
|
||
return success({records: result, links: links_html}); | ||
}); | ||
}); | ||
} | ||
|
||
|
||
exports.createPaginator = function createPaginator(obj) { | ||
|
||
return new Paginator(obj); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
{ | ||
"name": "basic-node-paginator", | ||
"version": "1.2.6", | ||
"description": "A basic, lightweight and independent paginator for the popular 'mysql' node module.", | ||
"main": "index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/UsamaAshraf/basic-node-paginator.git" | ||
}, | ||
"keywords": [ | ||
"basic", | ||
"simple", | ||
"node", | ||
"paging", | ||
"paginator" | ||
], | ||
"author": "Usama Ashraf <[email protected]>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/UsamaAshraf/basic-node-paginator/issues" | ||
}, | ||
"homepage": "https://github.com/UsamaAshraf/basic-node-paginator#readme" | ||
|
||
} |