refactor(db): migrate to libsql
This commit is contained in:
52 files changed
+523
-1450
No files matched your search
@@ -1,26 +1,15 @@
|
||||
import type { InferInsertModel } from "drizzle-orm";
|
||||
|
||||
import { objectEntries } from "@homarr/common";
|
||||
import { dbEnv } from "@homarr/core/infrastructure/db/env";
|
||||
|
||||
import type { HomarrDatabase, HomarrDatabaseMysql, HomarrDatabasePostgresql } from "./driver";
|
||||
import type { HomarrDatabase, HomarrTransaction } from "./driver";
|
||||
import * as schema from "./schema";
|
||||
|
||||
type TableKey = {
|
||||
[K in keyof typeof schema]: (typeof schema)[K] extends { _: { brand: "Table" } } ? K : never;
|
||||
}[keyof typeof schema];
|
||||
|
||||
export function isMysql(): boolean {
|
||||
return dbEnv.DRIVER === "mysql2";
|
||||
}
|
||||
|
||||
export function isPostgresql(): boolean {
|
||||
return dbEnv.DRIVER === "node-postgres";
|
||||
}
|
||||
|
||||
export const createDbInsertCollectionForTransaction = <TTableKey extends TableKey>(
|
||||
tablesInInsertOrder: TTableKey[],
|
||||
) => {
|
||||
export const createDbInsertCollection = <TTableKey extends TableKey>(tablesInInsertOrder: TTableKey[]) => {
|
||||
const context = tablesInInsertOrder.reduce(
|
||||
(acc, key) => {
|
||||
acc[key] = [];
|
||||
@@ -31,25 +20,10 @@ export const createDbInsertCollectionForTransaction = <TTableKey extends TableKe
|
||||
|
||||
return {
|
||||
...context,
|
||||
insertAll: (db: HomarrDatabase) => {
|
||||
db.transaction((transaction) => {
|
||||
insertAllAsync: async (db: HomarrDatabase | HomarrTransaction) => {
|
||||
await db.transaction(async (transaction) => {
|
||||
for (const [key, values] of objectEntries(context)) {
|
||||
if (values.length >= 1) {
|
||||
transaction
|
||||
.insert(schema[key])
|
||||
.values(values as never)
|
||||
.run();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
// We allow any database that supports async passed here but then fallback to mysql to prevent typescript errors
|
||||
insertAllAsync: async (db: HomarrDatabaseMysql | HomarrDatabasePostgresql) => {
|
||||
const innerDb = db as HomarrDatabaseMysql;
|
||||
await innerDb.transaction(async (transaction) => {
|
||||
for (const [key, values] of objectEntries(context)) {
|
||||
if (values.length >= 1) {
|
||||
// Below is actually the mysqlSchema when the driver is mysql
|
||||
await transaction.insert(schema[key] as never).values(values as never);
|
||||
}
|
||||
}
|
||||
@@ -57,27 +31,3 @@ export const createDbInsertCollectionForTransaction = <TTableKey extends TableKe
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const createDbInsertCollectionWithoutTransaction = <TTableKey extends TableKey>(
|
||||
tablesInInsertOrder: TTableKey[],
|
||||
) => {
|
||||
const { insertAll, insertAllAsync, ...collection } = createDbInsertCollectionForTransaction(tablesInInsertOrder);
|
||||
|
||||
return {
|
||||
...collection,
|
||||
insertAllAsync: async (db: HomarrDatabase) => {
|
||||
switch (dbEnv.DRIVER) {
|
||||
case "mysql2":
|
||||
case "node-postgres":
|
||||
// For mysql2 and node-postgres, we can use the async insertAllAsync method
|
||||
await insertAllAsync(db as unknown as HomarrDatabaseMysql | HomarrDatabasePostgresql);
|
||||
return;
|
||||
default:
|
||||
// For better-sqlite3, we need to use the synchronous insertAll method
|
||||
// default assumes better-sqlite3. It's original implementation.
|
||||
insertAll(db);
|
||||
break;
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3";
|
||||
import type { ExtractTablesWithRelations } from "drizzle-orm";
|
||||
import type { LibSQLDatabase, LibSQLTransaction } from "drizzle-orm/libsql";
|
||||
import type { MySql2Database } from "drizzle-orm/mysql2";
|
||||
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
||||
|
||||
@@ -6,6 +7,7 @@ import type * as mysqlSchema from "./schema/mysql";
|
||||
import type * as pgSchema from "./schema/postgresql";
|
||||
import type * as sqliteSchema from "./schema/sqlite";
|
||||
|
||||
export type HomarrDatabase = BetterSQLite3Database<typeof sqliteSchema>;
|
||||
export type HomarrDatabase = LibSQLDatabase<typeof sqliteSchema>;
|
||||
export type HomarrTransaction = LibSQLTransaction<typeof sqliteSchema, ExtractTablesWithRelations<typeof sqliteSchema>>;
|
||||
export type HomarrDatabaseMysql = MySql2Database<typeof mysqlSchema>;
|
||||
export type HomarrDatabasePostgresql = NodePgDatabase<typeof pgSchema>;
|
||||
@@ -8,5 +8,3 @@ export type { HomarrDatabaseMysql, HomarrDatabasePostgresql } from "./driver";
|
||||
export const db = createDb(schema);
|
||||
|
||||
export type Database = typeof db;
|
||||
|
||||
export { handleDiffrentDbDriverOperationsAsync as handleTransactionsAsync } from "./transactions";
|
||||
@@ -1,4 +1,4 @@
|
||||
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
||||
import { migrate } from "drizzle-orm/libsql/migrator";
|
||||
|
||||
import { createSharedDbConfig, createSqliteDb } from "@homarr/core/infrastructure/db";
|
||||
|
||||
@@ -12,7 +12,7 @@ const migrateAsync = async () => {
|
||||
const config = createSharedDbConfig(sqliteSchema);
|
||||
const db = createSqliteDb(config);
|
||||
|
||||
migrate(db, { migrationsFolder });
|
||||
await migrate(db, { migrationsFolder });
|
||||
|
||||
await seedDataAsync(db);
|
||||
await applyCustomMigrationsAsync(db);
|
||||
|
||||
@@ -47,11 +47,11 @@
|
||||
"@homarr/core": "workspace:^0.1.0",
|
||||
"@homarr/definitions": "workspace:^0.1.0",
|
||||
"@homarr/server-settings": "workspace:^0.1.0",
|
||||
"@libsql/client": "0.15.15",
|
||||
"@mantine/core": "^8.3.10",
|
||||
"@paralleldrive/cuid2": "^3.1.0",
|
||||
"@testcontainers/mysql": "^11.11.0",
|
||||
"@testcontainers/postgresql": "^11.11.0",
|
||||
"better-sqlite3": "^12.5.0",
|
||||
"dotenv": "^17.2.3",
|
||||
"drizzle-kit": "^0.31.8",
|
||||
"drizzle-orm": "^0.45.1",
|
||||
@@ -64,7 +64,6 @@
|
||||
"@homarr/eslint-config": "workspace:^0.2.0",
|
||||
"@homarr/prettier-config": "workspace:^0.1.0",
|
||||
"@homarr/tsconfig": "workspace:^0.1.0",
|
||||
"@types/better-sqlite3": "7.6.13",
|
||||
"@types/pg": "^8.16.0",
|
||||
"dotenv-cli": "^11.0.0",
|
||||
"esbuild": "^0.27.2",
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import Database from "better-sqlite3";
|
||||
import { drizzle } from "drizzle-orm/better-sqlite3";
|
||||
import { migrate } from "drizzle-orm/better-sqlite3/migrator";
|
||||
import { createClient } from "@libsql/client/node";
|
||||
import { drizzle } from "drizzle-orm/libsql";
|
||||
import { migrate } from "drizzle-orm/libsql/migrator";
|
||||
|
||||
import { DB_CASING } from "@homarr/core/infrastructure/db/constants";
|
||||
|
||||
import * as sqliteSchema from "../schema/sqlite";
|
||||
|
||||
export const createDb = (debug?: boolean) => {
|
||||
const sqlite = new Database(":memory:");
|
||||
export const createDbAsync = async (debug?: boolean) => {
|
||||
const sqlite = createClient({
|
||||
url: ":memory:",
|
||||
});
|
||||
const db = drizzle(sqlite, { schema: sqliteSchema, logger: debug, casing: DB_CASING });
|
||||
migrate(db, {
|
||||
await migrate(db, {
|
||||
migrationsFolder: "./packages/db/migrations/sqlite",
|
||||
});
|
||||
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
import { isMysql, isPostgresql } from "./collection";
|
||||
import type { HomarrDatabase, HomarrDatabaseMysql } from "./driver";
|
||||
import type { MySqlSchema } from "./schema";
|
||||
import * as schema from "./schema";
|
||||
|
||||
interface HandleTransactionInput {
|
||||
handleAsync: (db: HomarrDatabaseMysql, schema: MySqlSchema) => Promise<void>;
|
||||
handleSync: (db: HomarrDatabase) => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The below method is mostly used to handle transactions in different database drivers.
|
||||
* As better-sqlite3 transactions have to be synchronous, we have to implement them in a different way.
|
||||
* But it can also generally be used when dealing with different database drivers.
|
||||
*/
|
||||
export const handleDiffrentDbDriverOperationsAsync = async (db: HomarrDatabase, input: HandleTransactionInput) => {
|
||||
if (isMysql() || isPostgresql()) {
|
||||
// Schema type is always the correct one based on env variables
|
||||
await input.handleAsync(db as unknown as HomarrDatabaseMysql, schema as unknown as MySqlSchema);
|
||||
} else {
|
||||
input.handleSync(db);
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user