在Electron 中使用SQLite 的最好方式
上周刚刚发布了一个用

但是,由于
我想要做到的是,我在
例如:

万幸的是 drizzle 居然有一个 HTTP Proxy 的机制。这个机制能让你所有的
也就是说,我可以在这个
接下来我会简单描述一下我在
编写Schema
在你的项目里找一个地方,把
import { int, sqliteTable, text } from "drizzle-orm/sqlite-core";
export const posts = sqliteTable('posts', { id: int("id").primaryKey().default(0), title: text("title").notNull().default(""),})
在Renderer 里创建一个drizzle database 实例
根据 文档
export const database = drizzle(async (...args) => { try { // 通过 IPC 把 SQL 发送到 Main process const result = await window.api.execute(...args) return {rows: result} } catch (e: any) { console.error('Error from sqlite proxy server: ', e.response.data) return { rows: [] } }}, { schema: schema})
这里有一个window.api.execute()
const api = { execute: (...args) => ipcRenderer.invoke('db:execute', ...args),}
也就是说,实际上我们以上做的事情就是,通过db:execute
Main process
在
ipcMain.handle('db:execute', execute)
这里的 execute
就是
import { drizzle } from 'drizzle-orm/better-sqlite3'import Database from 'better-sqlite3'import { migrate } from 'drizzle-orm/better-sqlite3/migrator'import * as schema from '../renderer/src/db/schema'import fs from 'fs'import { app } from 'electron'import path from 'path'
// 初始化 sqliteconst dbPath = '../databse.db'
fs.mkdirSync(path.dirname(dbPath), { recursive: true })
const sqlite = new Database( dbPath)
// 创建 drizzle 实例export const db = drizzle(sqlite, { schema })
// 这里是 execute 方法export const execute = async (e, sqlstr, params, method) => { // 得到执行需要的参数后,用 better-sqlite3 执行 const result = sqlite.prepare(sqlstr) const ret = result[method](...params) return toDrizzleResult(ret)}
function toDrizzleResult(row: Record<string, any>)function toDrizzleResult(rows: Record<string, any> | Array<Record<string, any>>) { if (!rows) { return [] } if (Array.isArray(rows)) { return rows.map((row) => { return Object.keys(row).map((key) => row[key]) }) } else { return Object.keys(rows).map((key) => rows[key]) }}
在上面的代码中,我额外实现了一个 toDrizzleResult
的方法,是为了把
到这里,你就已经可以在
function App(): JSX.Element {
const [postList, setPosts] = useState([] as any[])
useEffect(() => { database.query.posts.findMany().then(result => { setPosts(result) }) }, [])
return ( <div> <div> <form onSubmit={async e => { e.preventDefault()
const formData = new FormData(e.target as HTMLFormElement) const title = formData.get('title') as string if (title) { await database.insert(posts).values({ id: Math.floor(Math.random() * 1000), title })
// refetch const result = await database.query.posts.findMany() setPosts(result) } }}> <input name="title" type="text" placeholder="title" /> <button>add</button> </form> </div> {postList.map(post => { return ( <div key={post.id}> {post.title} </div> ) })} </div> )}
export default App
但这时候执行,会报错。原因是我们还没有初始化数据库。我们需要在
首先需要用drizzle.config.ts
中指定了
import type { Config } from 'drizzle-kit'
export default { schema: './src/db/schema.ts', out: './drizzle', driver: 'better-sqlite'} satisfies Config
然后写一个 runMigrations
方法,用来初始化数据库:
export const runMigrate = async () => { migrate(db, { // 在 drizzle.config.ts 里指定的路径 migrationsFolder: path.join(__dirname, '../../drizzle') })}
这个方法需要在
async function createWindow() { // ...
await runMigrate() createWindow()
//...}
实例源码
你可以在 这里 找到这个示例的完整源码。
特别感谢 EGOIST 提供灵感。
