This repository was archived by the owner on Sep 16, 2025. It is now read-only.

Repository files navigation

QueryQL

npmCircleCIpiratepx

QueryQL makes it easy to add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string! Read our introductory article to learn more about why we wrote it and the problems it solves at Truepic.

QueryQL works with any Node.js web framework (be it Express, Koa, etc.), supports any query builder / ORM through adapters, and allows for custom validators so you can define validation in a familiar way.

Out of the box, QueryQL supports the following:

Installation

$ npm install @truepic/queryql

Getting Started

QueryQL takes a parsed query string (like Express' req.query) and translates it into the appropriate function calls that your query builder / ORM understands to filter, sort, and paginate the records.

Let's consider an example to illustrate:

/images?filter[id][in][]=2&filter[id][in][]=3&filter[status]=open&sort=name&page[size]=10
{filter: {id: {in: [2,3],},status: 'open',},sort: 'name',page: {size: 10,},}

To support this query, QueryQL only requires you to define (whitelist) what's allowed through what we call a querier. Here's how one might look for the /images endpoint:

constQueryQL=require('@truepic/queryql')classImageQuerierextendsQueryQL{defineSchema(schema){schema.filter('id','in')schema.filter('status','=')schema.sort('name')schema.page()}}

With your querier defined, you can now call it in your router / controller. Here's how it might look in an Express route:

app.get('/images',async(req,res,next)=>{constquerier=newImageQuerier(req.query,knex('images'))letimagestry{images=awaitquerier.run()}catch(error){// Handle validation error, such as by passing to an Express error handler:next(error)}res.send({ images })})

Behind-the-scenes, QueryQL takes your initial query builder (knex('images')), and applies the following Knex chain when querier.run() is called:

builder.where('id','in',[2,3]).where('status','=','open').orderBy('name','asc').limit(10).offset(0)

(Remember: While Knex is our default adapter and the query builder used in this example, adapters can be written for any query builder / ORM.)

This is a simple example, but hopefully it illustrates how easy it is to add filtering, sorting, and pagination to your REST API without manually touching your query builder / ORM.

Read the full documentation to learn how to add validation, customize the queries, and more.

Development

Prerequisites

The only prerequisite is a compatible version of Node.js (see engines.node in package.json).

Dependencies

Install dependencies with npm:

$ npm install

Tests

Jest is our testing framework of choice, with file-specific tests contained in the test/src directory. We strive for 100% code coverage.

To run the tests:

$ npm test

During development, it's recommended to run the tests automatically on file change:

$ npm test -- --watch [--notify]

Code Style & Linting

Prettier is setup to enforce a consistent code style. It's highly recommended to add an integration to your editor that automatically formats on save.

ESLint is setup with the "recommended" rules to enforce a level of code quality. It's also highly recommended to add an integration to your editor that automatically formats on save.

To run via the command line:

$ npm run lint

Releasing

After development is done in the development branch and is ready for release, it should be merged into the master branch, where the latest release code lives. Release It! is then used to interactively orchestrate the release process:

$ npm run release

About

Easily add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string!

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
This repository was archived by the owner on Sep 16, 2025. It is now read-only.

Repository files navigation

QueryQL

npmCircleCIpiratepx

QueryQL makes it easy to add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string! Read our introductory article to learn more about why we wrote it and the problems it solves at Truepic.

QueryQL works with any Node.js web framework (be it Express, Koa, etc.), supports any query builder / ORM through adapters, and allows for custom validators so you can define validation in a familiar way.

Out of the box, QueryQL supports the following:

Installation

$ npm install @truepic/queryql

Getting Started

QueryQL takes a parsed query string (like Express' req.query) and translates it into the appropriate function calls that your query builder / ORM understands to filter, sort, and paginate the records.

Let's consider an example to illustrate:

/images?filter[id][in][]=2&filter[id][in][]=3&filter[status]=open&sort=name&page[size]=10
{filter: {id: {in: [2,3],},status: 'open',},sort: 'name',page: {size: 10,},}

To support this query, QueryQL only requires you to define (whitelist) what's allowed through what we call a querier. Here's how one might look for the /images endpoint:

constQueryQL=require('@truepic/queryql')classImageQuerierextendsQueryQL{defineSchema(schema){schema.filter('id','in')schema.filter('status','=')schema.sort('name')schema.page()}}

With your querier defined, you can now call it in your router / controller. Here's how it might look in an Express route:

app.get('/images',async(req,res,next)=>{constquerier=newImageQuerier(req.query,knex('images'))letimagestry{images=awaitquerier.run()}catch(error){// Handle validation error, such as by passing to an Express error handler:next(error)}res.send({ images })})

Behind-the-scenes, QueryQL takes your initial query builder (knex('images')), and applies the following Knex chain when querier.run() is called:

builder.where('id','in',[2,3]).where('status','=','open').orderBy('name','asc').limit(10).offset(0)

(Remember: While Knex is our default adapter and the query builder used in this example, adapters can be written for any query builder / ORM.)

This is a simple example, but hopefully it illustrates how easy it is to add filtering, sorting, and pagination to your REST API without manually touching your query builder / ORM.

Read the full documentation to learn how to add validation, customize the queries, and more.

Development

Prerequisites

The only prerequisite is a compatible version of Node.js (see engines.node in package.json).

Dependencies

Install dependencies with npm:

$ npm install

Tests

Jest is our testing framework of choice, with file-specific tests contained in the test/src directory. We strive for 100% code coverage.

To run the tests:

$ npm test

During development, it's recommended to run the tests automatically on file change:

$ npm test -- --watch [--notify]

Code Style & Linting

Prettier is setup to enforce a consistent code style. It's highly recommended to add an integration to your editor that automatically formats on save.

ESLint is setup with the "recommended" rules to enforce a level of code quality. It's also highly recommended to add an integration to your editor that automatically formats on save.

To run via the command line:

$ npm run lint

Releasing

After development is done in the development branch and is ready for release, it should be merged into the master branch, where the latest release code lives. Release It! is then used to interactively orchestrate the release process:

$ npm run release

About

Easily add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string!

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 16, 2025. It is now read-only.

Repository files navigation

QueryQL

npmCircleCIpiratepx

QueryQL makes it easy to add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string! Read our introductory article to learn more about why we wrote it and the problems it solves at Truepic.

QueryQL works with any Node.js web framework (be it Express, Koa, etc.), supports any query builder / ORM through adapters, and allows for custom validators so you can define validation in a familiar way.

Out of the box, QueryQL supports the following:

Installation

$ npm install @truepic/queryql

Getting Started

QueryQL takes a parsed query string (like Express' req.query) and translates it into the appropriate function calls that your query builder / ORM understands to filter, sort, and paginate the records.

Let's consider an example to illustrate:

/images?filter[id][in][]=2&filter[id][in][]=3&filter[status]=open&sort=name&page[size]=10
{filter: {id: {in: [2,3],},status: 'open',},sort: 'name',page: {size: 10,},}

To support this query, QueryQL only requires you to define (whitelist) what's allowed through what we call a querier. Here's how one might look for the /images endpoint:

constQueryQL=require('@truepic/queryql')classImageQuerierextendsQueryQL{defineSchema(schema){schema.filter('id','in')schema.filter('status','=')schema.sort('name')schema.page()}}

With your querier defined, you can now call it in your router / controller. Here's how it might look in an Express route:

app.get('/images',async(req,res,next)=>{constquerier=newImageQuerier(req.query,knex('images'))letimagestry{images=awaitquerier.run()}catch(error){// Handle validation error, such as by passing to an Express error handler:next(error)}res.send({ images })})

Behind-the-scenes, QueryQL takes your initial query builder (knex('images')), and applies the following Knex chain when querier.run() is called:

builder.where('id','in',[2,3]).where('status','=','open').orderBy('name','asc').limit(10).offset(0)

(Remember: While Knex is our default adapter and the query builder used in this example, adapters can be written for any query builder / ORM.)

This is a simple example, but hopefully it illustrates how easy it is to add filtering, sorting, and pagination to your REST API without manually touching your query builder / ORM.

Read the full documentation to learn how to add validation, customize the queries, and more.

Development

Prerequisites

The only prerequisite is a compatible version of Node.js (see engines.node in package.json).

Dependencies

Install dependencies with npm:

$ npm install

Tests

Jest is our testing framework of choice, with file-specific tests contained in the test/src directory. We strive for 100% code coverage.

To run the tests:

$ npm test

During development, it's recommended to run the tests automatically on file change:

$ npm test -- --watch [--notify]

Code Style & Linting

Prettier is setup to enforce a consistent code style. It's highly recommended to add an integration to your editor that automatically formats on save.

ESLint is setup with the "recommended" rules to enforce a level of code quality. It's also highly recommended to add an integration to your editor that automatically formats on save.

To run via the command line:

$ npm run lint

Releasing

After development is done in the development branch and is ready for release, it should be merged into the master branch, where the latest release code lives. Release It! is then used to interactively orchestrate the release process:

$ npm run release

About

Easily add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string!

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 16, 2025. It is now read-only.

Repository files navigation

QueryQL

npmCircleCIpiratepx

QueryQL makes it easy to add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string! Read our introductory article to learn more about why we wrote it and the problems it solves at Truepic.

QueryQL works with any Node.js web framework (be it Express, Koa, etc.), supports any query builder / ORM through adapters, and allows for custom validators so you can define validation in a familiar way.

Out of the box, QueryQL supports the following:

Installation

$ npm install @truepic/queryql

Getting Started

QueryQL takes a parsed query string (like Express' req.query) and translates it into the appropriate function calls that your query builder / ORM understands to filter, sort, and paginate the records.

Let's consider an example to illustrate:

/images?filter[id][in][]=2&filter[id][in][]=3&filter[status]=open&sort=name&page[size]=10
{filter: {id: {in: [2,3],},status: 'open',},sort: 'name',page: {size: 10,},}

To support this query, QueryQL only requires you to define (whitelist) what's allowed through what we call a querier. Here's how one might look for the /images endpoint:

constQueryQL=require('@truepic/queryql')classImageQuerierextendsQueryQL{defineSchema(schema){schema.filter('id','in')schema.filter('status','=')schema.sort('name')schema.page()}}

With your querier defined, you can now call it in your router / controller. Here's how it might look in an Express route:

app.get('/images',async(req,res,next)=>{constquerier=newImageQuerier(req.query,knex('images'))letimagestry{images=awaitquerier.run()}catch(error){// Handle validation error, such as by passing to an Express error handler:next(error)}res.send({ images })})

Behind-the-scenes, QueryQL takes your initial query builder (knex('images')), and applies the following Knex chain when querier.run() is called:

builder.where('id','in',[2,3]).where('status','=','open').orderBy('name','asc').limit(10).offset(0)

(Remember: While Knex is our default adapter and the query builder used in this example, adapters can be written for any query builder / ORM.)

This is a simple example, but hopefully it illustrates how easy it is to add filtering, sorting, and pagination to your REST API without manually touching your query builder / ORM.

Read the full documentation to learn how to add validation, customize the queries, and more.

Development

Prerequisites

The only prerequisite is a compatible version of Node.js (see engines.node in package.json).

Dependencies

Install dependencies with npm:

$ npm install

Tests

Jest is our testing framework of choice, with file-specific tests contained in the test/src directory. We strive for 100% code coverage.

To run the tests:

$ npm test

During development, it's recommended to run the tests automatically on file change:

$ npm test -- --watch [--notify]

Code Style & Linting

Prettier is setup to enforce a consistent code style. It's highly recommended to add an integration to your editor that automatically formats on save.

ESLint is setup with the "recommended" rules to enforce a level of code quality. It's also highly recommended to add an integration to your editor that automatically formats on save.

To run via the command line:

$ npm run lint

Releasing

After development is done in the development branch and is ready for release, it should be merged into the master branch, where the latest release code lives. Release It! is then used to interactively orchestrate the release process:

$ npm run release

About

Easily add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string!

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
This repository was archived by the owner on Sep 16, 2025. It is now read-only.

Repository files navigation

QueryQL

npmCircleCIpiratepx

QueryQL makes it easy to add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string! Read our introductory article to learn more about why we wrote it and the problems it solves at Truepic.

QueryQL works with any Node.js web framework (be it Express, Koa, etc.), supports any query builder / ORM through adapters, and allows for custom validators so you can define validation in a familiar way.

Out of the box, QueryQL supports the following:

Installation

$ npm install @truepic/queryql

Getting Started

QueryQL takes a parsed query string (like Express' req.query) and translates it into the appropriate function calls that your query builder / ORM understands to filter, sort, and paginate the records.

Let's consider an example to illustrate:

/images?filter[id][in][]=2&filter[id][in][]=3&filter[status]=open&sort=name&page[size]=10
{filter: {id: {in: [2,3],},status: 'open',},sort: 'name',page: {size: 10,},}

To support this query, QueryQL only requires you to define (whitelist) what's allowed through what we call a querier. Here's how one might look for the /images endpoint:

constQueryQL=require('@truepic/queryql')classImageQuerierextendsQueryQL{defineSchema(schema){schema.filter('id','in')schema.filter('status','=')schema.sort('name')schema.page()}}

With your querier defined, you can now call it in your router / controller. Here's how it might look in an Express route:

app.get('/images',async(req,res,next)=>{constquerier=newImageQuerier(req.query,knex('images'))letimagestry{images=awaitquerier.run()}catch(error){// Handle validation error, such as by passing to an Express error handler:next(error)}res.send({ images })})

Behind-the-scenes, QueryQL takes your initial query builder (knex('images')), and applies the following Knex chain when querier.run() is called:

builder.where('id','in',[2,3]).where('status','=','open').orderBy('name','asc').limit(10).offset(0)

(Remember: While Knex is our default adapter and the query builder used in this example, adapters can be written for any query builder / ORM.)

This is a simple example, but hopefully it illustrates how easy it is to add filtering, sorting, and pagination to your REST API without manually touching your query builder / ORM.

Read the full documentation to learn how to add validation, customize the queries, and more.

Development

Prerequisites

The only prerequisite is a compatible version of Node.js (see engines.node in package.json).

Dependencies

Install dependencies with npm:

$ npm install

Tests

Jest is our testing framework of choice, with file-specific tests contained in the test/src directory. We strive for 100% code coverage.

To run the tests:

$ npm test

During development, it's recommended to run the tests automatically on file change:

$ npm test -- --watch [--notify]

Code Style & Linting

Prettier is setup to enforce a consistent code style. It's highly recommended to add an integration to your editor that automatically formats on save.

ESLint is setup with the "recommended" rules to enforce a level of code quality. It's also highly recommended to add an integration to your editor that automatically formats on save.

To run via the command line:

$ npm run lint

Releasing

After development is done in the development branch and is ready for release, it should be merged into the master branch, where the latest release code lives. Release It! is then used to interactively orchestrate the release process:

$ npm run release

About

Easily add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string!

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 16, 2025. It is now read-only.

Repository files navigation

QueryQL

npmCircleCIpiratepx

QueryQL makes it easy to add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string! Read our introductory article to learn more about why we wrote it and the problems it solves at Truepic.

QueryQL works with any Node.js web framework (be it Express, Koa, etc.), supports any query builder / ORM through adapters, and allows for custom validators so you can define validation in a familiar way.

Out of the box, QueryQL supports the following:

Installation

$ npm install @truepic/queryql

Getting Started

QueryQL takes a parsed query string (like Express' req.query) and translates it into the appropriate function calls that your query builder / ORM understands to filter, sort, and paginate the records.

Let's consider an example to illustrate:

/images?filter[id][in][]=2&filter[id][in][]=3&filter[status]=open&sort=name&page[size]=10
{filter: {id: {in: [2,3],},status: 'open',},sort: 'name',page: {size: 10,},}

To support this query, QueryQL only requires you to define (whitelist) what's allowed through what we call a querier. Here's how one might look for the /images endpoint:

constQueryQL=require('@truepic/queryql')classImageQuerierextendsQueryQL{defineSchema(schema){schema.filter('id','in')schema.filter('status','=')schema.sort('name')schema.page()}}

With your querier defined, you can now call it in your router / controller. Here's how it might look in an Express route:

app.get('/images',async(req,res,next)=>{constquerier=newImageQuerier(req.query,knex('images'))letimagestry{images=awaitquerier.run()}catch(error){// Handle validation error, such as by passing to an Express error handler:next(error)}res.send({ images })})

Behind-the-scenes, QueryQL takes your initial query builder (knex('images')), and applies the following Knex chain when querier.run() is called:

builder.where('id','in',[2,3]).where('status','=','open').orderBy('name','asc').limit(10).offset(0)

(Remember: While Knex is our default adapter and the query builder used in this example, adapters can be written for any query builder / ORM.)

This is a simple example, but hopefully it illustrates how easy it is to add filtering, sorting, and pagination to your REST API without manually touching your query builder / ORM.

Read the full documentation to learn how to add validation, customize the queries, and more.

Development

Prerequisites

The only prerequisite is a compatible version of Node.js (see engines.node in package.json).

Dependencies

Install dependencies with npm:

$ npm install

Tests

Jest is our testing framework of choice, with file-specific tests contained in the test/src directory. We strive for 100% code coverage.

To run the tests:

$ npm test

During development, it's recommended to run the tests automatically on file change:

$ npm test -- --watch [--notify]

Code Style & Linting

Prettier is setup to enforce a consistent code style. It's highly recommended to add an integration to your editor that automatically formats on save.

ESLint is setup with the "recommended" rules to enforce a level of code quality. It's also highly recommended to add an integration to your editor that automatically formats on save.

To run via the command line:

$ npm run lint

Releasing

After development is done in the development branch and is ready for release, it should be merged into the master branch, where the latest release code lives. Release It! is then used to interactively orchestrate the release process:

$ npm run release

About

Easily add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string!

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
This repository was archived by the owner on Sep 16, 2025. It is now read-only.

Repository files navigation

QueryQL

npmCircleCIpiratepx

QueryQL makes it easy to add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string! Read our introductory article to learn more about why we wrote it and the problems it solves at Truepic.

QueryQL works with any Node.js web framework (be it Express, Koa, etc.), supports any query builder / ORM through adapters, and allows for custom validators so you can define validation in a familiar way.

Out of the box, QueryQL supports the following:

Installation

$ npm install @truepic/queryql

Getting Started

QueryQL takes a parsed query string (like Express' req.query) and translates it into the appropriate function calls that your query builder / ORM understands to filter, sort, and paginate the records.

Let's consider an example to illustrate:

/images?filter[id][in][]=2&filter[id][in][]=3&filter[status]=open&sort=name&page[size]=10
{filter: {id: {in: [2,3],},status: 'open',},sort: 'name',page: {size: 10,},}

To support this query, QueryQL only requires you to define (whitelist) what's allowed through what we call a querier. Here's how one might look for the /images endpoint:

constQueryQL=require('@truepic/queryql')classImageQuerierextendsQueryQL{defineSchema(schema){schema.filter('id','in')schema.filter('status','=')schema.sort('name')schema.page()}}

With your querier defined, you can now call it in your router / controller. Here's how it might look in an Express route:

app.get('/images',async(req,res,next)=>{constquerier=newImageQuerier(req.query,knex('images'))letimagestry{images=awaitquerier.run()}catch(error){// Handle validation error, such as by passing to an Express error handler:next(error)}res.send({ images })})

Behind-the-scenes, QueryQL takes your initial query builder (knex('images')), and applies the following Knex chain when querier.run() is called:

builder.where('id','in',[2,3]).where('status','=','open').orderBy('name','asc').limit(10).offset(0)

(Remember: While Knex is our default adapter and the query builder used in this example, adapters can be written for any query builder / ORM.)

This is a simple example, but hopefully it illustrates how easy it is to add filtering, sorting, and pagination to your REST API without manually touching your query builder / ORM.

Read the full documentation to learn how to add validation, customize the queries, and more.

Development

Prerequisites

The only prerequisite is a compatible version of Node.js (see engines.node in package.json).

Dependencies

Install dependencies with npm:

$ npm install

Tests

Jest is our testing framework of choice, with file-specific tests contained in the test/src directory. We strive for 100% code coverage.

To run the tests:

$ npm test

During development, it's recommended to run the tests automatically on file change:

$ npm test -- --watch [--notify]

Code Style & Linting

Prettier is setup to enforce a consistent code style. It's highly recommended to add an integration to your editor that automatically formats on save.

ESLint is setup with the "recommended" rules to enforce a level of code quality. It's also highly recommended to add an integration to your editor that automatically formats on save.

To run via the command line:

$ npm run lint

Releasing

After development is done in the development branch and is ready for release, it should be merged into the master branch, where the latest release code lives. Release It! is then used to interactively orchestrate the release process:

$ npm run release

About

Easily add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string!

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
This repository was archived by the owner on Sep 16, 2025. It is now read-only.

Repository files navigation

QueryQL

npmCircleCIpiratepx

QueryQL makes it easy to add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string! Read our introductory article to learn more about why we wrote it and the problems it solves at Truepic.

QueryQL works with any Node.js web framework (be it Express, Koa, etc.), supports any query builder / ORM through adapters, and allows for custom validators so you can define validation in a familiar way.

Out of the box, QueryQL supports the following:

Installation

$ npm install @truepic/queryql

Getting Started

QueryQL takes a parsed query string (like Express' req.query) and translates it into the appropriate function calls that your query builder / ORM understands to filter, sort, and paginate the records.

Let's consider an example to illustrate:

/images?filter[id][in][]=2&filter[id][in][]=3&filter[status]=open&sort=name&page[size]=10
{filter: {id: {in: [2,3],},status: 'open',},sort: 'name',page: {size: 10,},}

To support this query, QueryQL only requires you to define (whitelist) what's allowed through what we call a querier. Here's how one might look for the /images endpoint:

constQueryQL=require('@truepic/queryql')classImageQuerierextendsQueryQL{defineSchema(schema){schema.filter('id','in')schema.filter('status','=')schema.sort('name')schema.page()}}

With your querier defined, you can now call it in your router / controller. Here's how it might look in an Express route:

app.get('/images',async(req,res,next)=>{constquerier=newImageQuerier(req.query,knex('images'))letimagestry{images=awaitquerier.run()}catch(error){// Handle validation error, such as by passing to an Express error handler:next(error)}res.send({ images })})

Behind-the-scenes, QueryQL takes your initial query builder (knex('images')), and applies the following Knex chain when querier.run() is called:

builder.where('id','in',[2,3]).where('status','=','open').orderBy('name','asc').limit(10).offset(0)

(Remember: While Knex is our default adapter and the query builder used in this example, adapters can be written for any query builder / ORM.)

This is a simple example, but hopefully it illustrates how easy it is to add filtering, sorting, and pagination to your REST API without manually touching your query builder / ORM.

Read the full documentation to learn how to add validation, customize the queries, and more.

Development

Prerequisites

The only prerequisite is a compatible version of Node.js (see engines.node in package.json).

Dependencies

Install dependencies with npm:

$ npm install

Tests

Jest is our testing framework of choice, with file-specific tests contained in the test/src directory. We strive for 100% code coverage.

To run the tests:

$ npm test

During development, it's recommended to run the tests automatically on file change:

$ npm test -- --watch [--notify]

Code Style & Linting

Prettier is setup to enforce a consistent code style. It's highly recommended to add an integration to your editor that automatically formats on save.

ESLint is setup with the "recommended" rules to enforce a level of code quality. It's also highly recommended to add an integration to your editor that automatically formats on save.

To run via the command line:

$ npm run lint

Releasing

After development is done in the development branch and is ready for release, it should be merged into the master branch, where the latest release code lives. Release It! is then used to interactively orchestrate the release process:

$ npm run release

About

Easily add filtering, sorting, and pagination to your Node.js REST API through your old friend: the query string!

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages