Security News
New Python Packaging Proposal Aims to Solve Phantom Dependency Problem with SBOMs
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
node-mysql-query-utils
Advanced tools
A MySQL helper to provide ways to connect to the database, build SQL queries, and perform common database operations for Node.js.
node-mysql-query-utils
is a MySQL query builder and helper for Node.js. It provides a simple and easy way to build and execute MySQL queries.
npm install node-mysql-query-utils
or
yarn add node-mysql-query-utils
This package provides three classes to help you manage and interact with your MySQL database:
Here’s a quick overview of how to make use of this library:
import {
DatabaseManagement,
TableModel,
SQLBuilder,
sqlHelper,
} from "node-mysql-query-utils";
// entry point of the application e.g. start server
// index.ts
DatabaseManagement.connectMultipleDatabases([
{
identifierName: "mainDB",
config: {
host: "localhost",
user: "root",
password: "password",
database: "test_db",
},
options: {
verbose: true, // optional, default is true. If true, will log all queries to console
},
},
]);
//or
DatabaseManagement.connectSingleDatabase(
"mainDB",
{
host: "localhost",
user: "root",
password: "password",
database: "test_db",
},
{
verbose: true, // optional, default is true. If true, will log all queries to console
}
);
// model folder
// user.ts
const mainDB = DatabaseManagement.getInstance("mainDB"); // get instance of mainDB
const columns = sqlHelper.createColumns([
"user_id",
"ctime",
"utime",
"email",
"mobile",
"password",
"is_active",
"is_deleted",
]);
export const userAccountModel = mainDB.createTableModel({
tableName: "user_account",
primaryKey: "user_id",
columns,
centralFields: {
ctimeField: "ctime", // created_at column name in db
utimeField: "utime", // updated_at column name in db
isActiveField: "is_active", // is_active column name in db
isDeletedField: "is_deleted", // is_deleted column name in db
statusField: "status", // status column name in db
},
});
// usage of userAccountModel in other files e.g. api-related files
// get user by id
The DatabaseManagement
class is a singleton class that helps manage database connections. It supports connecting to single or multiple databases and provides a way to retrieve instances of the connections.
import { DatabaseManagement } from "node-mysql-query-utils";
import { ConnectionOptions } from "mysql2/promise";
// Define connection configurations
const config: ConnectionOptions = {
host: "localhost",
user: "root",
password: "password",
database: "test_db",
};
// Connect to a single database
DatabaseManagement.connectSingleDatabase("mainDB", config);
// Retrieve the instance and use it to perform database operations
const dbInstance = DatabaseManagement.getInstance("mainDB");
import { DatabaseManagement } from "node-mysql-query-utils";
import { type DatabaseConnectionConfig } from "node-mysql-query-utils/dist/dto/types";
// Define multiple connection configurations
const configs: DatabaseConnectionConfig[] = [
{
identifierName: "mainDB",
config: {
host: "localhost",
user: "root",
password: "password",
database: "main_db",
},
},
{
identifierName: "analyticsDB",
config: {
host: "localhost",
user: "root",
password: "password",
database: "analytics_db",
},
},
];
// Connect to multiple databases
DatabaseManagement.connectMultipleDatabases(configs);
// Retrieve instances and use them to perform database operations
const mainDBInstance = DatabaseManagement.getInstance("mainDB");
const analyticsDBInstance = DatabaseManagement.getInstance("analyticsDB");
The SQLBuilder
class provides a way to build SQL queries for various operations such as SELECT, INSERT, UPDATE, DELETE, etc.
To generate the final SQL query and its parameters, you must call the .buildQuery()
method at the end of your query-building process.
If the SQLBuilder
constructor is provided with a queryFn
, you can use the .executeQuery()
method to execute the query directly.
import { SQLBuilder, sqlHelper } from "node-mysql-query-utils";
// Define the table name
const tableName = "user_account";
const columns = sqlHelper.createColumns([
"user_id",
"ctime",
"utime",
"email",
"mobile",
"password",
"is_active",
"is_deleted",
]);
// typescript
const sqlBuilder = new SQLBuilder<(typeof columns)[number]>();
// Javascript - no type hinting, but still works. Suggest using TableModel class for better type hinting if using Javascript
const sqlBuilder = new SQLBuilder();
// Accept QueryFunction for SQLBuilder to enable query execution
const sqlBuilder = new SQLBuilder(db.query.bind(db)); // Optional: put your own query function here if you don't connect DB by DatabaseManagement class from this package
// Accept second generic type for query function
const sqlBuilder = new SQLBuilder<(typeof columns)[number], any>(
db.query.bind(db)
); // Optional: put your own query function here if you don't connect DB by DatabaseManagement class from this package
// Call buildQuery to get the SQL query and parameters in the end
const { sql, params } = sqlBuilder.select().from(tableName).buildQuery();
// Can also use array destructuring
const [sql, params] = sqlBuilder.select().from(tableName).buildQuery();
// BuildQuery also accepts an options object. it will return complete query with format. params will be empty array if format is true
const [sql, params] = sqlBuilder
.select()
.from(tableName)
.buildQuery({ format: true });
// run your own query function if you don't connect DB by DatabaseManagement class from this package
const result = await db.query(sql, params);
// if query function is provided in SQLBuilder, you can execute the query directly
const result = await sqlBuilder.select().from(tableName).executeQuery();
// Select all columns, default is '*'
const [sql, params] = sqlBuilder.select().from(tableName).buildQuery();
const [sql, params] = sqlBuilder.select("*").from(tableName).buildQuery();
// Select specific columns
const [sql, params] = sqlBuilder
.select(["user_id", "email"])
.from(tableName)
.buildQuery();
// Select columns with aliases
const [sql, params] = sqlBuilder
.select([{ user_id: "id", mobile: "user_mobile" }, { email: "user_email" }])
.from(tableName)
.buildQuery();
// Select a single column
const [sql, params] = sqlBuilder.select("user_id").from(tableName).buildQuery();
// Select with raw SQL
const [sql, params] = sqlBuilder
.select([{
raw: 'CASE WHEN expire_time < FROM_UNIXTIME(?) THEN 1 ELSE 0 END',
alias: 'is_expired',
params: [dayjs().unix()],
}])
.from(tableName)
.buildQuery();
// No alias
const [sql, params] = sqlBuilder.select().from("user_account").buildQuery();
// alias example
const [sql, params] = sqlBuilder
.select()
.from("user_account", "u")
.buildQuery();
const [sql, params] = sqlBuilder.select().from("user_account u").buildQuery();
// Inner join
const [sql, params] = sqlBuilder
.select()
.from("user_account", "u")
.join(
"INNER",
"user_profile_pic",
"up",
"u.user_profile_pic_id = up.user_profile_pic_id"
)
.buildQuery();
// Left join
const [sql, params] = sqlBuilder
.select()
.from("user_account", "u")
.join(
"LEFT",
"user_profile_pic",
"up",
"u.user_profile_pic_id = up.user_profile_pic_id"
)
.buildQuery();
// Right join
const [sql, params] = sqlBuilder
.select()
.from("user_account", "u")
.join(
"RIGHT",
"user_profile_pic",
"up",
"u.user_profile_pic_id = up.user_profile_pic_id"
)
.buildQuery();
Only provide third argument if no alias is needed
// Inner join
const [sql, params] = sqlBuilder
.select()
.from("user_account", "u")
.join(
"INNER",
"user_profile_pic",
"u.user_profile_pic_id = user_profile_pic.user_profile_pic_id"
)
.buildQuery();
// All condition examples
const [sql, params] = sqlBuilder
.select()
.from("user_account")
.where({
email: "123@gmail.com", // equal to '
email: { "=": "123@gmail.com" }, // equal to '
email: { "!=": "123@gmail.com" }, // not equal to
user_id: { ">": 123 },
user_id: { "<": 123 },
user_id: { ">=": 123 },
user_id: { "<=": 123 },
is_active: { BETWEEN: [0, 1] },
is_active: { NOT_BETWEEN: [0, 1] },
status: { IN: [1, 2, 3, 4] },
status: { NOT_IN: [1, 2, 3, 4] },
nickname: { IS_NOT_NULL: true }, // must be true, false will throw error
nickname: { IS_NULL: true }, // must be true, false will throw error
nickname: { LIKE: { contains: 'name' } }, // contains 'name'
nickname: { NOT_LIKE: { startsWith: 'name' } }, // not starts with 'name'
nickname: { LIKE: { endsWith: 'name' } }, // ends with 'name'
nickname: { LIKE: '%_123' } // custom pattern
nickname: { REGEXP: '^[a-zA-Z0-9]*$' } // custom pattern
"u.user_id": { "!=": 1 }, // assume alias is set in From's second parameters (e.g. .from("user_account", "u"))
})
.buildQuery();
// AND example
const [sql, params] = sqlBuilder
.select()
.from("user_account")
.where({
email: "123@gmail.com",
is_active: 1,
})
.buildQuery();
// alternative AND example
const [sql, params] = sqlBuilder
.select()
.from("user_account")
.where({
AND: [{ email: { LIKE: "%@gmail.com" } }, { username: "jane" }],
});
// OR example
const [sql, params] = sqlBuilder
.select()
.from("user_account")
.where({
OR: [{ email: { LIKE: "%@gmail.com" } }, { username: "jane" }],
});
Supported Operators:
=
!=
>
<
>=
<=
LIKE
,NOT_LIKE
REGEXP
,IN
,NOT_IN
BETWEEN
NOT_BETWEEN
IS_NULL
IS_NOT_NULL
// Single order by
const [sql, params] = sqlBuilder
.select()
.from("user_account")
.orderBy([{ field: "email", direction: "ASC" }])
.buildQuery();
// Multiple order by
const [sql, params] = sqlBuilder
.select()
.from("user_account")
.orderBy([
{ field: "email", direction: "ASC" },
{ field: "user_id", direction: "DESC" },
])
.buildQuery();
// Limit
const [sql, params] = sqlBuilder
.select()
.from("user_account")
.limit(10)
.buildQuery();
// Limit and offset
const [sql, params] = sqlBuilder
.select()
.from("user_account")
.limit(10)
.offset(5)
.buildQuery();
// Insert single row
const [sql, params] = sqlBuilder
.insert(
"user_account",
{ email: "123@gmail.com" },
{
enableTimestamps = false, // if true, will add ctime and utime to insert object
ctimeField = "ctime",
utimeField = "utime",
ctimeValue = Math.floor(Date.now() / 1000), // default is current unix timestamp
utimeValue = Math.floor(Date.now() / 1000), // default is current unix timestamp
insertIgnore = false, // if true, will add IGNORE to the insert query
}
)
.buildQuery();
The insert
method accepts options parameter with the following properties:
Property | Type | Description |
---|---|---|
enableTimestamps | boolean | (Optional) If true, will add ctime and utime to the insert object. Default is false. |
ctimeField | string | (Optional) The field name for the create timestamp. Default is ctime . |
utimeField | string | (Optional) The field name for the update timestamp. Default is utime . |
ctimeValue | any | (Optional) The value for the create timestamp. Default is the current Unix timestamp. |
utimeValue | any | (Optional) The value for the update timestamp. Default is the current Unix timestamp. |
insertIgnore | boolean | (Optional) If true, will add IGNORE to the insert query. Default is false. |
// Update Method 1
const [sql, params] = sqlBuilder
.update(
"user_account",
{ email: "123@gmail.com" },
// Options
{
enableTimestamps = false, // if true, will add utime to update object
utimeField = "utime",
utimeValue = Math.floor(Date.now() / 1000), // default is current unix timestamp
}
)
.where({ user_id: 1 })
.buildQuery();
// Update Method 2 (Options not supported yet)
const [sql, params] = sqlBuilder
.update("user_account")
.set({ email: "123@gmail.com" })
.where({ user_id: 1 })
.buildQuery();
// Increment and Decrement (Added in version v1.0.4)
const [sql, params] = sqlBuilder
.update("user_account")
.set({ balance: { increment: 100 } })
.where({ user_id: 1 })
.buildQuery();
The update
method accepts options parameter with the following properties:
Property | Type | Description |
---|---|---|
enableTimestamps | boolean | (Optional) If true, will add utime to the update object. Default is false. |
primaryKey | string | (Optional) The primary key field name. For removing primaryKey in update object |
utimeField | string | (Optional) The field name for the update timestamp. Default is utime . |
utimeValue | any | (Optional) The value for the update timestamp. Default is the current Unix timestamp. |
// Delete Whole Table
const [sql, params] = sqlBuilder.deleteFrom("user_account").buildQuery();
// Delete with where
const [sql, params] = sqlBuilder
.deleteFrom("user_account")
.where({ user_id: 1 })
.buildQuery();
// Delete with limit
const [sql, params] = sqlBuilder
.deleteFrom("user_account")
.where({ user_id: { ">": 1 } })
.limit(1)
.buildQuery();
// Build query with format
const sqlBuilder = new SQLBuilder<(typeof columns)[number]>();
const [sql, params] = sqlBuilder
.select()
.from("user_account")
.buildQuery({ format: true });
// Execute query
const sqlBuilder = new SQLBuilder<(typeof columns)[number]>();
const result = await sqlBuilder.select().from("user_account").executeQuery();
// Without calling .buildQuery() or .executeQuery() as end of query building
const sqlBuilder = new SQLBuilder<(typeof columns)[number]>();
const result = sqlBuilder.select().from("user_account");
// result will be an instance of SQLBuilder
// SQLBuilder {
// queryFn: [Function: bound executeQuery] AsyncFunction,
// message: 'Call .buildQuery() or .executeQuery() to get the result'
// }
// To get the result, call .buildQuery() or .executeQuery()
const [sql, params] = result.buildQuery();
// or
const result = await result.executeQuery(); // if query function is provided in SQLBuilder
The TableModel
class is a wrapper around the SQLBuilder
class that provides a way to build and execute common database operations like SELECT, INSERT, UPDATE, DELETE, etc.
To generate the final SQL query and its parameters, you must call the .buildQuery()
method at the end of your query-building process. If you have provided a query function, you can use the .executeQuery()
method to execute the query directly.
There are two ways to define and use the TableModel
class:
Connect database by DatabaseManagement
class can refer to the Quick Start example. This method involves connecting to multiple databases using the DatabaseManagement
class and then retrieving instances to create table models.
Alternatively, you can define the table model by using the TableModel
class directly. This method is useful if you prefer to use your own query function or if you don't connect to the database using the DatabaseManagement
class from this package.
// Define the table model by using the TableModel class directly
const userModel = new TableModel({
tableName: "users",
primaryKey: "user_id",
columns: sqlHelper.createColumns(["user_id", "name", "email", "phone"]),
queryFn: db.query.bind(db), // Optional: put your own query function here if you don't connect DB by DatabaseManagement class from this package
});
The TableModel
class provides the following methods to perform database operations:
Method | Description |
---|---|
createSelect | Creates a SELECT query. Returns a function that returns an instance of the SQLBuilder class. You can chain the SQLBuilder methods to build your desired query. |
createInsert | Creates an INSERT query. Returns a function that returns an instance of the SQLBuilder class. You can chain the SQLBuilder methods to build your desired query. |
createUpdate | Creates an UPDATE query. Returns a function that returns an instance of the SQLBuilder class. You can chain the SQLBuilder methods to build your desired query. |
createDelete | Creates a DELETE query. Returns a function that returns an instance of the SQLBuilder class. You can chain the SQLBuilder methods to build your desired query. |
createCount | Creates a COUNT query. Returns a function that returns an instance of the SQLBuilder class. You can chain the SQLBuilder methods to build your desired query. |
findOne | Finds a single record. Returns an instance of the SQLBuilder class with the findOne method configured. |
findAll | Finds multiple records. Returns an instance of the SQLBuilder class with the findAll method configured. |
remove | Removes records based on conditions. Returns an instance of the SQLBuilder class with the remove method configured. |
removeOne | Removes a single record based on conditions. Returns an instance of the SQLBuilder class with the removeOne method configured. |
patchSingleField | Updates a single field in records based on conditions. Returns an instance of the SQLBuilder class with the patchSingleField method configured. |
softDeleteOne | Soft deletes a single record based on conditions. Returns an instance of the SQLBuilder class with the softDeleteOne method configured. |
softDelete | Soft deletes multiple records based on conditions. Returns an instance of the SQLBuilder class with the softDelete method configured. |
The TableModel
class provides the following methods to perform database operations.
Methods that start with create
(e.g., createSelect
, createInsert
) return a function that returns an instance of the SQLBuilder
class. You can chain the SQLBuilder
methods to build your desired query.
Other methods, such as findOne
, return an instance of the SQLBuilder
class that is already configured with some chained methods. These methods act as wrapper functions for common CRUD operations and are not intended for further chaining.
const selectUser = userModel.createSelect();
const result = await selectUser({
fields: ["user_id", "email", "nickname"],
})
.where({ user_id: 1 })
.executeQuery();
const insertUser = userModel.createInsert();
const result = await insertUser({
data: { user_id: 1, email: "123@email.com", nickname: "John Doe" },
}).executeQuery();
const updateUser = userModel.createUpdate();
const result = await updateUser({
data: { nickname: "John Doe 2" },
where: { user_id: { "<=": 5 } },
})
.limit(2)
.executeQuery();
const deleteUser = userModel.createDelete();
const result = await deleteUser({ where: { user_id: 1 } })
.limit(1)
.executeQuery();
const countResult = await countUser("user_id")
.where({ user_id: { "<": 2 } })
.executeQuery();
The following table lists common parameters that many methods accept. Note that some parameters may be available for certain methods while others may not, as each method performs different operations. TypeScript will provide hints for the available parameters for each method.
Parameter | Type | Description |
---|---|---|
fields | Array | An array of strings specifying the columns to select. |
where | Object | An object specifying the conditions for the query. |
orderBy | Array | An array of objects specifying the columns to order by and the direction (ASC or DESC). |
limit | Number | A number specifying the maximum number of rows to return. |
offset | Number | A number specifying the offset of the first row to return. |
options | Object | An object specifying additional options for the query. Can be referenced in Update Options. |
const [user] = await userModel
.findOne({ where: { user_id: 1 } })
.executeQuery();
const users = await userModel
.findAll({
fields: ["user_id", "email"],
where: { is_active: true },
orderBy: [{ column: "user_id", direction: "ASC" }],
limit: 10,
offset: 0,
})
.executeQuery();
const updatedOneUser = await userModel
.updateOne({
where: { user_id: 1 },
data: { email: "123@gmail.com" },
})
.executeQuery();
const updateAllUsers = await userModel
.updateAll({
data: { nickname: "John Doe" },
where: { user_id: { "<=": 5 } },
options: { enableTimestamps: true, utimeField: "utime" },
})
.executeQuery();
const insertedUser = await userModel
.insertRecord({
data: { user_id: 1, email: "123@gmail.com", nickname: "John Doe" },
options: {
enableTimestamps: true,
ctimeField: "ctime",
utimeField: "utime",
},
})
.executeQuery();
const deletedOneUser = await userModel
.removeOne({
where: { user_id: { ">": 1 } },
orderBy: [{ field: "user_id", direction: "ASC" }],
})
.executeQuery();
const deletedAllUsers = await userModel
.remove({ where: { user_id: 1 } })
.executeQuery();
const patchedActiveField = await userModel
.patchSingleField({
patchField: "is_active",
where: { user_id: 1 },
value: 1,
options: { enableTimestamps: true, utimeField: "utime" },
})
.executeQuery();
const softDeletedUser = await userModel
.softDeleteOne({
where: { user_id: 1 },
value: 1,
options: {
enableTimestamps: true,
deleteField: "is_deleted",
utimeField: "utime",
},
})
.executeQuery();
const softDeletedUsers = await userModel
.softDelete({
where: { user_id: { ">": 1 } },
value: 1,
options: {
enableTimestamps: true,
deleteField: "is_deleted",
utimeField: "utime",
},
})
.executeQuery();
Detailed changes for each version are documented in the CHANGELOG.md file.
[1.0.5] - 2024-11-28
Raw SQL Support in Fields:
fields
parameter of the SQLBuilder
class.RawField
type, enabling greater flexibility in query construction.Default Table Alias in TableModel
Class:
tableNameAlias
property in the TableModel
constructor to set a default alias for the table.createXXXXXX()
Methods in TableModel
Class:
createXXXXXX()
methods (createSelect
, createUpdate
, createInsert
, etc.) were using the same instance of SQLBuilder
.SQLBuilder
, preventing SQL query misconstruction and ensuring thread safety.FAQs
A simple MySQL query utils for Node.js
The npm package node-mysql-query-utils receives a total of 6 weekly downloads. As such, node-mysql-query-utils popularity was classified as not popular.
We found that node-mysql-query-utils demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
Security News
Socket CEO Feross Aboukhadijeh discusses open source security challenges, including zero-day attacks and supply chain risks, on the Cyber Security Council podcast.
Security News
Research
Socket researchers uncover how threat actors weaponize Out-of-Band Application Security Testing (OAST) techniques across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.