firebird-query
Advanced tools
Comparing version
@@ -1,74 +0,72 @@ | ||
import Firebird, { Database } from "node-firebird"; | ||
type ValueType = string | number | Date; | ||
declare const keyValueOperators: readonly ["=", "!=", "<>", ">", "<", ">=", "<="]; | ||
type KeyValueOperator = (typeof keyValueOperators)[number]; | ||
declare const keyOperators: readonly ["IS NULL", "IS NOT NULL"]; | ||
type KeyOperator = (typeof keyOperators)[number]; | ||
type KeyValueInputGeneratorArg = { | ||
operator?: KeyValueOperator; | ||
key: string; | ||
value: ValueType; | ||
evaluateIf?: boolean; | ||
}; | ||
type KeyInputGeneratorArg = { | ||
operator: KeyOperator; | ||
key: string; | ||
evaluateIf?: boolean; | ||
}; | ||
type Condition = KeyInputGeneratorArg | KeyValueInputGeneratorArg; | ||
type InsertParams<T> = { | ||
readonly tableName: string; | ||
readonly columnNames: ReadonlyArray<keyof T>; | ||
readonly rowValues: ReadonlyArray<{ | ||
[k in keyof T]: any; | ||
}>; | ||
}; | ||
type InsertOneParams<T> = { | ||
readonly tableName: string; | ||
readonly rowValues: { | ||
[k in string]: any; | ||
}; | ||
readonly returning?: ReadonlyArray<keyof T>; | ||
}; | ||
type UpdateOneParams<T> = { | ||
readonly tableName: string; | ||
readonly rowValues: { | ||
[k in string]: any; | ||
}; | ||
readonly returning?: ReadonlyArray<keyof T>; | ||
readonly conditions: { | ||
[k in string]: any; | ||
}; | ||
}; | ||
type UpdateOrInsertParams<T> = { | ||
readonly tableName: string; | ||
readonly rowValues: { | ||
[k in string]: any; | ||
}; | ||
readonly returning?: ReadonlyArray<keyof T>; | ||
}; | ||
export declare const pool: (max: number, options: Firebird.Options) => { | ||
queryRaw: <T = unknown>(strings: TemplateStringsArray, ...params: Array<ValueType | Condition[]>) => { | ||
import Firebird from "node-firebird"; | ||
import { DeleteOneParams, InsertOneParams, InsertParams, PrimetiveValue, UpdateOneParams, UpdateOrInsertParams, WhereObject } from "./sql_builder"; | ||
export declare class FirebirdQuery { | ||
private conn; | ||
constructor(options?: Firebird.Options, max?: number); | ||
private getDB; | ||
private manageQuery; | ||
private getTransaction; | ||
get queryRaw(): <T>(strings: TemplateStringsArray, ...params: (PrimetiveValue | WhereObject)[]) => { | ||
getQuery: () => string; | ||
execute: () => Promise<T[]>; | ||
paginated: (take: number, page?: number) => Promise<T[]>; | ||
}; | ||
insertMany: <T_1>({ tableName, columnNames, rowValues, }: InsertParams<T_1>) => { | ||
get insertOne(): <T extends { | ||
[key: string]: any; | ||
}>(params: InsertOneParams<T>) => { | ||
getQuery: () => string; | ||
execute: () => Promise<T>; | ||
}; | ||
get insertMany(): <T extends { | ||
[key: string]: any; | ||
}>(params: InsertParams<T>) => { | ||
getQuery: () => string; | ||
execute: () => Promise<string>; | ||
}; | ||
insertOne: <T_2 = void>({ tableName, rowValues, returning, }: InsertOneParams<T_2>) => { | ||
get updateOne(): <T>(params: UpdateOneParams<T>) => { | ||
getQuery: () => string; | ||
execute: () => Promise<T_2>; | ||
execute: () => Promise<T>; | ||
}; | ||
updateOne: <T_3 = void>({ tableName, rowValues, returning, conditions, }: UpdateOneParams<T_3>) => { | ||
get updateOrInsert(): <T>(params: UpdateOrInsertParams<T>) => { | ||
getQuery: () => string; | ||
execute: () => Promise<T_3>; | ||
execute: () => Promise<T>; | ||
}; | ||
updateOrInsert: <T_4 = void>({ tableName, rowValues, returning, }: UpdateOrInsertParams<T_4>) => { | ||
get deleteOne(): <T>(table: string, params: DeleteOneParams<T>) => { | ||
getQuery: () => string; | ||
execute: () => Promise<T_4>; | ||
execute: () => Promise<T>; | ||
}; | ||
$getPool: () => Promise<Database>; | ||
$Firebird: typeof Firebird; | ||
}; | ||
export {}; | ||
initTransaction(): Promise<{ | ||
queryRaw: <T>(strings: TemplateStringsArray, ...params: (PrimetiveValue | WhereObject)[]) => { | ||
getQuery: () => string; | ||
execute: () => Promise<T[]>; | ||
paginated: (take: number, page?: number) => Promise<T[]>; | ||
}; | ||
insertOne: <T_1 extends { | ||
[key: string]: any; | ||
}>(params: InsertOneParams<T_1>) => { | ||
getQuery: () => string; | ||
execute: () => Promise<T_1>; | ||
}; | ||
insertMany: <T_2 extends { | ||
[key: string]: any; | ||
}>(params: InsertParams<T_2>) => { | ||
getQuery: () => string; | ||
execute: () => Promise<string>; | ||
}; | ||
updateOne: <T_3>(params: UpdateOneParams<T_3>) => { | ||
getQuery: () => string; | ||
execute: () => Promise<T_3>; | ||
}; | ||
updateOrInsert: <T_4>(params: UpdateOrInsertParams<T_4>) => { | ||
getQuery: () => string; | ||
execute: () => Promise<T_4>; | ||
}; | ||
deleteOne: <T_5>(table: string, params: DeleteOneParams<T_5>) => { | ||
getQuery: () => string; | ||
execute: () => Promise<T_5>; | ||
}; | ||
commit: () => Promise<void>; | ||
rollback: () => Promise<void>; | ||
close: () => Promise<void>; | ||
}>; | ||
} |
@@ -6,165 +6,260 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.pool = void 0; | ||
exports.FirebirdQuery = void 0; | ||
const node_firebird_1 = __importDefault(require("node-firebird")); | ||
const keyValueOperators = ["=", "!=", "<>", ">", "<", ">=", "<="]; | ||
const keyOperators = ["IS NULL", "IS NOT NULL"]; | ||
const verifyIfConditionArray = (arg) => { | ||
var _a; | ||
const cond = arg; | ||
if (typeof cond !== "object") | ||
return false; | ||
return ((_a = cond[0]) === null || _a === void 0 ? void 0 : _a.key) !== undefined; | ||
const sql_builder_1 = require("./sql_builder"); | ||
const defaultOptions = { | ||
host: process.env.DB_HOST, | ||
port: Number.parseInt(process.env.DB_PORT) || 3050, | ||
database: process.env.DB_DATABASE, | ||
user: process.env.DB_USER || "SYSDBA", | ||
password: process.env.DB_PASSWORD, | ||
}; | ||
const isKeyValueInputGeneratorArg = (arg) => { | ||
return arg.value !== undefined; | ||
}; | ||
function processCondition(condition) { | ||
if (isKeyValueInputGeneratorArg(condition)) { | ||
const { key, operator = "=", value } = condition; | ||
return `${key} ${operator} ${node_firebird_1.default.escape(value)}`; | ||
class FirebirdQuery { | ||
constructor(options = defaultOptions, max = 10) { | ||
this.conn = node_firebird_1.default.pool(max, options); | ||
} | ||
else { | ||
const { key, operator } = condition; | ||
return `${key} ${operator}`; | ||
getDB() { | ||
return new Promise((res, rej) => { | ||
this.conn.get((err, db) => { | ||
if (err) { | ||
rej(err); | ||
} | ||
else { | ||
res(db); | ||
} | ||
}); | ||
}); | ||
} | ||
} | ||
function processConditions(conditions) { | ||
const validConditions = conditions.filter(({ evaluateIf = true }) => evaluateIf); | ||
if (validConditions.length === 0) | ||
return "1=1"; | ||
return validConditions.map(processCondition).join(" AND "); | ||
} | ||
const sqlBuilder = (strings, params) => { | ||
return strings | ||
.map((cur, i) => { | ||
const param = params[i]; | ||
if (verifyIfConditionArray(param)) { | ||
const conditions = param; | ||
const conditionResult = processConditions(conditions); | ||
return cur + conditionResult; | ||
} | ||
else { | ||
const isLastStr = i === strings.length - 1; | ||
const valueResult = !isLastStr ? node_firebird_1.default.escape(param) : ""; | ||
return cur + valueResult; | ||
} | ||
}) | ||
.join(""); | ||
}; | ||
const pool = (max, options) => { | ||
const dbPool = node_firebird_1.default.pool(max, options); | ||
const getConnection = async () => { | ||
return new Promise((resolve, reject) => { | ||
dbPool.get((err, db) => (err ? reject(err) : resolve(db))); | ||
manageQuery(query) { | ||
return new Promise((res, rej) => { | ||
this.conn.get((err, db) => { | ||
if (err) | ||
rej(err); | ||
db.query(query, [], (err, data) => { | ||
if (err) | ||
rej(err); | ||
db.detach((err) => (err ? rej(err) : this.conn.destroy())); | ||
res(data); | ||
}); | ||
}); | ||
}); | ||
}; | ||
const poolHandler = async (query, params = []) => { | ||
const db = await getConnection(); | ||
return new Promise((resolve, reject) => { | ||
db.query(query, params, (err, data) => { | ||
db.detach(); | ||
err ? reject(err) : resolve(data); | ||
} | ||
async getTransaction(db) { | ||
return new Promise((res, rej) => { | ||
db.transaction(node_firebird_1.default.ISOLATION_READ_COMMITTED, (err, transaction) => { | ||
if (err) { | ||
rej(err); | ||
} | ||
else { | ||
res(transaction); | ||
} | ||
}); | ||
}); | ||
}; | ||
const queryRaw = (strings, ...params) => { | ||
const sanitizedQuery = sqlBuilder(strings, params); | ||
} | ||
get queryRaw() { | ||
return handleRawQuery(async (query) => { | ||
return this.manageQuery(query); | ||
}); | ||
} | ||
get insertOne() { | ||
return handleInsertOne(async (query) => { | ||
return this.manageQuery(query); | ||
}); | ||
} | ||
get insertMany() { | ||
return handleInsertMany(async (query, length) => { | ||
await this.manageQuery(query); | ||
return `${length} rows inserted`; | ||
}); | ||
} | ||
get updateOne() { | ||
return handleUpdateOne(async (query) => { | ||
return this.manageQuery(query); | ||
}); | ||
} | ||
get updateOrInsert() { | ||
return handleUpdateOrInsert(async (query) => { | ||
return this.manageQuery(query); | ||
}); | ||
} | ||
get deleteOne() { | ||
return handleDeleteOne(async (query) => { | ||
return this.manageQuery(query); | ||
}); | ||
} | ||
async initTransaction() { | ||
const db = await this.getDB(); | ||
const transaction = await this.getTransaction(db); | ||
const rollbackHandler = () => { | ||
return new Promise((res, rej) => { | ||
transaction.rollbackRetaining((err) => { | ||
if (err) | ||
rej(err); | ||
res(); | ||
}); | ||
}); | ||
}; | ||
return { | ||
queryRaw: handleRawQuery((query) => { | ||
return new Promise((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) | ||
rej(err); | ||
res(data); | ||
}); | ||
}); | ||
}), | ||
insertOne: handleInsertOne((query) => { | ||
return new Promise((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) | ||
rej(err); | ||
res(data); | ||
}); | ||
}); | ||
}), | ||
insertMany: handleInsertMany((query, length) => { | ||
return new Promise((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) | ||
rej(err); | ||
res(`${length} rows inserted`); | ||
}); | ||
}); | ||
}), | ||
updateOne: handleUpdateOne((query) => { | ||
return new Promise((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) | ||
rej(err); | ||
res(data); | ||
}); | ||
}); | ||
}), | ||
updateOrInsert: handleUpdateOrInsert((query) => { | ||
return new Promise((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) | ||
rej(err); | ||
res(data); | ||
}); | ||
}); | ||
}), | ||
deleteOne: handleDeleteOne((query) => { | ||
return new Promise((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) | ||
rej(err); | ||
res(data); | ||
}); | ||
}); | ||
}), | ||
commit: async () => { | ||
return new Promise((res, rej) => { | ||
transaction.commit(async (err) => { | ||
if (err) { | ||
await rollbackHandler(); | ||
rej(err); | ||
} | ||
res(); | ||
}); | ||
}); | ||
}, | ||
rollback: async () => rollbackHandler(), | ||
close: async () => { | ||
return new Promise((res, rej) => { | ||
transaction.commit(async (err) => { | ||
if (err) { | ||
await rollbackHandler(); | ||
rej(err); | ||
} | ||
db.detach((err) => { | ||
if (err) | ||
rej(err); | ||
this.conn.destroy(); | ||
res(); | ||
}); | ||
}); | ||
}); | ||
}, | ||
}; | ||
} | ||
} | ||
exports.FirebirdQuery = FirebirdQuery; | ||
function handleRawQuery(cb) { | ||
return (strings, ...params) => { | ||
const sanitizedQuery = (0, sql_builder_1.sqlBuilder)(strings, params); | ||
return { | ||
getQuery: () => sanitizedQuery, | ||
execute: async () => { | ||
execute: () => { | ||
console.log("Executing: ", sanitizedQuery); | ||
const data = await poolHandler(sanitizedQuery); | ||
return data; | ||
return cb(sanitizedQuery); | ||
}, | ||
paginated: async (take, page = 1) => { | ||
const pagQuery = (0, sql_builder_1.paginatedQuery)(sanitizedQuery, take, page); | ||
console.log("Executing: ", pagQuery); | ||
return cb(pagQuery); | ||
}, | ||
}; | ||
}; | ||
const insertMany = ({ tableName, columnNames, rowValues, }) => { | ||
const sortedColumns = columnNames.slice().sort(); | ||
const sortedColumnsStr = sortedColumns.join(", "); | ||
const selectStatements = rowValues.map((row) => { | ||
const sortedRow = Object.entries(row).sort(([a], [b]) => a.localeCompare(b)); | ||
const valuesList = sortedRow | ||
.map(([, value]) => node_firebird_1.default.escape(value)) | ||
.join(", "); | ||
return `SELECT ${valuesList} FROM RDB$DATABASE`; | ||
}); | ||
const unionAll = selectStatements.join(" UNION ALL "); | ||
const query = `INSERT INTO ${tableName} (${sortedColumnsStr}) ${unionAll};`; | ||
// await poolHandler(query); | ||
// return `${rowValues.length} rows inserted`; | ||
} | ||
function handleInsertOne(cb) { | ||
return (params) => { | ||
const query = (0, sql_builder_1.insertOneQuery)(params); | ||
return { | ||
getQuery: () => query, | ||
execute: async () => { | ||
execute: () => { | ||
console.log("Executing: ", query); | ||
await poolHandler(query); | ||
return `${rowValues.length} rows inserted`; | ||
return cb(query); | ||
}, | ||
}; | ||
}; | ||
const insertOne = ({ tableName, rowValues, returning = [], }) => { | ||
const columns = Object.keys(rowValues); | ||
const columnsStr = columns.join(", "); | ||
const escapedValues = columns.map((key) => node_firebird_1.default.escape(rowValues[key])); | ||
const valuesStr = escapedValues.join(", "); | ||
let query = `INSERT INTO ${tableName} (${columnsStr}) VALUES (${valuesStr})`; | ||
if (returning.length > 0) { | ||
query += ` RETURNING ${returning.join(", ")}`; | ||
} | ||
query += ";"; | ||
} | ||
function handleInsertMany(cb) { | ||
return (params) => { | ||
const query = (0, sql_builder_1.insertManyQuery)(params); | ||
return { | ||
getQuery: () => query, | ||
execute: async () => { | ||
execute: () => { | ||
console.log("Executing: ", query); | ||
return poolHandler(query); | ||
return cb(query, params.rowValues.length); | ||
}, | ||
}; | ||
}; | ||
const updateOne = ({ tableName, rowValues, returning = [], conditions, }) => { | ||
const toSet = Object.entries(rowValues).map(([columnName, value]) => `${columnName} = ${node_firebird_1.default.escape(value)}`); | ||
const valuesStr = toSet.join(", "); | ||
const whereClauses = Object.entries(conditions).map(([columnName, value]) => `${columnName} = ${node_firebird_1.default.escape(value)}`); | ||
const whereStr = whereClauses.join(" AND "); | ||
let query = `UPDATE ${tableName} SET ${valuesStr} WHERE ${whereStr}`; | ||
if (returning.length > 0) { | ||
query += ` RETURNING ${returning.join(", ")}`; | ||
} | ||
query += ";"; | ||
} | ||
function handleUpdateOne(cb) { | ||
return (params) => { | ||
const query = (0, sql_builder_1.updateOneQuery)(params); | ||
return { | ||
getQuery: () => query, | ||
execute: async () => { | ||
execute: () => { | ||
console.log("Executing: ", query); | ||
return poolHandler(query); | ||
return cb(query); | ||
}, | ||
}; | ||
}; | ||
const updateOrInsert = ({ tableName, rowValues, returning = [], }) => { | ||
// Get an array of column names and escaped values. | ||
const columns = Object.keys(rowValues); | ||
const columnsStr = columns.join(", "); | ||
const escapedValues = columns.map((key) => node_firebird_1.default.escape(rowValues[key])); | ||
const valuesStr = escapedValues.join(", "); | ||
// Build the SQL query using template literals. | ||
let query = `UPDATE OR INSERT INTO ${tableName} (${columnsStr}) VALUES (${valuesStr})`; | ||
if (returning.length > 0) { | ||
query += ` RETURNING ${returning.join(", ")}`; | ||
} | ||
query += ";"; | ||
} | ||
function handleUpdateOrInsert(cb) { | ||
return (params) => { | ||
const query = (0, sql_builder_1.updateOrInsertQuery)(params); | ||
return { | ||
getQuery: () => query, | ||
execute: async () => { | ||
execute: () => { | ||
console.log("Executing: ", query); | ||
return poolHandler(query); | ||
return cb(query); | ||
}, | ||
}; | ||
}; | ||
return { | ||
queryRaw, | ||
insertMany, | ||
insertOne, | ||
updateOne, | ||
updateOrInsert, | ||
$getPool: getConnection, | ||
$Firebird: node_firebird_1.default, | ||
} | ||
function handleDeleteOne(cb) { | ||
return (table, params) => { | ||
const query = (0, sql_builder_1.deleteOneQuery)(table, params); | ||
return { | ||
getQuery: () => query, | ||
execute: () => { | ||
console.log("Executing: ", query); | ||
return cb(query); | ||
}, | ||
}; | ||
}; | ||
}; | ||
exports.pool = pool; | ||
} |
437
index.ts
@@ -1,258 +0,293 @@ | ||
import Firebird, { Database } from "node-firebird"; | ||
import Firebird from "node-firebird"; | ||
import { | ||
DeleteOneParams, | ||
InsertOneParams, | ||
InsertParams, | ||
PrimetiveValue, | ||
UpdateOneParams, | ||
UpdateOrInsertParams, | ||
WhereObject, | ||
deleteOneQuery, | ||
insertManyQuery, | ||
insertOneQuery, | ||
paginatedQuery, | ||
sqlBuilder, | ||
updateOneQuery, | ||
updateOrInsertQuery, | ||
} from "./sql_builder"; | ||
type ValueType = string | number | Date; | ||
const keyValueOperators = ["=", "!=", "<>", ">", "<", ">=", "<="] as const; | ||
type KeyValueOperator = (typeof keyValueOperators)[number]; | ||
const keyOperators = ["IS NULL", "IS NOT NULL"] as const; | ||
type KeyOperator = (typeof keyOperators)[number]; | ||
type KeyValueInputGeneratorArg = { | ||
operator?: KeyValueOperator; | ||
key: string; | ||
value: ValueType; | ||
evaluateIf?: boolean; | ||
const defaultOptions: Firebird.Options = { | ||
host: process.env.DB_HOST, | ||
port: Number.parseInt(process.env.DB_PORT) || 3050, | ||
database: process.env.DB_DATABASE, | ||
user: process.env.DB_USER || "SYSDBA", | ||
password: process.env.DB_PASSWORD, | ||
}; | ||
type KeyInputGeneratorArg = { | ||
operator: KeyOperator; | ||
key: string; | ||
evaluateIf?: boolean; | ||
}; | ||
type Condition = KeyInputGeneratorArg | KeyValueInputGeneratorArg; | ||
export class FirebirdQuery { | ||
private conn: Firebird.ConnectionPool; | ||
type InsertParams<T> = { | ||
readonly tableName: string; | ||
readonly columnNames: ReadonlyArray<keyof T>; | ||
readonly rowValues: ReadonlyArray<{ [k in keyof T]: any }>; | ||
}; | ||
constructor(options = defaultOptions, max = 10) { | ||
this.conn = Firebird.pool(max, options); | ||
} | ||
type InsertOneParams<T> = { | ||
readonly tableName: string; | ||
readonly rowValues: { [k in string]: any }; | ||
readonly returning?: ReadonlyArray<keyof T>; | ||
}; | ||
private getDB(): Promise<Firebird.Database> { | ||
return new Promise((res, rej) => { | ||
this.conn.get((err, db) => { | ||
if (err) { | ||
rej(err); | ||
} else { | ||
res(db); | ||
} | ||
}); | ||
}); | ||
} | ||
type UpdateOneParams<T> = { | ||
readonly tableName: string; | ||
readonly rowValues: { [k in string]: any }; | ||
readonly returning?: ReadonlyArray<keyof T>; | ||
readonly conditions: { [k in string]: any }; | ||
}; | ||
type UpdateOrInsertParams<T> = { | ||
readonly tableName: string; | ||
readonly rowValues: { [k in string]: any }; | ||
readonly returning?: ReadonlyArray<keyof T>; | ||
}; | ||
private manageQuery<T>(query: string) { | ||
return new Promise<T>((res, rej) => { | ||
this.conn.get((err, db) => { | ||
if (err) rej(err); | ||
db.query(query, [], (err, data) => { | ||
if (err) rej(err); | ||
db.detach((err) => (err ? rej(err) : this.conn.destroy())); | ||
res(data as T); | ||
}); | ||
}); | ||
}); | ||
} | ||
const verifyIfConditionArray = (arg: any): arg is Condition[] => { | ||
const cond = arg as Condition[]; | ||
if (typeof cond !== "object") return false; | ||
return cond[0]?.key !== undefined; | ||
}; | ||
private async getTransaction( | ||
db: Firebird.Database | ||
): Promise<Firebird.Transaction> { | ||
return new Promise((res, rej) => { | ||
db.transaction(Firebird.ISOLATION_READ_COMMITTED, (err, transaction) => { | ||
if (err) { | ||
rej(err); | ||
} else { | ||
res(transaction); | ||
} | ||
}); | ||
}); | ||
} | ||
const isKeyValueInputGeneratorArg = ( | ||
arg: Condition | ||
): arg is KeyValueInputGeneratorArg => { | ||
return (arg as KeyValueInputGeneratorArg).value !== undefined; | ||
}; | ||
get queryRaw() { | ||
return handleRawQuery(async <T>(query: string): Promise<T> => { | ||
return this.manageQuery<T>(query); | ||
}); | ||
} | ||
function processCondition(condition: any) { | ||
if (isKeyValueInputGeneratorArg(condition)) { | ||
const { key, operator = "=", value } = condition; | ||
return `${key} ${operator} ${Firebird.escape(value)}`; | ||
} else { | ||
const { key, operator } = condition; | ||
return `${key} ${operator}`; | ||
get insertOne() { | ||
return handleInsertOne(async <T>(query: string): Promise<T> => { | ||
return this.manageQuery<T>(query); | ||
}); | ||
} | ||
} | ||
function processConditions(conditions: Condition[]) { | ||
const validConditions = conditions.filter( | ||
({ evaluateIf = true }) => evaluateIf | ||
); | ||
if (validConditions.length === 0) return "1=1"; | ||
return validConditions.map(processCondition).join(" AND "); | ||
} | ||
const sqlBuilder = ( | ||
strings: TemplateStringsArray, | ||
params: Array<ValueType | Condition[]> | ||
) => { | ||
return strings | ||
.map((cur, i) => { | ||
const param = params[i]; | ||
if (verifyIfConditionArray(param)) { | ||
const conditions = param; | ||
const conditionResult = processConditions(conditions); | ||
return cur + conditionResult; | ||
} else { | ||
const isLastStr = i === strings.length - 1; | ||
const valueResult = !isLastStr ? Firebird.escape(param) : ""; | ||
return cur + valueResult; | ||
get insertMany() { | ||
return handleInsertMany( | ||
async (query: string, length: number): Promise<string> => { | ||
await this.manageQuery(query); | ||
return `${length} rows inserted`; | ||
} | ||
}) | ||
.join(""); | ||
}; | ||
); | ||
} | ||
export const pool = (max: number, options: Firebird.Options) => { | ||
const dbPool = Firebird.pool(max, options); | ||
get updateOne() { | ||
return handleUpdateOne(async <T>(query: string): Promise<T> => { | ||
return this.manageQuery<T>(query); | ||
}); | ||
} | ||
const getConnection = async (): Promise<Database> => { | ||
return new Promise((resolve, reject) => { | ||
dbPool.get((err, db) => (err ? reject(err) : resolve(db))); | ||
get updateOrInsert() { | ||
return handleUpdateOrInsert(async <T>(query: string): Promise<T> => { | ||
return this.manageQuery<T>(query); | ||
}); | ||
}; | ||
} | ||
const poolHandler = async <T = unknown>( | ||
query: string, | ||
params = [] | ||
): Promise<T[]> => { | ||
const db = await getConnection(); | ||
return new Promise((resolve, reject) => { | ||
db.query(query, params, (err, data) => { | ||
db.detach(); | ||
err ? reject(err) : resolve(data); | ||
}); | ||
get deleteOne() { | ||
return handleDeleteOne(async <T>(query: string): Promise<T> => { | ||
return this.manageQuery<T>(query); | ||
}); | ||
}; | ||
} | ||
const queryRaw = <T = unknown>( | ||
async initTransaction() { | ||
const db = await this.getDB(); | ||
const transaction = await this.getTransaction(db); | ||
const rollbackHandler = () => { | ||
return new Promise<void>((res, rej) => { | ||
transaction.rollbackRetaining((err) => { | ||
if (err) rej(err); | ||
res(); | ||
}); | ||
}); | ||
}; | ||
return { | ||
queryRaw: handleRawQuery(<T>(query: string): Promise<T[]> => { | ||
return new Promise<T[]>((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) rej(err); | ||
res(data); | ||
}); | ||
}); | ||
}), | ||
insertOne: handleInsertOne(<T>(query: string): Promise<T> => { | ||
return new Promise<T>((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) rej(err); | ||
res(data as T); | ||
}); | ||
}); | ||
}), | ||
insertMany: handleInsertMany( | ||
(query: string, length: number): Promise<string> => { | ||
return new Promise<string>((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) rej(err); | ||
res(`${length} rows inserted`); | ||
}); | ||
}); | ||
} | ||
), | ||
updateOne: handleUpdateOne(<T>(query: string): Promise<T> => { | ||
return new Promise<T>((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) rej(err); | ||
res(data as T); | ||
}); | ||
}); | ||
}), | ||
updateOrInsert: handleUpdateOrInsert(<T>(query: string): Promise<T> => { | ||
return new Promise<T>((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) rej(err); | ||
res(data as T); | ||
}); | ||
}); | ||
}), | ||
deleteOne: handleDeleteOne(<T>(query: string): Promise<T> => { | ||
return new Promise<T>((res, rej) => { | ||
transaction.query(query, [], (err, data) => { | ||
if (err) rej(err); | ||
res(data as T); | ||
}); | ||
}); | ||
}), | ||
commit: async () => { | ||
return new Promise<void>((res, rej) => { | ||
transaction.commit(async (err) => { | ||
if (err) { | ||
await rollbackHandler(); | ||
rej(err); | ||
} | ||
res(); | ||
}); | ||
}); | ||
}, | ||
rollback: async () => rollbackHandler(), | ||
close: async () => { | ||
return new Promise<void>((res, rej) => { | ||
transaction.commit(async (err) => { | ||
if (err) { | ||
await rollbackHandler(); | ||
rej(err); | ||
} | ||
db.detach((err) => { | ||
if (err) rej(err); | ||
this.conn.destroy(); | ||
res(); | ||
}); | ||
}); | ||
}); | ||
}, | ||
}; | ||
} | ||
} | ||
function handleRawQuery(cb: <T = unknown>(query: string) => Promise<T[]>) { | ||
return <T>( | ||
strings: TemplateStringsArray, | ||
...params: Array<ValueType | Condition[]> | ||
...params: Array<PrimetiveValue | WhereObject> | ||
) => { | ||
const sanitizedQuery = sqlBuilder(strings, params); | ||
return { | ||
getQuery: () => sanitizedQuery, | ||
execute: async () => { | ||
execute: () => { | ||
console.log("Executing: ", sanitizedQuery); | ||
const data = await poolHandler<T>(sanitizedQuery); | ||
return data; | ||
return cb(sanitizedQuery) as Promise<T[]>; | ||
}, | ||
paginated: async (take: number, page: number = 1) => { | ||
const pagQuery = paginatedQuery(sanitizedQuery, take, page); | ||
console.log("Executing: ", pagQuery); | ||
return cb(pagQuery) as Promise<T[]>; | ||
}, | ||
}; | ||
}; | ||
} | ||
const insertMany = <T>({ | ||
tableName, | ||
columnNames, | ||
rowValues, | ||
}: InsertParams<T>) => { | ||
const sortedColumns = columnNames.slice().sort(); | ||
const sortedColumnsStr = sortedColumns.join(", "); | ||
const selectStatements = rowValues.map((row) => { | ||
const sortedRow = Object.entries(row).sort(([a], [b]) => | ||
a.localeCompare(b) | ||
); | ||
const valuesList = sortedRow | ||
.map(([, value]) => Firebird.escape(value)) | ||
.join(", "); | ||
return `SELECT ${valuesList} FROM RDB$DATABASE`; | ||
}); | ||
const unionAll = selectStatements.join(" UNION ALL "); | ||
const query = `INSERT INTO ${tableName} (${sortedColumnsStr}) ${unionAll};`; | ||
// await poolHandler(query); | ||
// return `${rowValues.length} rows inserted`; | ||
function handleInsertOne(cb: <T = unknown>(query: string) => Promise<T>) { | ||
return <T extends { [key: string]: any }>(params: InsertOneParams<T>) => { | ||
const query = insertOneQuery(params); | ||
return { | ||
getQuery: () => query, | ||
execute: async () => { | ||
execute: () => { | ||
console.log("Executing: ", query); | ||
await poolHandler(query); | ||
return `${rowValues.length} rows inserted`; | ||
return cb(query) as Promise<T>; | ||
}, | ||
}; | ||
}; | ||
} | ||
const insertOne = <T = void>({ | ||
tableName, | ||
rowValues, | ||
returning = [], | ||
}: InsertOneParams<T>) => { | ||
const columns = Object.keys(rowValues); | ||
const columnsStr = columns.join(", "); | ||
const escapedValues = columns.map((key) => Firebird.escape(rowValues[key])); | ||
const valuesStr = escapedValues.join(", "); | ||
let query = `INSERT INTO ${tableName} (${columnsStr}) VALUES (${valuesStr})`; | ||
if (returning.length > 0) { | ||
query += ` RETURNING ${returning.join(", ")}`; | ||
} | ||
query += ";"; | ||
function handleInsertMany( | ||
cb: (query: string, length: number) => Promise<string> | ||
) { | ||
return <T extends { [key: string]: any }>(params: InsertParams<T>) => { | ||
const query = insertManyQuery(params); | ||
return { | ||
getQuery: () => query, | ||
execute: async () => { | ||
execute: () => { | ||
console.log("Executing: ", query); | ||
return poolHandler<T>(query) as T; | ||
return cb(query, params.rowValues.length) as Promise<string>; | ||
}, | ||
}; | ||
}; | ||
} | ||
const updateOne = <T = void>({ | ||
tableName, | ||
rowValues, | ||
returning = [], | ||
conditions, | ||
}: UpdateOneParams<T>) => { | ||
const toSet = Object.entries(rowValues).map( | ||
([columnName, value]) => `${columnName} = ${Firebird.escape(value)}` | ||
); | ||
const valuesStr = toSet.join(", "); | ||
const whereClauses = Object.entries(conditions).map( | ||
([columnName, value]) => `${columnName} = ${Firebird.escape(value)}` | ||
); | ||
const whereStr = whereClauses.join(" AND "); | ||
let query = `UPDATE ${tableName} SET ${valuesStr} WHERE ${whereStr}`; | ||
if (returning.length > 0) { | ||
query += ` RETURNING ${returning.join(", ")}`; | ||
} | ||
query += ";"; | ||
function handleUpdateOne(cb: <T = unknown>(query: string) => Promise<T>) { | ||
return <T>(params: UpdateOneParams<T>) => { | ||
const query = updateOneQuery(params); | ||
return { | ||
getQuery: () => query, | ||
execute: async () => { | ||
execute: () => { | ||
console.log("Executing: ", query); | ||
return poolHandler<T>(query) as T; | ||
return cb(query) as Promise<T>; | ||
}, | ||
}; | ||
}; | ||
} | ||
const updateOrInsert = <T = void>({ | ||
tableName, | ||
rowValues, | ||
returning = [], | ||
}: UpdateOrInsertParams<T>) => { | ||
// Get an array of column names and escaped values. | ||
const columns = Object.keys(rowValues); | ||
const columnsStr = columns.join(", "); | ||
const escapedValues = columns.map((key) => Firebird.escape(rowValues[key])); | ||
const valuesStr = escapedValues.join(", "); | ||
// Build the SQL query using template literals. | ||
let query = `UPDATE OR INSERT INTO ${tableName} (${columnsStr}) VALUES (${valuesStr})`; | ||
if (returning.length > 0) { | ||
query += ` RETURNING ${returning.join(", ")}`; | ||
} | ||
query += ";"; | ||
function handleUpdateOrInsert(cb: <T>(query: string) => Promise<T>) { | ||
return <T>(params: UpdateOrInsertParams<T>) => { | ||
const query = updateOrInsertQuery(params); | ||
return { | ||
getQuery: () => query, | ||
execute: async () => { | ||
execute: () => { | ||
console.log("Executing: ", query); | ||
return poolHandler<T>(query) as T; | ||
return cb(query) as Promise<T>; | ||
}, | ||
}; | ||
}; | ||
} | ||
return { | ||
queryRaw, | ||
insertMany, | ||
insertOne, | ||
updateOne, | ||
updateOrInsert, | ||
$getPool: getConnection, | ||
$Firebird: Firebird, | ||
function handleDeleteOne(cb: <T = unknown>(query: string) => Promise<T>) { | ||
return <T>(params: DeleteOneParams<T>) => { | ||
const query = deleteOneQuery(params); | ||
return { | ||
getQuery: () => query, | ||
execute: () => { | ||
console.log("Executing: ", query); | ||
return cb(query) as Promise<T>; | ||
}, | ||
}; | ||
}; | ||
}; | ||
} |
{ | ||
"name": "firebird-query", | ||
"version": "0.1.4", | ||
"description": "node-firebird wrapper for easy and safe query building.", | ||
"private": false, | ||
"license": "MIT", | ||
"version": "0.2.0", | ||
"description": "node-firebird plugin for easy and safe query building.", | ||
"author": { | ||
"name": "Junior Garozzo", | ||
"email": "juninogarozzo@gmail.com" | ||
}, | ||
"engines": { | ||
"node": ">= 16.17.0" | ||
}, | ||
"main": "dist/index.js", | ||
@@ -10,11 +19,24 @@ "types": "dist/index.d.ts", | ||
}, | ||
"keywords": [], | ||
"author": "Sergio Garozzo", | ||
"license": "ISC", | ||
"dependencies": { | ||
"node-firebird": "^1.1.5" | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/junigar/firebird-query" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/junigar/firebird-query/issues" | ||
}, | ||
"keywords": [ | ||
"node-firebird", | ||
"firebird", | ||
"firebird-orm", | ||
"firebird-query", | ||
"query-builder", | ||
"query" | ||
], | ||
"devDependencies": { | ||
"typescript": "^5.1.3" | ||
"typescript": "^5.1.3", | ||
"@types/node": "^20.3.1" | ||
}, | ||
"peerDependencies": { | ||
"node-firebird": "^1.1.5" | ||
} | ||
} |
@@ -9,5 +9,5 @@ { | ||
"skipLibCheck": true, | ||
"strict": true, | ||
"strict": false, | ||
"target": "ES2017" | ||
} | ||
} |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 5 instances in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
59228
160.34%19
171.43%1609
232.44%0
-100%2
100%10
900%1
Infinity%- Removed