From 5fb13e75b3a768f2913dfb122a13448b9fbc9368 Mon Sep 17 00:00:00 2001 From: Huakun Shen Date: Fri, 21 Mar 2025 08:05:29 -0400 Subject: [PATCH] feat: update drizzle configuration and schema management - Added a check for DB_FILE_NAME in drizzle.config.ts to ensure it's set. - Updated package.json to change the package name to @kksh/drizzle and added exports for schema and relations. - Enhanced README.md with instructions for using the schema generation. - Refactored schema.ts for improved readability and organization of imports. --- apps/desktop/package.json | 3 ++ apps/desktop/src/lib/orm/database.ts | 66 +++++++++++++++++++++++++ packages/drizzle/README.md | 12 +++++ packages/drizzle/drizzle.config.ts | 7 ++- packages/drizzle/drizzle/schema.ts | 72 +++++++++++++++++----------- packages/drizzle/index.ts | 3 +- packages/drizzle/package.json | 40 +++++++++------- 7 files changed, 153 insertions(+), 50 deletions(-) create mode 100644 apps/desktop/src/lib/orm/database.ts diff --git a/apps/desktop/package.json b/apps/desktop/package.json index 5e2ed15..9130bbc 100644 --- a/apps/desktop/package.json +++ b/apps/desktop/package.json @@ -17,6 +17,7 @@ "dependencies": { "@formkit/auto-animate": "^0.8.2", "@inlang/paraglide-sveltekit": "0.16.0", + "@kksh/drizzle": "workspace:*", "@kksh/extension": "workspace:*", "@kksh/supabase": "workspace:*", "@kksh/svelte5": "^0.1.15", @@ -28,8 +29,10 @@ "@tauri-apps/api": "^2.3.0", "@tauri-apps/plugin-autostart": "^2.2.0", "@tauri-apps/plugin-shell": "^2.2.0", + "@tauri-apps/plugin-sql": "^2.2.0", "@tauri-apps/plugin-stronghold": "^2.2.0", "dompurify": "^3.2.4", + "drizzle-orm": "^0.40.1", "eslint": "^9.21.0", "fuse.js": "^7.1.0", "gsap": "^3.12.7", diff --git a/apps/desktop/src/lib/orm/database.ts b/apps/desktop/src/lib/orm/database.ts new file mode 100644 index 0000000..aeb3cb5 --- /dev/null +++ b/apps/desktop/src/lib/orm/database.ts @@ -0,0 +1,66 @@ +import * as schema from "@kksh/drizzle/schema" +import Database from "@tauri-apps/plugin-sql" +import { drizzle } from "drizzle-orm/sqlite-proxy" + +/** + * Represents the result of a SELECT query. + */ +export type SelectQueryResult = { + [key: string]: any +} + +/** + * Loads the sqlite database via the Tauri Proxy. + */ +// export const sqlite = await Database.load("sqlite:test.db"); + +export async function getDb() { + return await Database.load("sqlite:test.db") +} + +/** + * The drizzle database instance. + */ +export const db = drizzle( + async (sql, params, method) => { + const sqlite = await getDb() + let rows: any = [] + let results = [] + + // If the query is a SELECT, use the select method + if (isSelectQuery(sql)) { + rows = await sqlite.select(sql, params).catch((e) => { + console.error("SQL Error:", e) + return [] + }) + } else { + // Otherwise, use the execute method + rows = await sqlite.execute(sql, params).catch((e) => { + console.error("SQL Error:", e) + return [] + }) + return { rows: [] } + } + + rows = rows.map((row: any) => { + return Object.values(row) + }) + + // If the method is "all", return all rows + results = method === "all" ? rows : rows[0] + await sqlite.close() + return { rows: results } + }, + // Pass the schema to the drizzle instance + { schema: schema, logger: true } +) + +/** + * Checks if the given SQL query is a SELECT query. + * @param sql The SQL query to check. + * @returns True if the query is a SELECT query, false otherwise. + */ +function isSelectQuery(sql: string): boolean { + const selectRegex = /^\s*SELECT\b/i + return selectRegex.test(sql) +} diff --git a/packages/drizzle/README.md b/packages/drizzle/README.md index 3b3ec44..c6e495e 100644 --- a/packages/drizzle/README.md +++ b/packages/drizzle/README.md @@ -1 +1,13 @@ # drizzle + +- Only use `pull` to generate the schema from existing database. +- Don't `migrate` or `push`. + +```bash +export DB_FILE_NAME="~/Library/Application Support/sh.kunkun.desktop/kk.dev.sqlite" +bunx drizzle-kit pull +``` + +We are using sqlite with fts5, which drizzle doesn't support yet, so pushing the schema will destroy the existing schema. + +We only use pulled schema to generate sql queries. diff --git a/packages/drizzle/drizzle.config.ts b/packages/drizzle/drizzle.config.ts index 2e6884e..c7ec2f3 100644 --- a/packages/drizzle/drizzle.config.ts +++ b/packages/drizzle/drizzle.config.ts @@ -1,12 +1,15 @@ import "dotenv/config" import { defineConfig } from "drizzle-kit" +if (!process.env.DB_FILE_NAME) { + throw new Error("DB_FILE_NAME is not set") +} + export default defineConfig({ out: "./drizzle", // schema: "./src/db/schema.ts", dialect: "sqlite", dbCredentials: { - url: "/Users/hk/Library/Application Support/sh.kunkun.desktop/kk.dev.sqlite" - // url: process.env.DB_FILE_NAME! + url: process.env.DB_FILE_NAME } }) diff --git a/packages/drizzle/drizzle/schema.ts b/packages/drizzle/drizzle/schema.ts index 3b989d4..73fbf85 100644 --- a/packages/drizzle/drizzle/schema.ts +++ b/packages/drizzle/drizzle/schema.ts @@ -1,9 +1,17 @@ -import { sqliteTable, AnySQLiteColumn, integer, text, numeric, foreignKey, blob, primaryKey } from "drizzle-orm/sqlite-core" - import { sql } from "drizzle-orm" +import { sql } from "drizzle-orm" +import { + blob, + foreignKey, + integer, + numeric, + primaryKey, + sqliteTable, + text +} from "drizzle-orm/sqlite-core" export const schemaVersion = sqliteTable("schema_version", { - version: integer().notNull(), -}); + version: integer().notNull() +}) export const extensions = sqliteTable("extensions", { extId: integer("ext_id").primaryKey({ autoIncrement: true }), @@ -12,59 +20,65 @@ export const extensions = sqliteTable("extensions", { enabled: numeric().default(sql`(TRUE)`), path: text(), data: numeric(), - installedAt: numeric("installed_at").default(sql`(CURRENT_TIMESTAMP)`), -}); + installedAt: numeric("installed_at").default(sql`(CURRENT_TIMESTAMP)`) +}) export const commands = sqliteTable("commands", { cmdId: integer("cmd_id").primaryKey({ autoIncrement: true }), - extId: integer("ext_id").notNull().references(() => extensions.extId, { onDelete: "cascade" } ), + extId: integer("ext_id") + .notNull() + .references(() => extensions.extId, { onDelete: "cascade" }), name: text().notNull(), enabled: numeric().default(sql`(TRUE)`), alias: text(), hotkey: text(), type: text().notNull(), - data: numeric(), -}); + data: numeric() +}) export const extensionData = sqliteTable("extension_data", { dataId: integer("data_id").primaryKey({ autoIncrement: true }), - extId: integer("ext_id").notNull().references(() => extensions.extId, { onDelete: "cascade" } ), + extId: integer("ext_id") + .notNull() + .references(() => extensions.extId, { onDelete: "cascade" }), dataType: text("data_type").notNull(), data: numeric().notNull(), metadata: numeric(), searchText: text("search_text"), createdAt: numeric("created_at").default(sql`(CURRENT_TIMESTAMP)`), - updatedAt: numeric("updated_at").default(sql`(CURRENT_TIMESTAMP)`), -}); + updatedAt: numeric("updated_at").default(sql`(CURRENT_TIMESTAMP)`) +}) export const extensionDataFts = sqliteTable("extension_data_fts", { dataId: numeric("data_id"), searchText: numeric("search_text"), extensionDataFts: numeric("extension_data_fts"), - rank: numeric(), -}); + rank: numeric() +}) export const extensionDataFtsData = sqliteTable("extension_data_fts_data", { id: integer().primaryKey(), - block: blob(), -}); + block: blob() +}) -export const extensionDataFtsIdx = sqliteTable("extension_data_fts_idx", { - segid: numeric().notNull(), - term: numeric().notNull(), - pgno: numeric(), -}, -(table) => [ - primaryKey({ columns: [table.segid, table.term], name: "extension_data_fts_idx_segid_term_pk"}) -]); +export const extensionDataFtsIdx = sqliteTable( + "extension_data_fts_idx", + { + segid: numeric().notNull(), + term: numeric().notNull(), + pgno: numeric() + }, + (table) => [ + primaryKey({ columns: [table.segid, table.term], name: "extension_data_fts_idx_segid_term_pk" }) + ] +) export const extensionDataFtsDocsize = sqliteTable("extension_data_fts_docsize", { id: integer().primaryKey(), - sz: blob(), -}); + sz: blob() +}) export const extensionDataFtsConfig = sqliteTable("extension_data_fts_config", { k: numeric().primaryKey().notNull(), - v: numeric(), -}); - + v: numeric() +}) diff --git a/packages/drizzle/index.ts b/packages/drizzle/index.ts index f67b2c6..61e2276 100644 --- a/packages/drizzle/index.ts +++ b/packages/drizzle/index.ts @@ -1 +1,2 @@ -console.log("Hello via Bun!"); \ No newline at end of file +export * as schema from "./drizzle/schema" +export * as relations from "./drizzle/relations" diff --git a/packages/drizzle/package.json b/packages/drizzle/package.json index 2ea1752..65ddc1c 100644 --- a/packages/drizzle/package.json +++ b/packages/drizzle/package.json @@ -1,19 +1,23 @@ { - "name": "drizzle", - "module": "index.ts", - "type": "module", - "private": true, - "devDependencies": { - "@types/bun": "latest", - "drizzle-kit": "^0.30.5", - "tsx": "^4.19.3" - }, - "peerDependencies": { - "typescript": "^5" - }, - "dependencies": { - "@libsql/client": "^0.15.0", - "dotenv": "^16.4.7", - "drizzle-orm": "^0.40.1" - } -} \ No newline at end of file + "name": "@kksh/drizzle", + "type": "module", + "private": true, + "exports": { + ".": "./index.ts", + "./schema": "./drizzle/schema.ts", + "./relations": "./drizzle/relations.ts" + }, + "devDependencies": { + "@types/bun": "latest", + "drizzle-kit": "^0.30.5", + "tsx": "^4.19.3" + }, + "peerDependencies": { + "typescript": "^5" + }, + "dependencies": { + "@libsql/client": "^0.15.0", + "dotenv": "^16.4.7", + "drizzle-orm": "^0.40.1" + } +}