Documentation
¶
Overview ¶
Package pagetoken — ЕДИНСТВЕННОЕ объявление формы курсора страницы.
Зачем пакет существует ¶
Форма токена была записана в дереве трижды: авторитетный кодек в слое репозитория, рукописное зеркало в проверке формата на границе приложения — и оно бежит ПЕРВЫМ — и свой декодер в общем пакете операций. Четвёртая копия жила в другом сервисе.
Пока значения совпадают, это не расхождение, а заряженная ловушка: смена формы вносится в три места, и первое же пропущенное даст ответ, зависящий от того, какой из декодеров бежал раньше. Оба при этом отвечают «валидно» на валидном входе — то есть расходятся ровно там, где расхождение не видно.
Конвенция требует этого прямо: «кодек курсора не переписывать — guard обязан звать тот же разбор, что исполняется на пути чтения».
Почему в фундаменте, а не в слое приложения ¶
Кодек зовут ОБА слоя: проверка формата на границе приложения и репозиторий. Репозиторий — адаптер, и импортировать слой use-case ему нельзя (правило направления зависимостей). Единственное место, видимое обоим и ни одному не принадлежащее, — фундамент.
Index ¶
Constants ¶
This section is empty.
Variables ¶
var Canonical = Codec{/* contains filtered or unexported fields */}
Canonical — форма iam: стандартный алфавит с дополнением, разделитель `|`.
var NULSeparatedRawURL = Codec{/* contains filtered or unexported fields */}
NULSeparatedRawURL — форма nlb: алфавит URL без дополнения, разделитель — нулевой байт. Объявлена здесь, а не у nlb, ровно затем, чтобы РАЗЛИЧИЕ ДВУХ ФОРМ было видно в одном месте: пока каждая жила у себя, несовместимость обнаруживалась только на чужом токене.
Functions ¶
func EncodeSubscriptionPosition ¶
func EncodeSubscriptionPosition(p SubscriptionPosition) string
EncodeSubscriptionPosition собирает непрозрачный токен позиции.
Пустой строки конструктор НЕ выпускает НИКОГДА: пустое значение поля позиции означает «позиция не задана», и производитель, способный выпустить пустое, сделал бы эти два состояния неразличимыми у вызывающего.
func SubscriptionPositionWellFormed ¶
SubscriptionPositionWellFormed отвечает, разбирается ли токен. Пустой — да («позиция не задана»).
Отдельная функция нужна проверке формата на границе приложения: ей позиция не нужна, нужен вердикт, — а повторять разбор своим кодом есть ровно то, чего пакет и избегает.
func WellFormed ¶
WellFormed отвечает, разбирается ли токен. Пустой — да (первая страница).
Отдельная функция нужна проверке формата: ей курсор не нужен, нужен вердикт, а повторять разбор своим кодом — ровно то, чего пакет и избегает.
Types ¶
type Codec ¶
type Codec struct {
// contains filtered or unexported fields
}
Codec — объявленная форма курсора: чем кодируется и чем разделяется тело.
type Cursor ¶
Cursor — граница страницы в keyset-порядке: последняя ОТДАННАЯ строка.
func Decode ¶
Decode разбирает токен.
Пустой токен — ПЕРВАЯ страница, и он возвращает (nil, true): отсутствие представимо отдельно от всякого значения, поэтому вызывающий не обязан различать «токена не было» и «токен разобрался в нулевой курсор».
Второй ответ — годность, а не ошибка: у вызывающих разный контракт отказа (проверка формата отвечает INVALID_ARGUMENT с именем поля, репозиторий — своим сигнальным значением), и навязывать им общий тип ошибки значило бы заставить каждого переводить её обратно.
type SubscriptionPosition ¶
type SubscriptionPosition struct {
// Settled — граница устоявшегося. Ноль — законная величина: «журнал ещё
// ничего не устоял».
Settled int64
}
SubscriptionPosition — позиция подписки: граница УСТОЯВШЕГОСЯ в журнале владельца.
Почему это ОТДЕЛЬНЫЙ тип, а не [Cursor] ¶
`Cursor` объявлен как «граница страницы в keyset-порядке: последняя ОТДАННАЯ строка». Для подписки это дословно запрещённая форма: номер выдаётся на вставке, видимость наступает на фиксации, поэтому писатель, закоммитивший позже с меньшим номером, оказывается ЗА границей по отданному — навсегда, молча и без пропуска в нумерации, видимого клиенту.
Взять `Cursor` было бы унификацией по самой узкой семантике: два предмета совпадают формой («строка-токен, кодирующая место в порядке») и расходятся смыслом границы. Совпадение формы не есть общность предмета.
Что означает Settled ¶
Каждый номер `≤ Settled` в журнале владельца либо УЖЕ ВИДИМ, либо не появится НИКОГДА (писатель откатился). Это и есть свойство, ради которого позиция непрозрачна: возобновление с неё не пропускает ни одной строки, закоммиченной после её выдачи. Производит эту величину сервер подписки (`pkg/subscription`); кодек её только переносит.
Скаляр здесь законен — незаконен его ПРОИЗВОДИТЕЛЬ «максимум видимого». Разрядность величины ни при чём.
func DecodeSubscriptionPosition ¶
func DecodeSubscriptionPosition(token string) (*SubscriptionPosition, bool)
DecodeSubscriptionPosition разбирает токен позиции.
Пустой токен — «позиция не задана», и он возвращает `(nil, true)`: отсутствие представимо ОТДЕЛЬНО от всякого значения, поэтому вызывающий не обязан различать «позиции не было» и «позиция разобралась в ноль». Ноль здесь — законная величина («ничего ещё не устоялось»), и слить его с отсутствием значило бы отдать журнал с начала тому, кто просил хвост.
Второй ответ — годность, а не ошибка: у вызывающих разный контракт отказа, и навязывать им общий тип значило бы заставить каждого переводить его обратно.