类型ORM列类型取决于数据库



>我有简单的实体

@Entity()
export class File {
    @PrimaryGeneratedColumn()
    id: number;
    @Column({type: "mediumblob"})
    data: Buffer;
}

我想在生产中使用Mysql("mediumblob",因为我想存储10MB文件(。

我也想运行集成测试,但有sqlite但它只支持"blob"。

然后我想要这样的测试:

describe("CR on File and blobs", () => {
    it("should store arbitrary binary file", async (done) => {
        const conn = await createConnection({
            type: "sqlite",
            database: ":memory:",
            entities: ["src/models/file.ts"],
            synchronize: true
        });
        const fileRepo = await conn.getRepository(File);
        fileRepo.createQueryBuilder("file")
            .where("file.id == :id", {id: 1})
            .select([
                "file.data"
            ])
            .stream();
        done();
    });
});

当我运行这样的代码时,我收到这样的错误 DataTypeNotSupportedError: Data type "mediumblob" in "File.data" is not supported by "sqlite" database.

如果我将列类型更改为blob那么mysql上传文件时出现以下错误116kb QueryFailedError: ER_DATA_TOO_LONG: Data too long for column 'data' at row 1

是否有可能以某种方式生成某种逻辑/映射来解决mysql/sqlite的不兼容性,以便"blob"用于sqlite"mediumblob"用于mysql

我们可以在@Column之上创建一个简单的装饰器,@DbAwareColumn。新的修饰器根据环境更正列类型。我希望您将sqlite用于测试环境

import { Column, ColumnOptions, ColumnType } from 'typeorm';
const mysqlSqliteTypeMapping: { [key: string]: ColumnType } = {
  'mediumtext': 'text',
  'timestamp': 'datetime',
  'mediumblob': 'blob'
};
export function resolveDbType(mySqlType: ColumnType): ColumnType {
  const isTestEnv = process.env.NODE_ENV === 'test';
  if (isTestEnv && mySqlType in mysqlSqliteTypeMapping) {
    return mysqlSqliteTypeMapping[mySqlType.toString()];
  }
  return mySqlType;
}
export function DbAwareColumn(columnOptions: ColumnOptions) {
  if (columnOptions.type) {
    columnOptions.type = resolveDbType(columnOptions.type);
  }
  return Column(columnOptions);
}

在实体中,我们可以将其用作

@Entity({name: 'document'})
export class Document {
  @DbAwareColumn({ name: 'body', type: 'mediumtext'})
  body: string;
  @DbAwareColumn({type: "mediumblob"})
  data: Buffer;
  @DbAwareColumn({type: "timestamp"})
  createdAt: Date;
}

我遇到了类似的问题。我正在使用Postgres,并希望使用SQLite进行单元测试。

@Hung的答案基本上就是我想要的。

但是,我在默认值旁边使用 JSON 类型,所以我不得不在那里添加一些改进。

我在这里发布它是为了与你分享,我希望它对其他人有用。

const Env = {isTest: process.env.NODE_ENV === 'test'};
function resolveType(type: ColumnType): ColumnType {
  if (!Env.isTest) return type;
  if (type === 'timestamp') return 'datetime';
  if (type === 'mediumblob') return 'blob';
  if (type === 'mediumtext') return 'text';
  if (type === 'jsonb') return 'text';
  if (type === 'json') return 'text';
  if (type === 'enum') return 'text';
  if (type === 'uuid') return 'text';
  return type;
}
function resolveDefault(defaultValue: unknown): any {
  if (!Env.isTest) return defaultValue;
  const whitelist = ['string', 'number'];
  const type = typeof defaultValue;
  if (!whitelist.includes(type)) return JSON.stringify(defaultValue);
  return defaultValue;
}
export function EnvSpecificDecoratorValue(options: ColumnOptions) {
  if (options.type) options.type = resolveType(options.type);
  if (options.default) options.default = resolveDefault(options.default);
  return options;
}

import { ColumnOptions, Column as OriginalColumn } from 'typeorm';
import { UpdateDateColumn as OriginalUpdateDateColumn } from 'typeorm';
import { CreateDateColumn as OriginalCreateDateColumn } from 'typeorm';

export function Column(columnOptions: ColumnOptions) {
  return OriginalColumn(EnvSpecificDecoratorValue(columnOptions));
}
export function CreateDateColumn(columnOptions: ColumnOptions) {
  return OriginalCreateDateColumn(EnvSpecificDecoratorValue(columnOptions));
}
export function UpdateDateColumn(columnOptions: ColumnOptions) {
  return OriginalUpdateDateColumn(EnvSpecificDecoratorValue(columnOptions));
}

现在你可以引用ColumnCreateDateColumnUpdateDateColumn因为它是原始装饰器,但从本地文件导入。

最新更新