First version without typescript errors

This commit is contained in:
Benjamin Toby 2026-06-21 07:05:49 +01:00
parent 9c8f6e20aa
commit eb86e1803d
16 changed files with 364 additions and 225 deletions

View File

@ -25,9 +25,6 @@ export default function () {
const dbSchema = global.DB_SCHEMA;
const { ROOT_DIR, BUN_MARIADB_TEMP_DB_FILE_PATH } = grabDirNames();
const { db_file_path } = grabDBDir({ config });
cpSync(db_file_path, BUN_MARIADB_TEMP_DB_FILE_PATH);
try {
const isVector = Boolean(opts.vector || opts.v);
@ -66,7 +63,6 @@ export default function () {
process.exit();
} catch (error) {
console.log(error);
cpSync(BUN_MARIADB_TEMP_DB_FILE_PATH, db_file_path);
process.exit(1);
}
});

View File

@ -3,4 +3,5 @@ export const AppData = {
MaxBackups: 10,
DefaultBackupDirName: ".backups",
DbSchemaManagerTableName: "__db_schema_manager__",
DbSchemaFileName: "schema.ts",
} as const;

View File

@ -2,10 +2,11 @@ import path from "path";
import fs from "fs";
import { AppData } from "../data/app-data";
import grabDirNames from "../data/grab-dir-names";
import type {
BunMariaDBConfig,
BunMariaDBConfigReturn,
BUN_MARIADB_DatabaseSchemaType,
import {
type BunMariaDBConfig,
type BunMariaDBConfigReturn,
type BUN_MARIADB_DatabaseSchemaType,
RequiredENVs,
} from "../types";
export default async function init(): Promise<BunMariaDBConfigReturn> {
@ -25,27 +26,53 @@ export default async function init(): Promise<BunMariaDBConfigReturn> {
const ConfigImport = await import(ConfigFilePath);
const Config = ConfigImport["default"] as BunMariaDBConfig;
if (!Config) {
console.error(
`No default export from \`${ConfigFilePath}\`. Please export a default module.`,
);
process.exit(1);
}
if (!Config.db_name) {
console.error(`\`db_name\` is required in your config`);
process.exit(1);
}
if (!Config.db_schema_file_name) {
console.error(`\`db_schema_file_name\` is required in your config`);
RequiredENVs.forEach((env_key) => {
if (
env_key == "BUN_MARIADB_SERVER_PORT" ||
env_key == "BUN_MARIADB_SERVER_SSL_KEY_PATH"
) {
return;
}
if (!process.env[env_key]) {
console.error(`\`${env_key}\` env variable is required.`);
process.exit(1);
}
});
if (!Config.db_dir) {
console.error(
`\`db_dir\` is required in your config. This directory holds all database related configuration. Also note that a \`${AppData["DbSchemaFileName"]}\` file is also required in this directory to define your database schema`,
);
process.exit(1);
}
let db_dir = ROOT_DIR;
if (Config.db_dir) {
db_dir = path.resolve(ROOT_DIR, Config.db_dir);
const db_dir = path.resolve(ROOT_DIR, Config.db_dir);
if (!fs.existsSync(Config.db_dir)) {
fs.mkdirSync(Config.db_dir, { recursive: true });
}
const DBSchemaFilePath = path.join(db_dir, AppData["DbSchemaFileName"]);
if (!fs.existsSync(DBSchemaFilePath)) {
console.error(
`Please create a schema file at \`${DBSchemaFilePath}\`. Don't forget to export a default module from this file.`,
);
process.exit(1);
}
const DBSchemaFilePath = path.join(db_dir, Config.db_schema_file_name);
const DbSchemaImport = await import(DBSchemaFilePath);
const DbSchema = DbSchemaImport[
"default"

View File

@ -5,9 +5,6 @@ import grabDBConnection from "./grab-db-connection";
type Param = {
query: string;
values?: string[] | object;
noErrorLogs?: boolean;
database?: string;
tableSchema?: BUN_MARIADB_TableSchemaType;
config?: ConnectionConfig;
};
@ -17,18 +14,12 @@ type Param = {
*/
export default async function dbHandler<
T extends { [k: string]: any } = { [k: string]: any },
>({
query,
values,
noErrorLogs,
database,
config,
}: Param): Promise<DBResponseObject> {
>({ query, values, config }: Param): Promise<DBResponseObject> {
let CONNECTION: Connection | undefined;
let results: T | null = null;
try {
CONNECTION = await grabDBConnection({ database, config });
CONNECTION = await grabDBConnection({ config });
if (query && values) {
const queryResults = await CONNECTION.query(query, values);
@ -46,10 +37,6 @@ export default async function dbHandler<
throw new Error("Authentication Failed!");
}
if (!noErrorLogs) {
console.log(error);
}
results = null;
} finally {
await CONNECTION?.end();

View File

@ -8,7 +8,7 @@ type Return = ConnectionConfig["ssl"] | undefined;
* # Grab SSL
*/
export default function grabDbSSL(): Return {
const caProivdedPath = process.env.DSQL_SSL_CA_CERT;
const caProivdedPath = process.env.BUN_MARIADB_SERVER_SSL_KEY_PATH;
if (!caProivdedPath?.match(/./)) {
return undefined;

View File

@ -8,17 +8,18 @@ import grabDbSSL from "./grab-db-ssl";
export default function grabDSQLConnectionConfig(
param?: DsqlConnectionParam,
): ConnectionConfig {
const CONN_TIMEOUT = 10000;
const configData = global.CONFIG;
const CONN_TIMEOUT = configData?.connection_timeout || 10000;
const config: ConnectionConfig = {
host: process.env.DSQL_DB_HOST,
user: process.env.DSQL_DB_USERNAME,
password: process.env.DSQL_DB_PASSWORD,
// database: param?.dbFullName,
port: process.env.DSQL_DB_PORT
? Number(process.env.DSQL_DB_PORT)
host: process.env.BUN_MARIADB_SERVER_HOST,
user: process.env.BUN_MARIADB_SERVER_USERNAME,
password: process.env.BUN_MARIADB_SERVER_PASSWORD,
database: configData?.db_name,
port: process.env.BUN_MARIADB_SERVER_PORT
? Number(process.env.BUN_MARIADB_SERVER_PORT)
: undefined,
charset: "utf8mb4",
charset: configData?.charset || "utf8mb4",
ssl: grabDbSSL(),
bigIntAsNumber: true,
supportBigNumbers: true,

View File

@ -4,37 +4,45 @@ type Params = {
data: any | any[];
};
export default async function ({ sql: passed_sql, table, data }: Params) {
let sql = passed_sql;
function quoteIdentifier(identifier: string): string {
return `\`${identifier.replace(/`/g, "``")}\``;
}
export default async function ({ sql: passedSql, table, data }: Params) {
const config = global.CONFIG;
const dbSchema = global.DB_SCHEMA;
const table_schema = dbSchema.tables.find((t) => t.tableName == table);
const now = Date.now();
const tableSchema = dbSchema?.tables.find(
(t: { tableName: string }) => t.tableName == table,
);
if (table_schema?.tableName) {
const set_sql_arr = Object.keys(
Array.isArray(data) ? data[0] : data,
).map((field) => `${field} = excluded.${field}`);
set_sql_arr.push(`updated_at = ${now}`);
const set_sql = set_sql_arr.join(", ");
const unique_fields = table_schema.fields.filter((f) => f.unique);
for (let i = 0; i < unique_fields.length; i++) {
const field = unique_fields[i];
sql += ` ON CONFLICT(${field?.fieldName}) DO UPDATE SET ${set_sql}`;
if (!tableSchema?.tableName) {
return passedSql;
}
if (table_schema.uniqueConstraints?.[0]) {
for (let i = 0; i < table_schema.uniqueConstraints.length; i++) {
const constraint = table_schema.uniqueConstraints[i];
sql += ` ON CONFLICT(${constraint?.constraintTableFields?.map((c) => c.value)?.join(", ")}) DO UPDATE SET ${set_sql}`;
}
}
const dataObject = Array.isArray(data) ? data[0] : data;
const dataKeys = Object.keys(dataObject || {});
if (dataKeys.length === 0) {
return passedSql;
}
return sql;
const hasUniqueField =
tableSchema.fields.some((field) => field.unique) ||
Boolean(tableSchema.uniqueConstraints?.length);
if (!hasUniqueField) {
return passedSql;
}
const setSql = dataKeys
.filter((field: string) => field !== "updated_at")
.map(
(field: string) =>
`${quoteIdentifier(field)} = VALUES(${quoteIdentifier(field)})`,
);
setSql.push(`updated_at = ${Date.now()}`);
return `${passedSql} ON DUPLICATE KEY UPDATE ${setSql.join(", ")}`;
}

View File

@ -1,4 +1,4 @@
import DbClient from ".";
import dbHandler from "../db-handler";
import _ from "lodash";
import type { APIResponseObject, ServerQueryParam } from "../../types";
import sqlGenerator from "../../utils/sql-generator";
@ -12,6 +12,10 @@ type Params<
targetId?: number | string;
};
function quoteIdentifier(identifier: string): string {
return `\`${identifier.replace(/`/g, "``")}\``;
}
export default async function DbDelete<
Schema extends { [k: string]: any } = { [k: string]: any },
Table extends string = string,
@ -39,30 +43,13 @@ export default async function DbDelete<
}
sqlObj = sqlGenerator({
tableName: table,
tableName: quoteIdentifier(table),
genObject: finalQuery,
});
const whereClause = sqlObj.string.match(/WHERE .*/)?.[0];
if (whereClause) {
let sql = `DELETE FROM ${table} ${whereClause}`;
sqlObj.string = sql;
const res = DbClient.run(sql, sqlObj.values);
return {
success: Boolean(res.changes),
postInsertReturn: {
affectedRows: res.changes,
insertId: Number(res.lastInsertRowid),
},
debug: {
sqlObj,
},
};
} else {
if (!whereClause) {
return {
success: false,
msg: `No WHERE clause`,
@ -71,6 +58,38 @@ export default async function DbDelete<
},
};
}
const sql = `DELETE FROM ${quoteIdentifier(table)} ${whereClause}`;
sqlObj.string = sql;
const res = await dbHandler({
query: sql,
values: sqlObj.values as any,
});
if (!res.success) {
return {
success: false,
msg: "Database delete failed",
debug: {
sqlObj,
},
};
}
const singleRes = res.single_res as any;
return {
success: Boolean(singleRes?.affectedRows),
postInsertReturn: {
affectedRows: Number(singleRes?.affectedRows),
insertId: Number(singleRes?.insertId),
},
debug: {
sqlObj,
},
};
} catch (error: any) {
return {
success: false,

View File

@ -1,4 +1,4 @@
import DbClient from ".";
import dbHandler from "../db-handler";
import type { APIResponseObject, SQLInsertGenReturn } from "../../types";
import sqlInsertGenerator from "../../utils/sql-insert-generator";
import grabDuplicateSafeInsertSql from "../grab-duplicate-safe-insert-sql";
@ -35,21 +35,41 @@ export default async function DbInsert<
data: finalData as any[],
}) || null;
let sql = sqlObj?.query || "";
if (!sqlObj) {
return {
success: false,
msg: "No insert SQL generated",
};
}
let sql = sqlObj.query;
if (update_on_duplicate && data[0]) {
sql = await grabDuplicateSafeInsertSql({ data, table, sql });
}
(sqlObj || ({} as any)).query = sql;
const res = await dbHandler({
query: sql,
values: sqlObj.values as any,
});
const res = DbClient.run(sql, sqlObj?.values || []);
if (!res.success) {
return {
success: false,
msg: "Database insert failed",
debug: {
sqlObj,
},
};
}
const singleRes = res.single_res as any;
return {
success: Boolean(Number(res.lastInsertRowid)),
success: Boolean(singleRes?.affectedRows || singleRes?.insertId),
postInsertReturn: {
affectedRows: res.changes,
insertId: Number(res.lastInsertRowid),
affectedRows: Number(singleRes?.affectedRows),
insertId: Number(singleRes?.insertId),
},
debug: {
sqlObj,

View File

@ -59,10 +59,6 @@ class MariaDBSchemaManager {
console.log("Schema synchronization complete!");
}
private getDatabaseName(): string | undefined {
return this.db_schema.dbName || this.db_schema.dbSlug;
}
private quoteIdentifier(identifier: string): string {
return `\`${identifier.replace(/`/g, "``")}\``;
}
@ -71,7 +67,8 @@ class MariaDBSchemaManager {
where: string;
values: QueryValues;
} {
const databaseName = this.getDatabaseName();
const config = global.CONFIG;
const databaseName = config?.db_name;
if (databaseName) {
return {
@ -87,12 +84,11 @@ class MariaDBSchemaManager {
}
private async run(query: string, values?: QueryValues): Promise<void> {
const config = global.CONFIG;
const res = await dbHandler({
query,
values: values as any,
config: this.getDatabaseName()
? { database: this.getDatabaseName() }
: undefined,
config: config?.db_config,
});
if (!res.success) {
@ -107,9 +103,7 @@ class MariaDBSchemaManager {
const res = await dbHandler<T>({
query,
values: values as any,
config: this.getDatabaseName()
? { database: this.getDatabaseName() }
: undefined,
config: global.CONFIG.db_config,
});
if (!res.success) {
@ -195,7 +189,9 @@ class MariaDBSchemaManager {
for (const tableName of tablesToDrop) {
console.log(`Dropping table: ${tableName}`);
await this.run(`DROP TABLE IF EXISTS ${this.quoteIdentifier(tableName)}`);
await this.run(
`DROP TABLE IF EXISTS ${this.quoteIdentifier(tableName)}`,
);
await this.removeDbManagerTable(tableName);
}
}
@ -308,7 +304,10 @@ class MariaDBSchemaManager {
const options = ["ENGINE=InnoDB"];
if (table.collation) {
options.push("DEFAULT CHARSET=utf8mb4", `COLLATE ${table.collation}`);
options.push(
"DEFAULT CHARSET=utf8mb4",
`COLLATE ${table.collation}`,
);
}
return ` ${options.join(" ")}`;
@ -321,11 +320,12 @@ class MariaDBSchemaManager {
await this.recreateTable(table);
}
private async getTableColumns(
tableName: string,
): Promise<ColumnInfoRow[]> {
private async getTableColumns(tableName: string): Promise<ColumnInfoRow[]> {
const tableSchemaWhere = this.tableSchemaWhere(tableName);
const rows = await this.query<{ COLUMN_NAME: string; COLUMN_TYPE: string }>(
const rows = await this.query<{
COLUMN_NAME: string;
COLUMN_TYPE: string;
}>(
`SELECT COLUMN_NAME AS name, COLUMN_TYPE AS type FROM information_schema.COLUMNS WHERE ${tableSchemaWhere.where} AND TABLE_NAME = ? ORDER BY ORDINAL_POSITION`,
tableSchemaWhere.values,
);
@ -379,7 +379,9 @@ class MariaDBSchemaManager {
existingRows = await this.query<Record<string, any>>(
`SELECT * FROM ${this.quoteIdentifier(table.tableName)}`,
);
await this.run(`DROP TABLE ${this.quoteIdentifier(table.tableName)}`);
await this.run(
`DROP TABLE ${this.quoteIdentifier(table.tableName)}`,
);
}
await this.createTable(table);
@ -395,7 +397,9 @@ class MariaDBSchemaManager {
const existingColumns = await this.getTableColumns(table.tableName);
const columnsToKeep = table.fields
.filter((field) =>
existingColumns.some((column) => column.name === field.fieldName),
existingColumns.some(
(column) => column.name === field.fieldName,
),
)
.map((field) => field.fieldName)
.filter((fieldName): fieldName is string => Boolean(fieldName));
@ -624,7 +628,9 @@ class MariaDBSchemaManager {
if (!stillExists) {
console.log(`Dropping index: ${indexName}`);
await this.run(`DROP INDEX ${this.quoteIdentifier(indexName)} ON ${this.quoteIdentifier(table.tableName)}`);
await this.run(
`DROP INDEX ${this.quoteIdentifier(indexName)} ON ${this.quoteIdentifier(table.tableName)}`,
);
}
}

View File

@ -1,5 +1,4 @@
import mysql from "mysql";
import DbClient from ".";
import dbHandler from "../db-handler";
import _ from "lodash";
import type { APIResponseObject, ServerQueryParam } from "../../types";
import sqlGenerator from "../../utils/sql-generator";
@ -14,6 +13,10 @@ type Params<
targetId?: number | string;
};
function quoteIdentifier(identifier: string): string {
return `\`${identifier.replace(/`/g, "``")}\``;
}
export default async function DbSelect<
Schema extends { [k: string]: any } = { [k: string]: any },
Table extends string = string,
@ -42,44 +45,75 @@ export default async function DbSelect<
}
sqlObj = sqlGenerator({
tableName: table,
tableName: quoteIdentifier(table),
genObject: finalQuery,
});
let sql = mysql.format(sqlObj.string, sqlObj.values);
const res = await dbHandler<Schema>({
query: sqlObj.string,
values: sqlObj.values as any,
});
const res = DbClient.query<Schema, Schema[]>(sql);
const batchRes = res.all();
if (!res.success) {
return {
success: false,
msg: "Database select failed",
debug: {
sqlObj,
sql: sqlObj.string,
},
};
}
const batchRes = (res.payload || []) as Schema[];
let resp: APIResponseObject<Schema> = {
success: Boolean(batchRes[0]),
success: true,
payload: batchRes,
singleRes: batchRes[0],
debug: {
sqlObj,
sql,
sql: sqlObj.string,
},
};
if (count) {
let count_sql_object = sqlGenerator({
tableName: table,
const countSqlObject = sqlGenerator({
tableName: quoteIdentifier(table),
genObject: finalQuery,
count,
});
let count_sql = mysql.format(
count_sql_object.string,
count_sql_object.values,
);
const countSql = `SELECT COUNT(*) AS count FROM (${countSqlObject.string}) AS c`;
count_sql = `SELECT COUNT(*) FROM (${count_sql}) as c`;
const countRes = await dbHandler<{ count: number }>({
query: countSql,
values: countSqlObject.values as any,
});
const count_res = DbClient.query<Schema, Schema[]>(count_sql).all();
if (!countRes.success) {
return {
...resp,
success: false,
msg: "Database count failed",
debug: {
...resp.debug,
count_sql: countSql,
},
};
}
const count_val = count_res[0]?.["COUNT(*)"];
resp["count"] = Number(count_val);
resp["debug"]["count_sql"] = count_sql;
const countRows = countRes.payload || [];
const countVal = countRows[0]?.count ?? countRows[0]?.["COUNT(*)"];
resp = {
...resp,
count: Number(countVal),
debug: {
...resp.debug,
count_sql: countSql,
},
};
}
return resp;

View File

@ -1,5 +1,4 @@
import DbClient from ".";
import _ from "lodash";
import dbHandler from "../db-handler";
import type { APIResponseObject, SQLInsertGenValueType } from "../../types";
type Params = {
@ -11,25 +10,45 @@ export default async function DbSQL<
T extends { [k: string]: any } = { [k: string]: any },
>({ sql, values }: Params): Promise<APIResponseObject<T>> {
try {
const trimmed_sql = sql.trim();
const trimmedSql = sql.trim();
const isSelect = trimmedSql.match(/^select/i);
const res = trimmed_sql.match(/^select/i)
? DbClient.query(trimmed_sql).all(...(values || []))
: DbClient.run(trimmed_sql, values || []);
const res = await dbHandler<T>({
query: trimmedSql,
values: values as any,
});
if (!res.success) {
return {
success: false,
msg: "Database query failed",
debug: {
sqlObj: {
sql: trimmedSql,
values,
},
sql,
},
};
}
const payload = isSelect ? ((res.payload || []) as T[]) : undefined;
const singleRes = isSelect ? payload?.[0] : (res.single_res as T);
const singleRaw = res.single_res as any;
return {
success: true,
payload: Array.isArray(res) ? (res as T[]) : undefined,
singleRes: Array.isArray(res) ? (res as T[])?.[0] : undefined,
postInsertReturn: Array.isArray(res)
payload,
singleRes,
postInsertReturn: isSelect
? undefined
: {
affectedRows: res.changes,
insertId: Number(res.lastInsertRowid),
affectedRows: Number(singleRaw?.affectedRows),
insertId: Number(singleRaw?.insertId),
},
debug: {
sqlObj: {
sql: trimmed_sql,
sql: trimmedSql,
values,
},
sql,

View File

@ -1,4 +1,4 @@
import DbClient from ".";
import dbHandler from "../db-handler";
import _ from "lodash";
import type {
APIResponseObject,
@ -17,6 +17,10 @@ type Params<
targetId?: number | string;
};
function quoteIdentifier(identifier: string): string {
return `\`${identifier.replace(/`/g, "``")}\``;
}
export default async function DbUpdate<
Schema extends { [k: string]: any } = { [k: string]: any },
Table extends string = string,
@ -45,16 +49,21 @@ export default async function DbUpdate<
}
const sqlQueryObj = sqlGenerator({
tableName: table,
tableName: quoteIdentifier(table),
genObject: finalQuery,
});
let values: SQLInsertGenValueType[] = [];
const whereClause = sqlQueryObj.string.match(/WHERE .*/)?.[0];
if (whereClause) {
let sql = `UPDATE ${table} SET`;
if (!whereClause) {
return {
success: false,
msg: `No WHERE clause`,
};
}
let values: SQLInsertGenValueType[] = [];
let sql = `UPDATE ${quoteIdentifier(table)} SET`;
const finalData: { [k: string]: SQLInsertGenValueType } = {
updated_at: Date.now(),
@ -69,9 +78,8 @@ export default async function DbUpdate<
const isLast = i == keys.length - 1;
sql += ` ${key}=?`;
const value = finalData[key];
values.push(value || null);
sql += ` ${quoteIdentifier(key)}=?`;
values.push(finalData[key] ?? null);
if (!isLast) {
sql += `,`;
@ -84,24 +92,33 @@ export default async function DbUpdate<
sqlObj.string = sql;
sqlObj.values = values as any[];
const res = DbClient.run(sql, values);
const res = await dbHandler({
query: sql,
values: values as any,
});
if (!res.success) {
return {
success: false,
msg: "Database update failed",
debug: {
sqlObj,
},
};
}
const singleRes = res.single_res as any;
return {
success: Boolean(res.changes),
success: Boolean(singleRes?.affectedRows || singleRes?.changedRows),
postInsertReturn: {
affectedRows: res.changes,
insertId: Number(res.lastInsertRowid),
affectedRows: Number(singleRes?.affectedRows),
insertId: Number(singleRes?.insertId),
},
debug: {
sqlObj,
},
};
} else {
return {
success: false,
msg: `No WHERE clause`,
};
}
} catch (error: any) {
return {
success: false,

View File

@ -1,7 +0,0 @@
import _ from "lodash";
import type { BUN_MARIADB_DatabaseSchemaType } from "../../types";
export const DbSchema: BUN_MARIADB_DatabaseSchemaType = {
dbName: "travis-ai",
tables: [],
};

View File

@ -28,18 +28,8 @@ export const UsersOmitedFields = [
* database metadata.
*/
export interface BUN_MARIADB_DatabaseSchemaType {
id?: string | number;
dbName?: string;
dbSlug?: string;
dbFullName?: string;
dbDescription?: string;
dbImage?: string;
tables: BUN_MARIADB_TableSchemaType[];
childrenDatabases?: BUN_MARIADB_ChildrenDatabaseObject[];
childDatabase?: boolean;
childDatabaseDbId?: string | number;
updateData?: boolean;
collation?: (typeof MariaDBCollations)[number];
collation?: MariaDbCollationsType;
}
/**
@ -58,6 +48,12 @@ export const MariaDBCollations = [
"utf8mb4_unicode_520_ci",
] as const;
export type MariaDbCollationsType = (typeof MariaDBCollations)[number];
export const MariaDBCharsets = ["utf8mb4"] as const;
export type MariaDbCharsetType = (typeof MariaDBCharsets)[number];
/**
* Describes a single table within a database schema, including its fields,
* indexes, unique constraints, and parent/child table relationships.
@ -1498,11 +1494,6 @@ export type SQLInsertGenParams = {
*/
export type BunMariaDBConfig = {
db_name: string;
/**
* The Name of the Database Schema File. Eg `db_schema.ts`. This is
* relative to `db_dir`, or root dir if `db_dir` is not provided
*/
db_schema_file_name: string;
/**
* The Directory for backups. Relative to db_dir.
*/
@ -1518,9 +1509,17 @@ export type BunMariaDBConfig = {
*/
typedef_file_path?: string;
/**
* Whether to enable `WAL` mode
* Configuration for the MariaDB Connection
*/
wal_mode?: boolean;
db_config?: ConnectionConfig;
/**
* Database charset. Defaults to `utf8mb4`
*/
charset?: MariaDbCharsetType;
/**
* Database Connection timeout. Defaults to `10000`
*/
connection_timeout?: number;
};
/**
@ -1589,3 +1588,11 @@ export type DBResponseObject<
payload?: T[];
single_res?: T;
};
export const RequiredENVs = [
"BUN_MARIADB_SERVER_HOST",
"BUN_MARIADB_SERVER_PORT",
"BUN_MARIADB_SERVER_USERNAME",
"BUN_MARIADB_SERVER_PASSWORD",
"BUN_MARIADB_SERVER_SSL_KEY_PATH",
] as const;

View File

@ -4,6 +4,10 @@ import type {
SQLInsertGenValueType,
} from "../types";
function quoteIdentifier(identifier: string): string {
return `\`${identifier.replace(/`/g, "``")}\``;
}
/**
* # SQL Insert Generator
*/
@ -12,7 +16,7 @@ export default function sqlInsertGenerator({
data,
dbFullName,
}: SQLInsertGenParams): SQLInsertGenReturn | undefined {
const finalDbName = dbFullName ? `${dbFullName}.` : "";
const finalDbName = dbFullName ? `${quoteIdentifier(dbFullName)}.` : "";
try {
if (Array.isArray(data) && data?.[0]) {
@ -64,9 +68,9 @@ export default function sqlInsertGenerator({
.join(",")})`,
);
});
let query = `INSERT INTO ${finalDbName}${tableName} (${insertKeys.join(
",",
)}) VALUES ${queryBatches.join(",")}`;
const insertColumns = insertKeys.map(quoteIdentifier).join(",");
let query = `INSERT INTO ${finalDbName}${quoteIdentifier(tableName)} (${insertColumns}) VALUES ${queryBatches.join(",")}`;
return {
query: query,