идентификатор новой сущности — всегда ULID
- R1 больше не ветвится по признаку внешней адресуемости: заранее отличить внутренние сущности, которые станут внешними, невозможно - целочисленный ключ остаётся у существующих схем и идёт вместе с AUTOINCREMENT — переиспользованный rowid молча наводит протухшую ссылку на другую строку (db-schema R12) - таблица R5 ограничена внешними источниками, регион «решение» убран
This commit is contained in:
@@ -152,32 +152,33 @@ down останавливает сразу и заставляет пересо
|
||||
типа. Такой дефект не падает, не виден в логе и переживает тесты, которые
|
||||
проверяют, что список не пуст.
|
||||
|
||||
### R11. Вид первичного ключа задаёт `arch/db-identifiers.md`
|
||||
### R11. Первичный ключ новой таблицы — TEXT ULID
|
||||
|
||||
**ДОЛЖЕН.** В репозитории, подписанном на `arch/db-identifiers.md`, вид
|
||||
ключа выбирается по её R1, и `AUTOINCREMENT` в миграции не пишется.
|
||||
**ДОЛЖЕН.** Колонка ключа объявляется как `TEXT`, значение приходит из
|
||||
приложения (`arch/db-identifiers.md` R1, R2).
|
||||
|
||||
**Почему.** Вопрос о виде ключа решается один раз на репозиторий
|
||||
(`arch/db-identifiers.md` R1). Повторив здесь его ветвление, мы завели бы
|
||||
второй источник правды, и соседние таблицы разъехались бы по разным
|
||||
ответам на один и тот же вопрос.
|
||||
**Почему.** Здесь конвенция схемы ничего не решает — она реализует решение,
|
||||
принятое в `arch/db-identifiers.md`. Повторить там ветвление или условие
|
||||
значило бы завести второй источник правды, и соседние таблицы разъехались бы
|
||||
по разным ответам на один вопрос.
|
||||
|
||||
`AUTOINCREMENT` не нужен ни в одной из веток R1. Строкового ключа он не
|
||||
касается вовсе, а целочисленному даёт единственную гарантию — что значение
|
||||
rowid не будет переиспользовано после удаления строки, — ценой служебной
|
||||
таблицы `sqlite_sequence` и записи в неё на каждой вставке. Гарантия эта
|
||||
имеет смысл, только если старые идентификаторы живут где-то вне базы.
|
||||
`AUTOINCREMENT` в такой таблице невозможен: SQLite разрешает его только на
|
||||
`INTEGER PRIMARY KEY`. То есть для новых таблиц запрещать нечего.
|
||||
|
||||
### R12. Вне `arch/db-identifiers.md` первичный ключ — автоинкремент
|
||||
### R12. Целочисленный ключ идёт вместе с `AUTOINCREMENT`
|
||||
|
||||
**ДОПУСКАЕТСЯ.** Репозиторий, не подписанный на `arch/db-identifiers.md`,
|
||||
берёт целочисленный автоинкрементный ключ.
|
||||
**ДОЛЖЕН.** Там, где первичный ключ всё-таки целочисленный — существующая
|
||||
схема, миграция легаси-таблицы, — он объявляется с `AUTOINCREMENT`.
|
||||
|
||||
**Почему.** Явное разрешение нужно, чтобы R11 не читался как требование
|
||||
подписаться на `arch/db-identifiers.md`. Выбор вида ключа — решение уровня
|
||||
репозитория, и конвенция про типы колонок его за репозиторий не принимает;
|
||||
приложению, сущности которого не адресуют снаружи, целочисленный ключ
|
||||
ничего не стоит.
|
||||
**Почему.** Без него SQLite выдаёт rowid как `max(rowid)+1`, поэтому после
|
||||
удаления последней строки номер переиспользуется. Протухшая ссылка на
|
||||
удалённую запись — из закладки, из чужой таблицы, из старого лога — молча
|
||||
наводится на другую сущность и возвращает правдоподобный, но чужой ответ.
|
||||
Обнаружить это по данным нельзя: обе строки валидны.
|
||||
|
||||
Цена — служебная таблица `sqlite_sequence` и запись в неё на каждой
|
||||
вставке — против этого пренебрежима. Для новых таблиц вопрос не возникает:
|
||||
там ключ строковый (R11).
|
||||
|
||||
<!-- local:механизировано -->
|
||||
<!-- /local -->
|
||||
|
||||
Reference in New Issue
Block a user