Автоматизация / отслеживание миграций Knex и осознанных моделей

Ситуация Я недавно начал работать над новым проектом с использованием nodejs. У меня есть опыт использования Python/Django и C#/.NET (не большой поклонник последнего). Node великолепен, но я должен сказать, что мне не хватает простоты построения моделей и автоматизации миграции в Django. В настоящее время я использую инфраструктуру AdonisJS, которая использует Knex. Knex - мощная библиотека, но все миграции необходимо создавать вручную. Кроме того, ORM AdonisJS, который управляет моделями, не зависит от Knex (менеджера миграции). Вы также не определяете атрибуты полей в Моделях, которые могут иметь преимущества для динамического выполнения действий в передней и задней части. Учитывая все вышесказанное, существует много места для человеческих ошибок, недопонимания и загрузки лодки, что требует большего набора текста. Я знаю, что горячая вещь в наши дни состоит в том, чтобы держать это свободно и быстро, но для этого конкретного проекта я ищу немного больше структуры, чем свободно определенные модели.

Текущее состояние То, на чем я остановился, - это создание нового класса с именем tableModel и класса полей для определения полей в табличной модели. Я уже закончил это, и я успешно пишу файлы миграции, используя усы. Я планирую также автоматически писать Модели, с которыми у меня не должно быть проблем (скрещенные пальцы).

Проблема Вот где это становится немного сложным, и где мне нужна помощь... Мне нужно отслеживать, что было добавлено или удалено с помощью миграции, чтобы я мог эффективно записывать взлеты и падения, так как модели таблиц меняются со временем.

Допустим, я добавил "tableModel", который создает миграцию для создания таблицы Foo с полями {id (bigint), user_id(int), name(string255)}

Позже я хочу добавить поле с именем description, чтобы просто добавить его в "tableModel", а затем запустить команду сборки, которая создаст миграцию. Как мне проверить, что уже было создано, поэтому я делаю только up() для описания?

Затем я хочу удалить поле имени, чтобы выделить его в своей "tableModel" и запустить команду переноса сборки. Как проверить, что было перенесено, и что теперь нужно добавить в down(). Редактировать: я бы добавил поле удаления вверх и соответствующий откат вниз.

Бонусный раунд Допустим, я хочу изменить user_id с int на bigint, потому что кто делает внешний ключ просто int? Как мне проверить не только то, что нужно добавить вверх и вниз, но и проверить, нужно ли мне изменить свойство в поле.
Изменить: просто написать вверх. и соответствующий откат вниз

Большой вопрос Как определить грязные классы "tableModels"?

Возможное решение? Я думаю, что, возможно, я должен захватить некоторый тип реестра или снимка, а затем запустить сравнение при построении миграций и / или моделей, а затем повторно захватить / снимок. Если это маршрут, следует ли мне хранить его в файле json, записать его в саму БД или есть другой / лучший вариант.

Если я создам экземпляры tableModel как константы, могу ли я на самом деле записать обратно в файл JS и захватить снимок как атрибут? Если это вариант, подходит ли файловая система Node и как лучше это сделать? Узел продолжает удивлять меня, так что я не буду сбит с толку, если какой-либо из этих вариантов.

Помогите! Если кто-то уже прошел этот путь или знает о каких-либо инструментах, которые я мог бы использовать, я был бы очень признателен и заранее благодарен вам. Кроме того, если я двигаюсь в совершенно неправильном направлении, то, пожалуйста, дайте мне знать, я и обрабатываю и ценю все виды обратной связи.

Пример Что следует отметить, когда я определяю "tableModel" для данной миграции или модели, это экземпляр класса, я не создаю расширенный класс, так как это не моя форма.

class tableModel {
    constructor(tableName, modelName = tableName, fields = []) {
    this.tableName = tableName
    this.modelName = modelName
    this.fields = fields
    }
// Bunch of other stuff

}

fooTableModel = new tableModel('fooTable', 'fooModel', fields = [

    new tableField.stringField('title'),
    new tableField.bigIntField('related_user_id'),
    new tableField.textField('description','Testing Default',false,true)


  ]
)

что соответствует:

tableModel {
  tableName: 'fooTable',
  modelName: 'fooModel',
  fields:
   [ stringField {
       name: 'title',
       type: 'string',
       _unique: false,
       allow_null: null,
       fieldAttributes: {},
       default_value: null },
     bigIntField {
       name: 'related_user_id',
       type: 'bigInteger',
       _unique: false,
       allow_null: null,
       fieldAttributes: {},
       default_value: 0 },
     textField {
       name: 'description',
       type: 'text',
       _unique: false,
       allow_null: true,
       fieldAttributes: {},
       default_value: 'Testing Default' } ]

2 ответа

У тебя есть up а также down обозначения перепутаны. Те, для миграции "последних" (запускает up функция) и делать откат (запускает down функция). Вверх и вниз, чтобы не относиться к удалению или добавлению столбцов таблицы.

Миграции вверх - для любых изменений, а вниз - для изменения этих изменений. Поэтому, если вы хотите удалить столбец из какой-либо таблицы, вы пишете команду в up, а затем напишите обратное в down (вы бы добавили его обратно в...), так что вы можете "откатить", и изменение будет эффективно отменено. Вы должны быть осторожны с такими вещами, поскольку вы можете оказаться в ситуации, когда вы действительно потеряете данные.

Хотите добавить колонку? Запишите это в upи опустите столбец в down,

Одним из основных моментов механизма миграции является отслеживание состояния изменений в вашей базе данных с течением времени. Поэтому, как правило, если вы создали таблицу в какой-либо миграции, то примерно через день вы понимаете, что вам нужно удалить / добавить столбцы, обычно вы не возвращаетесь и не редактируете существующую миграцию, особенно если миграция уже была запущена. Вы просто написали бы новую миграцию, чтобы удалить / добавить ваш столбец.

Поскольку вы используете knex, существует пара таблиц "knex", которые создаются. По умолчанию вы ищете knex_migrations, если кто-то специально не изменил настройки, чтобы изменить его название. Эта таблица содержит все миграции, которые выполнялись для вашей БД, для каждого пакета. Из CLI, если у вас установлен глобальный файл knex.js, вы можете запустить knex migrate:latestи это подтолкнет все миграции, которые существуют в вашем каталоге, в целевую базу данных, если они еще не выполнялись. Это делается путем изучения того, что knex_migrations Таблица. Если вы бросили изменение и вам не понравилось, и если вы правильно сделали down функция, вы можете вызвать knex migrate:rollback отменить изменения. Если есть 3 файла миграции, которые еще не были запущены, вызывается knex migrate:latest запустит все 3 из этих файлов миграции под новым номером пакета, который на 1 больше, чем самый последний номер пакета. И наоборот, если вы вызываете knex migrate:rollback, он найдет наибольший номер пакета (может быть более 1 миграции в пакете...) и вызовет функцию down для всех этих файлов, чтобы эффективно откатить эти изменения.

Все это говорит о том, что knex - это инструмент для построения запросов. У него есть куча вспомогательных функций, которые помогут вам создать sql. Лично я считаю, что это отвлекает. Зачем часами часами разбираться со всеми вспомогательными функциями, когда я могу просто запустить необработанный SQL и запустить его. Таким образом, это то, что мы сделали в нашей системе. мы используем knex.raw('') и написать наши собственные DDL и DML. Он прекрасно работает и делает именно то, что нам нужно. Нам не нужно разбираться в магии построения запросов.

Короткий ответ заключается в том, что knex автоматически узнает, что для вас было, а что нет (опять же, через knex_migrations стол, который он создает для вас...). Вещи могут стать странными, хотя, когда это начинает вовлекать git и различные ветви. Я рекомендую, если вы пишете миграции в какой-либо ветви и вам нужно заняться другой работой, всегда не забывайте сначала выполнить откат всех миграций, которые вы сделали в этой ветви, ДО переключения ветвей. В противном случае вы будете в странных состояниях БД, которые не совпадают с кодом приложения.

Я бы лично занимался обновлением моделей независимо от написания миграций. Например, если я добавляю description столбец к некоторой таблице, тогда я, вероятно, хочу вручную обновить ORM, чтобы отразить изменение новой схемы БД. В общем, я обнаружил, что пытаясь использовать инструмент, который автоматически делает это для вас (скорее, если я изменяю форму, все, что происходит, пишет все нижележащие sql...), как правило, заводит меня в кучу неприятностей, и я просто тратить больше времени, пытаясь разгадать вещи. Но это только мои 2 цента:)

Вот где это становится немного сложным, и где мне нужна помощь... Мне нужно отслеживать, что было добавлено или удалено с помощью миграции, чтобы я мог эффективно записывать взлеты и падения, когда TableModel меняются со временем.

Вы можете сохранить изменения в файле DB/txt, и они могут действовать как снимки. Поэтому, если вы хотите выполнить откат к определенной миграции, вы найдете изменения (вверх / вниз), сделанные для этой мутации, и скорректируете их соответствующим образом.

Позже я хочу добавить поле с именем description, чтобы просто добавить его в "tableModel", а затем запустить команду сборки, которая создаст миграцию. Как мне проверить, что уже было создано, поэтому я делаю только up() для описания?

Здесь вы либо напрямую вызываете базу данных, и проверяете, какие поля уже созданы. Если поле уже занято и атрибуты совпадают, вы можете либо проигнорировать его, либо остановить транзакцию все вместе.

Бонусный раунд Допустим, я хочу изменить user_id с int на bigint, потому что кто делает внешний ключ просто int? Как мне проверить не только то, что нужно добавить вверх и вниз, но и проверить, нужно ли мне изменить свойство в поле. Опять же, вызовите саму БД на рассматриваемой таблице. Я знаю, что вызов SQL будет: describe [table_name];

Прочитав окончание, я думаю, что вы ответили на это самостоятельно, но я думаю, что захват этих изменений будет лучше всего работать в базе данных NoSql, поскольку вы используете Node или PostGres с его полем json.

Другие вопросы по тегам