如何使用TypeScript映射数据库架构和模型?

时间:2017-01-13 21:35:33

标签: typescript

我有一个名为student的数据库表。

id | name | createdAt  | deleted
--------------------------------
1  | foo  | 2017-01-13 | false

当我从数据库中检索值时,我将获得映射到正确类型的值。我有这个表的界面:

interface Student {
  id: number;
  name: string;
  createdAt: Date;
  deleted: boolean;
}

要从数据库中获取值,请执行以下操作:

await knex('student').where('deleted', false);

我正在考虑如何替换硬编码字符串以引用表/列,因此可以重命名/删除列并在编译时检测问题而不是运行时。我创建了一个像这样的对象:

const tables = { student: 'student' };
const cols = {
  id: 'id',
  name: 'name',
  createdAt: 'createdAt',
  deleted: 'deleted',
};

await knex(tables.student).where(cols.deleted, false);

有效。但是这种方法的问题在于,如果有人更改模型接口(Student)并忘记更改cols对象,它仍然可以在编译时工作。

如果我const cols: Student它将验证所有列,但cols对象上所有列的类型应为字符串。

有没有办法可以做到这一点?也许从这条线路或者可能采用完全不同的方法?

2 个答案:

答案 0 :(得分:1)

使用新的2.1.0功能非常容易解决。

const tables = { student: 'student' };
const cols: { [P in keyof Student]: string } = {
  id: 'id',
  name: 'name',
  createdAt: 'createdAt',
  deleted: 'deleted',
};

await knex(tables.student).where(cols.deleted, false);

如果您更改学生而不是cols对象,则会抱怨。

答案 1 :(得分:0)

我可以想象一个类似于地图的结构,如下所示

interface MetaDataDescription {
    dbName: string;
    type: any;
}

class StudentMetaData {
    static ID: MetaDataDescription = {dbName: 'id', type: number};
    static NAME: MetaDataDescription = {dbName: 'name', type: string};
    //etc...
}

然后,您将在运行时从Student中给出的数据(字段名称dbName和字段类型type)生成界面StudentMetaData。 (同样适用于所有其他型号)

访问此通用接口中的数据将像genericInstance[StudentMetaData.ID.dbName]一样保持编译时的完整性。

在查询中,您将编写await knex(tables.student).where(StudentMetaData.DELETED.dbName, false);,同时保留编译时间检查..

对整个结构的任何更改都将在元数据类中的单个点中进行,