2021.11 v1.15

十一月份的改动主要围绕项目实际使用中遇到的问题修复,许多和十月份更新的 TypeScript 声明文件有关,也有一些新增的特性比如精度更高的 duration 计时、开发环境执行效率更高的 model.sync({ force }) 等等。

预计十二月底发布 v2.x 版本,敬请期待 :-)

时间戳

Leoric 默认会根据模型定义开启或者关闭时间戳相关功能,主要有三个字段:

其中 createdAt、updatedAt 要更为出名一些,Sequelize 还支持 Model.init(attributes, { timestamps: true }) 来快速声明这两个字段。deletedAt 主要与软删除有关,在 Leoric 中,只要有这个字段即默认开启软删除。

十一月的改动主要是加上了下划线风格的属性名,如果模型定义的字段名是 created_at、updated_at,Leoric 也会认为它们俩是时间戳字段,并开启相关的自动更新逻辑。

logQuery & logQueryError

本月有三个相关改动:

v1.15.x 版本的 logQuery(sql, duration) 将返回精度更高的 duration 字段,便于准确记录查询耗时以及相关性能优化。

breaking change 将在 v2.x 版本发布,主要是将 logQueryError(sql, err, duration, options) 改成 logQueryError(err, sql, duration, options),调整了一下 err 参数位置,更加符合 Node.js 传统风格。

model.sync({ force | alter })

另一个将在 v2.x 版本发布的改动是 model.sync() 的入参变化,v1.x 版本中默认采取的逻辑是 model.sync({ alter }),大致描述如下:

v2.x 修改之后,将有三种同步模式:

相关代码改动:

联表查询的条件过滤

执行联表查询时,条件过滤一般有如下几种情况:

原先的处理逻辑有个“优化”,会提取查询条件中与主表有关的,并将它们放到专门的 subquery,再基于这个子集作关联查询。这个方案理论上能够优化查询时间,实际使用中也能够应对 1、3,但是遇到第 2 种情况可能导致返回的数据不足,例如:

await Post.bulkCreate([
  { id: 2, title: 'Archbishop Lazarus' },
  { id: 3, title: 'Archangel Tyrael' },
]);

await Comment.bulkCreate([
  { articleId: 2, content: 'foo' },
  { articleId: 2, content: 'bar' },
  { articleId: 3, content: 'baz' },
]);

如果遇到这样的查询条件:

await Post.include('comments').order('posts.id').where({
  'posts.title': { $like: 'Arch%' },
  'comments.content': 'baz',
});

生成的 SQL 将过早过滤数据,导致查询不到正确结果:

   SELECT `posts`.*, `comments`.*
     FROM (
       SELECT *
         FROM `articles`
        WHERE `title` LIKE 'Arch%'
          AND `gmt_deleted` IS NULL
        LIMIT 1) AS `posts`
LEFT JOIN `comments` AS `comments`
       ON `posts`.`id` = `comments`.`article_id`
      AND `comments`.`gmt_deleted` IS NULL
    WHERE `comments`.`content` = 'baz'

本月移除了这项优化,确保遇到上述几种情况时,至少主表的返回条数是正确的,关联表的查询结果则视查询条件和 LIMIT 而定。

TypeScript 声明文件

十月份更新的 .d.ts 声明文件在 cnpmcore 等实际应用中使用时发现许多问题,都已修复并记录到 test/types 测试用例中,相关改动包括:

中间纠结过 .d.ts 文件的修复应该算 fix 还是 docs,从 TypeScript 应用使用的角度,如果 .d.ts 有问题,会直接影响应用编译,因此最后还是觉得应该算 fix 而非 docs

仍然有不少用法还没有在 .d.ts 文件中列出,十二月份将作补充。

Model.findOne()

Model.findOne() 在查询不到结果的时候,原先的范围可能是 null 也可能是 undefined,为了简化应用代码的处理逻辑,我们将无结果时的返回值固定为 null。

Model.bulkCreate([])