Tony J Watson
Tony J Watson

Reputation: 709

Custom functions for knex

There's a number of operations that I do all the time and I was hoping there would be a way to "extend" knex to be able to do them.

I would like to something like:

oneExists
    result = knex.count(id).from('table').where({'code': 25})
    if (result.length === 0) return false
    if (result.length === 1) return true
    throw an error

I would like to be able to do something like

knex.oneExists.count('id').from('table').where({'code': 25}).

at the moment i'm writing the code like this:

KnexUtil.oneExists(knex.select('id').from('table').where({code: 25})) 

which returns a promise

I've looked through the knex codebase and i'm not sure:

  1. how to chain this (and whether i would do this in /lib/query/compiler.js)
  2. how to just make an extension to knex so i don't need to modify the original codebase

Upvotes: 4

Views: 5546

Answers (3)

Evhenii
Evhenii

Reputation: 88

Starting from v0.19.1, knex have build-in ability to extend QueryBuilder

import Knex from 'knex'
Knex.QueryBuilder.extend('someFn', function (arg) {
  console.log('Do Smth', arg)
  return this
})
const knex = Knex({ client: 'pg' })
knex.select().from('table').someFn(0).toString()

Upvotes: 5

Soheil555
Soheil555

Reputation: 11

If using TypeScript:

import { knex, Knex as KnexOriginal } from "knex";

declare module "knex" {
  namespace Knex {
    interface QueryBuilder {
      customFunction<TRecord, TResult>(
        value: number
      ): KnexOriginal.QueryBuilder<TRecord, TResult>;
    }
  }
}

knex.QueryBuilder.extend("customFunction", function (value: number) {
  console.log("Custom Function:", value);
  return this;
});

const pg = knex({ client: "pg" });
pg("table").select("*").customFunction(10).toString()

Check out documentation about how to extend knex

Upvotes: 1

Justin
Justin

Reputation: 2039

Sure you can. I would recommend just creating your own plugin, something like the following:

// my-plugin.js
'use strict';

module.exports = function (Bookshelf) {
    Bookshelf.Model = Bookshelf.Model.extend({
        foo: function ( bar ) {
            if( bar )
                console.log('Method foo was called on a model with the arguments:', arguments.join(', '));
        }
    });

    Bookshelf.Collection = Bookshelf.Collection.extend({
        foo: function ( bar ) {
            if( bar )
                console.log('Method foo was called on a collection with the arguments:', arguments.join(', '));
        }
    });
};

Then inside your main application file, add:

Bookshelf.plugin( require( './my-plugin' ) );

BookshelfJS plugins basically allow you to extend the models and collections (and more), which allows you to add your own method, or overwrite existing ones (while still being able to call the original method from within your plugin)

For a better understanding, it might be a good idea for you to look at some existing BookshelfJS plugins, some already come with bookshelf, inside the plugins directory.

Another plugin that may be good to look at to better understand how the plugins work, would be the Soft Delete Plugin. In that plugin, you can see how some BookshelfJS methods are overridden in both the models and the collections objects, with methods that execute the original version of the method, then return the parsed/modified result (Lines #37-#59 and Lines #37-#57), as well as adding completely new methods (Lines #61-#72)

Edit: Obviously this is more BookshelfJS than KnexJS, but I didn't see any way to create plugins for KnexJS, since it's just a query constructor, all the real magic is in the ORM

Upvotes: 1

Related Questions