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.

Manually initializing a destroyed connection pool did not change database schema name

See original GitHub issue

Summary

I am setting up test script to create multiple database schema to utilize AVA parallel test run. As a result, I need to create the schema first, then switch the application connection pool to use the new created schema. However I encountered a bug in doing so, and would like to ask the official proper way to change the database schema name.

Environment

Knex version: 0.21.0 Database + version: MySQL 5.7 OS: Windows 10

Bug

According to the documentation:

If you ever need to explicitly teardown the connection pool, you may use knex.destroy([callback]). You may use knex.destroy by passing a callback, or by chaining as a promise, just not both. To manually initialize a destroyed connection pool, you may use knex.initialize([config]), if no config is passed, it will use the first knex configuration used.

I expect I can change the database name by knex.destroy and knex.initialize(newConfig) with new configuration. This does not work.

Reduced test case as follows:

const knex = require('knex')

function getConfig () {
  return {
    client: 'mysql',
    connection: {
      host: 'localhost',
      user: 'root',
      password: ''
    }
  }
}

const db = knex(getConfig()).on('query', function (data) {
  console.log(data.sql)
})

const method = 1

;(async () => {
  // Randomly (in my case it is based on server listening port) assigned a database name for AVA parallel testing
  const dbName = 'TMP_DB_' + (Math.floor(Math.random() * 999) + 9001)
  try {
    await db.raw(`CREATE DATABASE ${dbName}`)
    await db.raw(`USE ${dbName}`)
    await db.schema.createTable('tmp1', (table) => {
      table.increments()
      table.string('val1', 10).notNullable()
    })
    if (method === 1) {
      // I tried the documented way, but the `connection.database` is not changed with the following code
      await db.destroy()
      const newConfig = getConfig()
      newConfig.connection.database = dbName
      db.initialize(newConfig)
    } else if (method === 2) {
      // Is this the proper way to set the `connection.database`?
      db.client.connectionSettings.database = dbName
    }
    // This will result in `Error: ER_NO_DB_ERROR: No database selected` if database name is not set
    await Promise.all([
      db('tmp1').insert({ val1: 'a' }),
      db('tmp1').insert({ val1: 'b' }),
      db('tmp1').insert({ val1: 'c' })
    ])
  } finally {
    try {
      await db.raw(`DROP DATABASE ${dbName}`)
    } catch (ignore) {}
    await db.destroy()
  }
  console.log('End')
})().catch(e => console.log(e.stack))

Question

My additional question together with this bug, is how to change the database schema of the connection pool? Is the const method = 2 the proper way to do so? Or it can only be treated as undocumented way and may change in the future?

Issue Analytics

  • State:open
  • Created 3 years ago
  • Comments:10 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
VeryCrazyDogcommented, Nov 25, 2021

@MehdiSaffar I haven’t thought of using Proxy at that time (maybe I didn’t even know Proxy at that time). Thanks a lot for sharing, though I am no longer working with project using RDBMS now.

0reactions
MehdiSaffarcommented, Nov 23, 2021

@VeryCrazyDog Here is a temporary approach with ES6 proxies you could use if you want, not sure how correct it is but it seems to work on my side. Example:

const defaultConfig = YOUR_KNEX_CONFIG

const makeKnex = require('knex')

const wrapper = { instance: makeKnex(defaultConfig) }

async function reconnect (config) {
  await wrapper.instance.destroy()
  wrapper.instance = makeKnex(config)
}

const knexInstance = new Proxy(wrapper, {
  get: (target, prop) => {
    if (prop === 'reconnect') {
      return reconnect
    }

    return target.instance[prop]
  }
})

module.exports = knexInstance
Read more comments on GitHub >

github_iconTop Results From Across the Web

17 Tuning Data Source Connection Pools - Oracle Help Center
This chapter provides information on how to properly tune the connection pool ... Test Table Name is required to enable any database connection...
Read more >
How to set up datasource with Spring for HikariCP?
In order to get Spring & Hibernate to make use of Hikari Connection pool, you need to define the HikariDataSource and feed it...
Read more >
c3p0-v0.9.5.5 - JDBC3 Connection and Statement Pooling
DataSource scheme for acquiring database Connections. ... Usually this is not at all a problem. c3p0 works around this by acquiring "default" Connections...
Read more >
Connection Pooling - SQLAlchemy 1.4 Documentation
A connection pool is a standard technique used to maintain long running connections in memory for efficient re-use, as well as to provide ......
Read more >
Database Engine events and errors - SQL Server
Set the database compatibility level to 80 or lower for this statement to ... ls does not allow specifying a schema name as...
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