Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extending knex #1158

Closed
thetutlage opened this issue Jan 27, 2016 · 14 comments · Fixed by #3334

Comments

@thetutlage
Copy link
Contributor

commented Jan 27, 2016

Is there any way to extend knex ( have not found one ) to add my own methods.

Below will not work because after the first method call knex returns an instance of queryBuilder.

var knex = require('knex')(config)
knex.paginate = function () {}

I also have an idea to have an extend method, which can be used to add/extend new methods, but before working on it, i want to know are you guys even interested in something like this or not.

@rhys-vdw rhys-vdw added the question label Jan 27, 2016

@wubzz

This comment has been minimized.

Copy link
Collaborator

commented Jan 27, 2016

+1 For extend support

@elhigu

This comment has been minimized.

Copy link
Collaborator

commented Jan 27, 2016

I think there is no official way to extend query builder, I recall that there has been some talk about it for 1.0 stable version. Anyways maybe something really hacky like this could work for your case?

var knex = require('knex')({client: 'pg'})
knex.client.QueryBuilder.prototype.newFunc = function () { 
  console.log("New query builder function"); 
  return this; 
}
knex('table').newFunc().toString();
// outputs: 
// New query builder function
// 'select * from "table"'
@thetutlage

This comment has been minimized.

Copy link
Contributor Author

commented Jan 28, 2016

how about having a extend method on knex instance to add new methods.

knex.extend('paginate', function () {
   // this will be the current query chain
})

i did something like this and can submit a PR

@elhigu

This comment has been minimized.

Copy link
Collaborator

commented Jan 28, 2016

@rhys-vdw has there been discussion about knex extending interfaces for 1.0? If 0.x is getting that feature would be probably good to try to do it pretty much the same way. @tgriesser do you have an idea if there are some less obvious problems that this kind of feature could cause?

I don't know knex codebase / use cases enough to be able to say if this feature would be ok to add 🎱

Would that extended method be available also in all subquerybuilders?

@wubzz

This comment has been minimized.

Copy link
Collaborator

commented Jan 28, 2016

@thetutlage Sugar syntax suggestion:

knex.extend({
    myNewFunction: function() {
        /**Do something**/
        return this;
    },

    myNewFunctionTwo: function() {
        /**Do something**/
        return this;
    }
});
knex.QueryBuilder.extend({
    myNewFunction: function() {
        /**Do something**/
        return this;
    },

    myNewFunctionTwo: function() {
        /**Do something**/
        return this;
    }
});

Since knex and the QB are two different 'classes', this makes more sense. My two cents..

@thetutlage

This comment has been minimized.

Copy link
Contributor Author

commented Jan 28, 2016

@wubzz i am planning to have a single method on the knex instance, not on the query builder and then that method will take care on how to add it lazily adding to the queryBuilder ( this will happen when an instance of queryBuilder is returned by the knex internally ).

Yes we can have support for an object to have multiple methods, or a single key/value pair

thetutlage added a commit to thetutlage/knex that referenced this issue Jan 28, 2016
Added extend method discussed in tgriesser#1158
Extend method will let the outside world add methods to the knex query
builder.
@thetutlage

This comment has been minimized.

Copy link
Contributor Author

commented Jan 28, 2016

Also submitted a PR. I am open to make changes for the good. Also want to know how interested the core contributors are in having the support for extending knex.

@rhys-vdw

This comment has been minimized.

Copy link
Collaborator

commented Jan 28, 2016

I'm on the fence about extend. Yes, I agree this would be a simple and useful way of modifying the knex instance. However, I'd like to rule out using the new OO language features as a possibility for this first. Certainly it would take a lot of work, but it might be worth seeing what it would take to use ES syntax to achieve the same end.

Due to knex's interface being a function, it might end up looking like this, which is not ideal:

import QueryBuilder from 'knex/QueryBuilder';
import makeKnex from 'knex/makeKnex';

class CustomQueryBuilder extends QueryBuilder {
  // ...
}

export default makeKnex({ QueryBuilder: CustomQueryBuilder });

But maybe there is a nicer way?

Also @tgriesser, can you weigh in?

@timruffles

This comment has been minimized.

Copy link
Collaborator

commented Feb 2, 2016

I'd be up for working on this. A lot of the outstanding issues could be mitigated with some way to extend knex's qbuilder.

Would one of the maintainers be interested in such a feature?

@thetutlage

This comment has been minimized.

Copy link
Contributor Author

commented Feb 2, 2016

@timruffles I am not sure, haven't heard from anyone of them apart from @rhys-vdw

@thetutlage thetutlage closed this Feb 7, 2016

thetutlage added a commit to thetutlage/knex that referenced this issue Jul 28, 2016
Added extend method discussed in tgriesser#1158
Extend method will let the outside world add methods to the knex query
builder.
@RWOverdijk

This comment has been minimized.

Copy link
Contributor

commented Sep 5, 2016

👍 I could really use this. I'd even be willing to help implement this. Can we reopen the issue? It looks relatively simple to implement. A QueryBuilder class that's then used in stead of a function.

@elhigu

This comment has been minimized.

Copy link
Collaborator

commented Sep 6, 2016

@RWOverdijk if you are able to implement extension stuff in a way that it is tested to works also in subquery builder and with initialized transaction, I would be ok with merging the feature. @rhys-vdw @tgriesser @wubzz any objections?

@elhigu elhigu reopened this Sep 6, 2016

andjosh added a commit to andjosh/skyfall that referenced this issue Feb 1, 2017
@rickyk586

This comment has been minimized.

Copy link

commented Apr 1, 2017

Here's how I was able to monkey patch it for v0.12.7

var Knex = require('Knex');
var KnexQueryBuilder = require('knex/lib/query/builder');

var knexClient = Knex(config);

KnexQueryBuilder.prototype.newMethod = function(){
	console.log('in new method');
	return this;
};
knexClient.queryBuilder = function(){
	return new KnexQueryBuilder(knexClient.client);
};
@nickell

This comment has been minimized.

Copy link

commented Feb 8, 2018

@rickyk586 Thanks for showing how you monkey patched it. I used your example for a while and just noticed modify in the docs. It may not help with your use-case but for mine it goes like this:

// Regular function
function throwIfNone(queryBuilder, errMsg = 'Entity not found') {
    queryBuilder._throwIfNone = errMsg
}

function checkThrowIfNone(response, obj, builder) {
    if (
        builder._throwIfNone &&
        obj.response &&
        obj.response.rowCount === 0
    ) {
        const err = new Error(builder._throwIfNone)
        throw err
    }
}

db.client.on('query-response', checkThrowIfNone)

// Inside some async method
const { first_name } = await db('user_table')
    .first('first_name')
    .modify(throwIfNone, 'User not found')

This particular method has come in handy when we're destructuring a response. It may not be as pretty in usage as adding a method to the query builder prototype but it's nice to avoid messing with knex internals.

Repository owner deleted a comment from Cmacu Feb 20, 2018

Repository owner deleted a comment from nicholaswmin Feb 20, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
8 participants
You can’t perform that action at this time.