我有一个名为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
对象上所有列的类型应为字符串。
有没有办法可以做到这一点?也许从这条线路或者可能采用完全不同的方法?
答案 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);
,同时保留编译时间检查..
对整个结构的任何更改都将在元数据类中的单个点中进行,