One of the things I love about Sails, is how it seems to be equipped with practical usable features and nuances. I recently discovered one and I wanted to share it in this article.
I wrote about paginating Waterline query results a previous article and while I have used the method written in that article, it always feels good to see that Sails have that covered as well.
The paginate query modifier
If you’ve used Sails for a while, you will know that you can chain methods like sort, meta, select, omit, populate, etc. on a Waterline query. These methods are called query modifiers as they modify the query you are making. Waterline also expose another of these so called query modifiers which is a syntactic sugar for getting paginated query results back from Waterline. This method is called paginate
.
To use the paginate
query modifier, you call it with a required page argument - which is the page
you want Waterline to return and an optional pageSize
second argument which will default to 30 if not set. Let’s see an example of using the paginate method.
const servers = await Server.find({ isRunning: true }).paginate(0)
You can also specify the page size:
const servers = await Server.find({ isRunning: true }).paginate(0, 10)
The paginate method also accepts an options object so you can call it like so:
const servers = await Server.find({ isRunning: true }).paginate({ page: 0, limit: 10 })
Note you don’t have to specify either the limit
property or the positional pageSize
argument if you want to use the default pageSize
which is 30.
One thing to recall is the page
value expected by the paginate query modifier is zero-based. What this means is that, to get the first page, you have to pass in 0
to paginate as the page value. This makes sense as the paginate query modifier is essentially syntactic sugar and will pass the page
value to the skip query modifier.
Usage
So now that you know the general form of the paginate query modifier, let’s look at a practical usage of it as you don’t want to just get the first page every time(right?).
Generally, with a typical pagination flow, the page
value should is passed via a page
query string. For example say you have a route to return a list of servers e.g /servers
.
The caller of route can pass in the page
value as a query string so you can get requests like: /servers?page=1
, /servers?page=2
, etc. You get the idea.
To implement the above logic, in your action just add a page input which is a number and set it’s default value to 1. This is because we want visits to the /servers
route to return the first page even though the page value wasn’t set via the page query string. Also taking into account that the paginate query modifier expects a zero-based page value, we should remove 1
from page before passing it to the paginate query modifier.
Here is the implementation
// controllers/servers/get-servers.js
{
inputs: {
page: {
type: 'number',
defaultsTo: 1
}
},
exits: {},
fn: async function({ page }) {
const servers = await Server.find({ isRunning: true }).paginate(page - 1)
return servers
}
}
Isn’t that beautiful? So again we are decreasing the page value from the query string by 1
because of aesthetic as we want the to client to call the route using one-based page values because it reads more naturally than saying “give me page 0”, saying “give me page 1” makes more sense in userland. If you don’t care about that in your app, you can always start the page with the value of 0
.
Conclusion
Discovering this nice little query modifier made me super happy with the thought of how much more of Sails I am yet to discover and be awed about. I will continue to share as always so you can build more amazing Sails applications.