Пагинация
Не люблю, когда для обхода данных нужна пагинация. Всякие LIMIT/OFFSET
,
nextToken
и прочие костыли.
Я понимаю, что нельзя отдать все одним запросом, поэтому делается апишка с
пагинацией. Но не понимаю, почему не пишут функцию, которая пагинирует сама и
возвращает ленивую коллекцию. Чтобы раз — зарядил один цикл for
, и оно внутри
само пагинируется: пробрасываются токены, офсеты и остальное.
Я всегда пишу такую функцию, чтобы не бодаться с пагинацией. Ведь что такое пагинация? Это минное поле багов. Нужно проверить, что не ошибся на единицу, что нет пересечения в результатах, что проверил последний результат на пустоту, что не ушел в бесконечный цикл… отловить все это в тестах невозможно. Нужен реальный источник данных плюс сами данные.
Даже если в языке нет ленивых коллекций, то наверняка есть итераторы или
стримы. Скажем, смотрю на джавный S3 SDK. Есть метод listObjects
, который
вернет до тысячи объектов. Нужен следующий чанк — прокидывай nextToken
. А что
мешало написать метод, который вернет Iterator<ListObjectResult>
или
Stream<S3Object>
? Ведь это же так просто.
Поэтому правило: если нельзя отдать одним запросом, то хотя бы дай функцию, которая пагинирует сама.
Более широкий тезис: источник данных хорош настолько, насколько легко забрать из
него данные. Скажем, знаете ли вы, насколько кривая апишка у OpenSearch? У него
нет встроенной функции “дай мне все” или “сбрось данные в CSV”. Для забора
данных нужны две апишки. Первая вернет ScrollID
и первый чанк данных. Далее
нужно вызывать другую апишку с этим скроллом, пока не соберешь остальные
данные. При этом ты обязан сообщить время жизни скролла, после которого он
умирает. Время должен прикинуть сам на глазок.
На практике это два экрана кода плюс отладка на стейджинге. После этого на код
запрещено дышать, чтобы не сломалось. На фоне этой мерзости только одно утешение
— Постгрес. Его апишка COPY
гоняет миллионы записей в обе стороны,
поддерживает три(!) формата, простая как лопата, быстрая как не знаю что.
Пагинация все еще необходима из-за ограничений. Но во-первых, ее всегда можно чем-то прикрыть, а во-вторых — иногда избежать.
Нашли ошибку? Выделите мышкой и нажмите Ctrl/⌘+Enter
Дима, 29th Oct 2024, link
А можно пример такой функции на Clojure?