question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Using Knex without connection, then execute with connection

See original GitHub issue

Hi guys

Let’s say I have a service called QueryBuilderService where I have the details of each of the queries I use in my app.

Let’s say I have another service, DatabaseService, which uses QueryBuilderService but also takes care of handling transactions and reusing multiple queries (for example, createUser() in DatabaseService calls createUser() and getUser() in QueryBuilderService, within a transaction).

My question is: I am currently using a knex connection inside both services. I create it in DatabaseService and I pass it to QueryBuilderService as a constructor argument. Basically it looks like this:

class DatabaseService() {
  constructor() {
     ...
     this.query = new QueryBuilderService(myKnexConnection);
  }

  getUsers() {
    return this.query.getUsers()
    .then(/* do something */);
  }
}

class QueryBuilderService() {
  constructor(knexConnection) {
     ...
     this.knex = knexConnection;
  }

  getUsers() {
    return this.knex.select('users');
    //etc etc etc
  }
}

I want to get rid of that dependency: I want QueryBuilderService to use knex as a query building library only and no longer receive the connection in the constructor. I know this can be achieved, what I don’t know is how to specify the connection from the “outside” (when calling any QueryBuilderService method from DatabaseService).

Do you guys have any idea?

Thanks in advance!

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Comments:16 (9 by maintainers)

github_iconTop GitHub Comments

6reactions
elhigucommented, May 29, 2017

You can use knex as a plain query builder if you initialize it without connection parameters like this:

const knex = require('knex')({ client: 'pg' });
const userOneQuery = knex('UserTable').where('id', 1);

Notice that query was just built, but not compiled to sql and bindings nor it is executed.

If you want now execute the query above, there is no official way to do it with knex. However for example in tests there is currently used trick where you would execute that query like this:


const dbConnectionKnex = require('knex')({
  client: 'pg',
  connection: { /* connection setup */ }
});

// run query built in 1st part of example
let queryToExecute = userOneQuery.clone();
// I'm not 100% that this works with real queries..
queryToExecute.client = dbConnectionKnex.client;
queryToExecute.then(res => {
  console.log('Fetched user one!', res);
});

Anyways this is not nice at all and may be broken by accident in future knex versions, because this is not documented functionality of knex and will never be in this format.

Other less hacky way to do this would be to always pass connection that is used to run the query to each query method that is how for example objection ORM recommends passing the connection pool / transaction in which knex instance its query should be ran.

EDIT: this last part was pretty much the same that is suggested by @wubzz above 👍

1reaction
wubzzcommented, May 29, 2017

I might be mistaken but I think you’re confusing myKnexConnection with an instance of require('knex')({...}). The knex instance is not a connection in itself, all that stuff is handled “in the background” of knex, so to speak. See pool settings in initialize.

Spontaneous response is you won’t be able to completely get rid of having to supply the argument one way or the other, but perhaps an idea is to have static methods in order to lose the need for a constructor. For example:

const dbClient = require('knex')({...});

class DatabaseService {
	static getUsers() {
		return QueryBuilderService.getUsers(dbClient);
	}
}

class QueryBuilderService {
	static getUsers(queryBuilder) {
		return queryBuilder.from('users').select();
	}
}

Hope I didn’t misunderstand.

Edit: To be clear, queryBuilder argument to QueryBuilderService could either be a pooled client dbClient or a transaction object created through dbClient.transaction (for your example of createUser + getUser).

Read more comments on GitHub >

github_iconTop Results From Across the Web

Problem with connection acquisition when using knex and ...
I am running Serverless with Serverless Offline plugin to develop a Node 14 application locally. The database is a Postgres instance, which I...
Read more >
Installation | Knex.js
The most common cause for this is using up all the pool for transaction connections and then attempting to run queries outside of...
Read more >
Knex Query Builder
Most of the knex APIs mutate current object and return it. ... The method sets the db connection to use for the query...
Read more >
Knex.js: SQL Query Builder for Javascript
Knex.js is a "batteries included" SQL query builder for PostgreSQL, CockroachDB, MSSQL, MySQL, MariaDB, SQLite3, Better-SQLite3, Oracle, and Amazon Redshift ...
Read more >
Transactions | Knex.js
All queries within a transaction are executed on the same database connection, and run the entire set of queries as a single unit...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found