заведён реестр префиксов, правила канона перенумерованы
- идентификатор правила теперь `<ПРЕФИКС>-<номер>` вместо `R<номер>`: префикс уникален по всему канону, поэтому ссылка больше не требует пути к файлу и не зависит от того, на какой оси файл лежит - префикс выбирается под файл, а не выводится по формуле, и хранится в conventions/prefixes.toml вместе с выбывшими; номера сохранены один в один вместе с дырами
This commit is contained in:
@@ -1,3 +1,7 @@
|
||||
---
|
||||
prefix: MIGR
|
||||
---
|
||||
|
||||
# Схема и миграции (SQLite, Go)
|
||||
|
||||
Как пишутся миграции и какие типы колонок выбираются для схемы SQLite в
|
||||
@@ -12,7 +16,7 @@ Go-приложении. Форма записи — `LANGUAGE.md`.
|
||||
|
||||
## Миграции
|
||||
|
||||
### R1. Миграции ведёт goose
|
||||
### MIGR-1. Миграции ведёт goose
|
||||
|
||||
**ДОЛЖЕН.** Набор миграций репозитория применяется одним инструментом —
|
||||
goose.
|
||||
@@ -24,7 +28,7 @@ goose.
|
||||
существующую таблицу. На сервере это означает ручной разбор состояния
|
||||
схемы вместо автоматического деплоя.
|
||||
|
||||
### R2. Файлы миграций лежат рядом со store-слоем
|
||||
### MIGR-2. Файлы миграций лежат рядом со store-слоем
|
||||
|
||||
**СЛЕДУЕТ.** Миграции хранятся рядом с кодом, который работает с этой
|
||||
схемой.
|
||||
@@ -35,14 +39,14 @@ goose.
|
||||
код без миграции, либо миграция без кода; расходятся они на сервере, где
|
||||
схема ещё старая.
|
||||
|
||||
### R3. Форма миграции выбирается по тому, нужен ли код
|
||||
### MIGR-3. Форма миграции выбирается по тому, нужен ли код
|
||||
|
||||
**ДОЛЖЕН.** Миграция пишется в той форме, которой требует её содержимое:
|
||||
|
||||
| № | Что делает миграция | Форма |
|
||||
|---|---|---|
|
||||
| R3.1 | DDL: создание таблиц, индексы, изменение структуры | SQL-файл |
|
||||
| R3.2 | требует кода: генерация идентификаторов, backfill, перенос данных между формами | Go-миграция (`goose.AddMigrationContext`) |
|
||||
| MIGR-3.1 | DDL: создание таблиц, индексы, изменение структуры | SQL-файл |
|
||||
| MIGR-3.2 | требует кода: генерация идентификаторов, backfill, перенос данных между формами | Go-миграция (`goose.AddMigrationContext`) |
|
||||
|
||||
**Почему.** DDL ничего не вычисляет, и SQL-файл показывает ровно тот текст,
|
||||
который уедет в базу; обёртка на Go вокруг него добавляет место, где можно
|
||||
@@ -50,12 +54,12 @@ goose.
|
||||
|
||||
Обратное направление дороже. Перенос данных и генерация идентификаторов
|
||||
выражаются на SQL либо громоздко, либо неточно: идентификатор по
|
||||
`arch/db-identifiers.md` R2 порождает приложение, и SQL-миграция вынуждена
|
||||
`KEYS-2` порождает приложение, и SQL-миграция вынуждена
|
||||
завести для него второй генератор — ровно то, что запрещает
|
||||
`arch/db-identifiers.md` R3. Единообразие формы здесь покупается
|
||||
`KEYS-3`. Единообразие формы здесь покупается
|
||||
дублированием логики, которая уже есть в коде.
|
||||
|
||||
### R4. В деплое схема движется только вперёд
|
||||
### MIGR-4. В деплое схема движется только вперёд
|
||||
|
||||
**НЕ ДОЛЖЕН.** Откат схемы на сервере не выполняется down-миграцией;
|
||||
ошибка исправляется новой миграцией вперёд.
|
||||
@@ -67,14 +71,14 @@ goose.
|
||||
следующей миграцией, оставляет целыми и данные, и журнал применённых
|
||||
версий.
|
||||
|
||||
### R5. Down пишется, когда он честно обращает up
|
||||
### MIGR-5. Down пишется, когда он честно обращает up
|
||||
|
||||
**ДОЛЖЕН.** Наличие down-миграции определяется тем, обратим ли up:
|
||||
|
||||
| № | Что делает up | Down |
|
||||
|---|---|---|
|
||||
| R5.1 | добавляет структуру: таблицу, колонку, индекс | пишется, убирает добавленное |
|
||||
| R5.2 | необратимо преобразует данные | не пишется |
|
||||
| MIGR-5.1 | добавляет структуру: таблицу, колонку, индекс | пишется, убирает добавленное |
|
||||
| MIGR-5.2 | необратимо преобразует данные | не пишется |
|
||||
|
||||
**Почему.** Down — инструмент разработки, где ветку переключают туда-сюда,
|
||||
и именно там он обязан действительно обращать up. Имитация опаснее
|
||||
@@ -83,7 +87,7 @@ goose.
|
||||
down останавливает сразу и заставляет пересоздать базу — это дешевле, чем
|
||||
отладка по данным, которых уже нет.
|
||||
|
||||
### R6. ER-схема обновляется в том же изменении
|
||||
### MIGR-6. ER-схема обновляется в том же изменении
|
||||
|
||||
**ДОЛЖЕН.** Изменение структуры и правка ER-схемы в спеках едут одним
|
||||
изменением.
|
||||
@@ -99,7 +103,7 @@ down останавливает сразу и заставляет пересо
|
||||
Правила ниже описывают хранение в SQLite: выбор типа диктует движок базы,
|
||||
а не язык приложения.
|
||||
|
||||
### R7. Enum-поля — `TEXT`, допустимые значения держит код
|
||||
### MIGR-7. Enum-поля — `TEXT`, допустимые значения держит код
|
||||
|
||||
**ДОЛЖЕН.** Поле-перечисление (`state`, `kind`, …) объявляется как `TEXT`
|
||||
без `CHECK`-ограничения на список значений.
|
||||
@@ -115,7 +119,7 @@ down останавливает сразу и заставляет пересо
|
||||
таблицы соответствия, которую пришлось бы держать в голове для числового
|
||||
кода.
|
||||
|
||||
### R8. Метки времени — `TEXT` в формате из `arch/time.md`
|
||||
### MIGR-8. Метки времени — `TEXT` в формате из `arch/time.md`
|
||||
|
||||
**ДОЛЖЕН.** Колонка с меткой времени объявляется как `TEXT`, значения
|
||||
пишутся в формате из `arch/time.md`.
|
||||
@@ -127,7 +131,7 @@ down останавливает сразу и заставляет пересо
|
||||
преобразования, а значит и без потери индекса. Соседство двух форматов в
|
||||
одной колонке ломает и сравнение, и разбор на стороне Go.
|
||||
|
||||
### R9. Умолчание `DEFAULT (datetime('now'))` не ставится
|
||||
### MIGR-9. Умолчание `DEFAULT (datetime('now'))` не ставится
|
||||
|
||||
**НЕ ДОЛЖЕН.** Колонка с меткой времени не получает значение по умолчанию
|
||||
на уровне схемы.
|
||||
@@ -138,10 +142,10 @@ down останавливает сразу и заставляет пересо
|
||||
по ошибке.
|
||||
|
||||
Вдобавок `datetime('now')` даёт `YYYY-MM-DD HH:MM:SS` — без `T` и без `Z`,
|
||||
то есть не тот формат, которого требует R8. В колонке оказываются строки
|
||||
то есть не тот формат, которого требует MIGR-8. В колонке оказываются строки
|
||||
двух видов, и ломается ровно то, ради чего формат выбран.
|
||||
|
||||
### R10. Булевы поля — `INTEGER` со значениями 0 и 1
|
||||
### MIGR-10. Булевы поля — `INTEGER` со значениями 0 и 1
|
||||
|
||||
**ДОЛЖЕН.** Булево значение хранится как `INTEGER` 0/1.
|
||||
|
||||
@@ -152,10 +156,10 @@ down останавливает сразу и заставляет пересо
|
||||
типа. Такой дефект не падает, не виден в логе и переживает тесты, которые
|
||||
проверяют, что список не пуст.
|
||||
|
||||
### R11. Первичный ключ новой таблицы — TEXT ULID
|
||||
### MIGR-11. Первичный ключ новой таблицы — TEXT ULID
|
||||
|
||||
**ДОЛЖЕН.** Колонка ключа объявляется как `TEXT`, значение приходит из
|
||||
приложения (`arch/db-identifiers.md` R1, R2).
|
||||
приложения (`KEYS-1`, `KEYS-2`).
|
||||
|
||||
**Почему.** Здесь конвенция схемы ничего не решает — она реализует решение,
|
||||
принятое в `arch/db-identifiers.md`. Повторить там ветвление или условие
|
||||
@@ -165,7 +169,7 @@ down останавливает сразу и заставляет пересо
|
||||
`AUTOINCREMENT` в такой таблице невозможен: SQLite разрешает его только на
|
||||
`INTEGER PRIMARY KEY`. То есть для новых таблиц запрещать нечего.
|
||||
|
||||
### R12. Целочисленный ключ идёт вместе с `AUTOINCREMENT`
|
||||
### MIGR-12. Целочисленный ключ идёт вместе с `AUTOINCREMENT`
|
||||
|
||||
**ДОЛЖЕН.** Там, где первичный ключ всё-таки целочисленный — существующая
|
||||
схема, миграция легаси-таблицы, — он объявляется с `AUTOINCREMENT`.
|
||||
@@ -178,7 +182,7 @@ down останавливает сразу и заставляет пересо
|
||||
|
||||
Цена — служебная таблица `sqlite_sequence` и запись в неё на каждой
|
||||
вставке — против этого пренебрежима. Для новых таблиц вопрос не возникает:
|
||||
там ключ строковый (R11).
|
||||
там ключ строковый (MIGR-11).
|
||||
|
||||
<!-- local:механизировано -->
|
||||
<!-- /local -->
|
||||
|
||||
Reference in New Issue
Block a user