[{"data":1,"prerenderedAt":338},["ShallowReactive",2],{"content:\u002Fposts\u002F2025\u002Fdrizzle.orm-use":3,"surround:\u002Fposts\u002F2025\u002Fdrizzle.orm-use":327},{"id":4,"title":5,"body":6,"canonical":302,"categories":303,"date":305,"description":306,"draft":307,"extension":308,"image":309,"meta":310,"navigation":311,"path":312,"permalink":302,"readingTime":313,"recommend":302,"references":302,"seo":318,"sitemap":319,"stem":324,"tags":325,"type":302,"updated":305,"__hash__":326},"content\u002Fposts\u002F2025\u002Fdrizzle.orm-use.md","Drizzle ORM 使用",{"type":7,"value":8,"toc":275},"minimark",[9,17,22,29,41,48,57,63,67,71,77,84,89,93,96,105,109,112,119,122,125,132,135,138,145,149,153,159,163,169,173,179,182,185,191,194,200,204,207,214,220,224,229,233,238,241,245,252],[10,11],"link-card",{"className":12,"icon":14,"link":15,"title":16},[13],"gradient-card","https:\u002F\u002Form.drizzle.team\u002Ffavicon.ico","https:\u002F\u002Form.drizzle.team\u002F","Drizzle ORM 官网",[18,19,21],"h2",{"id":20},"为什么要用-drizzle","为什么要用 Drizzle",[23,24,25],"ol",{},[26,27,28],"li",{},"sql-like:只要你会 SQL，你就可以看懂它的语法。其他 ORM 和数据框架往往会使您偏离\u002F抽象出 SQL，这会导致双重学习曲线：需要同时了解 SQL 和框架的 API。",[30,31,38],"pre",{"className":32,"code":34,"filename":35,"language":36,"meta":37},[33],"language-ts","await db\n    .select()\n    .from(countries)\n    .leftJoin(cities, eq(cities.countryId, countries.id))\n    .where(eq(countries.id, 10))\n","index.ts","ts","",[39,40,34],"code",{"__ignoreMap":37},[30,42,46],{"className":43,"code":44,"filename":45,"language":36,"meta":37},[33],"\u002F\u002F manage your schema\nexport const countries = pgTable('countries', {\n    id: serial('id').primaryKey(),\n    name: varchar('name', { length: 256 }),\n});\n\nexport const cities = pgTable('cities', {\n    id: serial('id').primaryKey(),\n    name: varchar('name', { length: 256 }),\n    countryId: integer('country_id').references(() => countries.id),\n});\n","schema.ts",[39,47,44],{"__ignoreMap":37},[30,49,55],{"className":50,"code":52,"filename":53,"language":54,"meta":37},[51],"language-sql","-- generate migrations\nCREATE TABLE IF NOT EXISTS \"countries\" (\n    \"id\" serial PRIMARY KEY NOT NULL,\n    \"name\" varchar(256)\n);\n\nCREATE TABLE IF NOT EXISTS \"cities\" (\n    \"id\" serial PRIMARY KEY NOT NULL,\n    \"name\" varchar(256),\n    \"country_id\" integer\n);\n\nALTER TABLE \"cities\" ADD CONSTRAINT \"cities_country_id_countries_id_fk\" FOREIGN KEY (\"country_id\") REFERENCES \"countries\"(\"id\") ON DELETE no action ON UPDATE no action;\n\n","migration.sql","sql",[39,56,52],{"__ignoreMap":37},[23,58,60],{"start":59},2,[26,61,62],{},"可以在 serverless 环境中使用",[18,64,66],{"id":65},"怎么使用","怎么使用？",[68,69,70],"p",{},"这里我使用 Nirto 和 SQLite 演示",[72,73,74],"blockquote",{},[68,75,76],{},"Nitro 中使用文件路由，我们可以根据文件夹结构来生成指定路由",[10,78],{"className":79,"icon":81,"link":82,"title":83},[13,80],"active","https:\u002F\u002Fgithub.com\u002F\u002Ffavicon.ico","https:\u002F\u002Fgithub.com\u002FWhbbit1999\u002Fdrizzle-nitro","代码地址",[85,86,88],"h3",{"id":87},"创建-schema","创建 schema",[90,91,92],"h4",{"id":92},"env",[68,94,95],{},"记录 SQLite 文件名称，配置文件中使用",[30,97,103],{"className":98,"code":100,"filename":101,"language":102,"meta":37},[99],"language-dotenv","DATABASE_URL=file:local.db\n",".env","dotenv",[39,104,100],{"__ignoreMap":37},[90,106,108],{"id":107},"drizzleconfig","drizzle.config",[68,110,111],{},"drizzle 配置文件，说明 schema 和迁移文件所在位置",[30,113,117],{"className":114,"code":115,"filename":116,"language":36,"meta":37},[33],"import { defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n    dialect: \"sqlite\",\n    schema: \".\u002Fdb\u002Fschema\u002Findex.ts\",\n    out: \".\u002Fdb\u002Fmigrations\",\n    dbCredentials: {\n        url: process.env.DATABASE_URL,\n    },\n    verbose: true,\n    strict: true,\n    breakpoints: true,\n});\n","drizzle.config.ts",[39,118,115],{"__ignoreMap":37},[90,120,121],{"id":121},"schema",[68,123,124],{},"数据库模型",[30,126,130],{"className":127,"code":128,"filename":129,"language":36,"meta":37},[33],"import { InferSelectModel } from 'drizzle-orm'\nimport { int, sqliteTable, text } from \"drizzle-orm\u002Fsqlite-core\";\n\nexport const user = sqliteTable(\"user\", {\n    id: int(\"id\").primaryKey({ autoIncrement: true }),\n    username: text(\"username\").notNull(),\n    password: text(\"password\").notNull(),\n    email: text('email').unique().notNull(),\n})\n\nexport type User = InferSelectModel\u003Ctypeof user>\n","user.schema.ts",[39,131,128],{"__ignoreMap":37},[90,133,134],{"id":134},"db",[68,136,137],{},"导出 db 函数，供外部使用",[30,139,143],{"className":140,"code":141,"filename":142,"language":36,"meta":37},[33],"import { drizzle } from 'drizzle-orm\u002Flibsql\u002Fnode';\n\nimport * as schema from \".\u002Fschema\u002Findex\";\n\nconst db = drizzle({\n    connection: {\n        url: process.env.DATABASE_URL,\n        authToken: process.env.DATABASE_AUTH_TOKEN\n    },\n    schema,\n});\n\nexport { db }\n","db\u002Findex.ts",[39,144,141],{"__ignoreMap":37},[85,146,148],{"id":147},"api-编写","api 编写",[90,150,152],{"id":151},"增-usersindexpostts","增 users\u002Findex.post.ts",[30,154,157],{"className":155,"code":156,"language":36,"meta":37},[33],"import { db } from \"..\u002F..\u002F..\u002Fdb\"\nimport { user } from \"..\u002F..\u002F..\u002Fdb\u002Fschema\"\n\nexport default defineEventHandler(async (event) => {\n    const body = await readBody(event)\n\n    const [inserted] = await db.insert(user).values(body).returning()\n\n    return {\n        inserted\n    }\n})\n",[39,158,156],{"__ignoreMap":37},[90,160,162],{"id":161},"删-usersiddeletets","删 users\u002F[id].delete.ts",[30,164,167],{"className":165,"code":166,"language":36,"meta":37},[33],"import { eq } from \"drizzle-orm\"\n\nimport { db } from \"..\u002F..\u002F..\u002Fdb\"\nimport { user } from \"..\u002F..\u002F..\u002Fdb\u002Fschema\"\n\nexport default defineEventHandler(async (event) => {\n    const id = await getRouterParam(event, 'id')\n\n    if (!id) {\n        throw createError({ statusCode: 400, message: 'id is required' })\n    }\n\n    const result = await db.delete(user).where(eq(user.id, +id))\n    return {\n        result\n    }\n})\n",[39,168,166],{"__ignoreMap":37},[90,170,172],{"id":171},"改-usersidputts","改 users\u002F[id].put.ts",[30,174,177],{"className":175,"code":176,"language":36,"meta":37},[33],"import { eq } from \"drizzle-orm\"\n\nimport { db } from \"..\u002F..\u002F..\u002Fdb\"\nimport { user } from \"..\u002F..\u002F..\u002Fdb\u002Fschema\"\n\nexport default defineEventHandler(async (event) => {\n    const body = await readBody(event)\n    const id = getRouterParam(event, 'id')\n\n    if (!id) {\n        throw createError({ statusCode: 400, message: 'id is required' })\n    }\n\n    const [inserted] = await db.update(user).set(body).where(eq(user.id, +id)).returning()\n\n    return {\n        inserted\n    }\n})\n",[39,178,176],{"__ignoreMap":37},[90,180,181],{"id":181},"查",[68,183,184],{},"根据id 查询 users\u002F[id].get.ts",[30,186,189],{"className":187,"code":188,"language":36,"meta":37},[33],"import { db } from \"..\u002F..\u002F..\u002Fdb\"\n\nexport default defineEventHandler(async (event) => {\n    const id = getRouterParam(event, 'id')\n\n    const user = await db.query.user.findFirst({\n        where(fields, operators) {\n            return operators.eq(fields.id, +id);\n        },\n    })\n\n    return {\n        user\n    }\n})\n",[39,190,188],{"__ignoreMap":37},[68,192,193],{},"查询全部 users\u002Findex.get.ts",[30,195,198],{"className":196,"code":197,"language":36,"meta":37},[33],"import { db } from \"..\u002F..\u002F..\u002Fdb\"\n\nexport default defineEventHandler(async (event) => {\n    const user = await db.query.user.findMany()\n\n    return {\n        user\n    }\n})\n",[39,199,197],{"__ignoreMap":37},[18,201,203],{"id":202},"drizzle-kit-studio-的功能","drizzle-kit studio 的功能",[85,205,206],{"id":206},"查看数据",[68,208,209,210,213],{},"你可以使用 ",[39,211,212],{"code":212},"npx drizzle-kit studio"," 来在本地查看数据库表的情况，如下图所示",[68,215,216],{},[217,218],"img",{"alt":37,"src":219},"https:\u002F\u002Fbitmc.uno\u002Fpicgo\u002F67af0e702733a-78.webp",[85,221,223],{"id":222},"运行sql语句","运行SQL语句",[68,225,226],{},[217,227],{"alt":37,"src":228},"https:\u002F\u002Fbitmc.uno\u002Fpicgo\u002F67af0ed29b396-78.webp",[85,230,232],{"id":231},"在线编写-drizzle","在线编写 drizzle",[68,234,235],{},[217,236],{"alt":37,"src":237},"https:\u002F\u002Fbitmc.uno\u002Fpicgo\u002F67af0f36e041a-78.webp",[18,239,240],{"id":240},"常用代码片段",[85,242,244],{"id":243},"为所有的-schema-添加创建编辑删除时间","为所有的 schema 添加创建｜编辑｜删除时间",[30,246,250],{"className":247,"code":248,"filename":249,"language":36,"meta":37},[33],"import { boolean, integer, pgTable, timestamp, varchar } from \"drizzle-orm\u002Fpg-core\";\n\nexport const timestamps = {\n    createdAt: timestamp('created_at').notNull().defaultNow(),\n    updatedAt: timestamp('updated_at'),\n    deletedAt: timestamp('deleted_at'),\n}\n","global.schema.ts",[39,251,248],{"__ignoreMap":37},[253,254,255,261,268],"folding",{},[256,257,258],"template",{"v-slot:title":37},[68,259,260],{},"使用示例",[30,262,266],{"className":263,"code":264,"filename":265,"language":36,"meta":37},[33],"import { boolean, integer, pgTable, timestamp, varchar } from \"drizzle-orm\u002Fpg-core\";\nimport { createInsertSchema, createSelectSchema } from \"drizzle-zod\";\n\nimport { timestamps } from '.\u002Fglobal.schema.ts'\n\nexport const users = pgTable(\"users\", {\n    id: integer().primaryKey().generatedAlwaysAsIdentity(),\n    name: varchar({ length: 255 }).notNull(),\n    email: varchar({ length: 255 }).notNull().unique(),\n\n    ...timestamps\n});\n","users.schema.ts",[39,267,264],{"__ignoreMap":37},[30,269,273],{"className":270,"code":271,"filename":272,"language":36,"meta":37},[33],"import { boolean, integer, pgTable, text, timestamp, varchar } from \"drizzle-orm\u002Fpg-core\";\nimport { createInsertSchema, createSelectSchema } from \"drizzle-zod\";\n\nimport { timestamps } from '.\u002Fglobal.schema.ts'\n\nexport const posts = pgTable(\"posts\", {\n    id: integer().primaryKey().generatedAlwaysAsIdentity(),\n    title: varchar({ length: 255 }).notNull(),\n    content: text().notNull(),\n\n    ...timestamps\n});\n","posts.schema.ts",[39,274,271],{"__ignoreMap":37},{"title":37,"searchDepth":276,"depth":276,"links":277},4,[278,279,294,299],{"id":20,"depth":59,"text":21},{"id":65,"depth":59,"text":66,"children":280},[281,288],{"id":87,"depth":282,"text":88,"children":283},3,[284,285,286,287],{"id":92,"depth":276,"text":92},{"id":107,"depth":276,"text":108},{"id":121,"depth":276,"text":121},{"id":134,"depth":276,"text":134},{"id":147,"depth":282,"text":148,"children":289},[290,291,292,293],{"id":151,"depth":276,"text":152},{"id":161,"depth":276,"text":162},{"id":171,"depth":276,"text":172},{"id":181,"depth":276,"text":181},{"id":202,"depth":59,"text":203,"children":295},[296,297,298],{"id":206,"depth":282,"text":206},{"id":222,"depth":282,"text":223},{"id":231,"depth":282,"text":232},{"id":240,"depth":59,"text":240,"children":300},[301],{"id":243,"depth":282,"text":244},null,[304],"代码","2025-02-12 10:35:29","虽然 Drizzle ORM 还没有到 1.0，但是凭借其出色的性能，已经得到了不少的关注了。在它官网的基准测试里，比现在很火的 Prisma 快了好多。我们一起来看一下这个库如何使用吧！",false,"md","https:\u002F\u002Fbitmc.uno\u002Fpicgo\u002F67ac3e8a1817b-78.webp",{},true,"\u002Fposts\u002F2025\u002Fdrizzle.orm-use",{"text":314,"minutes":315,"time":316,"words":317},"4 min read",3.71,222600,742,{"title":5,"description":306},{"loc":312,"images":320},[321,322,323],{"loc":219},{"loc":228},{"loc":237},"posts\u002F2025\u002Fdrizzle.orm-use",[],"Oql-2IvZ3RXrfq3eB2ht31MIGT8BJbCGoKxBOVjxoCQ",[328,333],{"title":329,"path":330,"stem":331,"date":332,"type":302,"children":-1},"【翻译】如何优化 Vue 应用性能","\u002Fposts\u002F2025\u002Fhow-to-optimize-performance-in-vue-apps","posts\u002F2025\u002FHow To Optimize Performance In Vue Apps","2025-02-05 15:53:41",{"title":334,"path":335,"stem":336,"date":337,"type":302,"children":-1},"【翻译】构建 Pinia 插件进行跨标签页状态同步","\u002Fposts\u002F2025\u002Fbuilding-a-pinia-plugin-for-cross-tab-state-syncing","posts\u002F2025\u002Fbuilding-a-pinia-plugin-for-cross-tab-state-syncing","2025-02-14 11:32:59",1789642590414]