ключ точки — интервал одной формы, класс «эпизодных метрик» убран
Перепись по 22 метрикам с интервалами опровергла признак из первой редакции: start всегда равен date, интервалы несёт не только сон, обе формы точки не смешиваются внутри метрики одной доставки, а разные интервалы под одной меткой всегда несут разное содержимое. Значит ключ единый — метрика + слой + начало + конец, у измерения вырожденный, без ветвления по классу.
This commit is contained in:
@@ -36,9 +36,9 @@ Module path — `git.vakhrushev.me/av/healthlog`.
|
|||||||
- **Сохранили — значит приняли.** Код ответа отражает доставку, а не разбор:
|
- **Сохранили — значит приняли.** Код ответа отражает доставку, а не разбор:
|
||||||
битый JSON — 400, непонятое содержимое — 200.
|
битый JSON — 400, непонятое содержимое — 200.
|
||||||
- **Ничего не теряем молча.** Идентичность — координаты
|
- **Ничего не теряем молча.** Идентичность — координаты
|
||||||
(`метрика + слой + метка`), а у точки-интервала — `метрика + слой + начало +
|
(`метрика + слой + начало + конец`), у точки-измерения конец равен началу:
|
||||||
конец`: под одной меткой лежит до трёх эпизодов сна, и эпизодность выводится
|
под одной меткой лежит до трёх записей сна. Ключ одной формы для всех точек —
|
||||||
из формы точки, а не из списка метрик. `source` в ключ не входит, он
|
отдельного класса «эпизодных метрик» нет. `source` в ключ не входит, он
|
||||||
нестабилен. Хеш
|
нестабилен. Хеш
|
||||||
канонизированного содержимого остался детектором изменений. При
|
канонизированного содержимого остался детектором изменений. При
|
||||||
столкновении выигрывает **более полная** точка, а не последняя. Изменение
|
столкновении выигрывает **более полная** точка, а не последняя. Изменение
|
||||||
|
|||||||
+15
-14
@@ -24,8 +24,8 @@ healthlog принимает выгрузки Apple Health из приложен
|
|||||||
- **Сохранили — значит приняли.** Код ответа отражает доставку, а не разбор
|
- **Сохранили — значит приняли.** Код ответа отражает доставку, а не разбор
|
||||||
(см. «Приём»).
|
(см. «Приём»).
|
||||||
- **Ничего не теряем молча.** Идентичность — устойчивые координаты
|
- **Ничего не теряем молча.** Идентичность — устойчивые координаты
|
||||||
(`метрика + слой + метка времени`), а у точки-интервала — `метрика + слой +
|
(`метрика + слой + начало + конец`; у точки-измерения конец равен началу);
|
||||||
начало + конец`; `source` в ключ не входит, он
|
`source` в ключ не входит, он
|
||||||
нестабилен. Хеш канонизированного содержимого остаётся детектором изменений,
|
нестабилен. Хеш канонизированного содержимого остаётся детектором изменений,
|
||||||
чтобы не писать зря. При столкновении выигрывает более полная точка, а не
|
чтобы не писать зря. При столкновении выигрывает более полная точка, а не
|
||||||
последняя пришедшая: бедная доставка не должна стирать поля у богатой.
|
последняя пришедшая: бедная доставка не должна стирать поля у богатой.
|
||||||
@@ -461,22 +461,23 @@ hour метки выровнены на час heart_rate 00:00:00
|
|||||||
**Идентичность точки — координаты, а не содержимое.**
|
**Идентичность точки — координаты, а не содержимое.**
|
||||||
|
|
||||||
```
|
```
|
||||||
ключ: метрика + слой + метка времени
|
ключ: метрика + слой + начало + конец конец = начало, если end нет
|
||||||
значения: qty / Min / Avg / Max / source / … ← перезаписываются
|
значения: qty / Min / Avg / Max / source / … ← перезаписываются
|
||||||
```
|
```
|
||||||
|
|
||||||
**У точки-интервала ключ — интервал.** Метка на эпизоде не уникальна: под одним
|
**Ключ — интервал, а не метка.** Метка на записи сна не уникальна: под одним
|
||||||
`date` лежит до трёх записей сна, и это не дефект, а способ Apple выразить
|
`date` лежит до трёх записей, и это не дефект, а способ Apple выразить
|
||||||
вложенность «в кровати» и фазы внутри неё. Ключ
|
вложенность «в кровати» и фазы внутри неё. Измерено на всём корпусе (находка
|
||||||
`метрика + слой + начало + конец` измерен на всём корпусе (находка 47): 174
|
47): 174 координаты против 170 по метке, ноль столкновений против 33 **внутри
|
||||||
координаты против 170 по метке, ноль столкновений против 33 **внутри одной
|
одной доставки**, где тай-брейк по времени приёма неприменим в принципе.
|
||||||
доставки**, где тай-брейк по времени приёма неприменим в принципе. `value` в
|
`value` в ключе ничего не добавляет.
|
||||||
ключе ничего не добавляет.
|
|
||||||
|
|
||||||
Эпизодность выводится из формы точки — есть `start` и `end`, отличные от `date`,
|
Форма ключа **одна для всех точек**. Интервалы несут 22 метрики, а не только
|
||||||
— а не из списка имён метрик: список был бы вторым способом описывать то, что
|
сон; `start`, когда он есть, всегда равен `date`; обе формы точки не
|
||||||
уже сказано данными. Час объекта берётся по началу эпизода, иначе
|
смешиваются внутри метрики одной доставки. Поэтому отдельного класса «эпизодных
|
||||||
принадлежность объекту зависела бы от длительности.
|
метрик» нет — нечего выводить и нечего поддерживать в каталоге и Read API. Час
|
||||||
|
объекта берётся по началу, иначе принадлежность объекту зависела бы от
|
||||||
|
длительности.
|
||||||
|
|
||||||
`HKObject.uuid` дал бы идентичность даром, но в выгрузку Apple он не попадает —
|
`HKObject.uuid` дал бы идентичность даром, но в выгрузку Apple он не попадает —
|
||||||
там у записи только `type`, `sourceName`, `sourceVersion`, `creationDate`,
|
там у записи только `type`, `sourceName`, `sourceVersion`, `creationDate`,
|
||||||
|
|||||||
@@ -1495,6 +1495,35 @@ type sourceName sourceVersion creationDate startDate endDate value
|
|||||||
идентичности обязана выражаться через `start`/`end`: иначе `import(экспорт)` не
|
идентичности обязана выражаться через `start`/`end`: иначе `import(экспорт)` не
|
||||||
сойдётся с `replay(HAE)` и журнал перестанет быть журналом.
|
сойдётся с `replay(HAE)` и журнал перестанет быть журналом.
|
||||||
|
|
||||||
|
### Уточнение: ключ один, и это интервал
|
||||||
|
|
||||||
|
Перепись по всем 22 метрикам, несущим `start`/`end`, поправила формулировку:
|
||||||
|
|
||||||
|
- **`start` всегда равен `date`** — ноль исключений на всём корпусе. Признак
|
||||||
|
«`start` и `end`, отличные от `date`» неработоспособен: отличается только
|
||||||
|
`end`.
|
||||||
|
- **Интервалы несёт не один сон, а 22 метрики** (`heart_rate`,
|
||||||
|
`physical_effort`, `walking_speed`, `apple_stand_hour`, …).
|
||||||
|
- **Обе формы точки никогда не смешиваются** внутри одной метрики в одной
|
||||||
|
доставке: интервальность — свойство режима выгрузки, а не отдельной точки.
|
||||||
|
Значит ключ с интервалом не разорвёт надвое точку, которая приехала то с
|
||||||
|
`end`, то без.
|
||||||
|
- **Разные интервалы под одной меткой** встречаются только у `sleep_analysis`
|
||||||
|
(3 метки) и `resting_heart_rate` (2 метки), и во **всех** случаях содержимое
|
||||||
|
точек различается. То есть это разные данные, а не поправленный задним числом
|
||||||
|
интервал: ключ с интервалом ничего не задваивает.
|
||||||
|
|
||||||
|
Отсюда ключ не двух форм, а одной:
|
||||||
|
|
||||||
|
```
|
||||||
|
координата = метрика + слой + начало + конец
|
||||||
|
у точки-измерения конец = начало
|
||||||
|
```
|
||||||
|
|
||||||
|
Понятия «эпизодная схема» не требуется вовсе — выводить нечего, ветвления в
|
||||||
|
коде нет, и правило разрешения столкновений по полноте продолжает работать
|
||||||
|
ровно там, где работало.
|
||||||
|
|
||||||
### Как это решают другие
|
### Как это решают другие
|
||||||
|
|
||||||
- **Health CSV Importer** дедуплицирует по `Start Date + End Date + Data Type +
|
- **Health CSV Importer** дедуплицирует по `Start Date + End Date + Data Type +
|
||||||
|
|||||||
@@ -121,23 +121,34 @@ double, и хеш-детектор начнёт видеть изменения
|
|||||||
|
|
||||||
Сжатие наблюдалось около 25 раз — ~2 МБ в сутки вместо ~50 МБ.
|
Сжатие наблюдалось около 25 раз — ~2 МБ в сутки вместо ~50 МБ.
|
||||||
|
|
||||||
### Эпизод адресуется интервалом, а не меткой
|
### Координата — интервал, у измерения вырожденный
|
||||||
|
|
||||||
Координата `метрика + слой + метка` верна для точки-измерения и неверна для
|
Ключ `метрика + слой + метка` верен для точки-измерения и неверен для
|
||||||
точки-интервала: под одной меткой лежит до трёх разных эпизодов сна. Поэтому
|
точки-интервала: под одной меткой лежит до трёх записей сна. Ключ единый:
|
||||||
у точки, несущей `start` и `end`, координата — `метрика + слой + start + end`.
|
|
||||||
|
|
||||||
Замер по всем 94 доставкам (1880 эпизодных точек, находка 47): метка одна даёт
|
```
|
||||||
170 координат и 33 столкновения **внутри одной доставки**, интервал — 174
|
координата = метрика + слой + начало + конец конец = начало, если end нет
|
||||||
координаты и ноль столкновений; `value` в ключе не добавляет ни одной
|
```
|
||||||
координаты. Из 174 координат ни одна не несёт двух разных содержимых, то есть
|
|
||||||
на эпизодном сне правило разрешения столкновений не срабатывает ни разу.
|
|
||||||
|
|
||||||
**Эпизодность выводится из данных, а не курируется списком** — так же, как слой
|
Замер по 94 доставкам (находка 47): метка одна даёт 170 координат сна и 33
|
||||||
выводится из выравнивания меток, а не из заголовка. Признак: точка несёт `start`
|
столкновения **внутри одной доставки**, интервал — 174 и ноль; `value` в ключе
|
||||||
и `end`, отличные от `date`. Список имён метрик здесь был бы вторым способом
|
не добавляет ни одной координаты.
|
||||||
описывать то, что уже сказано формой точки, и разошёлся бы с ней на первой же
|
|
||||||
новой метрике HAE.
|
Первая редакция вводила отдельный класс «эпизодных схем» с признаком «`start` и
|
||||||
|
`end`, отличные от `date`». Перепись по всем 22 метрикам с интервалами его
|
||||||
|
опровергла:
|
||||||
|
|
||||||
|
- **`start` всегда равен `date`** — признак не сработал бы ни разу;
|
||||||
|
- **интервалы несёт не только сон**, а 22 метрики, так что «эпизодная схема» —
|
||||||
|
не класс, а норма;
|
||||||
|
- **обе формы точки не смешиваются** внутри метрики одной доставки, поэтому
|
||||||
|
единый ключ не разорвёт надвое точку, приехавшую то с `end`, то без;
|
||||||
|
- **разные интервалы под одной меткой всегда несут разное содержимое**
|
||||||
|
(проверено по всем метрикам), так что ключ с интервалом не задваивает
|
||||||
|
поправленное задним числом.
|
||||||
|
|
||||||
|
Одна форма ключа вместо двух убирает из кода ветвление и понятие, которое
|
||||||
|
пришлось бы поддерживать в каталоге, Read API и импорте экспорта Apple.
|
||||||
|
|
||||||
Почему не «принять потерю и писать `WARN`»: в дублях внутри одной доставки
|
Почему не «принять потерю и писать `WARN`»: в дублях внутри одной доставки
|
||||||
`received_at` общий, и тай-брейк по времени приёма неприменим в принципе —
|
`received_at` общий, и тай-брейк по времени приёма неприменим в принципе —
|
||||||
|
|||||||
@@ -20,13 +20,12 @@
|
|||||||
`Default` соответствует трём разным режимам.
|
`Default` соответствует трём разным режимам.
|
||||||
- Точки складываются в **часовые объекты** (`bucket`, ключ `метрика + слой +
|
- Точки складываются в **часовые объекты** (`bucket`, ключ `метрика + слой +
|
||||||
час`), содержимое — gzip-BLOB. Запись — read-modify-write со слиянием.
|
час`), содержимое — gzip-BLOB. Запись — read-modify-write со слиянием.
|
||||||
- **Идентичность точки — координаты** (`метрика + слой + метка`). `source` в
|
- **Идентичность точки — координаты** (`метрика + слой + начало + конец`; у
|
||||||
ключ не входит: он нестабилен и меняется задним числом. При столкновении
|
точки-измерения конец равен началу). Ключ одной формы для всех точек: под
|
||||||
|
одной меткой лежит до трёх записей сна, и 33 столкновения происходят внутри
|
||||||
|
одной доставки, где тай-брейк по времени приёма неприменим. `source` в ключ
|
||||||
|
не входит: он нестабилен и меняется задним числом. При столкновении
|
||||||
выигрывает **более полная** точка, а не последняя пришедшая.
|
выигрывает **более полная** точка, а не последняя пришедшая.
|
||||||
- **Точка-интервал адресуется интервалом**: `метрика + слой + начало + конец`.
|
|
||||||
Под одной меткой лежит до трёх эпизодов сна, и 33 столкновения из измеренных
|
|
||||||
происходят внутри одной доставки, где тай-брейк по времени приёма неприменим.
|
|
||||||
Эпизодность выводится из формы точки, а не из списка имён метрик.
|
|
||||||
- **Канонизация с округлением** чисел до ~12 значащих цифр; хеш канонической
|
- **Канонизация с округлением** чисел до ~12 значащих цифр; хеш канонической
|
||||||
формы — детектор изменений, а не ключ.
|
формы — детектор изменений, а не ключ.
|
||||||
- `sleep_analysis` разводится на два имени: поэпизодное и суточную сводку —
|
- `sleep_analysis` разводится на два имени: поэпизодное и суточную сводку —
|
||||||
|
|||||||
@@ -2,11 +2,33 @@
|
|||||||
|
|
||||||
### Requirement: Идентичность точки по координатам
|
### Requirement: Идентичность точки по координатам
|
||||||
|
|
||||||
Система SHALL адресовать точку-измерение координатами
|
Система SHALL адресовать точку координатами
|
||||||
`метрика + слой + метка времени`. Поле `source` в ключ входить MUST NOT: оно
|
`метрика + слой + начало + конец`. У точки-измерения конец равен началу; у
|
||||||
нестабильно — то же измерение с тем же значением приезжает то как
|
точки-интервала — концу интервала. Ключ MUST быть одной формы для всех точек:
|
||||||
`Apple Watch Ultra 3|iPad (Anton)`, то как `Apple Watch Ultra 3`, потому что
|
интервальная и точечная формы не встречаются вперемешку внутри одной метрики
|
||||||
Health переосмысливает атрибуцию задним числом.
|
одной доставки (проверено на всём корпусе), поэтому ветвление по «классу
|
||||||
|
метрики» не нужно и вводить его MUST NOT.
|
||||||
|
|
||||||
|
Поле `source` в ключ входить MUST NOT: оно нестабильно — то же измерение с тем
|
||||||
|
же значением приезжает то как `Apple Watch Ultra 3|iPad (Anton)`, то как
|
||||||
|
`Apple Watch Ultra 3`, потому что Health переосмысливает атрибуцию задним
|
||||||
|
числом.
|
||||||
|
|
||||||
|
Начало точки берётся из `start`, а при его отсутствии — из `date`; конец — из
|
||||||
|
`end`, а при его отсутствии — из начала. Измерено: `start`, когда он есть,
|
||||||
|
**всегда** совпадает с `date` (ноль исключений на 22 метриках), поэтому правило
|
||||||
|
не вводит второго источника метки — оно лишь закрывает случай, когда HAE
|
||||||
|
перестанет их дублировать.
|
||||||
|
|
||||||
|
Час объекта определяется по началу точки: интервал пересекает границы часов, и
|
||||||
|
любой другой выбор сделал бы принадлежность объекту зависящей от длительности.
|
||||||
|
|
||||||
|
Ключ по одной метке проверялся и отвергнут: он схлопывает записи сна. Измерено
|
||||||
|
на всех 94 доставках — 170 координат против 174 и **33 столкновения внутри
|
||||||
|
одной доставки**, где `received_at` общий, тай-брейк по нему неприменим в
|
||||||
|
принципе, и исход решал бы порядок элементов в JSON-массиве, а он нестабилен.
|
||||||
|
При этом разные интервалы под одной меткой всегда несут разное содержимое
|
||||||
|
(проверено по всем метрикам), то есть ключ с интервалом ничего не задваивает.
|
||||||
|
|
||||||
Идентичность по хешу содержимого проверялась и отвергнута: она задваивала
|
Идентичность по хешу содержимого проверялась и отвергнута: она задваивала
|
||||||
минутный слой целиком — 120 точек в часе вместо 60.
|
минутный слой целиком — 120 точек в часе вместо 60.
|
||||||
@@ -21,44 +43,28 @@ Health переосмысливает атрибуцию задним число
|
|||||||
- **WHEN** точка с теми же координатами приезжает с другой строкой `source`
|
- **WHEN** точка с теми же координатами приезжает с другой строкой `source`
|
||||||
- **THEN** она остаётся одной точкой, а не превращается в две
|
- **THEN** она остаётся одной точкой, а не превращается в две
|
||||||
|
|
||||||
### Requirement: Идентичность эпизода по интервалу
|
#### Scenario: Записи с одной меткой и разными интервалами не схлопываются
|
||||||
|
|
||||||
Система SHALL адресовать точку-интервал координатами
|
|
||||||
`метрика + слой + начало + конец`. Метки времени для неё недостаточно: под
|
|
||||||
одной меткой лежит до трёх разных эпизодов сна.
|
|
||||||
|
|
||||||
Эпизодность SHALL выводиться из формы точки — точка несёт `start` и `end`,
|
|
||||||
отличные от `date`, — а не назначаться списком имён метрик. Список был бы
|
|
||||||
вторым способом описывать то, что уже сказано формой точки, и разошёлся бы с
|
|
||||||
ней на первой же новой метрике HAE.
|
|
||||||
|
|
||||||
Измерено на всех 94 доставках (1880 эпизодных точек, находка 47): ключ по метке
|
|
||||||
даёт 170 координат и 33 столкновения **внутри одной доставки**, ключ по
|
|
||||||
интервалу — 174 координаты и ноль столкновений. Внутридоставочные столкновения
|
|
||||||
и делают ключ по метке неисправимым: `received_at` там общий, тай-брейк по нему
|
|
||||||
неприменим в принципе, и исход решал бы порядок элементов в JSON-массиве — а он
|
|
||||||
нестабилен.
|
|
||||||
|
|
||||||
Час объекта для точки-интервала SHALL определяться по началу эпизода: эпизод
|
|
||||||
пересекает границы часов, и любой другой выбор сделал бы принадлежность
|
|
||||||
объекту зависящей от длительности.
|
|
||||||
|
|
||||||
#### Scenario: Эпизоды с одной меткой и разными интервалами не схлопываются
|
|
||||||
|
|
||||||
- **WHEN** в доставке приходят точки `sleep_analysis` с одинаковым `date` и
|
- **WHEN** в доставке приходят точки `sleep_analysis` с одинаковым `date` и
|
||||||
разными парами `start`/`end`
|
разными парами `start`/`end`
|
||||||
- **THEN** каждая сохраняется отдельной точкой
|
- **THEN** каждая сохраняется отдельной точкой
|
||||||
|
|
||||||
#### Scenario: Повтор эпизода в следующей доставке не задваивает
|
#### Scenario: Повтор записи в следующей доставке не задваивает
|
||||||
|
|
||||||
- **WHEN** точка с тем же `start` и `end` приезжает следующей доставкой
|
- **WHEN** точка с тем же началом и концом приезжает следующей доставкой
|
||||||
- **THEN** она остаётся одной точкой
|
- **THEN** она остаётся одной точкой
|
||||||
|
|
||||||
|
#### Scenario: Точка-измерение адресуется вырожденным интервалом
|
||||||
|
|
||||||
|
- **WHEN** точка не несёт `end`
|
||||||
|
- **THEN** её конец равен началу, и ключ имеет ту же форму, что у интервала
|
||||||
|
|
||||||
### Requirement: Разрешение столкновений по полноте
|
### Requirement: Разрешение столкновений по полноте
|
||||||
|
|
||||||
Когда по одним координатам приходят разные содержимые, система SHALL оставлять
|
Когда по одним координатам приходят разные содержимые, система SHALL оставлять
|
||||||
**более полную** точку — ту, у которой больше значащих полей, — а не последнюю
|
**более полную** точку — ту, у которой больше значащих полей, — а не последнюю
|
||||||
пришедшую. Иначе бедная доставка стирает `start`/`end` у богатой.
|
пришедшую. Иначе бедная доставка стирает у богатой поля, которых сама не несёт:
|
||||||
|
0.66% координат различаются именно набором полей при одинаковом значении.
|
||||||
|
|
||||||
Если полнота равна, а значения различаются, исход MUST быть детерминированным
|
Если полнота равна, а значения различаются, исход MUST быть детерминированным
|
||||||
и не зависеть от порядка, в котором доставки дошли до хранилища: свёртка по
|
и не зависеть от порядка, в котором доставки дошли до хранилища: свёртка по
|
||||||
@@ -71,9 +77,9 @@ Health переосмысливает атрибуцию задним число
|
|||||||
|
|
||||||
#### Scenario: Бедная точка не стирает поля богатой
|
#### Scenario: Бедная точка не стирает поля богатой
|
||||||
|
|
||||||
- **WHEN** сохранена точка с `qty`, `start` и `end`
|
- **WHEN** сохранена точка с `Avg`, `Min`, `Max` и `context`
|
||||||
- **AND** по тем же координатам приезжает точка только с `qty`
|
- **AND** по тем же координатам приезжает точка только с `Avg`, `Min` и `Max`
|
||||||
- **THEN** сохранённая точка остаётся с `start` и `end`
|
- **THEN** сохранённая точка остаётся с `context`
|
||||||
|
|
||||||
#### Scenario: Одинаково полные точки с разными значениями
|
#### Scenario: Одинаково полные точки с разными значениями
|
||||||
|
|
||||||
|
|||||||
@@ -33,8 +33,8 @@
|
|||||||
- [ ] 4.1 Модель объекта в `internal/store`; содержимое — исходные байты точек, gzip-BLOB, точки упорядочены по времени
|
- [ ] 4.1 Модель объекта в `internal/store`; содержимое — исходные байты точек, gzip-BLOB, точки упорядочены по времени
|
||||||
- [ ] 4.2 Слияние: координатный ключ, победа более полной точки, при равной полноте — детерминированный исход по порядку канонических форм
|
- [ ] 4.2 Слияние: координатный ключ, победа более полной точки, при равной полноте — детерминированный исход по порядку канонических форм
|
||||||
- [ ] 4.3 Столкновение с различием канонической формы — `WARN` без значений и счётчик перезаписей
|
- [ ] 4.3 Столкновение с различием канонической формы — `WARN` без значений и счётчик перезаписей
|
||||||
- [ ] 4.4 Ключ точки-интервала — `метрика + слой + start + end`; эпизодность выводится из формы точки (`start`/`end`, отличные от `date`), а не из списка имён. Час объекта — по началу эпизода
|
- [ ] 4.4 Ключ точки — `метрика + слой + начало + конец` одной формы для всех точек: начало из `start`, иначе из `date`; конец из `end`, иначе равен началу. Час объекта — по началу. Ветвления по «классу метрики» быть не должно
|
||||||
- [ ] 4.4a Тест на фикстуре 1.3a: три эпизода с одной меткой и разными интервалами дают три точки, а не одну; повтор той же тройки следующей доставкой не задваивает
|
- [ ] 4.4a Тест на фикстуре 1.3a: три записи с одной меткой и разными интервалами дают три точки, а не одну; повтор той же тройки следующей доставкой не задваивает; точка без `end` кладётся вырожденным интервалом
|
||||||
- [ ] 4.5 Хеш объекта как детектор изменений: совпал — записи нет
|
- [ ] 4.5 Хеш объекта как детектор изменений: совпал — записи нет
|
||||||
- [ ] 4.6 `_txlock=immediate` в DSN; повтор оборачивает **всю тройку** чтение-слияние-запись; путь «хеш совпал» — под `TxOptions{ReadOnly: true}`
|
- [ ] 4.6 `_txlock=immediate` в DSN; повтор оборачивает **всю тройку** чтение-слияние-запись; путь «хеш совпал» — под `TxOptions{ReadOnly: true}`
|
||||||
- [ ] 4.7 Распознавание занятости — `errors.As` на `*sqlite.Error`, коды 5 и 517, обёрнуто в `store`
|
- [ ] 4.7 Распознавание занятости — `errors.As` на `*sqlite.Error`, коды 5 и 517, обёрнуто в `store`
|
||||||
|
|||||||
Reference in New Issue
Block a user