Reputation: 100361
I have a database table called student
.
id | name | createdAt | deleted
--------------------------------
1 | foo | 2017-01-13 | false
When I retrieve values from the database I will get values mapped to the correct type. I have an interface for this table:
interface Student {
id: number;
name: string;
createdAt: Date;
deleted: boolean;
}
To grab values from the database I'm doing something like:
await knex('student').where('deleted', false);
I'm thinking how to replace the hard-coded strings to refer to the table/columns, so it will be possible to rename/remove columns and detect issues in compile time rather then runtime. I created an object like:
const tables = { student: 'student' };
const cols = {
id: 'id',
name: 'name',
createdAt: 'createdAt',
deleted: 'deleted',
};
await knex(tables.student).where(cols.deleted, false);
It works. But the problem with this approach is that if someone change the model interface (Student
) and forget to change the cols object it is still going to work on compile time.
If I do const cols: Student
it would validate all columns, but the type for all columns on the cols
object should be a string.
Is there a way I can do this? Maybe from this line of though or maybe in a completely different approach?
Upvotes: 1
Views: 3388
Reputation: 5290
I can imagine a map-like structure like the following
interface MetaDataDescription {
dbName: string;
type: any;
}
class StudentMetaData {
static ID: MetaDataDescription = {dbName: 'id', type: number};
static NAME: MetaDataDescription = {dbName: 'name', type: string};
//etc...
}
Then you would at runtime generate your interface Student
from the data (dbName
for the field name and type
for the field type) given in StudentMetaData
. (and likewise for all other models)
Accessing data in this generic interface would be done like genericInstance[StudentMetaData.ID.dbName]
keeping compile time integrity.
In the query you would then write await knex(tables.student).where(StudentMetaData.DELETED.dbName, false);
, also keeping compile time checks..
Any change to the whole structure would be in a single point in the metadata class(es),
Upvotes: 1
Reputation: 968
Really easy to fix with the new 2.1.0 features.
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);
This will complain if you change Student, but not the cols object.
Upvotes: 2