DrizzleORM v0.28.0 发布
Aug 6, 2023

Breaking changes(重大变更)

删除了对嵌套关系的过滤支持

0.28.0 版本中,以下示例将无法使用:

const usersWithPosts = await db.query.users.findMany({
  where: (table, { sql }) => (sql`json_array_length(${table.posts}) > 0`),
  with: {
    posts: true,
  },
});

where 回调中的 table 对象不会包含来自 withextras 的字段。我们删除了这些字段,以便能够构建更高效的关系查询,从而改进了行读取和性能。

如果在之前的 where 回调中使用了这些字段,有几种解决方法:

  1. 在代码级别手动应用这些过滤器到获取到的行后;
  2. 使用核心 API。

为 mysql2 驱动添加了关系查询模式 config

Drizzle 关系查询始终生成一条要在数据库上运行的 SQL 语句,其中有一些限制。为了最好地支持每个数据库,我们引入了模式。

Drizzle 关系查询在内部使用子查询的 Lateral Join,并且目前 PlanetScale 不支持它们。

当使用普通 MySQL 数据库的 mysql2 驱动时 - 您应该指定 mode: “default”。 当使用 PlanetScale 的 mysql2 驱动时 - 您需要指定 mode: “planetscale”。

import { drizzle } from 'drizzle-orm/mysql2';
import mysql from 'mysql2/promise';
import * as schema from './schema';

const connection = await mysql.createConnection({
  uri: process.env.PLANETSCALE_DATABASE_URL,
});

const db = drizzle(connection, { schema, mode: 'planetscale' });

改进了大型模式的 IntelliSense 性能

我们对一个包含 85 个表、666 个列、26 个枚举、172 个索引和 133 个外键的数据库模式运行了诊断。我们优化了内部类型,导致 IntelliSense 的速度提高了 430%

改进了关系查询性能和读取使用情况

在这个版本中,我们完全改变了关系查询 API 生成查询的方式。

总结一下,我们在查询生成策略中进行了以下改变:

  1. Lateral Join:在新版本中,我们使用由 “LEFT JOIN LATERAL” 子句表示的 Lateral Join,高效地从相关表中检索特定数据。对于在 PlanetScale 和 SQLite 中使用的 MySQL,我们使用简单的子查询选择,从而改进了查询计划和整体性能。

  2. 选择性数据检索:在新版本中,我们只检索表中必要的数据。这种有针对性的数据检索减少了获取不必要信息的数量,从而减少了要处理的数据集大小,并加快了执行速度。

  3. 减少聚合:在新版本中,我们减少了聚合函数的数量(例如 COUNT,json_agg)。通过直接在 Lateral Join 中使用 json_build_array,Drizzle 以更流畅的方式聚合数据,从而改进了查询性能。

  4. 简化分组:在新版本中,删除了 GROUP BY 子句,因为 Lateral Join 和子查询已经更有效地处理了数据聚合。

针对这个 Drizzle 查询

const items = await db.query.comments.findMany({
  limit,
  orderBy: comments.id,
  with: {
    user: {
      columns: { name: true },
    },
    post: {
      columns: { title: true },
      with: {
        user: {
          columns: { name: true },
        },
      },
    },
  },
});
-- 现在生成的查询
select "comments"."id",
       "comments"."user_id",
       "comments"."post_id",
       "comments"."content",
       "comments_user"."data" as "user",
       "comments_post"."data" as "post"
from "comments"
         left join lateral (select json_build_array("comments_user"."name") as "data"
                            from (select *
                                  from "users" "comments_user"
                                  where "comments_user"."id" = "comments"."user_id"
                                  limit 1) "comments_user") "comments_user" on true
         left join lateral (select json_build_array("comments_post"."title", "comments_post_user"."data") as "data"
                            from (select *
                                  from "posts" "comments_post"
                                  where "comments_post"."id" = "comments"."post_id"
                                  limit 1) "comments_post"
                                     left join lateral (select json_build_array("comments_post_user"."name") as "data"
                                                        from (select *
                                                              from "users" "comments_post_user"
                                                              where "comments_post_user"."id" = "comments_post"."user_id"
                                                              limit 1) "comments_post_user") "comments_post_user"
                                               on true) "comments_post" on true
order by "comments"."id"
limit 1
-- 以前生成的查询
SELECT "id",
       "user_id",
       "post_id",
       "content",
       "user"::JSON,
       "post"::JSON
FROM
  (SELECT "comments".*,
          CASE
              WHEN count("comments_post"."id") = 0 THEN '[]'
              ELSE json_agg(json_build_array("comments_post"."title", "comments_post"."user"::JSON))::text
          END AS "post"
   FROM
     (SELECT "comments".*,
             CASE
                 WHEN count("comments_user"."id") = 0 THEN '[]'
                 ELSE json_agg(json_build_array("comments_user"."name"))::text
             END AS "user"
      FROM "comments"
      LEFT JOIN
        (SELECT "comments_user".*
         FROM "users" "comments_user") "comments_user" ON "comments"."user_id" = "comments_user"."id"
      GROUP BY "comments"."id",
               "comments"."user_id",
               "comments"."post_id",
               "comments"."content") "comments"
   LEFT JOIN
     (SELECT "comments_post".*
      FROM
        (SELECT "comments_post".*,
                CASE
                    WHEN count("comments_post_user"."id") = 0 THEN '[]'
                    ELSE json_agg(json_build_array("comments_post_user"."name"))
                END AS "user"
         FROM "posts" "comments_post"
         LEFT JOIN
           (SELECT "comments_post_user".*
            FROM "users" "comments_post_user") "comments_post_user" ON "comments_post"."user_id" = "comments_post_user"."id"
         GROUP BY "comments_post"."id") "comments_post") "comments_post" ON "comments"."post_id" = "comments_post"."id"
   GROUP BY "comments"."id",
            "comments"."user_id",
            "comments"."post_id",
            "comments"."content",
            "comments"."user") "comments"
LIMIT 1

了解更多关于关系查询的信息,请参阅文档。

可以插入包含所有列默认值的行

现在,您可以提供一个空对象或一个包含空对象的数组,Drizzle 将会将所有默认值插入到数据库中。

// 插入一行,包含所有默认值
await db.insert(usersTable).values({});

// 插入两行,包含所有默认值
await db.insert(usersTable).values([{}, {}]);
Become a Gold Sponsor