TypeORM:迁移然后生成新的迁移?

TypeORM:迁移然后生成新的迁移?,typeorm,Typeorm,这可能是一个愚蠢的问题,但对我来说似乎是一个合理的用例(除非我遗漏了一些明显的错误)。这就是我所处的位置: 在生产中,我希望通过环境变量提供数据库连接参数,以连接到非现场托管的数据库(例如在AWS中) 在生产中,我需要能够使用TypeORM CLI轻松地将迁移应用于数据库(TypeORM迁移:运行) 在开发过程中,我希望提供一个docker compose.yml文件,以便新开发人员可以使用docker compose up-d快速创建我的应用程序的工作副本,并快速查看代码更改的结果(我仍在开

这可能是一个愚蠢的问题,但对我来说似乎是一个合理的用例(除非我遗漏了一些明显的错误)。这就是我所处的位置:

  • 在生产中,我希望通过环境变量提供数据库连接参数,以连接到非现场托管的数据库(例如在AWS中)
  • 在生产中,我需要能够使用TypeORM CLI轻松地将迁移应用于数据库(
    TypeORM迁移:运行
  • 在开发过程中,我希望提供一个
    docker compose.yml
    文件,以便新开发人员可以使用
    docker compose up-d
    快速创建我的应用程序的工作副本,并快速查看代码更改的结果(我仍在开发一个解决方案,以监视更改并重新编译,因为我的应用程序是用TypeScript编写的,必须先构建,然后才能运行)
  • 对于我的单元测试,我希望构建一个空数据库,以便在每个测试中用硬编码数据填充它(确保测试的幂等性和一致性),并且我希望这些测试具有高性能和低成本
  • 在开发过程中,我希望能够使用TypeORM CLI轻松创建迁移(
    TypeORM migration:generate
    )--这就是我遇到的问题

在生产环境中,默认情况下TypeORM将从环境变量中读取数据,因此这在开箱即用的情况下工作得很好。我甚至可以运行
TypeORM迁移:run
,并且假设连接参数正确,它就可以工作

因为我正在使用Docker Compose来加速开发中应用程序的工作副本,所以我可以在
Docker Compose.yml
文件中提供环境变量,以便我的应用程序可以连接到Docker中的数据库。这很好——仍然使用环境变量处理所有事情

对于单元测试,我像这样将TypeORM集成到我的应用程序中(这是一个HapiJS插件):

现在在我的单元测试中,我只是简单地将
useInMemoryDb
设置为true,它将忽略环境变量,而是启动一个内存中的Sqlite数据库。由于它在内存中,所以性能非常好,但它可以容纳的数据量有限,并且缺乏持久性——这两个问题对于单元测试来说都无关紧要。因为qlite而不是MySQL,它将我限制为SQL操作的一个子集,但这很好——我们只是记录哪些功能不受支持,并确保开发人员遵守SQL规范

现在讨论创建迁移的问题

如果我在开发机器上键入
typerm migration:generate
,它将失败,因为没有连接选项(没有设置环境变量)。奇怪的是,我尝试创建一个
.env
文件来设置环境变量,但typerm没有读取该文件(我仍然收到一个“未找到连接选项”错误)。我可以通过创建一个
或mconfig.json
文件来解决这个问题。但是这是我遇到的一个障碍

因为我正在使用Docker Compose来运行开发中的应用程序,所以数据库位于一个临时容器中,没有公开的端口,当有人试图创建迁移时,这些端口甚至可能不会运行。因此,
或mconfig.json
文件必须指向我可以保证存在于开发环境中的某个对象我不能相信开发人员已经安装了MySQL、Postgres或其他任何东西,所以我选择使用Sqlite

如果我使用内存中的Sqlite数据库并设置
synchronize:true
,则不会创建任何迁移,因为该数据库始终与我的模型定义匹配。如果我使用内存中的Sqlite数据库并设置
synchronize:false
,则创建的迁移包括所有表和列,而不仅仅是新表和列。我需要d执行
迁移:在执行
迁移:生成
之前运行
,但是如果我只是将类似
类型化迁移:运行&&typeorm迁移:生成
的内容放入我的NPM脚本中,那么当
迁移:运行
完成运行和
迁移时,Sqlite数据库已经被销毁:生成
开始

我考虑在磁盘上写入Sqlite数据库,并在完成后将其清理干净(例如
类型迁移:运行和类型迁移:生成和管理tmpdb
)但我不喜欢
或mconfig.json
在磁盘上指定一个文件的想法,因为该文件需要在
.gitignore
中排除,并且可能是由一次性代码执行意外创建的(例如,有人在不使用Docker Compose的情况下运行应用程序)

我也不喜欢这样,我只想为这个特定用例(生成迁移)启动一个单用途数据库,但为了让CLI找到配置选项,我必须在全局配置文件中指定它们(
ormconfig.json
)--这让人感觉很不舒服。一个一次性的用例应该使用一次性的解决方案,而不是那些有着天知道有多少副作用的东西



那么,有没有解决这个一般性问题的方法呢?我希望能够根据我的模型定义和现有迁移生成迁移,而不管运行
migration:generate
时是否存在数据库。

问题:我注意到,当使用Sqlite作为驱动程序向表中添加列时,TypeORM会创建一个临时表并复制所有数据,而不是仅仅运行
ALTER table
。因此,我认为理想的解决方案是使用MySQL(可能是旋转Docker容器,在那里生成迁移,然后销毁它?)实际上,我刚刚意识到从Sqlite数据库生成的迁移与MySQL完全不兼容。这对我来说似乎有点奇怪,因为我认为SQL是标准化的,但这确实意味着使用Sqlite
import * as path from "path";
import * as Hapi from "@hapi/hapi";
import {createConnection, getConnectionOptions} from "typeorm";

export default {
    name: "TypeORM",
    version: "1.0.0",
    register: async function (server:Hapi.Server, options:Hapi.ServerRegisterOptions)
    {
        const connectionOptions = await getConnectionOptions();

        Object.assign(connectionOptions, {
            entities: [path.join(__dirname, "../models/**/*")],
            migrations: [path.join(__dirname, "../migrations/**/*")],
            // subscribers: [path.join(__dirname, "../subscribers/**/*")],
            synchronize: false
        });

        if ((options as any).useInMemoryDb)
        {
            console.log("Switching to in-memory database for unit testing");

            Object.assign(connectionOptions, {
                type: "sqlite",
                host: null,
                port: null,
                username: null,
                password: null,
                database: ":memory:",
                synchronize: true
            });
        }

        const connection = await createConnection(connectionOptions);

        server.decorate("server", "getConnectionManager", () => connection.manager);
        server.decorate("server", "getConnection", () => connection);
    }
};