Refactor DB Handler. Use Bun native SQL adapter.

This commit is contained in:
Benjamin Toby 2026-06-24 15:52:19 +01:00
parent eb86e1803d
commit 44f6c18a84
107 changed files with 324 additions and 4923 deletions

View File

@ -1,2 +0,0 @@
import { Command } from "commander";
export default function (): Command;

View File

@ -1,41 +0,0 @@
import { Command } from "commander";
import init from "../../functions/init";
import grabDBDir from "../../utils/grab-db-dir";
import chalk from "chalk";
import { select } from "@inquirer/prompts";
import listTables from "./list-tables";
import runSQL from "./run-sql";
export default function () {
return new Command("admin")
.description("View Tables and Data, Run SQL Queries, Etc.")
.action(async () => {
const { config } = await init();
const { db_file_path } = grabDBDir({ config });
console.log(chalk.bold(chalk.blue("\nBun SQLite Admin\n")));
try {
while (true) {
const paradigm = await select({
message: "Choose an action:",
choices: [
{ name: "Tables", value: "list_tables" },
{ name: "SQL", value: "run_sql" },
{ name: chalk.dim("✕ Exit"), value: "exit" },
],
});
if (paradigm === "exit")
break;
if (paradigm === "list_tables") {
const result = await listTables();
if (result === "__exit__")
break;
}
if (paradigm === "run_sql")
await runSQL();
}
}
catch (error) {
console.error(error.message);
}
process.exit();
});
}

View File

@ -1,3 +0,0 @@
type Params = {};
export default function listTables(params?: Params): Promise<"__exit__" | void>;
export {};

View File

@ -1,78 +0,0 @@
import { Database } from "bun:sqlite";
import chalk from "chalk";
import { select } from "@inquirer/prompts";
import { AppData } from "../../data/app-data";
import showEntries from "./show-entries";
import showFields from "./show-fields";
import dbHandler from "../../lib/db-handler";
export default async function listTables(params) {
const tables = (await dbHandler({
query: `SELECT table_name FROM ${AppData["DbSchemaManagerTableName"]}`,
})).payload;
if (!tables?.length) {
console.log(chalk.yellow("\nNo tables found.\n"));
return;
}
// Level 1: table selection loop
while (true) {
const tableName = await select({
message: "Select a table:",
choices: [
...tables.map((t) => ({
name: t.table_name,
value: t.table_name,
})),
{ name: chalk.dim("← Go Back"), value: "__back__" },
{ name: chalk.dim("✕ Exit"), value: "__exit__" },
],
});
if (tableName === "__back__")
break;
if (tableName === "__exit__")
return "__exit__";
// Level 2: action loop — stays here until "Go Back"
while (true) {
const action = await select({
message: `"${tableName}" — choose an action:`,
choices: [
{ name: "Entries", value: "entries" },
{ name: "Fields", value: "fields" },
{ name: "Schema", value: "schema" },
{ name: chalk.dim("← Go Back"), value: "__back__" },
{ name: chalk.dim("✕ Exit"), value: "__exit__" },
],
});
if (action === "__back__")
break;
if (action === "__exit__")
return "__exit__";
if (action === "entries") {
const result = await showEntries({ tableName });
if (result === "__exit__")
return "__exit__";
}
if (action === "fields") {
const result = await showFields({ tableName });
if (result === "__exit__")
return "__exit__";
}
// if (action === "schema") {
// const columns = db
// .query<ColumnInfo, []>(`PRAGMA table_info("${tableName}")`)
// .all();
// console.log(`\n${chalk.bold(`Schema for "${tableName}":`)} \n`);
// console.table(
// columns.map((c) => ({
// "#": c.cid,
// Name: c.name,
// Type: c.type,
// "Not Null": c.notnull ? "YES" : "NO",
// Default: c.dflt_value ?? "(none)",
// "Primary Key": c.pk ? "YES" : "NO",
// })),
// );
// console.log();
// }
}
}
}

View File

@ -1,3 +0,0 @@
type Params = {};
export default function runSQL(params?: Params): Promise<void>;
export {};

View File

@ -1,26 +0,0 @@
import { Database } from "bun:sqlite";
import { input } from "@inquirer/prompts";
import chalk from "chalk";
import dbHandler from "../../lib/db-handler";
export default async function runSQL(params) {
const sql = await input({
message: "Enter SQL query:",
validate: (val) => val.trim().length > 0 || "Query cannot be empty",
});
try {
const res = await dbHandler({ query: sql });
if (res.payload) {
console.log(`\n${chalk.bold(`Result (${res.payload.length} row${res.payload.length !== 1 ? "s" : ""}):`)} \n`);
if (res.payload.length)
console.table(res.payload);
else
console.log(chalk.yellow("No res returned.\n"));
}
else if (res.single_res) {
console.log(chalk.green(`\nSuccess! Affected rows: ${res.single_res.changes}, Last insert ID: ${res.single_res.lastInsertRowid}\n`));
}
}
catch (error) {
console.error(chalk.red(`\nSQL Error: ${error.message}\n`));
}
}

View File

@ -1,5 +0,0 @@
type Params = {
tableName: string;
};
export default function showEntries({ tableName }: Params): Promise<"__exit__" | undefined>;
export {};

View File

@ -1,83 +0,0 @@
import { Database } from "bun:sqlite";
import chalk from "chalk";
import { select, input } from "@inquirer/prompts";
import dbHandler from "../../lib/db-handler";
const LIMIT = 50;
export default async function showEntries({ tableName }) {
let page = 0;
let searchField = null;
let searchTerm = null;
while (true) {
const offset = page * LIMIT;
const rows = searchTerm
? (await dbHandler({
query: `SELECT * FROM "${tableName}" WHERE "${searchField}" LIKE ? LIMIT ${LIMIT} OFFSET ${offset}`,
values: [`%${searchTerm}%`],
})).payload
: (await dbHandler({
query: `SELECT * FROM "${tableName}" LIMIT ${LIMIT} OFFSET ${offset}`,
})).payload;
const countRow = searchTerm
? (await dbHandler({
query: `SELECT COUNT(*) as count FROM "${tableName}" WHERE "${searchField}" LIKE ?`,
values: [`%${searchTerm}%`],
})).payload
: (await dbHandler({
query: `SELECT COUNT(*) as count FROM "${tableName}"`,
})).payload;
const total = countRow?.[0]?.count;
const searchInfo = searchTerm
? chalk.dim(` · searching "${searchField}" = "${searchTerm}"`)
: "";
if (!rows) {
return;
}
console.log(`\n${chalk.bold(tableName)} — Page ${page + 1}${searchInfo} (${rows.length} of ${total}):\n`);
if (rows.length) {
console.log(rows);
// if (rows.length) console.table(rows);
}
else {
console.log(chalk.yellow("No rows found."));
console.log();
}
const choices = [];
if (page > 0)
choices.push({ name: "← Previous Page", value: "prev" });
if (offset + rows.length < total)
choices.push({ name: "Next Page →", value: "next" });
choices.push({ name: "Search by Field", value: "search" });
if (searchTerm)
choices.push({ name: "Clear Search", value: "clear_search" });
choices.push({ name: chalk.dim("← Go Back"), value: "__back__" });
choices.push({ name: chalk.dim("✕ Exit"), value: "__exit__" });
const action = await select({ message: "Navigate:", choices });
if (action === "__back__")
break;
if (action === "__exit__")
return "__exit__";
if (action === "next")
page++;
if (action === "prev")
page--;
if (action === "clear_search") {
searchField = null;
searchTerm = null;
page = 0;
}
// if (action === "search") {
// const columns = db
// .query<ColumnInfo, []>(`PRAGMA table_info("${tableName}")`)
// .all();
// searchField = await select({
// message: "Search by field:",
// choices: columns.map((c) => ({ name: c.name, value: c.name })),
// });
// searchTerm = await input({
// message: `Search term for "${searchField}":`,
// validate: (v) => v.trim().length > 0 || "Cannot be empty",
// });
// page = 0;
// }
}
}

View File

@ -1,5 +0,0 @@
type Params = {
tableName: string;
};
export default function showFields({ tableName, }: Params): Promise<"__exit__" | void>;
export {};

View File

@ -1,69 +0,0 @@
import { Database } from "bun:sqlite";
import chalk from "chalk";
import { select } from "@inquirer/prompts";
export default async function showFields({ tableName, }) {
// const columns = db
// .query<ColumnInfo, []>(`PRAGMA table_info("${tableName}")`)
// .all();
// const indexes = db
// .query<IndexInfo, []>(`PRAGMA index_list("${tableName}")`)
// .all();
// const foreignKeys = db
// .query<ForeignKey, []>(`PRAGMA foreign_key_list("${tableName}")`)
// .all();
// const indexedFields = new Map<string, { unique: boolean }>();
// for (const idx of indexes) {
// const cols = db
// .query<IndexColumn, []>(`PRAGMA index_info("${idx.name}")`)
// .all();
// for (const col of cols) {
// indexedFields.set(col.name, { unique: idx.unique === 1 });
// }
// }
// while (true) {
// const fieldName = await select({
// message: `"${tableName}" — select a field:`,
// choices: [
// ...columns.map((c) => ({ name: c.name, value: c.name })),
// { name: chalk.dim("← Go Back"), value: "__back__" },
// { name: chalk.dim("✕ Exit"), value: "__exit__" },
// ],
// });
// if (fieldName === "__back__") break;
// if (fieldName === "__exit__") return "__exit__";
// const col = columns.find((c) => c.name === fieldName)!;
// const idx = indexedFields.get(fieldName);
// const fk = foreignKeys.find((f) => f.from === fieldName);
// console.log(`\n${chalk.bold(`Field: "${fieldName}"`)}\n`);
// console.log(` ${chalk.dim("Table")} ${tableName}`);
// console.log(` ${chalk.dim("Column #")} ${col.cid}`);
// console.log(
// ` ${chalk.dim("Type")} ${col.type || chalk.italic("(none)")}`,
// );
// console.log(
// ` ${chalk.dim("Primary Key")} ${col.pk ? chalk.green("YES") : "NO"}`,
// );
// console.log(
// ` ${chalk.dim("Not Null")} ${col.notnull ? chalk.yellow("YES") : "NO"}`,
// );
// console.log(
// ` ${chalk.dim("Default")} ${col.dflt_value ?? chalk.italic("(none)")}`,
// );
// console.log(
// ` ${chalk.dim("Indexed")} ${idx ? chalk.cyan("YES") : "NO"}`,
// );
// console.log(
// ` ${chalk.dim("Unique")} ${idx?.unique ? chalk.cyan("YES") : "NO"}`,
// );
// if (fk) {
// console.log(
// ` ${chalk.dim("Foreign Key")} ${chalk.magenta(`${fk.table}(${fk.to})`)}`,
// );
// console.log(` ${chalk.dim("On Update")} ${fk.on_update}`);
// console.log(` ${chalk.dim("On Delete")} ${fk.on_delete}`);
// } else {
// console.log(` ${chalk.dim("Foreign Key")} NO`);
// }
// console.log();
// }
}

View File

@ -1,2 +0,0 @@
import { Command } from "commander";
export default function (): Command;

View File

@ -1,22 +0,0 @@
import { Command } from "commander";
import init from "../functions/init";
import path from "path";
import grabDBDir from "../utils/grab-db-dir";
import fs from "fs";
import grabDBBackupFileName from "../utils/grab-db-backup-file-name";
import chalk from "chalk";
import trimBackups from "../utils/trim-backups";
export default function () {
return new Command("backup")
.description("Backup Database")
.action(async (opts) => {
console.log(`Backing up database ...`);
const { config } = await init();
const { backup_dir, db_file_path } = grabDBDir({ config });
const new_db_file_name = grabDBBackupFileName({ config });
fs.cpSync(db_file_path, path.join(backup_dir, new_db_file_name));
trimBackups({ config });
console.log(`${chalk.bold(chalk.green(`DB Backup Success!`))}`);
process.exit();
});
}

View File

@ -1,6 +0,0 @@
#!/usr/bin/env bun
/**
* # Declare Global Variables
*/
declare global { }
export {};

View File

@ -1,33 +0,0 @@
#!/usr/bin/env bun
import { program } from "commander";
import schema from "./schema";
import typedef from "./typedef";
import backup from "./backup";
import restore from "./restore";
import admin from "./admin";
/**
* # Describe Program
*/
program
.name(`bun-mariadb`)
.description(`MariaDB manager for Bun`)
.version(`1.0.0`);
/**
* # Declare Commands
*/
program.addCommand(schema());
program.addCommand(typedef());
program.addCommand(backup());
program.addCommand(restore());
program.addCommand(admin());
/**
* # Handle Unavailable Commands
*/
program.on("command:*", () => {
console.error("Invalid command: %s\nSee --help for a list of available commands.", program.args.join(" "));
process.exit(1);
});
/**
* # Parse Arguments
*/
program.parse(Bun.argv);

View File

@ -1,2 +0,0 @@
import { Command } from "commander";
export default function (): Command;

View File

@ -1,44 +0,0 @@
import { Command } from "commander";
import init from "../functions/init";
import grabDBDir from "../utils/grab-db-dir";
import fs from "fs";
import chalk from "chalk";
import grabSortedBackups from "../utils/grab-sorted-backups";
import { select } from "@inquirer/prompts";
import grabBackupData from "../utils/grab-backup-data";
import path from "path";
export default function () {
return new Command("restore")
.description("Restore Database")
.action(async (opts) => {
console.log(`Restoring up database ...`);
const { config } = await init();
const { backup_dir, db_file_path } = grabDBDir({ config });
const backups = grabSortedBackups({ config });
if (!backups?.[0]) {
console.error(`No Backups to restore. Use the \`backup\` command to create a backup`);
process.exit(1);
}
try {
const selected_backup = await select({
message: "Select a backup:",
choices: backups.map((b, i) => {
const { backup_date } = grabBackupData({
backup_name: b,
});
return {
name: `Backup #${i + 1}: ${backup_date.toDateString()} ${backup_date.getHours()}:${backup_date.getMinutes()}:${backup_date.getSeconds().toString().padStart(2, "0")}`,
value: b,
};
}),
});
fs.cpSync(path.join(backup_dir, selected_backup), db_file_path);
console.log(`${chalk.bold(chalk.green(`DB Restore Success!`))}`);
process.exit();
}
catch (error) {
console.error(`Backup Restore ERROR => ${error.message}`);
process.exit();
}
});
}

View File

@ -1,2 +0,0 @@
import { Command } from "commander";
export default function (): Command;

View File

@ -1,54 +0,0 @@
import { Command } from "commander";
import { MariaDBSchemaManager } from "../lib/mariadb/db-schema-manager";
import init from "../functions/init";
import grabDirNames from "../data/grab-dir-names";
import path from "path";
import dbSchemaToTypeDef from "../lib/mariadb/schema-to-typedef";
import _ from "lodash";
import appendDefaultFieldsToDbSchema from "../utils/append-default-fields-to-db-schema";
import chalk from "chalk";
import { writeLiveSchema } from "../functions/live-schema";
import grabDBDir from "../utils/grab-db-dir";
import { cpSync } from "fs";
export default function () {
return new Command("schema")
.description("Build DB From Schema")
.option("-v, --vector", "Recreate Vector Tables. This will drop and rebuild all vector tables")
.option("-t, --typedef", "Generate typescript type definitions")
.action(async (opts) => {
console.log(`Starting process ...`);
const { config, dbSchema } = await init();
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);
const isTypeDef = Boolean(opts.typedef || opts.t);
const finaldbSchema = appendDefaultFieldsToDbSchema({
dbSchema,
});
const manager = new MariaDBSchemaManager({
schema: finaldbSchema,
recreate_vector_table: isVector,
});
await manager.syncSchema();
manager.close();
if (isTypeDef && config.typedef_file_path) {
const out_file = path.resolve(ROOT_DIR, config.typedef_file_path);
dbSchemaToTypeDef({
dbSchema: finaldbSchema,
dst_file: out_file,
config,
});
}
writeLiveSchema({ schema: finaldbSchema });
console.log(`${chalk.bold(chalk.green(`DB Schema setup success!`))}`);
process.exit();
}
catch (error) {
console.log(error);
cpSync(BUN_MARIADB_TEMP_DB_FILE_PATH, db_file_path);
process.exit(1);
}
});
}

View File

@ -1,2 +0,0 @@
import { Command } from "commander";
export default function (): Command;

View File

@ -1,31 +0,0 @@
import { Command } from "commander";
import init from "../functions/init";
import dbSchemaToTypeDef from "../lib/mariadb/schema-to-typedef";
import path from "path";
import grabDirNames from "../data/grab-dir-names";
import appendDefaultFieldsToDbSchema from "../utils/append-default-fields-to-db-schema";
import chalk from "chalk";
export default function () {
return new Command("typedef")
.description("Build DB From Schema")
.action(async (opts) => {
console.log(`Creating Type Definition From DB Schema ...`);
const { config, dbSchema } = await init();
const { ROOT_DIR } = grabDirNames();
const finaldbSchema = appendDefaultFieldsToDbSchema({ dbSchema });
if (config.typedef_file_path) {
const out_file = path.resolve(ROOT_DIR, config.typedef_file_path);
dbSchemaToTypeDef({
dbSchema: finaldbSchema,
dst_file: out_file,
config,
});
}
else {
console.error(``);
process.exit(1);
}
console.log(`${chalk.bold(chalk.green(`Typedef gen success!`))}`);
process.exit();
});
}

View File

@ -1,6 +0,0 @@
export declare const AppData: {
readonly ConfigFileName: "bun-sqlite.config.ts";
readonly MaxBackups: 10;
readonly DefaultBackupDirName: ".backups";
readonly DbSchemaManagerTableName: "__db_schema_manager__";
};

View File

@ -1,6 +0,0 @@
export const AppData = {
ConfigFileName: "bun-sqlite.config.ts",
MaxBackups: 10,
DefaultBackupDirName: ".backups",
DbSchemaManagerTableName: "__db_schema_manager__",
};

View File

@ -1,12 +0,0 @@
import type { BunSQLiteConfig } from "../types";
type Params = {
config?: BunSQLiteConfig;
};
export default function grabDirNames(params?: Params): {
ROOT_DIR: string;
BUN_MARIADB_DIR: string;
BUN_MARIADB_TEMP_DIR: string;
BUN_MARIADB_LIVE_SCHEMA: string;
BUN_MARIADB_TEMP_DB_FILE_PATH: string;
};
export {};

View File

@ -1,15 +0,0 @@
import path from "path";
export default function grabDirNames(params) {
const ROOT_DIR = process.cwd();
const BUN_MARIADB_DIR = path.join(ROOT_DIR, ".bun-sqlite");
const BUN_MARIADB_TEMP_DIR = path.join(BUN_MARIADB_DIR, ".tmp");
const BUN_MARIADB_TEMP_DB_FILE_PATH = path.join(BUN_MARIADB_TEMP_DIR, "temp.db");
const BUN_MARIADB_LIVE_SCHEMA = path.join(BUN_MARIADB_DIR, "live-schema.json");
return {
ROOT_DIR,
BUN_MARIADB_DIR,
BUN_MARIADB_TEMP_DIR,
BUN_MARIADB_LIVE_SCHEMA,
BUN_MARIADB_TEMP_DB_FILE_PATH,
};
}

View File

@ -1,2 +0,0 @@
import type { BunSQLiteConfigReturn } from "../types";
export default function init(): Promise<BunSQLiteConfigReturn>;

View File

@ -1,46 +0,0 @@
import path from "path";
import fs from "fs";
import { AppData } from "../data/app-data";
import grabDirNames from "../data/grab-dir-names";
export default async function init() {
try {
const { ROOT_DIR } = grabDirNames();
const { ConfigFileName } = AppData;
const ConfigFilePath = path.join(ROOT_DIR, ConfigFileName);
if (!fs.existsSync(ConfigFilePath)) {
console.log("ConfigFilePath", ConfigFilePath);
console.error(`Please create a \`${ConfigFileName}\` file at the root of your project.`);
process.exit(1);
}
const ConfigImport = await import(ConfigFilePath);
const Config = ConfigImport["default"];
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`);
process.exit(1);
}
let db_dir = ROOT_DIR;
if (Config.db_dir) {
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, Config.db_schema_file_name);
const DbSchemaImport = await import(DBSchemaFilePath);
const DbSchema = DbSchemaImport["default"];
const backup_dir = Config.db_backup_dir || AppData["DefaultBackupDirName"];
const BackupDir = path.resolve(db_dir, backup_dir);
if (!fs.existsSync(BackupDir)) {
fs.mkdirSync(BackupDir, { recursive: true });
}
return { config: Config, dbSchema: DbSchema };
}
catch (error) {
console.error(`Initialization ERROR => ` + error.message);
process.exit(1);
}
}

View File

@ -1,7 +0,0 @@
import type { BUN_MARIADB_DatabaseSchemaType } from "../types";
type Params = {
schema: BUN_MARIADB_DatabaseSchemaType;
};
export declare function writeLiveSchema({ schema }: Params): void;
export declare function readLiveSchema(): BUN_MARIADB_DatabaseSchemaType | undefined;
export {};

View File

@ -1,15 +0,0 @@
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
import grabDirNames from "../data/grab-dir-names";
import path from "path";
const { BUN_MARIADB_LIVE_SCHEMA } = grabDirNames();
export function writeLiveSchema({ schema }) {
mkdirSync(path.dirname(BUN_MARIADB_LIVE_SCHEMA), { recursive: true });
writeFileSync(BUN_MARIADB_LIVE_SCHEMA, JSON.stringify(schema));
}
export function readLiveSchema() {
if (!existsSync(BUN_MARIADB_LIVE_SCHEMA)) {
return undefined;
}
const live_schema = readFileSync(BUN_MARIADB_LIVE_SCHEMA, "utf-8");
return JSON.parse(live_schema);
}

19
dist/index.d.ts vendored
View File

@ -1,19 +0,0 @@
import DbDelete from "./lib/mariadb/db-delete";
import DbInsert from "./lib/mariadb/db-insert";
import DbSelect from "./lib/mariadb/db-select";
import DbSQL from "./lib/mariadb/db-sql";
import DbUpdate from "./lib/mariadb/db-update";
import grabDbSchema from "./utils/grab-db-schema";
import grabJoinFieldsFromQueryObject from "./utils/grab-join-fields-from-query-object";
declare const BunMariaDB: {
readonly select: typeof DbSelect;
readonly insert: typeof DbInsert;
readonly update: typeof DbUpdate;
readonly delete: typeof DbDelete;
readonly sql: typeof DbSQL;
readonly utils: {
readonly grab_db_schema: typeof grabDbSchema;
readonly grab_join_fields_from_query_object: typeof grabJoinFieldsFromQueryObject;
};
};
export default BunMariaDB;

19
dist/index.js vendored
View File

@ -1,19 +0,0 @@
import DbDelete from "./lib/mariadb/db-delete";
import DbInsert from "./lib/mariadb/db-insert";
import DbSelect from "./lib/mariadb/db-select";
import DbSQL from "./lib/mariadb/db-sql";
import DbUpdate from "./lib/mariadb/db-update";
import grabDbSchema from "./utils/grab-db-schema";
import grabJoinFieldsFromQueryObject from "./utils/grab-join-fields-from-query-object";
const BunMariaDB = {
select: DbSelect,
insert: DbInsert,
update: DbUpdate,
delete: DbDelete,
sql: DbSQL,
utils: {
grab_db_schema: grabDbSchema,
grab_join_fields_from_query_object: grabJoinFieldsFromQueryObject,
},
};
export default BunMariaDB;

View File

@ -1,20 +0,0 @@
import type { ConnectionConfig } from "mariadb";
import type { BUN_MARIADB_TableSchemaType, DBResponseObject } from "../types";
type Param = {
query: string;
values?: string[] | object;
noErrorLogs?: boolean;
database?: string;
tableSchema?: BUN_MARIADB_TableSchemaType;
config?: ConnectionConfig;
};
/**
* # Main DB Handler Function
* @requires DSQL_DB_CONN - Gobal Variable for Datasquirel Database
*/
export default function dbHandler<T extends {
[k: string]: any;
} = {
[k: string]: any;
}>({ query, values, noErrorLogs, database, config, }: Param): Promise<DBResponseObject>;
export {};

View File

@ -1,46 +0,0 @@
import grabDBConnection from "./grab-db-connection";
/**
* # Main DB Handler Function
* @requires DSQL_DB_CONN - Gobal Variable for Datasquirel Database
*/
export default async function dbHandler({ query, values, noErrorLogs, database, config, }) {
let CONNECTION;
let results = null;
try {
CONNECTION = await grabDBConnection({ database, config });
if (query && values) {
const queryResults = await CONNECTION.query(query, values);
results = queryResults[0];
}
else {
const queryResults = await CONNECTION.query(query);
results = queryResults[0];
}
}
catch (error) {
if (error.message &&
typeof error.message == "string" &&
error.message.match(/Access denied for user.*password/i)) {
throw new Error("Authentication Failed!");
}
if (!noErrorLogs) {
console.log(error);
}
results = null;
}
finally {
await CONNECTION?.end();
}
if (results) {
return {
success: true,
payload: Array.isArray(results) ? results : undefined,
single_res: Array.isArray(results) ? undefined : results,
};
}
else {
return {
success: false,
};
}
}

View File

@ -1,6 +0,0 @@
import type { Connection } from "mariadb";
import type { DsqlConnectionParam } from "../types";
/**
* # Grab General CONNECTION for DSQL
*/
export default function grabDBConnection(param?: DsqlConnectionParam): Promise<Connection>;

View File

@ -1,15 +0,0 @@
import * as mariadb from "mariadb";
import grabDSQLConnectionConfig from "./grab-dsql-connection-config";
/**
* # Grab General CONNECTION for DSQL
*/
export default async function grabDBConnection(param) {
const config = grabDSQLConnectionConfig(param);
try {
return await mariadb.createConnection(config);
}
catch (error) {
console.log(`Error Grabbing DSQL Connection =>`, config);
throw error;
}
}

View File

@ -1,7 +0,0 @@
import type { ConnectionConfig } from "mariadb";
type Return = ConnectionConfig["ssl"] | undefined;
/**
* # Grab SSL
*/
export default function grabDbSSL(): Return;
export {};

View File

@ -1,20 +0,0 @@
import fs from "fs";
import path from "path";
/**
* # Grab SSL
*/
export default function grabDbSSL() {
const caProivdedPath = process.env.DSQL_SSL_CA_CERT;
if (!caProivdedPath?.match(/./)) {
return undefined;
}
const caFilePath = path.resolve(process.cwd(), caProivdedPath);
if (!fs.existsSync(caFilePath)) {
console.log(`${caFilePath} does not exist`);
return undefined;
}
return {
ca: fs.readFileSync(caFilePath),
rejectUnauthorized: false,
};
}

View File

@ -1,6 +0,0 @@
import { type ConnectionConfig } from "mariadb";
import type { DsqlConnectionParam } from "../types";
/**
* # Grab General CONNECTION for DSQL
*/
export default function grabDSQLConnectionConfig(param?: DsqlConnectionParam): ConnectionConfig;

View File

@ -1,29 +0,0 @@
import {} from "mariadb";
import grabDbSSL from "./grab-db-ssl";
/**
* # Grab General CONNECTION for DSQL
*/
export default function grabDSQLConnectionConfig(param) {
const CONN_TIMEOUT = 10000;
const config = {
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)
: undefined,
charset: "utf8mb4",
ssl: grabDbSSL(),
bigIntAsNumber: true,
supportBigNumbers: true,
bigNumberStrings: false,
dateStrings: true,
metaAsArray: true,
socketTimeout: CONN_TIMEOUT,
connectTimeout: CONN_TIMEOUT,
compress: true,
...param?.config,
};
return config;
}

View File

@ -1,7 +0,0 @@
type Params = {
sql: string;
table: string;
data: any | any[];
};
export default function ({ sql: passed_sql, table, data }: Params): Promise<string>;
export {};

View File

@ -1,24 +0,0 @@
import init from "../functions/init";
export default async function ({ sql: passed_sql, table, data }) {
let sql = passed_sql;
const { dbSchema } = await init();
const table_schema = dbSchema.tables.find((t) => t.tableName == table);
const now = Date.now();
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 (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}`;
}
}
}
return sql;
}

View File

@ -1,16 +0,0 @@
import type { APIResponseObject, ServerQueryParam } from "../../types";
type Params<Schema extends {
[k: string]: any;
} = {
[k: string]: any;
}, Table extends string = string> = {
table: Table;
query?: ServerQueryParam<Schema>;
targetId?: number | string;
};
export default function DbDelete<Schema extends {
[k: string]: any;
} = {
[k: string]: any;
}, Table extends string = string>({ table, query, targetId, }: Params<Schema, Table>): Promise<APIResponseObject>;
export {};

View File

@ -1,56 +0,0 @@
import DbClient from ".";
import _ from "lodash";
import sqlGenerator from "../../utils/sql-generator";
export default async function DbDelete({ table, query, targetId, }) {
let sqlObj = null;
try {
let finalQuery = query || {};
if (targetId) {
finalQuery = _.merge(finalQuery, {
query: {
id: {
value: String(targetId),
},
},
});
}
sqlObj = sqlGenerator({
tableName: 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 {
return {
success: false,
msg: `No WHERE clause`,
debug: {
sqlObj,
},
};
}
}
catch (error) {
return {
success: false,
error: error.message,
debug: {
sqlObj,
},
};
}
}

View File

@ -1,15 +0,0 @@
import type { BUN_MARIADB_TableSchemaType } from "../../types";
type Param = {
paradigm: "JavaScript" | "TypeScript" | undefined;
table: BUN_MARIADB_TableSchemaType;
query?: any;
typeDefName?: string;
allValuesOptional?: boolean;
addExport?: boolean;
dbName?: string;
};
export default function generateTypeDefinition({ paradigm, table, query, typeDefName, allValuesOptional, addExport, dbName, }: Param): {
typeDefinition: string | null;
tdName: string;
};
export {};

View File

@ -1,63 +0,0 @@
export default function generateTypeDefinition({ paradigm, table, query, typeDefName, allValuesOptional, addExport, dbName, }) {
let typeDefinition = ``;
let tdName = ``;
try {
tdName = typeDefName
? typeDefName
: dbName
? `BUN_MARIADB_${dbName}_${table.tableName}`.toUpperCase()
: `BUN_MARIADB_${query.single}_${query.single_table}`.toUpperCase();
const fields = table.fields;
function typeMap(schemaType) {
if (schemaType.options && schemaType.options.length > 0) {
let opts = schemaType.options.map((opt) => schemaType.dataType?.match(/int/i) || typeof opt == "number"
? `${opt}`
: `"${opt}"`);
opts.push(`""`);
return opts.join(" | ");
}
if (schemaType.dataType?.match(/blob/i)) {
return `Float32Array<ArrayBuffer> | Buffer<ArrayBuffer> | null`;
}
if (schemaType.dataType?.match(/int|double|decimal|real/i)) {
return `number | ""`;
}
if (schemaType.dataType?.match(/text|varchar|timestamp/i)) {
return `string`;
}
if (schemaType.dataType?.match(/boolean/i)) {
return "0 | 1";
}
return "string";
}
const typesArrayTypeScript = [];
const typesArrayJavascript = [];
typesArrayTypeScript.push(`${addExport ? "export " : ""}type ${tdName} = {`);
typesArrayJavascript.push(`/**\n * @typedef {object} ${tdName}`);
fields.forEach((field) => {
if (field.fieldDescription) {
typesArrayTypeScript.push(` /** \n * ${field.fieldDescription}\n */`);
}
const nullValue = allValuesOptional
? "?"
: field.notNullValue
? ""
: "?";
typesArrayTypeScript.push(` ${field.fieldName}${nullValue}: ${typeMap(field)};`);
typesArrayJavascript.push(` * @property {${typeMap(field)}${nullValue}} ${field.fieldName}`);
});
typesArrayTypeScript.push(`}`);
typesArrayJavascript.push(` */`);
if (paradigm?.match(/javascript/i)) {
typeDefinition = typesArrayJavascript.join("\n");
}
if (paradigm?.match(/typescript/i)) {
typeDefinition = typesArrayTypeScript.join("\n");
}
}
catch (error) {
console.log(error.message);
typeDefinition = null;
}
return { typeDefinition, tdName };
}

View File

@ -1,16 +0,0 @@
import type { APIResponseObject } from "../../types";
type Params<Schema extends {
[k: string]: any;
} = {
[k: string]: any;
}, Table extends string = string> = {
table: Table;
data: Schema[];
update_on_duplicate?: boolean;
};
export default function DbInsert<Schema extends {
[k: string]: any;
} = {
[k: string]: any;
}, Table extends string = string>({ table, data, update_on_duplicate, }: Params<Schema, Table>): Promise<APIResponseObject>;
export {};

View File

@ -1,43 +0,0 @@
import DbClient from ".";
import sqlInsertGenerator from "../../utils/sql-insert-generator";
import grabDuplicateSafeInsertSql from "../grab-duplicate-safe-insert-sql";
export default async function DbInsert({ table, data, update_on_duplicate, }) {
let sqlObj = null;
try {
const finalData = data.map((d) => ({
created_at: Date.now(),
updated_at: Date.now(),
...d,
}));
sqlObj =
sqlInsertGenerator({
tableName: table,
data: finalData,
}) || null;
let sql = sqlObj?.query || "";
if (update_on_duplicate && data[0]) {
sql = await grabDuplicateSafeInsertSql({ data, table, sql });
}
(sqlObj || {}).query = sql;
const res = DbClient.run(sql, sqlObj?.values || []);
return {
success: Boolean(Number(res.lastInsertRowid)),
postInsertReturn: {
affectedRows: res.changes,
insertId: Number(res.lastInsertRowid),
},
debug: {
sqlObj,
},
};
}
catch (error) {
return {
success: false,
error: error.message,
debug: {
sqlObj,
},
};
}
}

View File

@ -1,39 +0,0 @@
#!/usr/bin/env bun
import type { BUN_MARIADB_DatabaseSchemaType } from "../../types";
declare class MariaDBSchemaManager {
private db_manager_table_name;
private recreate_vector_table;
private db_schema;
constructor({ schema, recreate_vector_table, }: {
schema: BUN_MARIADB_DatabaseSchemaType;
recreate_vector_table?: boolean;
});
syncSchema(): Promise<void>;
private getDatabaseName;
private quoteIdentifier;
private tableSchemaWhere;
private run;
private query;
private createDbManagerTable;
private insertDbManagerTable;
private removeDbManagerTable;
private getExistingTables;
private getLiveTableNames;
private dropRemovedTables;
private syncTable;
private resolveTable;
private createTable;
private buildTableOptions;
private updateTable;
private getTableColumns;
private addColumn;
private checkIfTableExists;
private recreateTable;
private insertRows;
private buildColumnDefinition;
private mapDataType;
private buildForeignKeyConstraint;
private syncIndexes;
close(): void;
}
export { MariaDBSchemaManager };

View File

@ -1,419 +0,0 @@
#!/usr/bin/env bun
import _ from "lodash";
import dbHandler from "../db-handler";
import { AppData } from "../../data/app-data";
import { readLiveSchema } from "../../functions/live-schema";
class MariaDBSchemaManager {
db_manager_table_name;
recreate_vector_table;
db_schema;
constructor({ schema, recreate_vector_table = false, }) {
this.db_manager_table_name = AppData["DbSchemaManagerTableName"];
this.recreate_vector_table = recreate_vector_table;
this.db_schema = schema;
}
async syncSchema() {
console.log("Starting schema synchronization...");
await this.createDbManagerTable();
const existingTables = await this.getExistingTables();
const schemaTables = this.db_schema.tables.map((t) => t.tableName);
for (const table of this.db_schema.tables) {
await this.syncTable(table, existingTables);
}
await this.dropRemovedTables(existingTables, schemaTables);
console.log("Schema synchronization complete!");
}
getDatabaseName() {
return this.db_schema.dbName || this.db_schema.dbSlug;
}
quoteIdentifier(identifier) {
return `\`${identifier.replace(/`/g, "``")}\``;
}
tableSchemaWhere(tableName) {
const databaseName = this.getDatabaseName();
if (databaseName) {
return {
where: "TABLE_SCHEMA = ?",
values: [databaseName, tableName],
};
}
return {
where: "TABLE_SCHEMA = DATABASE()",
values: [tableName],
};
}
async run(query, values) {
const res = await dbHandler({
query,
values: values,
config: this.getDatabaseName()
? { database: this.getDatabaseName() }
: undefined,
});
if (!res.success) {
throw new Error(`Database query failed: ${query}`);
}
}
async query(query, values) {
const res = await dbHandler({
query,
values: values,
config: this.getDatabaseName()
? { database: this.getDatabaseName() }
: undefined,
});
if (!res.success) {
throw new Error(`Database query failed: ${query}`);
}
return (res.payload || []);
}
async createDbManagerTable() {
await this.run(`
CREATE TABLE IF NOT EXISTS ${this.quoteIdentifier(this.db_manager_table_name)} (
table_name VARCHAR(255) NOT NULL PRIMARY KEY,
created_at BIGINT NOT NULL,
updated_at BIGINT NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci
`);
}
async insertDbManagerTable(tableName) {
const now = Date.now();
await this.run(`INSERT INTO ${this.quoteIdentifier(this.db_manager_table_name)} (table_name, created_at, updated_at) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE updated_at = VALUES(updated_at)`, [tableName, now, now]);
}
async removeDbManagerTable(tableName) {
await this.run(`DELETE FROM ${this.quoteIdentifier(this.db_manager_table_name)} WHERE table_name = ?`, [tableName]);
}
async getExistingTables() {
const rows = await this.query(`SELECT table_name FROM ${this.quoteIdentifier(this.db_manager_table_name)}`);
return rows.map((row) => row.table_name);
}
async getLiveTableNames() {
const tableSchemaWhere = this.tableSchemaWhere("");
const rows = await this.query(`SELECT TABLE_NAME FROM information_schema.TABLES WHERE ${tableSchemaWhere.where} AND TABLE_TYPE = 'BASE TABLE'`, tableSchemaWhere.values);
return rows.map((row) => row.TABLE_NAME);
}
async dropRemovedTables(existingTables, schemaTables) {
console.log(`Cleaning up tables ...`);
const tablesToDrop = existingTables.filter((tableName) => !schemaTables.includes(tableName) &&
!schemaTables.some((schemaTable) => tableName.startsWith(`${schemaTable}_`)));
const currentSchema = readLiveSchema();
if (currentSchema?.tables?.[0]) {
for (const table of currentSchema.tables) {
if (!table?.tableName)
continue;
const doesTableExist = schemaTables.find((tableName) => tableName === table.tableName);
if (!doesTableExist) {
tablesToDrop.push(table.tableName);
}
}
}
for (const tableName of tablesToDrop) {
console.log(`Dropping table: ${tableName}`);
await this.run(`DROP TABLE IF EXISTS ${this.quoteIdentifier(tableName)}`);
await this.removeDbManagerTable(tableName);
}
}
async syncTable(table, existingTables) {
let tableExists = existingTables.includes(table.tableName);
const liveTables = await this.getLiveTableNames();
if (table.tableNameOld && table.tableNameOld !== table.tableName) {
if (liveTables.includes(table.tableNameOld)) {
console.log(`Renaming table: ${table.tableNameOld} -> ${table.tableName}`);
await this.run(`RENAME TABLE ${this.quoteIdentifier(table.tableNameOld)} TO ${this.quoteIdentifier(table.tableName)}`);
await this.insertDbManagerTable(table.tableName);
await this.removeDbManagerTable(table.tableNameOld);
tableExists = true;
}
}
if (!tableExists) {
await this.createTable(table);
await this.insertDbManagerTable(table.tableName);
}
else {
await this.updateTable(table);
await this.insertDbManagerTable(table.tableName);
}
await this.syncIndexes(table);
}
resolveTable(table) {
if (!table.parentTableName) {
return _.cloneDeep(table);
}
const parentTable = this.db_schema.tables.find((schemaTable) => schemaTable.tableName === table.parentTableName);
if (!parentTable) {
throw new Error(`Parent table \`${table.parentTableName}\` not found for \`${table.tableName}\``);
}
return _.merge({}, parentTable, {
tableName: table.tableName,
tableDescription: table.tableDescription,
collation: table.collation,
fields: [...(parentTable.fields || []), ...(table.fields || [])],
indexes: [...(parentTable.indexes || []), ...(table.indexes || [])],
uniqueConstraints: [
...(parentTable.uniqueConstraints || []),
...(table.uniqueConstraints || []),
],
});
}
async createTable(table) {
if (!table.tableName.match(/_temp_\d+$/)) {
console.log(`Creating table: ${table.tableName}`);
}
const newTable = this.resolveTable(table);
const columnDefinitions = [];
const foreignKeys = [];
for (const field of newTable.fields || []) {
columnDefinitions.push(this.buildColumnDefinition(field));
if (field.foreignKey && !newTable.isVector) {
foreignKeys.push(this.buildForeignKeyConstraint(field));
}
}
if (newTable.uniqueConstraints) {
for (const constraint of newTable.uniqueConstraints) {
if (constraint.constraintTableFields &&
constraint.constraintTableFields.length > 0) {
const fields = constraint.constraintTableFields
.map((field) => this.quoteIdentifier(field.value))
.join(", ");
const constraintName = constraint.constraintName ||
`unique_${fields.replace(/`/g, "")}`;
columnDefinitions.push(`CONSTRAINT ${this.quoteIdentifier(constraintName)} UNIQUE (${fields})`);
}
}
}
const sql = `CREATE TABLE IF NOT EXISTS ${this.quoteIdentifier(newTable.tableName)} (${[...columnDefinitions, ...foreignKeys].join(", ")})${this.buildTableOptions(newTable)}`;
await this.run(sql);
}
buildTableOptions(table) {
const options = ["ENGINE=InnoDB"];
if (table.collation) {
options.push("DEFAULT CHARSET=utf8mb4", `COLLATE ${table.collation}`);
}
return ` ${options.join(" ")}`;
}
async updateTable(table) {
console.log(`Updating table: ${table.tableName}`);
await this.recreateTable(table);
}
async getTableColumns(tableName) {
const tableSchemaWhere = this.tableSchemaWhere(tableName);
const rows = await this.query(`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);
return rows.map((row) => ({
name: row.COLUMN_NAME,
type: row.COLUMN_TYPE,
}));
}
async addColumn(tableName, field) {
console.log(`Adding column: ${tableName}.${field.fieldName}`);
const columnDef = this.buildColumnDefinition(field)
.replace(/PRIMARY KEY/gi, "")
.replace(/AUTO_INCREMENT/gi, "")
.replace(/UNIQUE/gi, "")
.trim();
await this.run(`ALTER TABLE ${this.quoteIdentifier(tableName)} ADD COLUMN ${columnDef}`);
}
async checkIfTableExists(table) {
const tableSchemaWhere = this.tableSchemaWhere(table);
const row = await this.query(`SELECT 1 AS exists FROM information_schema.TABLES WHERE ${tableSchemaWhere.where} AND TABLE_NAME = ? LIMIT 1`, tableSchemaWhere.values);
return Boolean(row[0]?.exists);
}
async recreateTable(table) {
if (table.isVector && !this.recreate_vector_table) {
return;
}
const doesTableExist = await this.checkIfTableExists(table.tableName);
if (table.isVector) {
let existingRows = [];
if (doesTableExist) {
existingRows = await this.query(`SELECT * FROM ${this.quoteIdentifier(table.tableName)}`);
await this.run(`DROP TABLE ${this.quoteIdentifier(table.tableName)}`);
}
await this.createTable(table);
if (existingRows.length > 0) {
await this.insertRows(table.tableName, existingRows);
}
return;
}
const tempTableName = `${table.tableName}_temp_${Date.now()}`;
const existingColumns = await this.getTableColumns(table.tableName);
const columnsToKeep = table.fields
.filter((field) => existingColumns.some((column) => column.name === field.fieldName))
.map((field) => field.fieldName)
.filter((fieldName) => Boolean(fieldName));
await this.createTable({ ...table, tableName: tempTableName });
if (columnsToKeep.length > 0) {
const columnList = columnsToKeep
.map((column) => this.quoteIdentifier(column))
.join(", ");
await this.run(`INSERT INTO ${this.quoteIdentifier(tempTableName)} (${columnList}) SELECT ${columnList} FROM ${this.quoteIdentifier(table.tableName)}`);
}
await this.run(`DROP TABLE ${this.quoteIdentifier(table.tableName)}`);
await this.run(`RENAME TABLE ${this.quoteIdentifier(tempTableName)} TO ${this.quoteIdentifier(table.tableName)}`);
}
async insertRows(tableName, rows) {
for (const row of rows) {
const columns = Object.keys(row);
if (columns.length === 0) {
continue;
}
const values = columns.map((column) => row[column]);
const columnList = columns
.map((column) => this.quoteIdentifier(column))
.join(", ");
const placeholders = columns.map(() => "?").join(", ");
await this.run(`INSERT INTO ${this.quoteIdentifier(tableName)} (${columnList}) VALUES (${placeholders})`, values);
}
}
buildColumnDefinition(field) {
if (!field.fieldName) {
throw new Error("Field name is required");
}
const parts = [this.quoteIdentifier(field.fieldName)];
parts.push(this.mapDataType(field));
if (field.primaryKey) {
parts.push("PRIMARY KEY");
if (field.autoIncrement) {
parts.push("AUTO_INCREMENT");
}
}
if (field.notNullValue || field.primaryKey) {
if (!field.primaryKey) {
parts.push("NOT NULL");
}
}
if (field.unique && !field.primaryKey) {
parts.push("UNIQUE");
}
if (field.defaultValue !== undefined) {
if (typeof field.defaultValue === "string") {
parts.push(`DEFAULT '${field.defaultValue.replace(/'/g, "''")}'`);
}
else {
parts.push(`DEFAULT ${field.defaultValue}`);
}
}
else if (field.defaultValueLiteral) {
parts.push(`DEFAULT ${field.defaultValueLiteral}`);
}
if (field.onUpdate) {
parts.push(`ON UPDATE ${field.onUpdate}`);
}
else if (field.onUpdateLiteral) {
parts.push(`ON UPDATE ${field.onUpdateLiteral}`);
}
return parts.join(" ");
}
mapDataType(field) {
const dataType = field.dataType?.toLowerCase() || "text";
const vectorSize = field.vectorSize || 1536;
if (field.isVector) {
return `LONGTEXT COMMENT 'vector_size=${vectorSize}'`;
}
if (dataType.includes("int") ||
dataType === "bigint" ||
dataType === "smallint" ||
dataType === "tinyint") {
if (field.integerLength) {
return `INT(${field.integerLength})`;
}
return "INT";
}
if (dataType === "bigint") {
if (field.integerLength) {
return `BIGINT(${field.integerLength})`;
}
return "BIGINT";
}
if (dataType === "smallint") {
if (field.integerLength) {
return `SMALLINT(${field.integerLength})`;
}
return "SMALLINT";
}
if (dataType === "tinyint") {
if (field.integerLength) {
return `TINYINT(${field.integerLength})`;
}
return "TINYINT";
}
if (dataType.includes("double")) {
return "DOUBLE";
}
if (dataType.includes("float")) {
return "FLOAT";
}
if (dataType.includes("decimal") || dataType.includes("numeric")) {
if (field.integerLength && field.decimals) {
return `DECIMAL(${field.integerLength}, ${field.decimals})`;
}
return "DECIMAL";
}
if (dataType.includes("blob") || dataType.includes("binary")) {
return "BLOB";
}
if (dataType === "boolean" || dataType === "bool") {
return "TINYINT(1)";
}
if (dataType.includes("timestamp")) {
return "TIMESTAMP";
}
if (dataType.includes("datetime")) {
return "DATETIME";
}
if (dataType.includes("date") || dataType.includes("time")) {
return "DATETIME";
}
if (dataType.includes("varchar")) {
if (field.integerLength) {
return `VARCHAR(${field.integerLength})`;
}
return "VARCHAR(255)";
}
return "TEXT";
}
buildForeignKeyConstraint(field) {
const fk = field.foreignKey;
const constraintName = fk.foreignKeyName
? `CONSTRAINT ${this.quoteIdentifier(fk.foreignKeyName)} `
: "";
let constraint = `${constraintName}FOREIGN KEY (${this.quoteIdentifier(field.fieldName)}) REFERENCES ${this.quoteIdentifier(fk.destinationTableName)}(${this.quoteIdentifier(fk.destinationTableColumnName)})`;
if (fk.cascadeDelete) {
constraint += " ON DELETE CASCADE";
}
if (fk.cascadeUpdate) {
constraint += " ON UPDATE CASCADE";
}
return constraint;
}
async syncIndexes(table) {
if (!table.indexes || table.indexes.length === 0) {
return;
}
const tableSchemaWhere = this.tableSchemaWhere(table.tableName);
const rows = await this.query(`SELECT INDEX_NAME AS name FROM information_schema.STATISTICS WHERE ${tableSchemaWhere.where} AND TABLE_NAME = ? AND INDEX_NAME <> 'PRIMARY' GROUP BY INDEX_NAME ORDER BY INDEX_NAME`, tableSchemaWhere.values);
const existingIndexes = rows.map((row) => row.name);
for (const indexName of existingIndexes) {
const stillExists = table.indexes.some((index) => index.indexName === indexName);
if (!stillExists) {
console.log(`Dropping index: ${indexName}`);
await this.run(`DROP INDEX ${this.quoteIdentifier(indexName)} ON ${this.quoteIdentifier(table.tableName)}`);
}
}
for (const index of table.indexes) {
if (!index.indexName ||
!index.indexTableFields ||
index.indexTableFields.length === 0) {
continue;
}
if (!existingIndexes.includes(index.indexName)) {
console.log(`Creating index: ${index.indexName}`);
const fields = index.indexTableFields
.map((field) => this.quoteIdentifier(field))
.join(", ");
await this.run(`CREATE INDEX ${this.quoteIdentifier(index.indexName)} ON ${this.quoteIdentifier(table.tableName)} (${fields})`);
}
}
}
close() { }
}
export { MariaDBSchemaManager };

View File

@ -1,7 +0,0 @@
import type { BUN_MARIADB_DatabaseSchemaType, BunSQLiteConfig } from "../../types";
type Params = {
dbSchema: BUN_MARIADB_DatabaseSchemaType;
config: BunSQLiteConfig;
};
export default function dbSchemaToType({ config, dbSchema, }: Params): string[] | undefined;
export {};

View File

@ -1,44 +0,0 @@
import _ from "lodash";
import generateTypeDefinition from "./db-generate-type-defs";
export default function dbSchemaToType({ config, dbSchema, }) {
let datasquirelSchema = dbSchema;
if (!datasquirelSchema)
return;
let tableNames = `export const BunSQLiteTables = [\n${datasquirelSchema.tables
.map((tbl) => ` "${tbl.tableName}",`)
.join("\n")}\n] as const`;
const dbTablesSchemas = datasquirelSchema.tables;
const defDbName = config.db_name
?.toUpperCase()
.replace(/[^a-zA-Z0-9]/g, "_");
const defNames = [];
const schemas = dbTablesSchemas
.map((table) => {
let final_table = _.cloneDeep(table);
if (final_table.parentTableName) {
const parent_table = dbTablesSchemas.find((t) => t.tableName === final_table.parentTableName);
if (parent_table) {
final_table = _.merge(parent_table, {
tableName: final_table.tableName,
tableDescription: final_table.tableDescription,
});
}
}
const defObj = generateTypeDefinition({
paradigm: "TypeScript",
table: final_table,
typeDefName: `BUN_MARIADB_${defDbName}_${final_table.tableName.toUpperCase()}`,
allValuesOptional: true,
addExport: true,
});
if (defObj.tdName?.match(/./)) {
defNames.push(defObj.tdName);
}
return defObj.typeDefinition;
})
.filter((schm) => typeof schm == "string");
const allTd = defNames?.[0]
? `export type BUN_MARIADB_${defDbName}_ALL_TYPEDEFS = ${defNames.join(` & `)}`
: ``;
return [tableNames, ...schemas, allTd];
}

View File

@ -1,17 +0,0 @@
import type { APIResponseObject, ServerQueryParam } from "../../types";
type Params<Schema extends {
[k: string]: any;
} = {
[k: string]: any;
}, Table extends string = string> = {
query?: ServerQueryParam<Schema>;
table: Table;
count?: boolean;
targetId?: number | string;
};
export default function DbSelect<Schema extends {
[k: string]: any;
} = {
[k: string]: any;
}, Table extends string = string>({ table, query, count, targetId, }: Params<Schema, Table>): Promise<APIResponseObject<Schema>>;
export {};

View File

@ -1,58 +0,0 @@
import mysql from "mysql";
import DbClient from ".";
import _ from "lodash";
import sqlGenerator from "../../utils/sql-generator";
export default async function DbSelect({ table, query, count, targetId, }) {
let sqlObj = null;
try {
let finalQuery = query || {};
if (targetId) {
finalQuery = _.merge(finalQuery, {
query: {
id: {
value: String(targetId),
},
},
});
}
sqlObj = sqlGenerator({
tableName: table,
genObject: finalQuery,
});
let sql = mysql.format(sqlObj.string, sqlObj.values);
const res = DbClient.query(sql);
const batchRes = res.all();
let resp = {
success: Boolean(batchRes[0]),
payload: batchRes,
singleRes: batchRes[0],
debug: {
sqlObj,
sql,
},
};
if (count) {
let count_sql_object = sqlGenerator({
tableName: table,
genObject: finalQuery,
count,
});
let count_sql = mysql.format(count_sql_object.string, count_sql_object.values);
count_sql = `SELECT COUNT(*) FROM (${count_sql}) as c`;
const count_res = DbClient.query(count_sql).all();
const count_val = count_res[0]?.["COUNT(*)"];
resp["count"] = Number(count_val);
resp["debug"]["count_sql"] = count_sql;
}
return resp;
}
catch (error) {
return {
success: false,
error: error.message,
debug: {
sqlObj,
},
};
}
}

View File

@ -1,11 +0,0 @@
import type { APIResponseObject, SQLInsertGenValueType } from "../../types";
type Params = {
sql: string;
values?: SQLInsertGenValueType[];
};
export default function DbSQL<T extends {
[k: string]: any;
} = {
[k: string]: any;
}>({ sql, values }: Params): Promise<APIResponseObject<T>>;
export {};

View File

@ -1,34 +0,0 @@
import DbClient from ".";
import _ from "lodash";
export default async function DbSQL({ sql, values }) {
try {
const trimmed_sql = sql.trim();
const res = trimmed_sql.match(/^select/i)
? DbClient.query(trimmed_sql).all(...(values || []))
: DbClient.run(trimmed_sql, values || []);
return {
success: true,
payload: Array.isArray(res) ? res : undefined,
singleRes: Array.isArray(res) ? res?.[0] : undefined,
postInsertReturn: Array.isArray(res)
? undefined
: {
affectedRows: res.changes,
insertId: Number(res.lastInsertRowid),
},
debug: {
sqlObj: {
sql: trimmed_sql,
values,
},
sql,
},
};
}
catch (error) {
return {
success: false,
error: error.message,
};
}
}

View File

@ -1,17 +0,0 @@
import type { APIResponseObject, ServerQueryParam } from "../../types";
type Params<Schema extends {
[k: string]: any;
} = {
[k: string]: any;
}, Table extends string = string> = {
table: Table;
data: Schema;
query?: ServerQueryParam<Schema>;
targetId?: number | string;
};
export default function DbUpdate<Schema extends {
[k: string]: any;
} = {
[k: string]: any;
}, Table extends string = string>({ table, data, query, targetId, }: Params<Schema, Table>): Promise<APIResponseObject>;
export {};

View File

@ -1,74 +0,0 @@
import DbClient from ".";
import _ from "lodash";
import sqlGenerator from "../../utils/sql-generator";
export default async function DbUpdate({ table, data, query, targetId, }) {
let sqlObj = { string: "", values: [] };
try {
let finalQuery = query || {};
if (targetId) {
finalQuery = _.merge(finalQuery, {
query: {
id: {
value: String(targetId),
},
},
});
}
const sqlQueryObj = sqlGenerator({
tableName: table,
genObject: finalQuery,
});
let values = [];
const whereClause = sqlQueryObj.string.match(/WHERE .*/)?.[0];
if (whereClause) {
let sql = `UPDATE ${table} SET`;
const finalData = {
updated_at: Date.now(),
...data,
};
const keys = Object.keys(finalData);
for (let i = 0; i < keys.length; i++) {
const key = keys[i];
if (!key)
continue;
const isLast = i == keys.length - 1;
sql += ` ${key}=?`;
const value = finalData[key];
values.push(value || null);
if (!isLast) {
sql += `,`;
}
}
sql += ` ${whereClause}`;
values = [...values, ...sqlQueryObj.values];
sqlObj.string = sql;
sqlObj.values = values;
const res = DbClient.run(sql, values);
return {
success: Boolean(res.changes),
postInsertReturn: {
affectedRows: res.changes,
insertId: Number(res.lastInsertRowid),
},
debug: {
sqlObj,
},
};
}
else {
return {
success: false,
msg: `No WHERE clause`,
};
}
}
catch (error) {
return {
success: false,
error: error.message,
debug: {
sqlObj,
},
};
}
}

View File

@ -1,8 +0,0 @@
import type { BUN_MARIADB_DatabaseSchemaType, BunSQLiteConfig } from "../../types";
type Params = {
dbSchema: BUN_MARIADB_DatabaseSchemaType;
dst_file: string;
config: BunSQLiteConfig;
};
export default function dbSchemaToTypeDef({ dbSchema, dst_file, config, }: Params): void;
export {};

View File

@ -1,18 +0,0 @@
import path from "node:path";
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
import dbSchemaToType from "./db-schema-to-typedef";
export default function dbSchemaToTypeDef({ dbSchema, dst_file, config, }) {
try {
if (!dbSchema)
throw new Error("No schema found");
const definitions = dbSchemaToType({ dbSchema, config });
const ourfileDir = path.dirname(dst_file);
if (!existsSync(ourfileDir)) {
mkdirSync(ourfileDir, { recursive: true });
}
writeFileSync(dst_file, definitions?.join("\n\n") || "", "utf-8");
}
catch (error) {
console.log(`Schema to Typedef Error =>`, error.message);
}
}

View File

@ -1,2 +0,0 @@
import type { BUN_MARIADB_DatabaseSchemaType } from "../../types";
export declare const DbSchema: BUN_MARIADB_DatabaseSchemaType;

View File

@ -1,5 +0,0 @@
import _ from "lodash";
export const DbSchema = {
dbName: "travis-ai",
tables: [],
};

1417
dist/types/index.d.ts vendored

File diff suppressed because it is too large Load Diff

187
dist/types/index.js vendored
View File

@ -1,187 +0,0 @@
/**
* User fields that should be omitted from general-purpose payloads and public
* responses.
*/
export const UsersOmitedFields = [
"password",
"social_id",
"verification_status",
"date_created",
"date_created_code",
"date_created_timestamp",
"date_updated",
"date_updated_code",
"date_updated_timestamp",
];
/**
* Supported MariaDB collations that can be applied at the database or table
* level.
*/
export const MariaDBCollations = [
"utf8mb4_bin",
"utf8mb4_unicode_520_ci",
];
/**
* Supported editor/content modes for text fields.
*/
export const TextFieldTypesArray = [
{ title: "Plain Text", value: "plain" },
{ title: "Rich Text", value: "richText" },
{ title: "Markdown", value: "markdown" },
{ title: "JSON", value: "json" },
{ title: "YAML", value: "yaml" },
{ title: "HTML", value: "html" },
{ title: "CSS", value: "css" },
{ title: "Javascript", value: "javascript" },
{ title: "Shell", value: "shell" },
{ title: "Code", value: "code" },
];
/**
* Core SQLite column types supported by the schema builder.
*/
export const BUN_MARIADB_DATATYPES = [
{ value: "TEXT" },
{ value: "INTEGER" },
{ value: "BLOB" },
{ value: "REAL" },
];
/**
* Supported logical operators for server-side query generation.
*/
export const ServerQueryOperators = ["AND", "OR"];
/**
* Supported comparison operators for server-side query generation.
*/
export const ServerQueryEqualities = [
"EQUAL",
"LIKE",
"LIKE_RAW",
"LIKE_LOWER",
"LIKE_LOWER_RAW",
"NOT LIKE",
"NOT LIKE_RAW",
"NOT_LIKE_LOWER",
"NOT_LIKE_LOWER_RAW",
"NOT EQUAL",
"REGEXP",
"FULLTEXT",
"IN",
"NOT IN",
"BETWEEN",
"NOT BETWEEN",
"IS NULL",
"IS NOT NULL",
"IS NOT",
"EXISTS",
"NOT EXISTS",
"GREATER THAN",
"GREATER THAN OR EQUAL",
"LESS THAN",
"LESS THAN OR EQUAL",
"MATCH",
"MATCH_BOOLEAN",
];
export const SQlComparisons = [
">",
"<>",
"<",
"=",
">=",
"<=",
"!=",
"IS NOT",
"IS",
"IS NULL",
"IS NOT NULL",
"IN",
"NOT IN",
"LIKE",
"NOT LIKE",
"GLOB",
"NOT GLOB",
];
/**
* Uppercase HTTP methods supported by the CRUD helpers.
*/
export const DataCrudRequestMethods = [
"GET",
"POST",
"PUT",
"PATCH",
"DELETE",
"OPTIONS",
];
/**
* Lowercase variant of the supported HTTP methods, used where string casing
* must match external APIs.
*/
export const DataCrudRequestMethodsLowerCase = [
"get",
"post",
"put",
"patch",
"delete",
"options",
];
/**
* High-level CRUD actions supported by the DSQL helpers.
*/
export const DsqlCrudActions = ["insert", "update", "delete", "get"];
/**
* Reserved query parameter names used throughout the API layer.
*/
export const QueryFields = [
"duplicate",
"user_id",
"delegated_user_id",
"db_id",
"table_id",
"db_slug",
];
/**
* Supported Docker Compose service names used by the deployment helpers.
*/
export const DockerComposeServices = [
"setup",
"cron",
"reverse-proxy",
"webapp",
"websocket",
"static",
"db",
"maxscale",
"post-db-setup",
"web-app-post-db-setup",
"post-replica-db-setup",
"db-replica-1",
"db-replica-2",
"db-cron",
"web-app-post-db-setup",
];
/**
* Supported index strategies for generated schemas.
*/
export const IndexTypes = ["regular", "full_text", "vector"];
/**
* Default fields automatically suggested for new tables.
*/
export const DefaultFields = [
{
fieldName: "id",
dataType: "INTEGER",
primaryKey: true,
autoIncrement: true,
notNullValue: true,
fieldDescription: "The unique identifier of the record.",
},
{
fieldName: "created_at",
dataType: "INTEGER",
fieldDescription: "The time when the record was created. (Unix Timestamp)",
},
{
fieldName: "updated_at",
dataType: "INTEGER",
fieldDescription: "The time when the record was updated. (Unix Timestamp)",
},
];

View File

@ -1,6 +0,0 @@
import { type BUN_MARIADB_DatabaseSchemaType } from "../types";
type Params = {
dbSchema: BUN_MARIADB_DatabaseSchemaType;
};
export default function ({ dbSchema }: Params): BUN_MARIADB_DatabaseSchemaType;
export {};

View File

@ -1,12 +0,0 @@
import _ from "lodash";
import { DefaultFields } from "../types";
export default function ({ dbSchema }) {
const finaldbSchema = _.cloneDeep(dbSchema);
finaldbSchema.tables = finaldbSchema.tables.map((t) => {
const newTable = _.cloneDeep(t);
newTable.fields = newTable.fields.filter((f) => !f.fieldName?.match(/^(id|created_at|updated_at)$/));
newTable.fields.unshift(...DefaultFields);
return newTable;
});
return finaldbSchema;
}

View File

@ -1,9 +0,0 @@
type Params = {
backup_name: string;
};
export default function grabBackupData({ backup_name }: Params): {
backup_date: Date;
backup_date_timestamp: number;
origin_backup_name: string;
};
export {};

View File

@ -1,7 +0,0 @@
export default function grabBackupData({ backup_name }) {
const backup_parts = backup_name.split("-");
const backup_date_timestamp = Number(backup_parts.pop());
const origin_backup_name = backup_parts.join("-");
const backup_date = new Date(backup_date_timestamp);
return { backup_date, backup_date_timestamp, origin_backup_name };
}

View File

@ -1,6 +0,0 @@
import type { BunSQLiteConfig } from "../types";
type Params = {
config: BunSQLiteConfig;
};
export default function grabDBBackupFileName({ config }: Params): string;
export {};

View File

@ -1,4 +0,0 @@
export default function grabDBBackupFileName({ config }) {
const new_db_file_name = `${config.db_name}-${Date.now()}`;
return new_db_file_name;
}

View File

@ -1,10 +0,0 @@
import type { BunSQLiteConfig } from "../types";
type Params = {
config: BunSQLiteConfig;
};
export default function grabDBDir({ config }: Params): {
db_dir: string;
backup_dir: string;
db_file_path: string;
};
export {};

View File

@ -1,14 +0,0 @@
import path from "path";
import grabDirNames from "../data/grab-dir-names";
import { AppData } from "../data/app-data";
export default function grabDBDir({ config }) {
const { ROOT_DIR } = grabDirNames();
let db_dir = ROOT_DIR;
if (config.db_dir) {
db_dir = config.db_dir;
}
const backup_dir_name = config.db_backup_dir || AppData["DefaultBackupDirName"];
const backup_dir = path.resolve(db_dir, backup_dir_name);
const db_file_path = path.resolve(db_dir, config.db_name);
return { db_dir, backup_dir, db_file_path };
}

View File

@ -1 +0,0 @@
export default function grabDbSchema(): Promise<import("../types").BUN_MARIADB_DatabaseSchemaType>;

View File

@ -1,5 +0,0 @@
import init from "../functions/init";
export default async function grabDbSchema() {
const { dbSchema } = await init();
return dbSchema;
}

View File

@ -1,7 +0,0 @@
import type { BunSQLiteQueryFieldValues, ServerQueryParam } from "../types";
type Params<Q extends Record<string, any> = Record<string, any>> = {
query: ServerQueryParam<Q>;
ignore_select_fields?: boolean;
};
export default function grabJoinFieldsFromQueryObject<Q extends Record<string, any> = Record<string, any>, F extends string = string, T extends string = string>({ query, ignore_select_fields, }: Params<Q>): BunSQLiteQueryFieldValues<F, T>[];
export {};

View File

@ -1,55 +0,0 @@
import _ from "lodash";
export default function grabJoinFieldsFromQueryObject({ query, ignore_select_fields, }) {
const fields_values = [];
const new_query = _.cloneDeep(query);
if (new_query.join) {
for (let i = 0; i < new_query.join.length; i++) {
const join = new_query.join[i];
if (!join)
continue;
if (Array.isArray(join)) {
for (let i = 0; i < join.length; i++) {
const single_join = join[i];
fields_values.push(...grabSingleJoinData({
join: single_join,
ignore_select_fields,
}));
}
}
else {
fields_values.push(...grabSingleJoinData({
join: join,
ignore_select_fields,
}));
}
}
}
return fields_values;
}
function grabSingleJoinData({ join, ignore_select_fields, }) {
let values = [];
const join_select_fields = join?.selectFields;
if (!join_select_fields?.[0] && !ignore_select_fields) {
throw new Error(`\`selectFields\` required in joins. To ignore this error, pass the \`ignore_select_fields\` parameter`);
}
if (join_select_fields?.[0]) {
for (let i = 0; i < join_select_fields.length; i++) {
const select_field = join_select_fields[i];
if (select_field) {
values.push({
table: join.tableName,
field: typeof select_field == "object"
? String(select_field.field)
: String(select_field),
});
}
}
}
if (join.group_concat) {
values.push({
table: join.tableName,
field: join.group_concat.field,
});
}
return values;
}

View File

@ -1,6 +0,0 @@
import type { BunSQLiteConfig } from "../types";
type Params = {
config: BunSQLiteConfig;
};
export default function grabSortedBackups({ config }: Params): string[];
export {};

View File

@ -1,18 +0,0 @@
import grabDBDir from "../utils/grab-db-dir";
import fs from "fs";
export default function grabSortedBackups({ config }) {
const { backup_dir } = grabDBDir({ config });
const backups = fs.readdirSync(backup_dir);
/**
* Order Backups. Most recent first.
*/
const ordered_backups = backups.sort((a, b) => {
const a_date = Number(a.split("-").pop());
const b_date = Number(b.split("-").pop());
if (a_date > b_date) {
return -1;
}
return 1;
});
return ordered_backups;
}

View File

@ -1,6 +0,0 @@
import type { QueryRawValueType, ServerQueryObjectValue } from "../types";
type Params = {
query_value: ServerQueryObjectValue;
};
export default function queryValueParser({ query_value, }: Params): QueryRawValueType | QueryRawValueType[];
export {};

View File

@ -1,21 +0,0 @@
export default function queryValueParser({ query_value, }) {
if (typeof query_value == "string" || typeof query_value == "number") {
return query_value;
}
if (Array.isArray(query_value)) {
let values = [];
for (let i = 0; i < query_value.length; i++) {
const single_value = query_value[i];
if (single_value) {
const single_parsed_value = queryValueParser({
query_value: single_value,
});
if (!Array.isArray(single_parsed_value)) {
values.push(single_parsed_value);
}
}
}
return values;
}
return query_value?.value;
}

View File

@ -1,2 +0,0 @@
import { ServerQueryEqualities } from "../types";
export default function sqlEqualityParser(eq: (typeof ServerQueryEqualities)[number]): string;

View File

@ -1,41 +0,0 @@
import { ServerQueryEqualities } from "../types";
export default function sqlEqualityParser(eq) {
switch (eq) {
case "EQUAL":
return "=";
case "LIKE":
return "LIKE";
case "NOT LIKE":
return "NOT LIKE";
case "NOT EQUAL":
return "<>";
case "IS NOT":
return "IS NOT";
case "IN":
return "IN";
case "NOT IN":
return "NOT IN";
case "BETWEEN":
return "BETWEEN";
case "NOT BETWEEN":
return "NOT BETWEEN";
case "IS NULL":
return "IS NULL";
case "IS NOT NULL":
return "IS NOT NULL";
case "EXISTS":
return "EXISTS";
case "NOT EXISTS":
return "NOT EXISTS";
case "GREATER THAN":
return ">";
case "GREATER THAN OR EQUAL":
return ">=";
case "LESS THAN":
return "<";
case "LESS THAN OR EQUAL":
return "<=";
default:
return "=";
}
}

View File

@ -1,20 +0,0 @@
import type { ServerQueryEqualities, ServerQueryObject, SQLInsertGenValueType } from "../types";
type Params = {
fieldName: string;
value?: SQLInsertGenValueType;
equality?: (typeof ServerQueryEqualities)[number];
queryObj: ServerQueryObject<{
[key: string]: any;
}, string>;
isValueFieldValue?: boolean;
};
type Return = {
str?: string;
param?: SQLInsertGenValueType;
};
/**
* # SQL Gen Operator Gen
* @description Generates an SQL operator for node module `mysql` or `serverless-mysql`
*/
export default function sqlGenOperatorGen({ fieldName, value, equality, queryObj, isValueFieldValue, }: Params): Return;
export {};

View File

@ -1,133 +0,0 @@
import sqlEqualityParser from "./sql-equality-parser";
/**
* # SQL Gen Operator Gen
* @description Generates an SQL operator for node module `mysql` or `serverless-mysql`
*/
export default function sqlGenOperatorGen({ fieldName, value, equality, queryObj, isValueFieldValue, }) {
if (queryObj.nullValue) {
return { str: `${fieldName} IS NULL` };
}
if (queryObj.notNullValue) {
return { str: `${fieldName} IS NOT NULL` };
}
if (value) {
const finalValue = isValueFieldValue ? value : "?";
const finalParams = isValueFieldValue ? undefined : value;
if (equality == "MATCH") {
return {
str: `MATCH(${fieldName}) AGAINST(${finalValue} IN NATURAL LANGUAGE MODE)`,
param: finalParams,
};
}
else if (equality == "MATCH_BOOLEAN") {
return {
str: `MATCH(${fieldName}) AGAINST(${finalValue} IN BOOLEAN MODE)`,
param: finalParams,
};
}
else if (equality == "LIKE_LOWER") {
return {
str: `LOWER(${fieldName}) LIKE LOWER(${finalValue})`,
param: `%${finalParams}%`,
};
}
else if (equality == "LIKE_LOWER_RAW") {
return {
str: `LOWER(${fieldName}) LIKE LOWER(${finalValue})`,
param: finalParams,
};
}
else if (equality == "LIKE") {
return {
str: `${fieldName} LIKE ${finalValue}`,
param: `%${finalParams}%`,
};
}
else if (equality == "LIKE_RAW") {
return {
str: `${fieldName} LIKE ${finalValue}`,
param: finalParams,
};
}
else if (equality == "NOT_LIKE_LOWER") {
return {
str: `LOWER(${fieldName}) NOT LIKE LOWER(${finalValue})`,
param: `%${finalParams}%`,
};
}
else if (equality == "NOT_LIKE_LOWER_RAW") {
return {
str: `LOWER(${fieldName}) NOT LIKE LOWER(${finalValue})`,
param: finalParams,
};
}
else if (equality == "NOT LIKE") {
return {
str: `${fieldName} NOT LIKE ${finalValue}`,
param: finalParams,
};
}
else if (equality == "NOT LIKE_RAW") {
return {
str: `${fieldName} NOT LIKE ${finalValue}`,
param: finalParams,
};
}
else if (equality == "REGEXP") {
return {
str: `LOWER(${fieldName}) REGEXP LOWER(${finalValue})`,
param: finalParams,
};
}
else if (equality == "FULLTEXT") {
return {
str: `MATCH(${fieldName}) AGAINST(${finalValue} IN BOOLEAN MODE)`,
param: finalParams,
};
}
else if (equality == "NOT EQUAL") {
return {
str: `${fieldName} != ${finalValue}`,
param: finalParams,
};
}
else if (equality == "IS NOT") {
return {
str: `${fieldName} IS NOT ${finalValue}`,
param: finalParams,
};
}
else if (equality) {
return {
str: `${fieldName} ${sqlEqualityParser(equality)} ${finalValue}`,
param: finalParams,
};
}
else {
return {
str: `${fieldName} = ${finalValue}`,
param: finalParams,
};
}
}
else {
if (equality == "IS NULL") {
return { str: `${fieldName} IS NULL` };
}
else if (equality == "IS NOT NULL") {
return { str: `${fieldName} IS NOT NULL` };
}
else if (equality) {
return {
str: `${fieldName} ${sqlEqualityParser(equality)} ?`,
param: value,
};
}
else {
return {
str: `${fieldName} = ?`,
param: value,
};
}
}
}

View File

@ -1,11 +0,0 @@
import type { ServerQueryParamsJoin, ServerQueryParamsJoinMatchObject, SQLInsertGenValueType } from "../types";
type Param = {
mtch: ServerQueryParamsJoinMatchObject;
join: ServerQueryParamsJoin;
table_name: string;
};
export default function sqlGenGenJoinStr({ join, mtch, table_name }: Param): {
str: string;
values: SQLInsertGenValueType[];
};
export {};

View File

@ -1,65 +0,0 @@
export default function sqlGenGenJoinStr({ join, mtch, table_name }) {
let values = [];
if (mtch.__batch) {
let btch_mtch = ``;
btch_mtch += `(`;
for (let i = 0; i < mtch.__batch.matches.length; i++) {
const __mtch = mtch.__batch.matches[i];
const { str, values: batch_values } = sqlGenGenJoinStr({
join,
mtch: __mtch,
table_name,
});
btch_mtch += str;
values.push(...batch_values);
if (i < mtch.__batch.matches.length - 1) {
btch_mtch += ` ${mtch.__batch.operator || "OR"} `;
}
}
btch_mtch += `)`;
return {
str: btch_mtch,
values,
};
}
const equality = mtch.raw_equality || "=";
const lhs = `${typeof mtch.source == "object" ? mtch.source.tableName : table_name}.${typeof mtch.source == "object" ? mtch.source.fieldName : mtch.source}`;
const rhs = `${(() => {
if (mtch.targetLiteral) {
values.push(mtch.targetLiteral);
// if (typeof mtch.targetLiteral == "number") {
// return `${mtch.targetLiteral}`;
// }
// return `'${mtch.targetLiteral}'`;
return `?`;
}
if (join.alias) {
return `${typeof mtch.target == "object"
? mtch.target.tableName
: join.alias}.${typeof mtch.target == "object"
? mtch.target.fieldName
: mtch.target}`;
}
return `${typeof mtch.target == "object"
? mtch.target.tableName
: join.tableName}.${typeof mtch.target == "object" ? mtch.target.fieldName : mtch.target}`;
})()}`;
if (mtch.between) {
values.push(mtch.between.min, mtch.between.max);
return {
str: `${lhs} BETWEEN ? AND ?`,
values,
};
}
if (mtch.not_between) {
values.push(mtch.not_between.min, mtch.not_between.max);
return {
str: `${lhs} NOT BETWEEN ? AND ?`,
values,
};
}
return {
str: `${lhs} ${equality} ${rhs}`,
values,
};
}

View File

@ -1,22 +0,0 @@
import type { ServerQueryParam, TableSelectFieldsObject } from "../types";
type Param<T extends {
[key: string]: any;
} = {
[key: string]: any;
}> = {
genObject?: ServerQueryParam<T>;
selectFields?: (keyof T | TableSelectFieldsObject<T>)[];
append_table_names?: boolean;
table_name: string;
full_text_match_str?: string;
full_text_search_str?: string;
};
export default function sqlGenGenQueryStr<T extends {
[key: string]: any;
} = {
[key: string]: any;
}>(params: Param<T>): {
str: string;
values: any[];
};
export {};

View File

@ -1,193 +0,0 @@
import { isUndefined } from "lodash";
import sqlGenGrabConcatStr from "./sql-generator-grab-concat-str";
import sqlGenGenJoinStr from "./sql-generator-gen-join-str";
import sqlGenGrabSelectFieldSQL from "./sql-generator-grab-select-field-sql";
export default function sqlGenGenQueryStr(params) {
let str = "SELECT";
const genObject = params.genObject;
const table_name = params.table_name;
const full_text_match_str = params.full_text_match_str;
const full_text_search_str = params.full_text_search_str;
let sqlSearhValues = [];
if (genObject?.select_sql) {
str += ` ${genObject.select_sql}`;
}
else if (genObject?.selectFields?.[0]) {
if (genObject.join) {
str += sqlGenGrabSelectFieldSQL({
selectFields: genObject.selectFields,
append_table_names: true,
table_name,
});
}
else {
str += sqlGenGrabSelectFieldSQL({
selectFields: genObject.selectFields,
table_name,
});
}
}
else {
if (genObject?.join) {
str += ` ${table_name}.*`;
}
else {
str += " *";
}
}
if (genObject?.countSubQueries) {
let countSqls = [];
for (let i = 0; i < genObject.countSubQueries.length; i++) {
const countSubQuery = genObject.countSubQueries[i];
if (!countSubQuery)
continue;
const tableAlias = countSubQuery.table_alias;
let subQStr = `(SELECT COUNT(*)`;
subQStr += ` FROM ${countSubQuery.table}${tableAlias ? ` ${tableAlias}` : ""}`;
subQStr += ` WHERE (`;
for (let j = 0; j < countSubQuery.srcTrgMap.length; j++) {
const csqSrc = countSubQuery.srcTrgMap[j];
if (!csqSrc)
continue;
subQStr += ` ${tableAlias || countSubQuery.table}.${csqSrc.src}`;
if (typeof csqSrc.trg == "string") {
subQStr += ` = ?`;
sqlSearhValues.push(csqSrc.trg);
}
else if (typeof csqSrc.trg == "object") {
subQStr += ` = ${csqSrc.trg.table}.${csqSrc.trg.field}`;
}
if (j < countSubQuery.srcTrgMap.length - 1) {
subQStr += ` AND `;
}
}
subQStr += ` )) AS ${countSubQuery.alias}`;
countSqls.push(subQStr);
}
str += `, ${countSqls.join(",")}`;
}
if (genObject?.join) {
const existingJoinTableNames = [table_name];
str +=
"," +
genObject.join
.flat()
.filter((j) => !isUndefined(j))
.map((joinObj) => {
const joinTableName = joinObj.alias
? joinObj.alias
: joinObj.tableName;
if (existingJoinTableNames.includes(joinTableName))
return null;
existingJoinTableNames.push(joinTableName);
if (joinObj.group_concat) {
return sqlGenGrabConcatStr({
field: `${joinTableName}.${joinObj.group_concat.field}`,
alias: joinObj.group_concat.alias,
separator: joinObj.group_concat.separator,
});
}
else if (joinObj.selectFields) {
return joinObj.selectFields
.map((selectField) => {
if (typeof selectField == "string") {
return `${joinTableName}.${selectField}`;
}
else if (typeof selectField == "object") {
let aliasSelectField = `${joinTableName}.${selectField.field}`;
if (selectField.count) {
aliasSelectField = `COUNT(${joinTableName}.${selectField.field})`;
}
else if (selectField.sum) {
aliasSelectField = `SUM(${selectField.distinct ? "DISTINCT " : ""}${joinTableName}.${selectField.field})`;
}
else if (selectField.average) {
aliasSelectField = `AVERAGE(${joinTableName}.${selectField.field})`;
}
else if (selectField.max) {
aliasSelectField = `MAX(${joinTableName}.${selectField.field})`;
}
else if (selectField.min) {
aliasSelectField = `MIN(${joinTableName}.${selectField.field})`;
}
else if (selectField.group_concat &&
selectField.alias) {
return sqlGenGrabConcatStr({
field: `${joinTableName}.${selectField.field}`,
alias: selectField.alias,
separator: selectField.group_concat
.separator,
distinct: selectField.group_concat
.distinct,
});
}
else if (selectField.distinct) {
aliasSelectField = `DISTINCT ${joinTableName}.${selectField.field}`;
}
if (selectField.alias)
aliasSelectField += ` AS ${selectField.alias}`;
return aliasSelectField;
}
})
.join(",");
}
else {
return `${joinTableName}.*`;
}
})
.filter((_) => Boolean(_))
.join(",");
}
if (genObject?.fullTextSearch &&
full_text_match_str &&
full_text_search_str) {
str += `, ${full_text_match_str} AS ${genObject.fullTextSearch.scoreAlias}`;
sqlSearhValues.push(full_text_search_str);
}
str += ` FROM ${table_name}`;
if (genObject?.join) {
str +=
" " +
genObject.join
.flat()
.filter((j) => !isUndefined(j))
.map((join) => {
return (join.joinType +
" " +
(join.alias
? `${join.tableName}` + " " + join.alias
: `${join.tableName}`) +
" ON " +
(() => {
if (Array.isArray(join.match)) {
return ("(" +
join.match
.map((mtch) => {
const { str, values } = sqlGenGenJoinStr({
mtch,
join,
table_name,
});
sqlSearhValues.push(...values);
return str;
})
.join(join.operator
? ` ${join.operator} `
: " AND ") +
")");
}
else if (typeof join.match == "object") {
const { str, values } = sqlGenGenJoinStr({
mtch: join.match,
join,
table_name,
});
sqlSearhValues.push(...values);
return str;
}
})());
})
.join(" ");
}
return { str, values: sqlSearhValues };
}

View File

@ -1,12 +0,0 @@
import type { ServerQueryParamsJoin, ServerQueryQueryObject, SQLInsertGenValueType } from "../types";
type Param = {
queryObj: ServerQueryQueryObject[string];
join?: (ServerQueryParamsJoin | ServerQueryParamsJoin[] | undefined)[];
field?: string;
table_name: string;
};
export default function sqlGenGenSearchStr({ queryObj, join, field, table_name, }: Param): {
str: string;
values: SQLInsertGenValueType[];
};
export {};

View File

@ -1,92 +0,0 @@
import sqlGenOperatorGen from "./sql-gen-operator-gen";
export default function sqlGenGenSearchStr({ queryObj, join, field, table_name, }) {
let sqlSearhValues = [];
const finalFieldName = (() => {
if (queryObj?.tableName) {
return `${queryObj.tableName}.${field}`;
}
if (join) {
return `${table_name}.${field}`;
}
return field;
})();
let str = `${finalFieldName}=?`;
function grabValue(val) {
const valueParsed = val;
if (!valueParsed)
return;
const valueString = typeof valueParsed == "string" || typeof valueParsed == "number"
? valueParsed
: valueParsed
? valueParsed.fieldName && valueParsed.tableName
? `${valueParsed.tableName}.${valueParsed.fieldName}`
: valueParsed.value
: undefined;
const valueEquality = typeof valueParsed == "object"
? valueParsed.equality || queryObj.equality
: queryObj.equality;
const operatorStrParam = sqlGenOperatorGen({
queryObj,
equality: valueEquality,
fieldName: finalFieldName || "",
value: valueString || "",
isValueFieldValue: Boolean(typeof valueParsed == "object" &&
valueParsed.fieldName &&
valueParsed.tableName),
});
return operatorStrParam;
}
if (Array.isArray(queryObj.value)) {
const strArray = [];
queryObj.value.forEach((val) => {
const operatorStrParam = grabValue(val);
if (!operatorStrParam)
return;
if (operatorStrParam.str && operatorStrParam.param) {
strArray.push(operatorStrParam.str);
sqlSearhValues.push(operatorStrParam.param);
}
else if (operatorStrParam.str) {
strArray.push(operatorStrParam.str);
}
});
str = "(" + strArray.join(` ${queryObj.operator || "AND"} `) + ")";
}
else if (typeof queryObj.value == "object") {
const operatorStrParam = grabValue(queryObj.value);
if (operatorStrParam?.str) {
str = operatorStrParam.str;
if (operatorStrParam.param) {
sqlSearhValues.push(operatorStrParam.param);
}
}
}
else if (queryObj.raw_equality && queryObj.value) {
str = `${finalFieldName} ${queryObj.raw_equality} ?`;
sqlSearhValues.push(queryObj.value);
}
else if (queryObj.between) {
str = `${finalFieldName} BETWEEN ? AND ?`;
sqlSearhValues.push(queryObj.between.min, queryObj.between.max);
}
else {
const valueParsed = queryObj.value ? queryObj.value : undefined;
const operatorStrParam = sqlGenOperatorGen({
equality: queryObj.equality,
fieldName: finalFieldName || "",
value: valueParsed,
queryObj,
});
if (operatorStrParam.str && operatorStrParam.param) {
str = operatorStrParam.str;
sqlSearhValues.push(operatorStrParam.param);
}
else if (operatorStrParam.str && !operatorStrParam.str.match(/\?/)) {
str = operatorStrParam.str;
}
else {
sqlSearhValues.push(valueParsed || "");
}
}
return { str, values: sqlSearhValues };
}

View File

@ -1,8 +0,0 @@
type Param = {
field: string;
alias: string;
separator?: string;
distinct?: boolean;
};
export default function sqlGenGrabConcatStr({ alias, field, separator, distinct, }: Param): string;
export {};

View File

@ -1,13 +0,0 @@
export default function sqlGenGrabConcatStr({ alias, field, separator = ",", distinct, }) {
let gc = `GROUP_CONCAT(`;
if (distinct) {
gc += `DISTINCT `;
}
gc += `${field}`;
if (!distinct) {
gc += `, '${separator}'`;
}
gc += `)`;
gc += ` AS ${alias}`;
return gc;
}

View File

@ -1,16 +0,0 @@
import type { TableSelectFieldsObject } from "../types";
type Param<T extends {
[key: string]: any;
} = {
[key: string]: any;
}> = {
selectFields: (keyof T | TableSelectFieldsObject<T>)[];
append_table_names?: boolean;
table_name: string;
};
export default function sqlGenGrabSelectFieldSQL<T extends {
[key: string]: any;
} = {
[key: string]: any;
}>({ selectFields, append_table_names, table_name }: Param<T>): string;
export {};

View File

@ -1,55 +0,0 @@
import sqlGenGrabConcatStr from "./sql-generator-grab-concat-str";
export default function sqlGenGrabSelectFieldSQL({ selectFields, append_table_names, table_name }) {
let str = "";
str += ` ${selectFields
?.map((fld) => {
let fld_str = ``;
const final_fld_name = typeof fld == "object"
? append_table_names
? `${table_name}.${String(fld)}`
: `${String(fld.fieldName)}`
: `${String(fld)}`;
if (typeof fld == "object") {
const fld_name = `${String(fld.fieldName)}`;
if (fld.count) {
fld_str += `COUNT(${fld_name})`;
}
else if (fld.sum) {
fld_str += `SUM(${fld_name})`;
}
else if (fld.average) {
fld_str += `AVERAGE(${fld_name})`;
}
else if (fld.max) {
fld_str += `MAX(${fld_name})`;
}
else if (fld.min) {
fld_str += `MIN(${fld_name})`;
}
else if (fld.distinct) {
fld_str += `DISTINCT ${fld_name}`;
}
else if (fld.group_concat) {
fld_str += sqlGenGrabConcatStr({
field: fld_name,
alias: fld.group_concat.alias,
separator: fld.group_concat.separator,
distinct: fld.group_concat.distinct,
});
}
else {
fld_str +=
final_fld_name + (fld.alias ? ` as ${fld.alias}` : ``);
}
if (fld.alias) {
fld_str += ` AS ${fld.alias}`;
}
}
else {
fld_str += final_fld_name;
}
return fld_str;
})
.join(",")}`;
return str;
}

View File

@ -1,25 +0,0 @@
import type { ServerQueryParam, SQLInsertGenValueType } from "../types";
type Param<T extends {
[key: string]: any;
} = {
[key: string]: any;
}> = {
genObject?: ServerQueryParam<T>;
tableName: string;
dbFullName?: string;
count?: boolean;
};
type Return = {
string: string;
values: SQLInsertGenValueType[];
};
/**
* # SQL Query Generator
* @description Generates an SQL Query for node module `mysql` or `serverless-mysql`
*/
export default function sqlGenerator<T extends {
[key: string]: any;
} = {
[key: string]: any;
}>({ tableName, genObject, dbFullName, count }: Param<T>): Return;
export {};

View File

@ -1,303 +0,0 @@
import sqlGenGenSearchStr from "./sql-generator-gen-search-str";
import sqlGenGenQueryStr from "./sql-generator-gen-query-str";
/**
* # SQL Query Generator
* @description Generates an SQL Query for node module `mysql` or `serverless-mysql`
*/
export default function sqlGenerator({ tableName, genObject, dbFullName, count }) {
const finalQuery = genObject?.query ? genObject.query : undefined;
const queryKeys = finalQuery ? Object.keys(finalQuery) : undefined;
const sqlSearhValues = [];
let fullTextMatchStr = genObject?.fullTextSearch
? ` MATCH(${genObject.fullTextSearch.fields
.map((f) => genObject.join ? `${tableName}.${String(f)}` : `${String(f)}`)
.join(",")}) AGAINST (? IN BOOLEAN MODE)`
: undefined;
const fullTextSearchStr = genObject?.fullTextSearch
? genObject.fullTextSearch.searchTerm
.split(` `)
.map((t) => `${t}`)
.join(" ")
: undefined;
let { str: queryString, values } = sqlGenGenQueryStr({
table_name: tableName,
append_table_names: true,
full_text_match_str: fullTextMatchStr,
full_text_search_str: fullTextSearchStr,
genObject,
});
sqlSearhValues.push(...values);
const sqlSearhString = queryKeys?.map((field) => {
const queryObj = finalQuery?.[field];
if (!queryObj)
return;
if (queryObj.__query) {
const subQueryGroup = queryObj.__query;
const subSearchKeys = Object.keys(subQueryGroup);
const subSearchString = subSearchKeys.map((_field) => {
const newSubQueryObj = subQueryGroup?.[_field];
if (newSubQueryObj) {
const { str, values } = sqlGenGenSearchStr({
queryObj: newSubQueryObj,
field: newSubQueryObj.fieldName || _field,
join: genObject?.join,
table_name: tableName,
});
sqlSearhValues.push(...values);
return str;
}
});
return ("(" +
subSearchString.join(` ${queryObj.operator || "AND"} `) +
")");
}
const { str, values } = sqlGenGenSearchStr({
queryObj,
field: queryObj.fieldName || field,
join: genObject?.join,
table_name: tableName,
});
sqlSearhValues.push(...values);
return str;
});
const cleanedUpSearchStr = sqlSearhString?.filter((str) => typeof str == "string");
const isSearchStr = cleanedUpSearchStr?.[0] && cleanedUpSearchStr.find((str) => str);
if (isSearchStr) {
const stringOperator = genObject?.searchOperator || "AND";
queryString += ` WHERE ${cleanedUpSearchStr.join(` ${stringOperator} `)}`;
}
if (genObject?.fullTextSearch && fullTextSearchStr && fullTextMatchStr) {
queryString += `${isSearchStr ? " AND" : " WHERE"} ${fullTextMatchStr}`;
sqlSearhValues.push(fullTextSearchStr);
}
if (genObject?.group) {
let group_by_txt = ``;
if (typeof genObject.group == "string") {
group_by_txt = genObject.group;
}
else if (Array.isArray(genObject.group)) {
for (let i = 0; i < genObject.group.length; i++) {
const group = genObject.group[i];
if (typeof group == "string") {
group_by_txt += `\`${group.toString()}\``;
}
else if (typeof group == "object" && group.table) {
group_by_txt += `${group.table}.${String(group.field)}`;
}
else if (typeof group == "object") {
group_by_txt += `${String(group.field)}`;
}
if (i < genObject.group.length - 1) {
group_by_txt += ",";
}
}
}
else if (typeof genObject.group == "object") {
if (genObject.group.table) {
group_by_txt = `${genObject.group.table}.${String(genObject.group.field)}`;
}
else {
group_by_txt = `${String(genObject.group.field)}`;
}
}
queryString += ` GROUP BY ${group_by_txt}`;
}
function grabOrderString(order) {
let orderFields = [];
let orderSrt = ``;
if (genObject?.fullTextSearch && genObject.fullTextSearch.scoreAlias) {
orderFields.push(genObject.fullTextSearch.scoreAlias);
}
else if (genObject?.join) {
orderFields.push(`${tableName}.${String(order.field)}`);
}
else {
orderFields.push(order.field);
}
orderSrt += ` ${orderFields.join(", ")} ${order.strategy}`;
return orderSrt;
}
if (genObject?.order) {
let orderSrt = ` ORDER BY`;
if (Array.isArray(genObject.order)) {
for (let i = 0; i < genObject.order.length; i++) {
const order = genObject.order[i];
if (order) {
orderSrt +=
grabOrderString(order) +
(i < genObject.order.length - 1 ? `,` : "");
}
}
}
else {
orderSrt += grabOrderString(genObject.order);
}
queryString += ` ${orderSrt}`;
}
if (genObject?.limit && !count)
queryString += ` LIMIT ${genObject.limit}`;
if (genObject?.offset) {
queryString += ` OFFSET ${genObject.offset}`;
}
else if (genObject?.page && genObject.limit && !count) {
queryString += ` OFFSET ${(genObject.page - 1) * genObject.limit}`;
}
return {
string: queryString,
values: sqlSearhValues,
};
}
// let queryString = (() => {
// let str = "SELECT";
// if (genObject?.select_sql) {
// str += ` ${genObject.select_sql}`;
// } else if (genObject?.selectFields?.[0]) {
// if (genObject.join) {
// str += sqlGenGrabSelectFieldSQL<T>({
// selectFields: genObject.selectFields,
// append_table_names: true,
// table_name: tableName,
// });
// } else {
// str += sqlGenGrabSelectFieldSQL({
// selectFields: genObject.selectFields,
// table_name: tableName,
// });
// }
// } else {
// if (genObject?.join) {
// str += ` ${tableName}.*`;
// } else {
// str += " *";
// }
// }
// if (genObject?.countSubQueries) {
// let countSqls: string[] = [];
// for (let i = 0; i < genObject.countSubQueries.length; i++) {
// const countSubQuery = genObject.countSubQueries[i];
// if (!countSubQuery) continue;
// const tableAlias = countSubQuery.table_alias;
// let subQStr = `(SELECT COUNT(*)`;
// subQStr += ` FROM ${countSubQuery.table}${
// tableAlias ? ` ${tableAlias}` : ""
// }`;
// subQStr += ` WHERE (`;
// for (let j = 0; j < countSubQuery.srcTrgMap.length; j++) {
// const csqSrc = countSubQuery.srcTrgMap[j];
// if (!csqSrc) continue;
// subQStr += ` ${tableAlias || countSubQuery.table}.${
// csqSrc.src
// }`;
// if (typeof csqSrc.trg == "string") {
// subQStr += ` = ?`;
// sqlSearhValues.push(csqSrc.trg);
// } else if (typeof csqSrc.trg == "object") {
// subQStr += ` = ${csqSrc.trg.table}.${csqSrc.trg.field}`;
// }
// if (j < countSubQuery.srcTrgMap.length - 1) {
// subQStr += ` AND `;
// }
// }
// subQStr += ` )) AS ${countSubQuery.alias}`;
// countSqls.push(subQStr);
// }
// str += `, ${countSqls.join(",")}`;
// }
// if (genObject?.join) {
// const existingJoinTableNames: string[] = [tableName];
// str +=
// "," +
// genObject.join
// .flat()
// .filter((j) => !isUndefined(j))
// .map((joinObj) => {
// const joinTableName = joinObj.alias
// ? joinObj.alias
// : joinObj.tableName;
// if (existingJoinTableNames.includes(joinTableName))
// return null;
// existingJoinTableNames.push(joinTableName);
// if (joinObj.group_concat) {
// return sqlGenGrabConcatStr({
// field: `${joinTableName}.${joinObj.group_concat.field}`,
// alias: joinObj.group_concat.alias,
// separator: joinObj.group_concat.separator,
// });
// } else if (joinObj.selectFields) {
// return joinObj.selectFields
// .map((selectField) => {
// if (typeof selectField == "string") {
// return `${joinTableName}.${selectField}`;
// } else if (typeof selectField == "object") {
// let aliasSelectField = selectField.count
// ? `COUNT(${joinTableName}.${selectField.field})`
// : `${joinTableName}.${selectField.field}`;
// if (selectField.alias)
// aliasSelectField += ` AS ${selectField.alias}`;
// return aliasSelectField;
// }
// })
// .join(",");
// } else {
// return `${joinTableName}.*`;
// }
// })
// .filter((_) => Boolean(_))
// .join(",");
// }
// if (
// genObject?.fullTextSearch &&
// fullTextMatchStr &&
// fullTextSearchStr
// ) {
// str += `, ${fullTextMatchStr} AS ${genObject.fullTextSearch.scoreAlias}`;
// sqlSearhValues.push(fullTextSearchStr);
// }
// str += ` FROM ${tableName}`;
// if (genObject?.join) {
// str +=
// " " +
// genObject.join
// .flat()
// .filter((j) => !isUndefined(j))
// .map((join) => {
// return (
// join.joinType +
// " " +
// (join.alias
// ? `${join.tableName}` + " " + join.alias
// : `${join.tableName}`) +
// " ON " +
// (() => {
// if (Array.isArray(join.match)) {
// return (
// "(" +
// join.match
// .map((mtch) =>
// sqlGenGenJoinStr({
// mtch,
// join,
// table_name: tableName,
// }),
// )
// .join(
// join.operator
// ? ` ${join.operator} `
// : " AND ",
// ) +
// ")"
// );
// } else if (typeof join.match == "object") {
// return sqlGenGenJoinStr({
// mtch: join.match,
// join,
// table_name: tableName,
// });
// }
// })()
// );
// })
// .join(" ");
// }
// return str;
// })();

View File

@ -1,5 +0,0 @@
import type { SQLInsertGenParams, SQLInsertGenReturn } from "../types";
/**
* # SQL Insert Generator
*/
export default function sqlInsertGenerator({ tableName, data, dbFullName, }: SQLInsertGenParams): SQLInsertGenReturn | undefined;

View File

@ -1,58 +0,0 @@
/**
* # SQL Insert Generator
*/
export default function sqlInsertGenerator({ tableName, data, dbFullName, }) {
const finalDbName = dbFullName ? `${dbFullName}.` : "";
try {
if (Array.isArray(data) && data?.[0]) {
let insertKeys = [];
data.forEach((dt) => {
const kys = Object.keys(dt);
kys.forEach((ky) => {
if (!insertKeys.includes(ky)) {
insertKeys.push(ky);
}
});
});
let queryBatches = [];
let queryValues = [];
data.forEach((item) => {
queryBatches.push(`(${insertKeys
.map((ky) => {
const value = item[ky];
const finalValue = typeof value == "string" ||
typeof value == "number"
? value
: typeof value == "function"
? value().value
: value
? value
: null;
if (!finalValue) {
queryValues.push(null);
return "?";
}
queryValues.push(finalValue);
const placeholder = typeof value == "function"
? value().placeholder
: "?";
return placeholder;
})
.filter((k) => Boolean(k))
.join(",")})`);
});
let query = `INSERT INTO ${finalDbName}${tableName} (${insertKeys.join(",")}) VALUES ${queryBatches.join(",")}`;
return {
query: query,
values: queryValues,
};
}
else {
return undefined;
}
}
catch ( /** @type {any} */error) {
console.log(`SQL insert gen ERROR: ${error.message}`);
return undefined;
}
}

View File

@ -1,6 +0,0 @@
import type { BunSQLiteConfig } from "../types";
type Params = {
config: BunSQLiteConfig;
};
export default function trimBackups({ config }: Params): void;
export {};

View File

@ -1,19 +0,0 @@
import grabDBDir from "../utils/grab-db-dir";
import fs from "fs";
import grabSortedBackups from "./grab-sorted-backups";
import { AppData } from "../data/app-data";
import path from "path";
export default function trimBackups({ config }) {
const { backup_dir } = grabDBDir({ config });
const backups = grabSortedBackups({ config });
const max_backups = config.max_backups || AppData["MaxBackups"];
for (let i = 0; i < backups.length; i++) {
const backup_name = backups[i];
if (!backup_name)
continue;
if (i > max_backups - 1) {
const backup_file_to_unlink = path.join(backup_dir, backup_name);
fs.unlinkSync(backup_file_to_unlink);
}
}
}

View File

@ -13,18 +13,6 @@ declare global {
var DB_SCHEMA: BUN_MARIADB_DatabaseSchemaType; var DB_SCHEMA: BUN_MARIADB_DatabaseSchemaType;
} }
await init();
if (!global.CONFIG) {
console.error(`Couldn't grab global Config.`);
process.exit(1);
}
if (!global.DB_SCHEMA) {
console.error(`Couldn't grab Database Schema.`);
process.exit(1);
}
const BunMariaDB = { const BunMariaDB = {
select: DbSelect, select: DbSelect,
insert: DbInsert, insert: DbInsert,

View File

@ -1,11 +1,9 @@
import type { Connection, ConnectionConfig } from "mariadb"; import type { DBInsertReturn, DBResponseObject } from "../types";
import type { BUN_MARIADB_TableSchemaType, DBResponseObject } from "../types"; import MariaDBClient from "./mariadb";
import grabDBConnection from "./grab-db-connection";
type Param = { type Param = {
query: string; query: string;
values?: string[] | object; values?: any[];
config?: ConnectionConfig;
}; };
/** /**
@ -14,43 +12,40 @@ type Param = {
*/ */
export default async function dbHandler< export default async function dbHandler<
T extends { [k: string]: any } = { [k: string]: any }, T extends { [k: string]: any } = { [k: string]: any },
>({ query, values, config }: Param): Promise<DBResponseObject> { >({ query, values }: Param): Promise<DBResponseObject> {
let CONNECTION: Connection | undefined;
let results: T | null = null;
try { try {
CONNECTION = await grabDBConnection({ config }); const res = await MariaDBClient.unsafe(query, values);
if (query && values) { const count = res.count;
const queryResults = await CONNECTION.query(query, values); const last_insert_id = res.lastInsertRowid;
results = queryResults[0]; const affected_rows = res.affectedRows;
} else {
const queryResults = await CONNECTION.query(query);
results = queryResults[0];
}
} catch (error: any) {
if (
error.message &&
typeof error.message == "string" &&
error.message.match(/Access denied for user.*password/i)
) {
throw new Error("Authentication Failed!");
}
results = null; const res_array = (() => {
} finally { try {
await CONNECTION?.end(); return JSON.parse(JSON.stringify(res)) as T[];
} catch (error) {
return undefined;
} }
})();
const insert_return: DBInsertReturn = {
count,
last_insert_id,
affected_rows,
};
if (results) {
return { return {
success: true, success: true,
payload: Array.isArray(results) ? results : undefined, payload: res_array,
single_res: Array.isArray(results) ? undefined : results, single_res: res_array?.[0],
insert_return,
}; };
} else { } catch (error: any) {
return { return {
success: false, success: false,
error: "DB Handler Error => " + error.message,
msg: "DB Handler Error => " + error.message,
}; };
} finally {
} }
} }

Some files were not shown because too many files have changed in this diff Show More