This commit is contained in:
Benjamin Toby 2026-07-14 08:12:13 +01:00
parent b5e4724e03
commit 3b5fba4063
26 changed files with 1097 additions and 321 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@moduletrace/bun-mariadb",
"version": "1.1.11",
"version": "1.0.0",
"description": "Mariadb manager for Bun",
"author": "Benjamin Toby",
"main": "dist/index.js",

View File

@ -6,31 +6,9 @@ import typedef from "./typedef";
import backup from "./backup";
import restore from "./restore";
import admin from "./admin";
import type {
BUN_MARIADB_DatabaseSchemaType,
BunMariaDBConfig,
} from "../types";
import init from "../functions/init";
/**
* # Declare Global Variables
*/
declare global {
var CONFIG: BunMariaDBConfig;
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);
}
init();
/**
* # Describe Program

View File

@ -7,6 +7,7 @@ import _ from "lodash";
import appendDefaultFieldsToDbSchema from "../utils/append-default-fields-to-db-schema";
import chalk from "chalk";
import { writeLiveSchema } from "../functions/live-schema";
import createDBSchema from "../lib/schema/create-db-schema";
export default function () {
return new Command("schema")
@ -31,12 +32,14 @@ export default function () {
dbSchema,
});
const manager = new MariaDBSchemaManager({
schema: finaldbSchema,
});
// const manager = new MariaDBSchemaManager({
// schema: finaldbSchema,
// });
await manager.syncSchema();
manager.close();
// await manager.syncSchema();
// manager.close();
await createDBSchema({ db_schema: finaldbSchema });
if (isTypeDef && config.typedef_file_path) {
const out_file = path.resolve(

View File

@ -4,4 +4,6 @@ export const AppData = {
DefaultBackupDirName: ".backups",
DbSchemaManagerTableName: "__db_schema_manager__",
DbSchemaFileName: "schema.ts",
MaxInitRetries: 50,
InitRetryIntervalMilliseconds: 5000,
} as const;

View File

@ -0,0 +1,41 @@
import path from "path";
import grabDirNames from "../data/grab-dir-names";
import { type BunMariaDBConfig } from "../types";
import { SQL } from "bun";
type Params = {
config: BunMariaDBConfig;
};
export default function grabMariaDBClient({
config,
}: Params): Bun.SQL | undefined {
const { ROOT_DIR } = grabDirNames();
try {
const MariaDBClient = new SQL({
hostname: process.env.BUN_MARIADB_SERVER_HOST,
username: process.env.BUN_MARIADB_SERVER_USERNAME,
password: process.env.BUN_MARIADB_SERVER_PASSWORD,
database: config.db_name,
port: process.env.BUN_MARIADB_SERVER_PORT
? Number(process.env.BUN_MARIADB_SERVER_PORT)
: undefined,
...config.db_config,
tls: config.ssl_ca
? {
ca: Bun.file(path.resolve(ROOT_DIR, config.ssl_ca)),
rejectUnauthorized: false,
}
: {
rejectUnauthorized: false,
},
adapter: "mariadb",
});
return MariaDBClient;
} catch (error: any) {
console.error(`Couldn't grab MariaDB Client => ` + error.message);
return;
}
}

View File

@ -4,12 +4,22 @@ import { AppData } from "../data/app-data";
import grabDirNames from "../data/grab-dir-names";
import {
type BunMariaDBConfig,
type BunMariaDBConfigReturn,
type BUN_MARIADB_DatabaseSchemaType,
RequiredENVs,
} from "../types";
import { SQL } from "bun";
import setMariaDBClient from "./set-mariadb-client";
export default async function init(): Promise<BunMariaDBConfigReturn> {
/**
* # Declare Global Variables
*/
declare global {
var CONFIG: BunMariaDBConfig;
var DB_SCHEMA: BUN_MARIADB_DatabaseSchemaType;
var MARIADB_CLIENT: Bun.SQL;
}
export default function init(): void {
try {
const { ROOT_DIR } = grabDirNames();
const { ConfigFileName } = AppData;
@ -23,7 +33,7 @@ export default async function init(): Promise<BunMariaDBConfigReturn> {
process.exit(1);
}
const ConfigImport = await import(ConfigFilePath);
const ConfigImport = require(ConfigFilePath);
const Config = ConfigImport["default"] as BunMariaDBConfig;
if (!Config) {
@ -73,7 +83,7 @@ export default async function init(): Promise<BunMariaDBConfigReturn> {
process.exit(1);
}
const DbSchemaImport = await import(DBSchemaFilePath);
const DbSchemaImport = require(DBSchemaFilePath);
const DbSchema = DbSchemaImport[
"default"
] as BUN_MARIADB_DatabaseSchemaType;
@ -89,10 +99,22 @@ export default async function init(): Promise<BunMariaDBConfigReturn> {
global.CONFIG = Config;
global.DB_SCHEMA = DbSchema;
return {
config: Config,
dbSchema: DbSchema,
};
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);
}
setMariaDBClient({ config: Config });
if (!global.MARIADB_CLIENT) {
console.error(`Couldn't set MariaDB Client.`);
process.exit(1);
}
} catch (error: any) {
console.error(`Initialization ERROR => ` + error.message);
process.exit(1);

View File

@ -0,0 +1,29 @@
import { type BunMariaDBConfig } from "../types";
import grabMariaDBClient from "./grab-mariadb-client";
type Params = {
config: BunMariaDBConfig;
};
export default function setMariaDBClient({ config }: Params): void {
try {
const MariaDBClient = grabMariaDBClient({ config });
if (!MariaDBClient) {
throw new Error(`Couldn't grab MariaDB Client`);
}
global.MARIADB_CLIENT = MariaDBClient;
// const test = await MariaDBClient.unsafe(`SHOW DATABASES`);
// if (!test.count) {
// console.error(`MariaDBClient Error: Database not ready.`);
// console.log(test);
// process.exit(1);
// }
} catch (error: any) {
console.error(`ERROR setting MariaDB Client => ` + error.message);
process.exit(1);
}
}

View File

@ -4,14 +4,10 @@ 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 type { BUN_MARIADB_DatabaseSchemaType, BunMariaDBConfig } from "./types";
import grabDbSchema from "./utils/grab-db-schema";
import grabJoinFieldsFromQueryObject from "./utils/grab-join-fields-from-query-object";
declare global {
var CONFIG: BunMariaDBConfig;
var DB_SCHEMA: BUN_MARIADB_DatabaseSchemaType;
}
init();
const BunMariaDB = {
select: DbSelect,

View File

@ -1,9 +1,14 @@
import type { DBInsertReturn, DBResponseObject } from "../types";
import MariaDBClient from "./mariadb";
import grabMariaDBClient from "../functions/grab-mariadb-client";
import type {
BunMariaDBConfig,
DBInsertReturn,
DBResponseObject,
} from "../types";
type Param = {
query: string;
values?: any[];
config?: BunMariaDBConfig;
};
/**
@ -12,9 +17,17 @@ type Param = {
*/
export default async function dbHandler<
T extends { [k: string]: any } = { [k: string]: any },
>({ query, values }: Param): Promise<DBResponseObject> {
>({ query, values, config }: Param): Promise<DBResponseObject<T>> {
try {
const res = await MariaDBClient.unsafe(query, values);
const CLIENT = config
? grabMariaDBClient({ config })
: global.MARIADB_CLIENT;
if (!CLIENT) {
throw new Error(`Couldn't grab MariaDB Client.`);
}
const res = await CLIENT.unsafe(query, values);
const count = res.count;

View File

@ -1,42 +0,0 @@
import * as mariadb from "mariadb";
import type { Connection } from "mariadb";
import type { DsqlConnectionParam } from "../types";
import grabDbSSL from "./grab-db-ssl";
/**
* # Grab General CONNECTION for DSQL
*/
export default async function grabDBConnection(
param?: DsqlConnectionParam,
): Promise<Connection> {
const configData = global.CONFIG;
const CONN_TIMEOUT = configData?.connection_timeout || 10000;
const config: mariadb.ConnectionConfig = {
host: process.env.BUN_MARIADB_SERVER_HOST,
user: process.env.BUN_MARIADB_SERVER_USERNAME,
password: process.env.BUN_MARIADB_SERVER_PASSWORD,
database: configData?.db_name,
port: process.env.BUN_MARIADB_SERVER_PORT
? Number(process.env.BUN_MARIADB_SERVER_PORT)
: undefined,
charset: configData?.charset || "utf8mb4",
ssl: grabDbSSL(),
bigIntAsNumber: true,
supportBigNumbers: true,
bigNumberStrings: false,
dateStrings: true,
metaAsArray: true,
socketTimeout: CONN_TIMEOUT,
connectTimeout: CONN_TIMEOUT,
compress: true,
...param?.config,
};
try {
return await mariadb.createConnection(config);
} catch (error) {
console.log(`Error Grabbing DSQL Connection =>`, config);
throw error;
}
}

View File

@ -1,6 +1,10 @@
import dbHandler from "../db-handler";
import _ from "lodash";
import type { DBResponseObject, ServerQueryParam } from "../../types";
import type {
BunMariaDBConfig,
DBResponseObject,
ServerQueryParam,
} from "../../types";
import sqlGenerator from "../../utils/sql-generator";
type Params<
@ -10,6 +14,7 @@ type Params<
table: Table;
query?: ServerQueryParam<Schema>;
targetId?: number | string;
config?: BunMariaDBConfig;
};
function quoteIdentifier(identifier: string): string {
@ -23,6 +28,7 @@ export default async function DbDelete<
table,
query,
targetId,
config,
}: Params<Schema, Table>): Promise<DBResponseObject> {
let sqlObj: ReturnType<typeof sqlGenerator> | null = null;
@ -66,6 +72,7 @@ export default async function DbDelete<
const res = await dbHandler({
query: sql,
values: sqlObj.values as any,
config,
});
if (!res.success) {

View File

@ -1,5 +1,9 @@
import dbHandler from "../db-handler";
import type { DBResponseObject, SQLInsertGenReturn } from "../../types";
import type {
BunMariaDBConfig,
DBResponseObject,
SQLInsertGenReturn,
} from "../../types";
import sqlInsertGenerator from "../../utils/sql-insert-generator";
import grabDuplicateSafeInsertSql from "../grab-duplicate-safe-insert-sql";
@ -10,6 +14,7 @@ type Params<
table: Table;
data: Schema[];
update_on_duplicate?: boolean;
config?: BunMariaDBConfig;
};
export default async function DbInsert<
@ -19,6 +24,7 @@ export default async function DbInsert<
table,
data,
update_on_duplicate,
config,
}: Params<Schema, Table>): Promise<DBResponseObject> {
let sqlObj: SQLInsertGenReturn | null = null;
@ -53,6 +59,7 @@ export default async function DbInsert<
const res = await dbHandler({
query: sql,
values: sqlObj.values,
config,
});
if (!res.success) {

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,10 @@
import dbHandler from "../db-handler";
import _ from "lodash";
import type { DBResponseObject, ServerQueryParam } from "../../types";
import type {
BunMariaDBConfig,
DBResponseObject,
ServerQueryParam,
} from "../../types";
import sqlGenerator from "../../utils/sql-generator";
type Params<
@ -11,6 +15,7 @@ type Params<
table: Table;
count?: boolean;
targetId?: number | string;
config?: BunMariaDBConfig;
};
function quoteIdentifier(identifier: string): string {
@ -25,6 +30,7 @@ export default async function DbSelect<
query,
count,
targetId,
config,
}: Params<Schema, Table>): Promise<DBResponseObject<Schema>> {
let sqlObj: ReturnType<typeof sqlGenerator> | null = null;
@ -52,6 +58,7 @@ export default async function DbSelect<
const res = await dbHandler<Schema>({
query: sqlObj.string,
values: sqlObj.values as any,
config,
});
if (!res.success) {
@ -89,6 +96,7 @@ export default async function DbSelect<
const countRes = await dbHandler<{ count: number }>({
query: countSql,
values: countSqlObject.values as any,
config,
});
if (!countRes.success) {
@ -104,7 +112,7 @@ export default async function DbSelect<
}
const countRows = countRes.payload || [];
const countVal = countRows[0]?.count ?? countRows[0]?.["COUNT(*)"];
const countVal = countRows[0]?.count ?? countRows[0]?.["count"];
resp = {
...resp,

View File

@ -1,6 +1,7 @@
import dbHandler from "../db-handler";
import _ from "lodash";
import type {
BunMariaDBConfig,
DBResponseObject,
SQLInsertGenValueType,
ServerQueryParam,
@ -15,6 +16,7 @@ type Params<
data: Schema;
query?: ServerQueryParam<Schema>;
targetId?: number | string;
config?: BunMariaDBConfig;
};
function quoteIdentifier(identifier: string): string {
@ -29,6 +31,7 @@ export default async function DbUpdate<
data,
query,
targetId,
config,
}: Params<Schema, Table>): Promise<DBResponseObject> {
let sqlObj: ReturnType<typeof sqlGenerator> = { string: "", values: [] };
@ -93,6 +96,7 @@ export default async function DbUpdate<
const res = await dbHandler({
query: sql,
values: values as any,
config,
});
sqlObj.string = sql;
@ -122,6 +126,7 @@ export default async function DbUpdate<
const updated_res = await dbHandler({
query: updated_sql,
values: updated_sql_values,
config,
});
const affected_rows = updated_res.payload?.length;

View File

@ -1,50 +1,49 @@
import { SQL } from "bun";
import init from "../../functions/init";
import grabDirNames from "../../data/grab-dir-names";
import path from "path";
// import { SQL } from "bun";
// import grabDirNames from "../../data/grab-dir-names";
// import path from "path";
await init();
// if (!global.CONFIG) {
// console.error(`Couldn't grab global Config.`);
// process.exit(1);
// }
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);
// }
if (!global.DB_SCHEMA) {
console.error(`Couldn't grab Database Schema.`);
process.exit(1);
}
// const config = global.CONFIG;
const config = global.CONFIG;
// const { ROOT_DIR } = grabDirNames();
const { ROOT_DIR } = grabDirNames();
// const MariaDBClient = new SQL({
// hostname: process.env.BUN_MARIADB_SERVER_HOST,
// username: process.env.BUN_MARIADB_SERVER_USERNAME,
// password: process.env.BUN_MARIADB_SERVER_PASSWORD,
// database: config.db_name,
// port: process.env.BUN_MARIADB_SERVER_PORT
// ? Number(process.env.BUN_MARIADB_SERVER_PORT)
// : undefined,
// ...config.db_config,
// tls: config.ssl_ca
// ? {
// ca: Bun.file(path.resolve(ROOT_DIR, config.ssl_ca)),
// rejectUnauthorized: false,
// }
// : {
// rejectUnauthorized: false,
// },
// adapter: "mariadb",
// });
const MariaDBClient = new SQL({
hostname: process.env.BUN_MARIADB_SERVER_HOST,
username: process.env.BUN_MARIADB_SERVER_USERNAME,
password: process.env.BUN_MARIADB_SERVER_PASSWORD,
database: config.db_name,
port: process.env.BUN_MARIADB_SERVER_PORT
? Number(process.env.BUN_MARIADB_SERVER_PORT)
: undefined,
...config.db_config,
tls: config.ssl_ca
? {
ca: Bun.file(path.resolve(ROOT_DIR, config.ssl_ca)),
rejectUnauthorized: false,
}
: {
rejectUnauthorized: false,
},
adapter: "mariadb",
});
// global.MARIADB_CLIENT = MariaDBClient;
const test = await MariaDBClient.unsafe(`SHOW DATABASES`);
// const test = await MariaDBClient.unsafe(`SHOW DATABASES`);
if (!test.count) {
console.error(`MariaDBClient Error: Database not ready.`);
console.log(test);
process.exit(1);
}
// if (!test.count) {
// console.error(`MariaDBClient Error: Database not ready.`);
// console.log(test);
// process.exit(1);
// }
export default MariaDBClient;
// export default MariaDBClient;

View File

@ -0,0 +1,46 @@
import type { BUN_MARIADB_FieldSchemaType } from "../../types";
import mapDataType from "./map-data-types";
import MariaDBQuoteGen from "./mariadb-quote-gen";
export default function buildColumnDefinition(
field: BUN_MARIADB_FieldSchemaType,
): string {
if (!field.fieldName) {
throw new Error("Field name is required");
}
const parts: string[] = [MariaDBQuoteGen(field.fieldName)];
parts.push(mapDataType(field));
if (field.autoIncrement) {
parts.push("AUTO_INCREMENT");
}
if (field.notNullValue || field.primaryKey || field.isVector) {
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(" ");
}

View File

@ -0,0 +1,22 @@
import { AppData } from "../../data/app-data";
import type { CreateDBSchemaParams } from "../../types";
import dbHandler from "../db-handler";
import MariaDBQuoteGen from "./mariadb-quote-gen";
export default async function createDBManagerTable({
db_schema,
config,
}: CreateDBSchemaParams) {
let sql = ``;
sql += `CREATE TABLE IF NOT EXISTS ${MariaDBQuoteGen(AppData["DbSchemaManagerTableName"])} (\n`;
sql += ` table_name VARCHAR(255) NOT NULL PRIMARY KEY,\n`;
sql += ` created_at BIGINT NOT NULL,\n`;
sql += ` updated_at BIGINT NOT NULL\n`;
sql += `) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_520_ci\n`;
await dbHandler({
query: sql,
config,
});
}

View File

@ -0,0 +1,23 @@
import type { CreateDBSchemaParams } from "../../types";
import createDBManagerTable from "./create-db-manager-table";
import handleDBSchemaTables from "./handle-db-schema-tables";
import orderDBSchema from "./order-db-schema";
export default async function createDBSchema(params: CreateDBSchemaParams) {
/**
* Create Schema Manager Table
*/
await createDBManagerTable(params);
/**
* Reorder Tables
*/
const ordered_db_schema = await orderDBSchema(params);
/**
* Handle Tables
*/
await handleDBSchemaTables({ ...params, db_schema: ordered_db_schema });
process.exit();
}

View File

@ -0,0 +1,18 @@
import { AppData } from "../../data/app-data";
import type {
BUN_MARIADB_DB_TABLE_MANAGER_TABLE,
CreateDBSchemaParams,
} from "../../types";
import dbHandler from "../db-handler";
import MariaDBQuoteGen from "./mariadb-quote-gen";
export default async function getExistingTablesFromTablesManagerTable({
config,
}: CreateDBSchemaParams) {
const rows = await dbHandler<BUN_MARIADB_DB_TABLE_MANAGER_TABLE>({
query: `SELECT table_name FROM ${MariaDBQuoteGen(AppData["DbSchemaManagerTableName"])}`,
config,
});
return rows.payload?.map((row) => row.table_name) || [];
}

View File

@ -0,0 +1,46 @@
import { AppData } from "../../data/app-data";
import type {
BUN_MARIADB_DB_TABLE_MANAGER_TABLE,
BUN_MARIADB_INFORMATION_SCHEMA_TABLES,
CreateDBSchemaTableHandlerParams,
} from "../../types";
import dbHandler from "../db-handler";
import DbInsert from "../mariadb/db-insert";
import buildColumnDefinition from "./build-column-definition";
import MariaDBQuoteGen from "./mariadb-quote-gen";
export default async function handleDBSchemaTable({
db_schema,
config,
table,
db_manager_table_name,
existing_live_table,
}: CreateDBSchemaTableHandlerParams) {
if (!db_manager_table_name || !existing_live_table?.TABLE_NAME) {
const insert_table = await DbInsert<BUN_MARIADB_DB_TABLE_MANAGER_TABLE>(
{
data: [
{
table_name: table.tableName,
},
],
table: AppData["DbSchemaManagerTableName"],
config,
},
);
let sql = ``;
sql += `CREATE TABLE IF NOT EXISTS ${MariaDBQuoteGen(table.tableName)}`;
sql += ` (`;
for (let i = 0; i < table.fields.length; i++) {
const field = table.fields[i];
if (!field) continue;
const col_def = buildColumnDefinition(field);
sql += ` ${col_def}`;
}
sql += ` )`;
}
}

View File

@ -0,0 +1,57 @@
import { AppData } from "../../data/app-data";
import type {
BUN_MARIADB_INFORMATION_SCHEMA_TABLES,
CreateDBSchemaParams,
} from "../../types";
import dbHandler from "../db-handler";
import getExistingTablesFromTablesManagerTable from "./get-existing-tables-from-tables-manager-table";
import handleDBSchemaTable from "./handle-db-schema-table";
export default async function handleDBSchemaTables(
params: CreateDBSchemaParams,
) {
const { db_schema, config } = params;
/**
* Grab Tables that have been recorded in the Schema
* Manager Table
*/
const existing_schema_tables =
await getExistingTablesFromTablesManagerTable(params);
const existing_live_tables =
await dbHandler<BUN_MARIADB_INFORMATION_SCHEMA_TABLES>({
query: `SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_TYPE = 'BASE TABLE' AND TABLE_NAME != ?`,
config: params.config,
values: [AppData["DbSchemaManagerTableName"]],
});
for (let i = 0; i < db_schema.tables.length; i++) {
const table = db_schema.tables[i];
const existing_table = existing_schema_tables.find(
(t) => t == table?.tableName,
);
const existing_live_table = existing_live_tables.payload?.find(
(t) => t.TABLE_NAME == table?.tableName,
);
if (!table) {
if (existing_live_table?.TABLE_NAME) {
await dbHandler<BUN_MARIADB_INFORMATION_SCHEMA_TABLES>({
query: `DROP TABLE ${existing_live_table.TABLE_NAME}`,
config: params.config,
});
}
continue;
}
await handleDBSchemaTable({
...params,
table,
db_manager_table_name: existing_table,
existing_live_table,
});
}
}

View File

@ -0,0 +1,102 @@
import type { BUN_MARIADB_FieldSchemaType } from "../../types";
export default function mapDataType(
field: BUN_MARIADB_FieldSchemaType,
): string {
const dataType = field.dataType?.toUpperCase() || "TEXT";
const vectorSize = field.vectorSize || 1536;
if (field.isVector) {
return `LONGTEXT COMMENT 'vector_size=${vectorSize}'`;
}
switch (dataType) {
case "CHAR":
return `CHAR(${field.integerLength || 255})`;
case "VARCHAR":
return `VARCHAR(${field.integerLength || 255})`;
case "TEXT":
return "TEXT";
case "TINYTEXT":
return "TINYTEXT";
case "MEDIUMTEXT":
return "MEDIUMTEXT";
case "LONGTEXT":
return "LONGTEXT";
case "TINYINT":
return field.integerLength
? `TINYINT(${field.integerLength})`
: "TINYINT";
case "SMALLINT":
return field.integerLength
? `SMALLINT(${field.integerLength})`
: "SMALLINT";
case "MEDIUMINT":
return field.integerLength
? `MEDIUMINT(${field.integerLength})`
: "MEDIUMINT";
case "INT":
return field.integerLength ? `INT(${field.integerLength})` : "INT";
case "BIGINT":
return field.integerLength
? `BIGINT(${field.integerLength})`
: "BIGINT";
case "FLOAT":
return "FLOAT";
case "DOUBLE":
return "DOUBLE";
case "DECIMAL":
if (field.integerLength && field.decimals) {
return `DECIMAL(${field.integerLength}, ${field.decimals})`;
}
return "DECIMAL(10,2)";
case "BINARY":
return `BINARY(${field.integerLength || 1})`;
case "VARBINARY":
return `VARBINARY(${field.integerLength || 255})`;
case "BLOB":
return "BLOB";
case "TINYBLOB":
return "TINYBLOB";
case "MEDIUMBLOB":
return "MEDIUMBLOB";
case "LONGBLOB":
return "LONGBLOB";
case "DATE":
return "DATE";
case "TIME":
return "TIME";
case "DATETIME":
return "DATETIME";
case "TIMESTAMP":
return "TIMESTAMP";
case "YEAR":
return "YEAR";
case "UUID":
return "CHAR(36)"; // MariaDB does not have a native UUID type
case "JSON":
return "JSON";
case "INET6":
return "INET6";
case "VECTOR": {
const dimensions = field.vectorSize || 1536;
return `VECTOR(${dimensions})`;
}
case "BOOLEAN":
return "TINYINT(1)";
case "ENUM": {
const enumVals = (field.options || [])
.map((v) => `'${String(v).replace(/'/g, "''")}'`)
.join(", ");
return `ENUM(${enumVals || "''"})`;
}
case "SET": {
const setVals = (field.options || [])
.map((v) => `'${String(v).replace(/'/g, "''")}'`)
.join(", ");
return `SET(${setVals || "''"})`;
}
default:
return "TEXT";
}
}

View File

@ -0,0 +1,3 @@
export default function MariaDBQuoteGen(str: string) {
return `\`${str.replace(/`/g, "``")}\``;
}

View File

@ -0,0 +1,86 @@
import _ from "lodash";
import type {
BUN_MARIADB_DatabaseSchemaType,
BUN_MARIADB_TableSchemaType,
CreateDBSchemaParams,
} from "../../types";
export default async function orderDBSchema({
db_schema,
}: CreateDBSchemaParams): Promise<BUN_MARIADB_DatabaseSchemaType> {
let new_db_schema = _.cloneDeep(db_schema);
const tables = new_db_schema.tables;
let new_tables_set = new Set<BUN_MARIADB_TableSchemaType>();
let new_tables_start_set = new Set<BUN_MARIADB_TableSchemaType>();
let new_tables_end_set = new Set<BUN_MARIADB_TableSchemaType>();
function setParentTable(table: BUN_MARIADB_TableSchemaType) {
const fields = table.fields;
let does_table_have_foreign_keys = false;
for (let f = 0; f < fields.length; f++) {
const field = fields[f];
if (!field) continue;
const dst_table_name = field.foreignKey?.destinationTableName;
if (dst_table_name) {
const fk_table = tables.find(
(tb) => tb.tableName == dst_table_name,
);
if (
fk_table &&
!new_tables_start_set.has(fk_table) &&
!new_tables_end_set.has(fk_table)
) {
setParentTable(fk_table);
}
new_tables_end_set.add(table);
if (fk_table) {
new_tables_start_set.add(fk_table);
}
does_table_have_foreign_keys = true;
}
}
return { does_table_have_foreign_keys };
}
for (let i = 0; i < tables.length; i++) {
const table = tables[i];
if (!table) {
continue;
}
let { does_table_have_foreign_keys } = setParentTable(table);
if (does_table_have_foreign_keys) {
new_tables_end_set.add(table);
} else {
new_tables_start_set.add(table);
}
}
const parsed_tables = [
...Array.from(new_tables_start_set),
...Array.from(new_tables_end_set),
];
for (let nt = 0; nt < parsed_tables.length; nt++) {
const new_table = parsed_tables[nt];
if (new_table) {
new_tables_set.add(new_table);
}
}
new_db_schema.tables = Array.from(new_tables_set);
return new_db_schema;
}

View File

@ -135,20 +135,49 @@ export const TextFieldTypesArray = [
* Native MariaDB column types supported by the schema builder.
*/
export const BUN_MARIADB_DATATYPES = [
// Strings & Text
{ value: "CHAR" },
{ value: "VARCHAR" },
{ value: "TEXT" },
{ value: "TINYTEXT" },
{ value: "MEDIUMTEXT" },
{ value: "LONGTEXT" },
// Numeric Integers
{ value: "TINYINT" },
{ value: "SMALLINT" },
{ value: "MEDIUMINT" },
{ value: "INT" },
{ value: "BIGINT" },
{ value: "DECIMAL" },
// Numeric Floats & Exact
{ value: "FLOAT" },
{ value: "DOUBLE" },
{ value: "DECIMAL" },
// Binary Layouts
{ value: "BINARY" },
{ value: "VARBINARY" },
{ value: "BLOB" },
{ value: "TINYBLOB" },
{ value: "MEDIUMBLOB" },
{ value: "LONGBLOB" },
{ value: "BOOLEAN" },
// Temporal (Dates / Times)
{ value: "DATE" },
{ value: "TIME" },
{ value: "DATETIME" },
{ value: "TIMESTAMP" },
{ value: "DATE" },
{ value: "YEAR" },
// Core Schema Primitives
{ value: "BOOLEAN" },
{ value: "UUID" },
{ value: "JSON" },
{ value: "INET6" },
{ value: "ENUM" },
{ value: "SET" },
{ value: "VECTOR" },
] as const;
/**
@ -1561,21 +1590,6 @@ export type BunMariaDBQueryFieldValues<
export type QueryRawValueType = string | number | null | undefined;
export type DsqlConnectionParam = {
/**
* No Database Connection
*/
noDb?: boolean;
/**
* Database Name
*/
database?: string;
/**
* Debug
*/
config?: ConnectionConfig;
};
export type DBResponseObject<
T extends { [k: string]: any } = { [k: string]: any },
> = {
@ -1602,3 +1616,27 @@ export const RequiredENVs = [
"BUN_MARIADB_SERVER_PASSWORD",
"BUN_MARIADB_SERVER_SSL_KEY_PATH",
] as const;
export type CreateDBSchemaParams = {
db_schema: BUN_MARIADB_DatabaseSchemaType;
config?: BunMariaDBConfig;
};
export type CreateDBSchemaTableHandlerParams = CreateDBSchemaParams & {
table: BUN_MARIADB_TableSchemaType;
db_manager_table_name?: string;
existing_live_table?: BUN_MARIADB_INFORMATION_SCHEMA_TABLES;
};
export type BUN_MARIADB_DB_TABLE_MANAGER_TABLE = {
table_name?: string;
created_at?: number;
updated_at?: number;
};
export type BUN_MARIADB_INFORMATION_SCHEMA_TABLES = {
TABLE_NAME?: string;
TABLE_TYPE?: "BASE TABLE";
ENGINE?: "InnoDB";
VERSION?: number;
};