如何使用TypeORM处理React-Native中的SQLite迁移?

时间:2019-11-29 08:32:19

标签: typescript sqlite react-native typeorm react-native-sqlite-storage

我正在编写一个React-Native应用程序,该应用程序高度依赖本地存储,并选择TypeORM来处理此问题。

我现在正在进入一个项目正在运行的阶段,我想添加新功能,这些功能需要调整我的数据模型。首先,我使用了react-native-example项目。我已经在此基础上建立了数据模型,现在想对其进行移植。

关于如何在React-Native上执行迁移,似乎没有权威的手册/指南。 由于我无权访问用户的数据库,因此无法手动运行迁移。到目前为止,我发现连接设置中有一个“ migrationsRun”选项,可以将其设置为true,从而在需要启动应用程序时强制执行迁移。

然后的问题是:应该如何创建实际的迁移,它们的外观如何(普通sql查询?),我应该在哪里放置它们?

任何有关本机应用程序中迁移的指南都将非常有帮助。

1 个答案:

答案 0 :(得分:4)

我遇到了同样的问题,并通过提供以下属性作为createConnection选项,设法使迁移在React Native上下文中运行:

  • 同步:false
  • migrationsRun:true
  • 迁移:[migrationFile]

migrationFile是直接导入的(而不是使用文件路径正则表达式),其外观类似于以下内容(带有内联SQL语句):

import { MigrationInterface } from 'typeorm'

module.exports = class PostRefactoring1579804977343 implements MigrationInterface {
  async up(queryRunner) {
    await queryRunner.query(`ALTER TABLE "workouts" ADD COLUMN "questionSetId" text`)
  }

  async down(queryRunner) {
    await queryRunner.query(`ALTER TABLE "workouts" DROP COLUMN "questionSetId"`)
  }
}

上面的迁移文件看起来与您在https://typeorm.io/#/migrations上看到的示例略有不同,因为我没有使用TypeScript,而且在直接导入文件时必须添加module.exports

主要(几乎)未记录的发现,似乎使它可以在本机中工作,是我在这里reactnativeconnectionoptions发现的神奇的migrationsRun

您可以根据需要将更多的迁移文件随时间添加到migrations阵列配置中,并确保为它们提供具有适当时间戳的唯一类名称。似乎保留了已运行迁移的设备日志-阻止它们在同一设备上运行多次

注意:具有synchronize: false的要求意味着您将需要在首次安装应用程序时进行模式的初始同步(我最初使用AsyncStorage中的标志将其设置为指示首次安装应用程序)< / p>

替代方法

以上方法意味着我们将在初始用户安装后手动维护架构设置。而我非常喜欢在可能的情况下自动管理架构的想法-迁移仅用于处理数据。

因此,实现此目标的另一种方法是在初始化连接时直接调用synchronizerunMigrations方法。在这种情况下,您将需要首先检查迁移脚本中是否存在特定的表,因为它们将首先运行,因此,如果这是用户在安装后第一次打开应用程序,则需要更新的表可能不存在

连接选项:

export const initialiseDataStoreService = async () => {
  const connection = await createConnection({
    type: 'react-native',
    database: 'main.sqlite',
    location: 'default',
    logging: [ 'error', 'schema'],
    entities: [
      CoreData,
      Workouts,
    ],
    migrations: [PostRefactoring1579804977343],
  })

  await connection.runMigrations()
  await connection.synchronize()

  return connection
}

更新的迁移脚本:

import { MigrationInterface, TableColumn } from 'typeorm'

module.exports = class PostRefactoring1579804977343 implements MigrationInterface {
  async up(queryRunner) {
    const hasWorkoutsTable = await queryRunner.hasTable('workouts')
    if (hasWorkoutsTable) {
      await queryRunner.addColumn(
        'workouts',
        new TableColumn({
          name: 'questionSetId',
          type: 'text',
          // we make the new field nullable in order to enable the update
          // for existing data (schema sync will later update this column to be non
          // nullable)
          isNullable: true,
        }),
      )
      await queryRunner.query(
        `UPDATE workouts SET questionSetId = "MIGRATION-PLACEHOLDER" WHERE questionSetId IS NULL`,
      )
    }
  }

  async down(queryRunner) {
    const hasWorkoutsTable = await queryRunner.hasTable('workouts')
    if (hasWorkoutsTable) {
      await queryRunner.dropColumn('workouts', 'questionSetId')
    }
  }
}