自從我開始開發我的第一個專案(我的 OT Pokémon 和 Habbo 的第一個網站)以來,我一直選擇 Raw SQL。老實說,我仍然非常喜歡編寫自己的查詢並更精確地控制這個「低級」層。 ORM 並不讓我完全放心,因為我已經花了幾天時間分析日誌來識別和優化低效查詢。
但是,在我使用 Raw SQL 的許多程式碼庫中,絕大多數沒有遷移控制,而且資料庫也沒有受到監控。一切都在即興創作的基礎上進行:「您需要一個新字段嗎?運行ALTER TABLE 並添加一個新列。」這種方法在所有場景下都是極其有害的,出現了幾個問題,例如:“我們應該在生產環境中上哪些列?”,“創建了哪些新實體?”,“環境是否同步?” - 以及許多其他類似的問題。
我的問題的解決方案
面對所有這些問題,我決定採用新的工具來讓我和與我一起工作的團隊的日常工作變得更健康。我不想放棄我所擁有的靈活性,但我也想更好地控制應用程式的自由度。經過大量研究,我發現了一個我認為最完整的解決這些問題的工具:Kysely,它是TypeScript 的查詢構建器,除了實用之外,還是完全類型安全的—對我來說非常重要的一點。這個函式庫引起了我的注意,以至於我開始直接和間接地積極為社群做出貢獻,為與 Kysely 整合的其他開源函式庫創建插件。
然而,使用 Kysely 時最大的困難之一是,與 ORM 不同,它沒有實體或自動產生類型/介面。所有這些工作都需要手動完成,這可能有點累人。在研究解決方案的過程中,我發現了一個最終在所有涉及 PostgreSQL 的專案中採用的工具:Kanel。 Kanel 自動產生資料庫類型,完美補充了 Kysely。
此外,Kanel 還有一個可以直接與 Kysely 一起使用的附加功能:Kanel-Kysely。我一直在積極為這個儲存庫做出貢獻,幫助開發新功能,例如遷移表的類型過濾器以及 Zod 物件到駝峰命名法的轉換。
配置 Kysely
我將使用 NestJS 來說明以下範例。因此,如果您不理解某些語法或程式碼中的某些內容,我建議您閱讀 NestJS 文件。在我看來,它是最好的 JavaScript 框架——特別是如果你想「逃避」JavaScript。但這是我另一篇文章的主題。
如果您想嚴格遵循範例,您需要先初始化一個帶有 NestJS 的儲存庫。不過,您也可以開發自己的程式碼。
首先,我們需要安裝 Kysely 本身、它的 CLI 和 Node.js 的 PostgreSQL 模組。
npm i kysely pg && npm i kysely-ctl --save-dev
接下來,我們需要在專案的根目錄中為 Kysely 建立一個設定檔。我還將為我們的遷移和種子檔案使用 Knex 前綴。
// kysely.config.ts import "dotenv/config"; import { defineConfig, getKnexTimestampPrefix } from "kysely-ctl"; import { Pool } from "pg"; export default defineConfig({ dialect: "pg", dialectConfig: { pool: new Pool({ connectionString: process.env.DATABASE_URL }), }, migrations: { migrationFolder: "src/database/migrations", getMigrationPrefix: getKnexTimestampPrefix, }, seeds: { seedFolder: "src/database/seeds", getSeedPrefix: getKnexTimestampPrefix, }, });
接下來,我們將在終端機中執行指令 npx kysely migrate make create_user_table。它將負責創建我們的第一個遷移。接下來,我們將建立一個新的使用者表,完成後,我們將使用命令 npx kysely migratelatest.
在資料庫中執行此遷移
// 20241225222128_create_user_table.ts import { sql, type Kysely } from 'kysely' export async function up(db: Kysely<any>): Promise<void> { await db.schema .createTable("user") .addColumn("id", "serial", (col) => col.primaryKey()) .addColumn("name", "text", (col) => col.notNull()) .addColumn("email", "text", (col) => col.unique().notNull()) .addColumn("password", "text", (col) => col.notNull()) .addColumn("created_at", "timestamp", (col) => col.defaultTo(sql`now()`).notNull(), ) .execute(); } export async function down(db: Kysely<any>): Promise<void> { await db.schema.dropTable("user").execute(); } </void></any></void></any>
完成所有這些步驟後,讓我們為我們的資料庫建立一個模組。另請注意,我正在使用 Kysely 外掛程式將我們的列轉換為駝峰命名法。
// src/database/database.module.ts import { EnvService } from "@/env/env.service"; import { Global, Logger, Module } from "@nestjs/common"; import { CamelCasePlugin, Kysely, PostgresDialect } from "kysely"; import { Pool } from "pg"; export const DATABASE_CONNECTION = "DATABASE_CONNECTION"; @Global() @Module({ providers: [ { provide: DATABASE_CONNECTION, useFactory: async (envService: EnvService) => { const dialect = new PostgresDialect({ pool: new Pool({ connectionString: envService.get("DATABASE_URL"), }), }); const nodeEnv = envService.get("NODE_ENV"); const db = new Kysely({ dialect, plugins: [new CamelCasePlugin()], log: nodeEnv === "dev" ? ["query", "error"] : ["error"], }); const logger = new Logger("DatabaseModule"); logger.log("Successfully connected to database"); return db; }, inject: [EnvService], }, ], exports: [DATABASE_CONNECTION], }) export class DatabaseModule {}
配置 Kanel
讓我們從安裝依賴項開始。
npm i kanel kanel-kysely --save-dev
接下來,讓我們為 Kanel 建立設定檔以開始工作。請注意,我將使用一些插件,例如camelCaseHook(將我們的介面轉換為camelCase)和kyselyTypeFilter(以排除Kysely的遷移表),我很高興能夠貢獻這些功能之一,並使我們的工作甚至更容易。
// .kanelrc.js require("dotenv/config"); const { kyselyCamelCaseHook, makeKyselyHook, kyselyTypeFilter } = require("kanel-kysely"); /** @type {import('kanel').Config} */ module.exports = { connection: { connectionString: process.env.DATABASE_URL, }, typeFilter: kyselyTypeFilter, preDeleteOutputFolder: true, outputPath: "./src/database/schema", preRenderHooks: [makeKyselyHook(), kyselyCamelCaseHook], };
建立檔案後,我們將在終端機中執行指令 npx kanel。請注意,在設定檔中指定的路徑中建立了一個目錄。此目錄對應於您的架構的名稱,在我們的範例中為Public,其中我們有兩個新檔案:PublicSchema.ts 和User.ts 。您的 User.ts 可能看起來完全像這樣:
// @generated // This file is automatically generated by Kanel. Do not modify manually. import type { ColumnType, Selectable, Insertable, Updateable } from 'kysely'; /** Identifier type for public.user */ export type UserId = number & { __brand: 'UserId' }; /** Represents the table public.user */ export default interface UserTable { id: ColumnType<userid userid undefined>; name: ColumnType<string string>; email: ColumnType<string string>; password: ColumnType<string string>; createdAt: ColumnType<date date string undefined>; } export type User = Selectable<usertable>; export type NewUser = Insertable<usertable>; export type UserUpdate = Updateable<usertable>; </usertable></usertable></usertable></date></string></string></string></userid>
不過,最重要的是這個目錄之外的檔案Public,檔案Database.ts,因為我們要傳遞的正是這個,以便Kysely能夠理解我們資料庫的整個結構。在我們的檔案 app.service.ts 中,我們將注入 DatabaseModule 提供者並將我們的類型 Database.
傳遞給 Kysely
npm i kysely pg && npm i kysely-ctl --save-dev
請注意,Kanel 產生的類型運作正常,因為我們的程式碼編輯器將準確建議我們在第一次遷移中建立的欄位。
最後的考慮因素
這是我非常喜歡在我的個人專案甚至工作中使用的組合(當我有自由這樣做時)。對於喜歡原始 SQL 提供的靈活性但也選擇「更安全」路徑的每個人來說,查詢產生器都是必不可少的工具。 Kanel 還為我節省了許多時間的調試和創建新類型的時間。我強烈建議你用這兩個創建一個項目,你絕對不會後悔的。
儲存庫連結: Frankenstein-nodejs
以上是基斯利·卡內爾 (Kisley Kanel):完美二人組的詳細內容。更多資訊請關注PHP中文網其他相關文章!

C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

JavaScript在Web開發中的主要用途包括客戶端交互、表單驗證和異步通信。 1)通過DOM操作實現動態內容更新和用戶交互;2)在用戶提交數據前進行客戶端驗證,提高用戶體驗;3)通過AJAX技術實現與服務器的無刷新通信。

理解JavaScript引擎內部工作原理對開發者重要,因為它能幫助編寫更高效的代碼並理解性能瓶頸和優化策略。 1)引擎的工作流程包括解析、編譯和執行三個階段;2)執行過程中,引擎會進行動態優化,如內聯緩存和隱藏類;3)最佳實踐包括避免全局變量、優化循環、使用const和let,以及避免過度使用閉包。

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SublimeText3 Linux新版
SublimeText3 Linux最新版

VSCode Windows 64位元 下載
微軟推出的免費、功能強大的一款IDE編輯器

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Dreamweaver Mac版
視覺化網頁開發工具

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中