2017-01-13 2 views
0

У меня есть таблица базы данных, которая называется student.Как использовать TypeScript для построения схемы и моделей базы данных?

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 должен быть строкой.

Есть ли способ, которым я могу это сделать? Может быть, из этой линии, хотя или, возможно, совершенно другого подхода?

ответ

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.

+0

Я Ждут» t знать об этой функции. Это именно то, что мне нужно. Милая! – BrunoLM

+1

Подробнее об этом можно найти здесь: https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript –

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);, а также хранение компилировать проверки времени ..

Любое изменение всей структуры была бы в одной точке в классе метаданных (ов),

+0

Это очень похоже на код Java EE в том месте, где он не должен. Существует несколько способов сделать это, используя функции TypeScript, не нужно создавать сложную и еще не безопасную OO-систему. –

+0

ОК, вы потеряете безопасность типа при назначении 'genericInstance [StudentMetaData.ID.dbName]', согласованного. Но даже несмотря на то, что ключевое слово 'keyof' является довольно гладким, вы все равно будете писать вещи дважды в своем решении. – Sebastian

+0

Конечно, но мой ответ только исправляет его код. Я бы просто исправить это в другом месте. Вы можете правильно ввести функцию where(), чтобы принимать только ключи от Student.Однако, поскольку я не уверен, что он использует с точки зрения архитектуры и библиотек, я не могу предоставить решение на этом фронте. Я не говорю, что мой ответ лучше, чем ваш, просто потому, что ваш кажется слишком ... корпоративным? для моих вкусов. –

Смежные вопросы