Singleton Design Pattern: creating one database instance for your backend application using knex
Vitor Rafael
Posted on June 1, 2023
1. Singleton Brief apresentation
The singleton design pattern allow a user to create a class and make sure that exists just one instance of this class in your application and a unique point of access to that instance.
There are some steps to create a singleton class:
1º add a private static field that store the class instance
2º declare a public static method that allow you to access the class
3º Implement lazy initialization inside the public method. It means this method will create an instance of the class if It does not exists yet.
4º Make sure the constructor of the class is private, so the class can be instanciated only inside of itself
2. Context of the implementation
On the implementation I will use the knex query build. Knex is a query builder mainly used on nodejs applications that allows you to create queries and do operations on database, with Knex you can create CRUDs;
With that on mind, I will create just a single class that provides a Knex configuration that you can use in all your application to do operations on the database.
*3. What you need to replicate this? *
- You will need a nodejs project configured using Fastify. With that, you can create routes to recieve data to store on a database.
- Also you need to install Knex on the project and configure it. You can see how to to that on:
4. UML Diagram
On this section I want to present you the UML diagram that represents the singletion class I will create:
5. Let's go to the code
import { knex as setupKnex, Knex } from 'knex'
import path from 'node:path'
import { env } from '../env'
class SetupKnexSingleton {
private static _instance: SetupKnexSingleton | null = null
public knex: Knex<any, unknown[]>
private client: string = 'sqlite'
private connectionPath: string = path.resolve(__dirname, env.DATABASE_URL)
private migrationsExtesions = 'ts'
private migrationsDirectory = './src/database/migrations'
private useAsDefault: boolean = true
private constructor() {
this.knex = setupKnex({
client: this.client,
connection: {
filename: this.connectionPath,
},
useNullAsDefault: this.useAsDefault,
migrations: {
extension: this.migrationsExtesions,
directory: this.migrationsDirectory,
},
})
}
public static getInstance(): SetupKnexSingleton {
if (SetupKnexSingleton._instance === null) {
SetupKnexSingleton._instance = new SetupKnexSingleton()
}
return SetupKnexSingleton._instance
}
}
export const knex = SetupKnexSingleton.getInstance().knex
On the class above, you can see we have:
1º private static _instance
2º The constructor is private
3º We have a method getInstance() that returns the instance of the class and inside this method we have the lasy initialization.
With that we have accomplished the use of the Design Pattern Singleton and created and Knex instance that can be used in all the application. The constructor is responsible for creating the Knex configuration.
Posted on June 1, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.