搜索
首页web前端js教程基斯利·卡内尔 (Kisley Kanel):完美二人组

自从我开始开发我的第一个项目(我的 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.tsUser.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 生成的类型工作正常,因为我们的代码编辑器将准确建议我们在第一次迁移中创建的列。

Kysely   Kanel: a dupla perfeita

最后的考虑因素

这是我非常喜欢在我的个人项目甚至工作中使用的组合(当我有自由这样做时)。对于喜欢原始 SQL 提供的灵活性但也选择“更安全”路径的每个人来说,查询生成器都是必不可少的工具。 Kanel 还为我节省了许多时间的调试和创建新类型的时间。我强烈建议你用这两个创建一个项目,你绝对不会后悔的。

存储库链接: Frankenstein-nodejs

以上是基斯利·卡内尔 (Kisley Kanel):完美二人组的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
从网站到应用程序:JavaScript的不同应用从网站到应用程序:JavaScript的不同应用Apr 22, 2025 am 12:02 AM

JavaScript在网站、移动应用、桌面应用和服务器端编程中均有广泛应用。1)在网站开发中,JavaScript与HTML、CSS一起操作DOM,实现动态效果,并支持如jQuery、React等框架。2)通过ReactNative和Ionic,JavaScript用于开发跨平台移动应用。3)Electron框架使JavaScript能构建桌面应用。4)Node.js让JavaScript在服务器端运行,支持高并发请求。

Python vs. JavaScript:比较用例和应用程序Python vs. JavaScript:比较用例和应用程序Apr 21, 2025 am 12:01 AM

Python更适合数据科学和自动化,JavaScript更适合前端和全栈开发。1.Python在数据科学和机器学习中表现出色,使用NumPy、Pandas等库进行数据处理和建模。2.Python在自动化和脚本编写方面简洁高效。3.JavaScript在前端开发中不可或缺,用于构建动态网页和单页面应用。4.JavaScript通过Node.js在后端开发中发挥作用,支持全栈开发。

C/C在JavaScript口译员和编译器中的作用C/C在JavaScript口译员和编译器中的作用Apr 20, 2025 am 12:01 AM

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

JavaScript在行动中:现实世界中的示例和项目JavaScript在行动中:现实世界中的示例和项目Apr 19, 2025 am 12:13 AM

JavaScript在现实世界中的应用包括前端和后端开发。1)通过构建TODO列表应用展示前端应用,涉及DOM操作和事件处理。2)通过Node.js和Express构建RESTfulAPI展示后端应用。

JavaScript和Web:核心功能和用例JavaScript和Web:核心功能和用例Apr 18, 2025 am 12:19 AM

JavaScript在Web开发中的主要用途包括客户端交互、表单验证和异步通信。1)通过DOM操作实现动态内容更新和用户交互;2)在用户提交数据前进行客户端验证,提高用户体验;3)通过AJAX技术实现与服务器的无刷新通信。

了解JavaScript引擎:实施详细信息了解JavaScript引擎:实施详细信息Apr 17, 2025 am 12:05 AM

理解JavaScript引擎内部工作原理对开发者重要,因为它能帮助编写更高效的代码并理解性能瓶颈和优化策略。1)引擎的工作流程包括解析、编译和执行三个阶段;2)执行过程中,引擎会进行动态优化,如内联缓存和隐藏类;3)最佳实践包括避免全局变量、优化循环、使用const和let,以及避免过度使用闭包。

Python vs. JavaScript:学习曲线和易用性Python vs. JavaScript:学习曲线和易用性Apr 16, 2025 am 12:12 AM

Python更适合初学者,学习曲线平缓,语法简洁;JavaScript适合前端开发,学习曲线较陡,语法灵活。1.Python语法直观,适用于数据科学和后端开发。2.JavaScript灵活,广泛用于前端和服务器端编程。

Python vs. JavaScript:社区,图书馆和资源Python vs. JavaScript:社区,图书馆和资源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

Atom编辑器mac版下载

Atom编辑器mac版下载

最流行的的开源编辑器

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。