livesey-database
v1.1.2
Published
a lightweight module that allows you to work with database queries without using ORM
Downloads
21
Maintainers
Readme
livesey-database
Overview
This package provides an abstract database client and a generic database interface for interacting with different SQL databases (MySQL and PostgreSQL). It allows for building and executing SQL queries in a fluent, chainable manner, abstracting the complexities of direct SQL syntax.
Features
- Fluent API for building SQL queries.
- Database-agnostic: Supports multiple databases (MySQL and PostgreSQL).
- Chainable methods: Build complex queries by chaining method calls.
- Error handling: Provides meaningful error messages for database operations.
Table of Contents
Getting Started
Installation
To install the package, use npm:
npm install livesey-database
Configuration
Before using the package, configure your environment variables in a .env
file or directly in your environment:
DB_TYPE=mysql # or postgres
DB_HOST=#your host
DB_USER=#your username
DB_PASSWORD=#your password
DB_NAME= #your database name
DB_PORT=3306 # or 5432 for PostgreSQL
DB_SSL=true # or false for non-SSL connections
To use it you have to install and import dotenv package:
- Installation:
npm i dotenv
Import for ECMAScript:
import dotenv from 'dotenv';
dotenv.config();
Import for CommonJS:
const dotenv = require("dotenv");
dotenv.config();
You also have to install and set pools for database packages, you will work with:
- Installation:
npm i pg # for PostgreSQL
npm i mysql2 # for MySQL
If you use PostgreSQL(ESM):
import pkg from 'pg';
const { Pool } = pkg;
const postgresPool = new Pool({
host: dbHost,
user: dbUser,
password: dbPassword,
database: dbName,
port: dbPort,
ssl: dbSsl === "true" ? { rejectUnauthorized: false } : false,
});
If you use PostgreSQL(CJS):
const { Pool } = require("pg");
const postgresPool = new Pool({
host: dbHost,
user: dbUser,
password: dbPassword,
database: dbName,
port: dbPort,
ssl: dbSsl === "true" ? { rejectUnauthorized: false } : false,
});
If you use MySQL(ESM):
import mysql from "mysql2/promise";
const mySqlPool = mysql.createPool({
host: dbHost,
user: dbUser,
password: dbPassword,
database: dbName,
port: dbPort,
});
If you use MySQL(CJS):
const mysql = require("mysql2/promise");
const mySqlPool = mysql.createPool({
host: dbHost,
user: dbUser,
password: dbPassword,
database: dbName,
port: dbPort,
});
Usage
1. Initialize the Database Client
You need to initialize the database client based on the environment configuration (MySQL or PostgreSQL).
import { MySQLClient, PostgresClient, Database } from 'livesey-database';
import { mySqlPool, postgresPool } from './dbConfig.js';
// Determine the database client type based on the environment configuration
const dbClient = process.env.DB_TYPE === 'mysql' ? new MySQLClient(mySqlPool) : new PostgresClient(postgresPool);
2. Schema Creation and Serialization
Define and Create Schemas
You can create your own table using JSON syntax that follows structures like these:
import { createSchema } from 'livesey-database';
export const PermissionSchema = {
'Table': {
'tableName': 'Permission',
'columns': {
'permissionId': {
'type': 'uuid',
'primaryKey': true,
'unique': true,
'notNull': true
},
'permissionName': {
'type': 'varchar',
'length': 255,
'notNull': true
},
'description': {
'type': 'text'
}
}
}
};
await createSchema(dbClient, PermissionSchema);
console.log('Permission table created successfully.');
Foreign Keys and Relationships
If you want to create relationship (OneToOne
, ManyToOne
, OneToMany
, ManyToMany
) you should define it in relations
sector.
export const RoleSchema = {
'Table': {
'tableName': 'Role',
'columns': {
'roleId': {
'type': 'uuid',
'primaryKey': true,
'unique': true,
'notNull': true
},
'roleName': {
'type': 'varchar',
'length': 255,
'notNull': true
}
},
'relations': {
'ManyToMany': {
'relatedEntity': 'Permission',
'foreignKey': 'roleId'
}
}
}
};
await createSchema(dbClient, RoleSchema);
console.log('Role table with ManyToMany relation was created successfully.');
3. Create a Database Instance
Once you have a dbClient, you can create a Database instance for the desired table.
const db = new Database('User', dbClient);
4. Perform Database Operations
Select Queries
To select all columns from a table:
const users = await db.select().execute();
console.log('All Users:', users);
To select specific columns with conditions:
const users = await db.select({ name: true, surname: true })
.where({ name: 'John', surname: 'Doe' })
.execute();
console.log('Selected Users:', users);
Insert Queries
To insert data into a table:
await db.insert()
.into(['name', 'price', 'quantity'])
.values(['Product A', 10.99, 5])
.execute();
console.log('Product inserted successfully');
Update Queries
To update data in a table:
await db.update()
.set({ name: 'Timber', surname: 'Saw' })
.where({ userId: 'c5fe6661-93ea-43f9-8b6a-92f31f00aa16' })
.execute();
console.log('User updated successfully');
Delete Queries
To delete data from a table:
await db.delete()
.where({ userId: 'c5fe6661-93ea-43f9-8b6a-92f31f00aa16' })
.execute();
console.log('User deleted successfully');
5. Close the Database Connection
Don't forget to release the database client connection when you are done:
try {
//some logic here
} catch (error) {
console.error('❌ Database error:', error.message);
} finally {
await dbClient.release(); // break connection with db
}
API Reference
DatabaseClient
An abstract class for creating a database client.
Constructor
new DatabaseClient()
Methods
async connect()
: Establish a connection to the database. Must be implemented in derived classes.async query(queryText, params)
: Execute a SQL query with optional parameters. Must be implemented in derived classes.release()
: Close the database connection. Must be implemented in derived classes.
MySQLClient
Implements the DatabaseClient
interface for MySQL databases.
Constructor
new MySQLClient(mySqlPool)
Methods
newMySQLClient(mySqlPool)
: Allows to use client like:MySQLClient.newMySQLClient(mySqlPool)
.async connect()
: Returns a MySQL connection from the pool.async query(queryText, params)
: Executes a SQL query using MySQL connection.release()
: Ends all connections in the MySQL pool.
PostgresClient
Implements the DatabaseClient
interface for PostgreSQL databases.
Constructor
new PostgresClient(postgresPool)
Methods
newPostgresClient(postgresPool)
: Allows to use client like:PostgresClient.newPostgresClient(postgresPool)
.async connect()
: Returns a PostgreSQL connection from the pool.async query(queryText, params)
: Executes a SQL query using PostgreSQL connection.release()
: Ends all connections in the PostgreSQL pool.
Database
A class to build and execute SQL queries for a specific table.
Constructor
new Database(tableName: string, dbClient: string)
: Initializes a new instance of theDatabase
class for a given table and database client.
Methods
select(fields: Array)
: Builds a SELECT SQL query.fields
is an array where keys are column names.where(conditions: Object)
: Adds a WHERE clause to the SQL query.conditions
is an object with column names and their corresponding values or operators.insert()
: Begins an INSERT SQL query.into(columns: Array)
: Specifies the columns for the INSERT SQL query.values(valuesArray: Array)
: Adds values for the INSERT SQL query.update()
: Begins an UPDATE SQL query.set(object: Object)
: Sets the columns and values to be updated.delete()
: Begins a DELETE SQL query.async execute()
: Executes the built SQL query.
DatabaseFunction
Extends Database
to provide higher-level operations such as finding, saving, updating, and deleting records.
Constructor
new DatabaseFunction(tableName: string, dbClient: string)
Methods
async findRecord(criteria: Object, selectFields: Array)
: Finds a record matching the criteria.async saveRecord(data: Object)
: Inserts a new record into the table.async updateRecord(criteria: Object, updateData: Object)
: Updates a record matching the criteria.async deleteRecord(criteria: Object)
: Deletes a record matching the criteria.
createSchema
Creates a table from schema(json object).
Methods
createSchema(dbClient: string, schema: Object)
: Function to create tables and manage relationships.
Indexes
Indexes are a crucial part of database optimization, improving the performance of queries by allowing faster data retrieval. The livesey-database
package provides utility functions to create, manage, and delete indexes in both MySQL and PostgreSQL databases.
Types of Indexes
- Standard Index: Speeds up data retrieval based on the values in one or more columns.
- Unique Index: Ensures that the values in the indexed column(s) are unique across all rows.
Functions for Managing Indexes
The package provides three key functions for working with indexes:
createIndex
createUniqueIndex
dropIndex
These functions allow you to easily create and manage indexes on tables, supporting both MySQL and PostgreSQL syntax.
createIndex
Creates a standard index on one or more columns of a specified table.
Parameters:
tableName
(string): Name of the table on which the index will be created.dbClient
(DatabaseClient): The database client to use for the operation.dbType
(string): The type of database (mysql
orpostgres
).columns
(string[]): The columns to be indexed.
Example:
await createIndex('User', dbClient, 'postgres', 'name', 'email');
In this example, an index will be created on the name
and email
columns of the User
table in a PostgreSQL database.
createUniqueIndex
Creates a unique index on one or more columns, ensuring that values in the indexed columns are unique.
Parameters:
tableName
(string): Name of the table on which the unique index will be created.dbClient
(DatabaseClient): The database client to use for the operation.dbType
(string): The type of database (mysql
orpostgres
).columns
(string[]): The columns to be indexed.
Example:
await createUniqueIndex('User', dbClient, 'mysql', 'email');
This creates a unique index on the email
column of the User
table in a MySQL database.
dropIndex
Drops an existing index from a table.
Parameters:
tableName
(string): The name of the table from which the index will be dropped.dbClient
(DatabaseClient): The database client to use for the operation.dbType
(string): The type of database (mysql
orpostgres
).indexName
(string): The name of the index to be dropped.
Example:
await dropIndex('User', dbClient, 'postgres', 'User_email_idx');
This command will drop the index named User_email_idx
from the User
table in a PostgreSQL database.
Tests
You can test this module using tests in src/test
folder. Here is the structure:
tests
├── connection.test.js
├── database.test.js
├── envConfig.js
├── functions.test.js
├── indexes.test.js
└── serializer.test.js
1 directory, 6 files
If you want to run tests on your local machine, you have to follow these steps:
- Install and configure environmental variables
You have to install dotenv
package via NPM:
npm i dotenv
Create .env
file and put there these variables(you can put more if you want to use additional functionality in pools):
DB_TYPE=mysql # or postgres
DB_HOST=#your host
DB_USER=#your username
DB_PASSWORD=#your password
DB_NAME= #your database name
DB_PORT=3306 # for MySQL or 5432 for PostgreSQL
DB_SSL=true # or false for non-SSL connections
- You have to install pg or mysql2 package via NPM:
npm i pg # for PostgreSQL
npm i mysql2 # for MySQL
All tests in
src/tests
are wrapped in quotes as comments - uncomment itUse
npm run test
to start tests
You can find this block of code in package.json
:
"scripts": {
"lint": "npx biome format . --write",
"test": "node --test tests/*.test.js"
}
So, if you want to correct syntax in test or in new code, you have to run npm run lint command
.
- Happy testing 👩💻
Contributing
Contributions are welcome! Please submit a pull request or open an issue on the GitHub repository.
License
This project is licensed under the MIT License. See the LICENSE file for more information.
Support
If you have any questions or need further assistance, please open an issue on our GitHub repository or contact the maintainer.
Contact
For any questions or inquiries, please contact [email protected].
By following the above documentation, you should be able to easily configure and use the database package in your application.