我有一个名为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.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 对象。
我可以想象一个类似地图的结构,如下所示
interface MetaDataDescription {
dbName: string;
type: any;
}
class StudentMetaData {
static ID: MetaDataDescription = {dbName: 'id', type: number};
static NAME: MetaDataDescription = {dbName: 'name', type: string};
//etc...
}
然后,您将在运行时从 StudentMetaData
中给出的数据(字段名称dbName
,字段类型type
)生成接口Student
。(所有其他型号也是如此)
访问此通用接口中的数据就像genericInstance[StudentMetaData.ID.dbName]
保持编译时完整性一样。
在查询中,您将编写await knex(tables.student).where(StudentMetaData.DELETED.dbName, false);
,同时保留编译时检查。
对整个结构的任何更改都将在元数据类中的单个点中进行,