[{"data":1,"prerenderedAt":1793},["ShallowReactive",2],{"navigation_docs_en":3,"-en-paginate-overview":441,"-en-paginate-overview-surround":1788},[4,45,60,81,112,129,146,173,197,213,242,279,356,372,384,403,429],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","\u002Fen\u002Fgetting-started","en\u002F1.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fen\u002Fgetting-started\u002Fintroduction","en\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Coming from Laravel","\u002Fen\u002Fgetting-started\u002Fcoming-from-laravel","en\u002F1.getting-started\u002F2.coming-from-laravel","i-lucide-arrow-right-left",{"title":21,"path":22,"stem":23,"icon":19},"Coming from Symfony","\u002Fen\u002Fgetting-started\u002Fcoming-from-symfony","en\u002F1.getting-started\u002F3.coming-from-symfony",{"title":25,"path":26,"stem":27,"icon":28},"Installation","\u002Fen\u002Fgetting-started\u002Finstallation","en\u002F1.getting-started\u002F4.installation","i-lucide-download",{"title":30,"path":31,"stem":32,"icon":33},"Your first module","\u002Fen\u002Fgetting-started\u002Ffirst-module","en\u002F1.getting-started\u002F5.first-module","i-lucide-package-plus",{"title":35,"path":36,"stem":37,"icon":38},"Project structure","\u002Fen\u002Fgetting-started\u002Fproject-structure","en\u002F1.getting-started\u002F6.project-structure","i-lucide-folder-tree",{"title":40,"path":41,"stem":42,"icon":43},"The shop sample application","\u002Fen\u002Fgetting-started\u002Fsample-app","en\u002F1.getting-started\u002F7.sample-app","i-lucide-shopping-cart",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"queue","i-lucide-layers","\u002Fen\u002Fqueue","en\u002F10.queue",[51,56],{"title":52,"path":53,"stem":54,"icon":55},"Overview","\u002Fen\u002Fqueue\u002Foverview","en\u002F10.queue\u002F1.overview","i-lucide-list-ordered",{"title":57,"path":58,"stem":59,"icon":47},"Tasks","\u002Fen\u002Fqueue\u002Ftasks","en\u002F10.queue\u002F2.tasks",{"title":61,"icon":62,"path":63,"stem":64,"children":65,"page":44},"events","i-lucide-workflow","\u002Fen\u002Fevents","en\u002F11.events",[66,71,76],{"title":67,"path":68,"stem":69,"icon":70},"Events","\u002Fen\u002Fevents\u002Foverview","en\u002F11.events\u002F1.overview","i-lucide-radio",{"title":72,"path":73,"stem":74,"icon":75},"Outbox","\u002Fen\u002Fevents\u002Foutbox","en\u002F11.events\u002F2.outbox","i-lucide-inbox",{"title":77,"path":78,"stem":79,"icon":80},"Scheduling","\u002Fen\u002Fevents\u002Fscheduler","en\u002F11.events\u002F3.scheduler","i-lucide-calendar-clock",{"title":82,"icon":83,"path":84,"stem":85,"children":86,"page":44},"auth","i-lucide-shield-check","\u002Fen\u002Fauth","en\u002F12.auth",[87,92,97,102,107],{"title":88,"path":89,"stem":90,"icon":91},"Authentication","\u002Fen\u002Fauth\u002Foverview","en\u002F12.auth\u002F1.overview","i-lucide-key-round",{"title":93,"path":94,"stem":95,"icon":96},"RBAC","\u002Fen\u002Fauth\u002Frbac","en\u002F12.auth\u002F2.rbac","i-lucide-users",{"title":98,"path":99,"stem":100,"icon":101},"Policies","\u002Fen\u002Fauth\u002Fpolicy","en\u002F12.auth\u002F3.policy","i-lucide-gavel",{"title":103,"path":104,"stem":105,"icon":106},"Using auth standalone","\u002Fen\u002Fauth\u002Fstandalone","en\u002F12.auth\u002F4.standalone","i-lucide-plug",{"title":108,"path":109,"stem":110,"icon":111},"Social login with goth, standalone","\u002Fen\u002Fauth\u002Fsocial-standalone","en\u002F12.auth\u002F5.social-standalone","i-lucide-log-in",{"title":113,"icon":114,"path":115,"stem":116,"children":117,"page":44},"mail","i-lucide-mail","\u002Fen\u002Fmail","en\u002F13.mail",[118,121,125],{"title":52,"path":119,"stem":120,"icon":114},"\u002Fen\u002Fmail\u002Foverview","en\u002F13.mail\u002F1.overview",{"title":122,"path":123,"stem":124,"icon":114},"SMTP","\u002Fen\u002Fmail\u002Fsmtp","en\u002F13.mail\u002F2.smtp",{"title":126,"path":127,"stem":128,"icon":114},"MJML","\u002Fen\u002Fmail\u002Fmjml","en\u002F13.mail\u002F3.mjml",{"title":130,"icon":131,"path":132,"stem":133,"children":134,"page":44},"notify","i-lucide-bell","\u002Fen\u002Fnotify","en\u002F14.notify",[135,138,142],{"title":52,"path":136,"stem":137,"icon":131},"\u002Fen\u002Fnotify\u002Foverview","en\u002F14.notify\u002F1.overview",{"title":139,"path":140,"stem":141,"icon":131},"Database channel","\u002Fen\u002Fnotify\u002Fdatabase","en\u002F14.notify\u002F2.database",{"title":143,"path":144,"stem":145,"icon":131},"Broadcast channel","\u002Fen\u002Fnotify\u002Fbroadcast","en\u002F14.notify\u002F3.broadcast",{"title":147,"icon":148,"path":149,"stem":150,"children":151,"page":44},"storage","i-lucide-hard-drive","\u002Fen\u002Fstorage","en\u002F15.storage",[152,155,159,163,168],{"title":52,"path":153,"stem":154,"icon":148},"\u002Fen\u002Fstorage\u002Foverview","en\u002F15.storage\u002F1.overview",{"title":156,"path":157,"stem":158},"Disk API","\u002Fen\u002Fstorage\u002Fdisk-api","en\u002F15.storage\u002F2.disk-api",{"title":160,"path":161,"stem":162,"icon":148},"Memory and local disk","\u002Fen\u002Fstorage\u002Flocal","en\u002F15.storage\u002F3.local",{"title":164,"path":165,"stem":166,"icon":167},"S3","\u002Fen\u002Fstorage\u002Fs3","en\u002F15.storage\u002F4.s3","i-lucide-cloud",{"title":169,"path":170,"stem":171,"icon":172},"Testing","\u002Fen\u002Fstorage\u002Ftesting","en\u002F15.storage\u002F5.testing","i-lucide-flask-conical",{"title":174,"icon":175,"path":176,"stem":177,"children":178,"page":44},"telemetry","i-lucide-activity","\u002Fen\u002Ftelemetry","en\u002F16.telemetry",[179,182,187,192],{"title":52,"path":180,"stem":181,"icon":175},"\u002Fen\u002Ftelemetry\u002Foverview","en\u002F16.telemetry\u002F1.overview",{"title":183,"path":184,"stem":185,"icon":186},"Logging","\u002Fen\u002Ftelemetry\u002Flogging","en\u002F16.telemetry\u002F2.logging","i-lucide-scroll-text",{"title":188,"path":189,"stem":190,"icon":191},"OpenTelemetry","\u002Fen\u002Ftelemetry\u002Fopentelemetry","en\u002F16.telemetry\u002F3.opentelemetry","i-lucide-radar",{"title":193,"path":194,"stem":195,"icon":196},"Sentry","\u002Fen\u002Ftelemetry\u002Fsentry","en\u002F16.telemetry\u002F4.sentry","i-lucide-bug",{"title":198,"icon":199,"path":200,"stem":201,"children":202,"page":44},"Reference","i-lucide-book-open","\u002Fen\u002Freference","en\u002F17.reference",[203,208],{"title":204,"path":205,"stem":206,"icon":207},"Configuration","\u002Fen\u002Freference\u002Fconfiguration","en\u002F17.reference\u002F1.configuration","i-lucide-settings",{"title":209,"path":210,"stem":211,"icon":212},"External dependencies","\u002Fen\u002Freference\u002Fdependencies","en\u002F17.reference\u002F2.dependencies","i-lucide-package",{"title":214,"icon":215,"path":216,"stem":217,"children":218,"page":44},"Concepts","i-lucide-lightbulb","\u002Fen\u002Fconcepts","en\u002F2.concepts",[219,223,228,232,237],{"title":220,"path":221,"stem":222,"icon":47},"Architecture","\u002Fen\u002Fconcepts\u002Farchitecture","en\u002F2.concepts\u002F1.architecture",{"title":224,"path":225,"stem":226,"icon":227},"Error model","\u002Fen\u002Fconcepts\u002Ferror-model","en\u002F2.concepts\u002F2.error-model","i-lucide-shield-alert",{"title":204,"path":229,"stem":230,"icon":231},"\u002Fen\u002Fconcepts\u002Fconfiguration","en\u002F2.concepts\u002F3.configuration","i-lucide-settings-2",{"title":233,"path":234,"stem":235,"icon":236},"Codegen pipeline","\u002Fen\u002Fconcepts\u002Fcodegen-pipeline","en\u002F2.concepts\u002F4.codegen-pipeline","i-lucide-file-json",{"title":238,"path":239,"stem":240,"icon":241},"Design patterns","\u002Fen\u002Fconcepts\u002Fdesign-patterns","en\u002F2.concepts\u002F5.design-patterns","i-lucide-puzzle",{"title":243,"icon":244,"path":245,"stem":246,"children":247,"page":44},"Kit","i-lucide-box","\u002Fen\u002Fkit","en\u002F3.kit",[248,251,256,261,266,270,275],{"title":52,"path":249,"stem":250,"icon":244},"\u002Fen\u002Fkit\u002Foverview","en\u002F3.kit\u002F1.overview",{"title":252,"path":253,"stem":254,"icon":255},"Application lifecycle","\u002Fen\u002Fkit\u002Fapp","en\u002F3.kit\u002F2.app","i-lucide-power",{"title":257,"path":258,"stem":259,"icon":260},"Server","\u002Fen\u002Fkit\u002Fserver","en\u002F3.kit\u002F3.server","i-lucide-server",{"title":262,"path":263,"stem":264,"icon":265},"Worker","\u002Fen\u002Fkit\u002Fworker","en\u002F3.kit\u002F4.worker","i-lucide-cog",{"title":267,"path":268,"stem":269,"icon":70},"Realtime","\u002Fen\u002Fkit\u002Frealtime","en\u002F3.kit\u002F5.realtime",{"title":271,"path":272,"stem":273,"icon":274},"Migrations","\u002Fen\u002Fkit\u002Fmigrations","en\u002F3.kit\u002F6.migrations","i-lucide-file-stack",{"title":276,"path":277,"stem":278,"icon":111},"Social login","\u002Fen\u002Fkit\u002Fsocial-login","en\u002F3.kit\u002F7.social-login",{"title":280,"icon":281,"path":282,"stem":283,"children":284,"page":44},"CLI Reference","i-lucide-terminal","\u002Fen\u002Fcli","en\u002F4.cli",[285,288,293,298,303,308,313,318,323,328,333,337,342,347,351],{"title":52,"path":286,"stem":287,"icon":281},"\u002Fen\u002Fcli\u002Foverview","en\u002F4.cli\u002F1.overview",{"title":289,"path":290,"stem":291,"icon":292},"add db","\u002Fen\u002Fcli\u002Fadd-db","en\u002F4.cli\u002F10.add-db","i-lucide-database-zap",{"title":294,"path":295,"stem":296,"icon":297},"add compose \u002F add docker","\u002Fen\u002Fcli\u002Fadd-compose","en\u002F4.cli\u002F11.add-compose","i-lucide-container",{"title":299,"path":300,"stem":301,"icon":302},"add mail","\u002Fen\u002Fcli\u002Fadd-mail","en\u002F4.cli\u002F12.add-mail","i-lucide-mail-plus",{"title":304,"path":305,"stem":306,"icon":307},"add notification","\u002Fen\u002Fcli\u002Fadd-notification","en\u002F4.cli\u002F13.add-notification","i-lucide-bell-plus",{"title":309,"path":310,"stem":311,"icon":312},"add realtime","\u002Fen\u002Fcli\u002Fadd-realtime","en\u002F4.cli\u002F14.add-realtime","i-lucide-radio-tower",{"title":314,"path":315,"stem":316,"icon":317},"add seeder","\u002Fen\u002Fcli\u002Fadd-seeder","en\u002F4.cli\u002F15.add-seeder","i-lucide-sprout",{"title":319,"path":320,"stem":321,"icon":322},"new project","\u002Fen\u002Fcli\u002Fnew-project","en\u002F4.cli\u002F2.new-project","i-lucide-folder-plus",{"title":324,"path":325,"stem":326,"icon":327},"new module","\u002Fen\u002Fcli\u002Fnew-module","en\u002F4.cli\u002F3.new-module","i-lucide-blocks",{"title":329,"path":330,"stem":331,"icon":332},"add surface","\u002Fen\u002Fcli\u002Fadd-surface","en\u002F4.cli\u002F4.add-surface","i-lucide-layers-2",{"title":334,"path":335,"stem":336,"icon":244},"add core","\u002Fen\u002Fcli\u002Fadd-core","en\u002F4.cli\u002F5.add-core",{"title":338,"path":339,"stem":340,"icon":341},"add handler","\u002Fen\u002Fcli\u002Fadd-handler","en\u002F4.cli\u002F6.add-handler","i-lucide-webhook",{"title":343,"path":344,"stem":345,"icon":346},"new migration","\u002Fen\u002Fcli\u002Fnew-migration","en\u002F4.cli\u002F7.new-migration","i-lucide-file-plus",{"title":348,"path":349,"stem":350,"icon":265},"worker generators","\u002Fen\u002Fcli\u002Fworker-generators","en\u002F4.cli\u002F8.worker-generators",{"title":352,"path":353,"stem":354,"icon":355},"upgrade templates","\u002Fen\u002Fcli\u002Fupgrade-templates","en\u002F4.cli\u002F9.upgrade-templates","i-lucide-refresh-cw",{"title":357,"icon":227,"path":358,"stem":359,"children":360,"page":44},"errs","\u002Fen\u002Ferrs","en\u002F5.errs",[361,364,368],{"title":52,"path":362,"stem":363,"icon":227},"\u002Fen\u002Ferrs\u002Foverview","en\u002F5.errs\u002F1.overview",{"title":365,"path":366,"stem":367},"API","\u002Fen\u002Ferrs\u002Fapi","en\u002F5.errs\u002F2.api",{"title":369,"path":370,"stem":371,"icon":227},"Integration","\u002Fen\u002Ferrs\u002Fintegration","en\u002F5.errs\u002F3.integration",{"title":373,"icon":231,"path":374,"stem":375,"children":376,"page":44},"envconf","\u002Fen\u002Fenvconf","en\u002F6.envconf",[377,380],{"title":52,"path":378,"stem":379,"icon":231},"\u002Fen\u002Fenvconf\u002Foverview","en\u002F6.envconf\u002F1.overview",{"title":381,"path":382,"stem":383},"Recipes","\u002Fen\u002Fenvconf\u002Frecipes","en\u002F6.envconf\u002F2.recipes",{"title":385,"icon":386,"path":387,"stem":388,"children":389,"page":44},"httperr","i-lucide-globe","\u002Fen\u002Fhttperr","en\u002F7.httperr",[390,393,398],{"title":52,"path":391,"stem":392,"icon":386},"\u002Fen\u002Fhttperr\u002Foverview","en\u002F7.httperr\u002F1.overview",{"title":394,"path":395,"stem":396,"icon":397},"Error responses","\u002Fen\u002Fhttperr\u002Ferror-responses","en\u002F7.httperr\u002F2.error-responses","i-lucide-octagon-alert",{"title":399,"path":400,"stem":401,"icon":402},"Validation","\u002Fen\u002Fhttperr\u002Fvalidation","en\u002F7.httperr\u002F3.validation","i-lucide-badge-check",{"title":404,"icon":405,"path":406,"stem":407,"children":408,"page":44},"dbx","i-lucide-database","\u002Fen\u002Fdbx","en\u002F8.dbx",[409,412,416,420,425],{"title":52,"path":410,"stem":411,"icon":405},"\u002Fen\u002Fdbx\u002Foverview","en\u002F8.dbx\u002F1.overview",{"title":413,"path":414,"stem":415,"icon":106},"pgx","\u002Fen\u002Fdbx\u002Fpg","en\u002F8.dbx\u002F2.pg",{"title":417,"path":418,"stem":419,"icon":47},"bun","\u002Fen\u002Fdbx\u002Fbunx","en\u002F8.dbx\u002F3.bunx",{"title":421,"path":422,"stem":423,"icon":424},"Transactions","\u002Fen\u002Fdbx\u002Ftransactions","en\u002F8.dbx\u002F4.transactions","i-lucide-git-merge",{"title":426,"path":427,"stem":428,"icon":317},"Seeders","\u002Fen\u002Fdbx\u002Fseed","en\u002F8.dbx\u002F5.seed",{"title":430,"icon":55,"path":431,"stem":432,"children":433,"page":44},"paginate","\u002Fen\u002Fpaginate","en\u002F9.paginate",[434,437],{"title":52,"path":435,"stem":436,"icon":55},"\u002Fen\u002Fpaginate\u002Foverview","en\u002F9.paginate\u002F1.overview",{"title":438,"path":439,"stem":440,"icon":19},"Cursor pagination","\u002Fen\u002Fpaginate\u002Fcursor","en\u002F9.paginate\u002F2.cursor",{"id":442,"title":52,"body":443,"description":1781,"extension":1782,"links":1783,"meta":1784,"navigation":1785,"path":435,"seo":1786,"stem":436,"__hash__":1787},"docs_en\u002Fen\u002F9.paginate\u002F1.overview.md",{"type":444,"value":445,"toc":1773},"minimark",[446,471,499,504,536,551,555,569,703,823,826,920,947,954,1078,1091,1108,1112,1121,1687,1691,1712,1716,1749,1753,1769],[447,448,449,452,453,456,457,461,462,465,466,470],"p",{},[450,451,430],"code",{}," is a standalone Go module (",[450,454,455],{},"github.com\u002Fgp-system\u002Fpaginate",") that centralizes the two boring-but-dangerous halves of pagination: ",[458,459,460],"strong",{},"normalizing"," client input (bounds, defaults, overflow protection) and ",[458,463,464],{},"wrapping"," results for the response model. It offers two modes: classic page\u002Fper-page (offset) pagination, covered on this page, and ",[467,468,469],"a",{"href":439},"cursor (keyset) pagination",", covered on its own page since it carries a different parameter shape and a different set of correctness rules.",[472,473,478],"pre",{"className":474,"code":475,"language":476,"meta":477,"style":477},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import \"github.com\u002Fgp-system\u002Fpaginate\"\n","go","",[450,479,480],{"__ignoreMap":477},[481,482,485,489,493,496],"span",{"class":483,"line":484},"line",1,[481,486,488],{"class":487},"s7zQu","import",[481,490,492],{"class":491},"sMK4o"," \"",[481,494,455],{"class":495},"sBMFI",[481,497,498],{"class":491},"\"\n",[500,501,503],"h2",{"id":502},"install","Install",[472,505,509],{"className":506,"code":507,"language":508,"meta":477,"style":477},"language-sh shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","go get github.com\u002Fgp-system\u002Fpaginate@v0.1.0 # the kit itself uses this tag\ngo get github.com\u002Fgp-system\u002Fpaginate@latest\n","sh",[450,510,511,526],{"__ignoreMap":477},[481,512,513,515,519,522],{"class":483,"line":484},[481,514,476],{"class":495},[481,516,518],{"class":517},"sfazB"," get",[481,520,521],{"class":517}," github.com\u002Fgp-system\u002Fpaginate@v0.1.0",[481,523,525],{"class":524},"sHwdD"," # the kit itself uses this tag\n",[481,527,529,531,533],{"class":483,"line":528},2,[481,530,476],{"class":495},[481,532,518],{"class":517},[481,534,535],{"class":517}," github.com\u002Fgp-system\u002Fpaginate@latest\n",[447,537,538,539,541,542,546,547,550],{},"Go 1.25+. ",[450,540,430],{}," depends only on ",[467,543,544],{"href":362},[450,545,357],{}," (for ",[450,548,549],{},"ErrInvalidCursor","); there is no query builder, no database driver, nothing else to pull in.",[500,552,554],{"id":553},"offset-pagination","Offset pagination",[447,556,557,560,561,564,565,568],{},[467,558,559],{"href":234},"Generated"," request parameters arrive as optional pointers (",[450,562,563],{},"*int","); ",[450,566,567],{},"Normalize"," clamps them once, instead of in every handler:",[472,570,572],{"className":474,"code":571,"language":476,"meta":477,"style":477},"func Normalize(page, perPage *int, opts ...Option) Params\n\ntype Params struct{ Page, PerPage int }\nfunc (p Params) Limit() int  \u002F\u002F SQL LIMIT\nfunc (p Params) Offset() int \u002F\u002F SQL OFFSET: (Page-1)*PerPage\n",[450,573,574,620,626,652,680],{"__ignoreMap":477},[481,575,576,579,583,586,590,593,596,599,603,605,608,611,614,617],{"class":483,"line":484},[481,577,578],{"class":491},"func",[481,580,582],{"class":581},"s2Zo4"," Normalize",[481,584,585],{"class":491},"(",[481,587,589],{"class":588},"sHdIc","page",[481,591,592],{"class":491},",",[481,594,595],{"class":588}," perPage",[481,597,598],{"class":491}," *",[481,600,602],{"class":601},"spNyl","int",[481,604,592],{"class":491},[481,606,607],{"class":588}," opts",[481,609,610],{"class":491}," ...",[481,612,613],{"class":495},"Option",[481,615,616],{"class":491},")",[481,618,619],{"class":495}," Params\n",[481,621,622],{"class":483,"line":528},[481,623,625],{"emptyLinePlaceholder":624},true,"\n",[481,627,629,632,635,638,642,644,647,649],{"class":483,"line":628},3,[481,630,631],{"class":491},"type",[481,633,634],{"class":495}," Params",[481,636,637],{"class":491}," struct{",[481,639,641],{"class":640},"sTEyZ"," Page",[481,643,592],{"class":491},[481,645,646],{"class":640}," PerPage ",[481,648,602],{"class":601},[481,650,651],{"class":491}," }\n",[481,653,655,657,660,663,666,668,671,674,677],{"class":483,"line":654},4,[481,656,578],{"class":491},[481,658,659],{"class":491}," (",[481,661,662],{"class":588},"p ",[481,664,665],{"class":495},"Params",[481,667,616],{"class":491},[481,669,670],{"class":581}," Limit",[481,672,673],{"class":491},"()",[481,675,676],{"class":601}," int",[481,678,679],{"class":524},"  \u002F\u002F SQL LIMIT\n",[481,681,683,685,687,689,691,693,696,698,700],{"class":483,"line":682},5,[481,684,578],{"class":491},[481,686,659],{"class":491},[481,688,662],{"class":588},[481,690,665],{"class":495},[481,692,616],{"class":491},[481,694,695],{"class":581}," Offset",[481,697,673],{"class":491},[481,699,676],{"class":601},[481,701,702],{"class":524}," \u002F\u002F SQL OFFSET: (Page-1)*PerPage\n",[472,704,706],{"className":474,"code":705,"language":476,"meta":477,"style":477},"p := paginate.Normalize(req.Params.Page, req.Params.PerPage) \u002F\u002F defaults: page 1, perPage 20\nrows, err := r.db.Query(ctx,\n    `SELECT ... ORDER BY created_at DESC LIMIT $1 OFFSET $2`, p.Limit(), p.Offset())\n",[450,707,708,756,789],{"__ignoreMap":477},[481,709,710,712,715,718,721,723,725,728,730,732,734,737,739,742,744,746,748,751,753],{"class":483,"line":484},[481,711,662],{"class":640},[481,713,714],{"class":491},":=",[481,716,717],{"class":640}," paginate",[481,719,720],{"class":491},".",[481,722,567],{"class":581},[481,724,585],{"class":491},[481,726,727],{"class":640},"req",[481,729,720],{"class":491},[481,731,665],{"class":640},[481,733,720],{"class":491},[481,735,736],{"class":640},"Page",[481,738,592],{"class":491},[481,740,741],{"class":640}," req",[481,743,720],{"class":491},[481,745,665],{"class":640},[481,747,720],{"class":491},[481,749,750],{"class":640},"PerPage",[481,752,616],{"class":491},[481,754,755],{"class":524}," \u002F\u002F defaults: page 1, perPage 20\n",[481,757,758,761,763,766,768,771,773,776,778,781,783,786],{"class":483,"line":528},[481,759,760],{"class":640},"rows",[481,762,592],{"class":491},[481,764,765],{"class":640}," err ",[481,767,714],{"class":491},[481,769,770],{"class":640}," r",[481,772,720],{"class":491},[481,774,775],{"class":640},"db",[481,777,720],{"class":491},[481,779,780],{"class":581},"Query",[481,782,585],{"class":491},[481,784,785],{"class":640},"ctx",[481,787,788],{"class":491},",\n",[481,790,791,794,797,800,802,805,807,810,813,815,817,820],{"class":483,"line":628},[481,792,793],{"class":491},"    `",[481,795,796],{"class":517},"SELECT ... ORDER BY created_at DESC LIMIT $1 OFFSET $2",[481,798,799],{"class":491},"`",[481,801,592],{"class":491},[481,803,804],{"class":640}," p",[481,806,720],{"class":491},[481,808,809],{"class":581},"Limit",[481,811,812],{"class":491},"(),",[481,814,804],{"class":640},[481,816,720],{"class":491},[481,818,819],{"class":581},"Offset",[481,821,822],{"class":491},"())\n",[447,824,825],{},"The bounds are tunable with options:",[472,827,829],{"className":474,"code":828,"language":476,"meta":477,"style":477},"p := paginate.Normalize(page, perPage,\n    paginate.WithDefaultPerPage(15), \u002F\u002F when the request omits perPage (default: 20)\n    paginate.WithMaxPerPage(50),     \u002F\u002F hard cap, whatever the client asks for (default: 100)\n    paginate.WithMaxPage(10_000))    \u002F\u002F cap on the page number (default: 1,000,000)\n",[450,830,831,853,875,894],{"__ignoreMap":477},[481,832,833,835,837,839,841,843,845,847,849,851],{"class":483,"line":484},[481,834,662],{"class":640},[481,836,714],{"class":491},[481,838,717],{"class":640},[481,840,720],{"class":491},[481,842,567],{"class":581},[481,844,585],{"class":491},[481,846,589],{"class":640},[481,848,592],{"class":491},[481,850,595],{"class":640},[481,852,788],{"class":491},[481,854,855,858,860,863,865,869,872],{"class":483,"line":528},[481,856,857],{"class":640},"    paginate",[481,859,720],{"class":491},[481,861,862],{"class":581},"WithDefaultPerPage",[481,864,585],{"class":491},[481,866,868],{"class":867},"sbssI","15",[481,870,871],{"class":491},"),",[481,873,874],{"class":524}," \u002F\u002F when the request omits perPage (default: 20)\n",[481,876,877,879,881,884,886,889,891],{"class":483,"line":628},[481,878,857],{"class":640},[481,880,720],{"class":491},[481,882,883],{"class":581},"WithMaxPerPage",[481,885,585],{"class":491},[481,887,888],{"class":867},"50",[481,890,871],{"class":491},[481,892,893],{"class":524},"     \u002F\u002F hard cap, whatever the client asks for (default: 100)\n",[481,895,896,898,900,903,905,908,911,914,917],{"class":483,"line":654},[481,897,857],{"class":640},[481,899,720],{"class":491},[481,901,902],{"class":581},"WithMaxPage",[481,904,585],{"class":491},[481,906,907],{"class":867},"10",[481,909,910],{"class":491},"_",[481,912,913],{"class":867},"000",[481,915,916],{"class":491},"))",[481,918,919],{"class":524},"    \u002F\u002F cap on the page number (default: 1,000,000)\n",[447,921,922,924,925,928,929,932,933,936,937,940,941,943,944,946],{},[450,923,902],{}," is not cosmetic: ",[450,926,927],{},"Offset()"," is the product ",[450,930,931],{},"(page-1)*perPage",". Without a cap, a hostile ",[450,934,935],{},"?page="," value could provoke an int overflow or a pathological ",[450,938,939],{},"OFFSET",". After ",[450,942,567],{},", ",[450,945,927],{}," is guaranteed safe.",[447,948,949,950,953],{},"Results are wrapped for the response by ",[450,951,952],{},"Page[T]",":",[472,955,957],{"className":474,"code":956,"language":476,"meta":477,"style":477},"func NewPage[T any](items []T, total int64, p Params) Page[T]\n\ntype Page[T any] struct {\n    Items   []T\n    Total   int64\n    Page    int\n    PerPage int\n}\n",[450,958,959,1011,1015,1036,1047,1055,1064,1072],{"__ignoreMap":477},[481,960,961,963,966,969,972,975,978,981,984,986,988,991,994,996,998,1000,1002,1004,1006,1008],{"class":483,"line":484},[481,962,578],{"class":491},[481,964,965],{"class":581}," NewPage",[481,967,968],{"class":491},"[",[481,970,971],{"class":588},"T",[481,973,974],{"class":495}," any",[481,976,977],{"class":491},"](",[481,979,980],{"class":588},"items",[481,982,983],{"class":491}," []",[481,985,971],{"class":495},[481,987,592],{"class":491},[481,989,990],{"class":588}," total",[481,992,993],{"class":601}," int64",[481,995,592],{"class":491},[481,997,804],{"class":588},[481,999,634],{"class":495},[481,1001,616],{"class":491},[481,1003,641],{"class":495},[481,1005,968],{"class":491},[481,1007,971],{"class":495},[481,1009,1010],{"class":491},"]\n",[481,1012,1013],{"class":483,"line":528},[481,1014,625],{"emptyLinePlaceholder":624},[481,1016,1017,1019,1021,1023,1025,1027,1030,1033],{"class":483,"line":628},[481,1018,631],{"class":491},[481,1020,641],{"class":495},[481,1022,968],{"class":491},[481,1024,971],{"class":588},[481,1026,974],{"class":495},[481,1028,1029],{"class":491},"]",[481,1031,1032],{"class":491}," struct",[481,1034,1035],{"class":491}," {\n",[481,1037,1038,1041,1044],{"class":483,"line":654},[481,1039,1040],{"class":640},"    Items   ",[481,1042,1043],{"class":491},"[]",[481,1045,1046],{"class":495},"T\n",[481,1048,1049,1052],{"class":483,"line":682},[481,1050,1051],{"class":640},"    Total   ",[481,1053,1054],{"class":601},"int64\n",[481,1056,1058,1061],{"class":483,"line":1057},6,[481,1059,1060],{"class":640},"    Page    ",[481,1062,1063],{"class":601},"int\n",[481,1065,1067,1070],{"class":483,"line":1066},7,[481,1068,1069],{"class":640},"    PerPage ",[481,1071,1063],{"class":601},[481,1073,1075],{"class":483,"line":1074},8,[481,1076,1077],{"class":491},"}\n",[447,1079,1080,1082,1083,1086,1087,1090],{},[450,1081,952],{}," mirrors the scaffolded ",[450,1084,1085],{},"shared\u002Fpaginator.tsp"," ",[450,1088,1089],{},"Paginated\u003CT>"," model, so mapping onto the generated response model is mechanical.",[1092,1093,1094,1095,1098,1099,1102,1103,1107],"note",{},"Offset pagination is the comfortable default for small, admin-style listings, where ",[450,1096,1097],{},"Total"," and jump-to-page matter more than raw throughput. On a large or fast-growing table, ",[467,1100,1101],{"href":439},"cursor pagination"," is the one that stays fast and stable as the table grows; see ",[467,1104,1106],{"href":1105},"\u002Fen\u002Fpaginate\u002Fcursor#which-one-when","Which one, when"," for the full comparison.",[500,1109,1111],{"id":1110},"standalone-example","Standalone example",[447,1113,1114,1116,1117,1120],{},[450,1115,430],{}," needs nothing from the kit: a plain ",[450,1118,1119],{},"net\u002Fhttp"," handler is enough to show the normalize-then-wrap shape.",[472,1122,1125],{"className":474,"code":1123,"filename":1124,"language":476,"meta":477,"style":477},"package main\n\nimport (\n    \"encoding\u002Fjson\"\n    \"net\u002Fhttp\"\n    \"strconv\"\n\n    \"github.com\u002Fgp-system\u002Fpaginate\"\n)\n\ntype Product struct {\n    ID   string `json:\"id\"`\n    Name string `json:\"name\"`\n}\n\nfunc listProducts(w http.ResponseWriter, r *http.Request) {\n    page := atoiPtr(r.URL.Query().Get(\"page\"))\n    perPage := atoiPtr(r.URL.Query().Get(\"per_page\"))\n    p := paginate.Normalize(page, perPage, paginate.WithMaxPerPage(50))\n\n    items, total := fetchProducts(p.Limit(), p.Offset()) \u002F\u002F your own query\n    json.NewEncoder(w).Encode(paginate.NewPage(items, total, p))\n}\n\nfunc atoiPtr(s string) *int {\n    if s == \"\" {\n        return nil\n    }\n    n, err := strconv.Atoi(s)\n    if err != nil {\n        return nil\n    }\n    return &n\n}\n\nfunc fetchProducts(limit, offset int) ([]Product, int64) {\n    return nil, 0 \u002F\u002F your repository call\n}\n","main.go",[450,1126,1127,1135,1139,1146,1156,1164,1173,1177,1185,1191,1196,1208,1226,1241,1246,1251,1290,1333,1370,1406,1411,1449,1493,1498,1503,1526,1543,1552,1558,1584,1599,1606,1611,1623,1628,1633,1668,1682],{"__ignoreMap":477},[481,1128,1129,1132],{"class":483,"line":484},[481,1130,1131],{"class":491},"package",[481,1133,1134],{"class":495}," main\n",[481,1136,1137],{"class":483,"line":528},[481,1138,625],{"emptyLinePlaceholder":624},[481,1140,1141,1143],{"class":483,"line":628},[481,1142,488],{"class":487},[481,1144,1145],{"class":491}," (\n",[481,1147,1148,1151,1154],{"class":483,"line":654},[481,1149,1150],{"class":491},"    \"",[481,1152,1153],{"class":495},"encoding\u002Fjson",[481,1155,498],{"class":491},[481,1157,1158,1160,1162],{"class":483,"line":682},[481,1159,1150],{"class":491},[481,1161,1119],{"class":495},[481,1163,498],{"class":491},[481,1165,1166,1168,1171],{"class":483,"line":1057},[481,1167,1150],{"class":491},[481,1169,1170],{"class":495},"strconv",[481,1172,498],{"class":491},[481,1174,1175],{"class":483,"line":1066},[481,1176,625],{"emptyLinePlaceholder":624},[481,1178,1179,1181,1183],{"class":483,"line":1074},[481,1180,1150],{"class":491},[481,1182,455],{"class":495},[481,1184,498],{"class":491},[481,1186,1188],{"class":483,"line":1187},9,[481,1189,1190],{"class":491},")\n",[481,1192,1194],{"class":483,"line":1193},10,[481,1195,625],{"emptyLinePlaceholder":624},[481,1197,1199,1201,1204,1206],{"class":483,"line":1198},11,[481,1200,631],{"class":491},[481,1202,1203],{"class":495}," Product",[481,1205,1032],{"class":491},[481,1207,1035],{"class":491},[481,1209,1211,1214,1217,1220,1223],{"class":483,"line":1210},12,[481,1212,1213],{"class":640},"    ID   ",[481,1215,1216],{"class":601},"string",[481,1218,1219],{"class":491}," `",[481,1221,1222],{"class":517},"json:\"id\"",[481,1224,1225],{"class":491},"`\n",[481,1227,1229,1232,1234,1236,1239],{"class":483,"line":1228},13,[481,1230,1231],{"class":640},"    Name ",[481,1233,1216],{"class":601},[481,1235,1219],{"class":491},[481,1237,1238],{"class":517},"json:\"name\"",[481,1240,1225],{"class":491},[481,1242,1244],{"class":483,"line":1243},14,[481,1245,1077],{"class":491},[481,1247,1249],{"class":483,"line":1248},15,[481,1250,625],{"emptyLinePlaceholder":624},[481,1252,1254,1256,1259,1261,1264,1267,1269,1272,1274,1276,1278,1281,1283,1286,1288],{"class":483,"line":1253},16,[481,1255,578],{"class":491},[481,1257,1258],{"class":581}," listProducts",[481,1260,585],{"class":491},[481,1262,1263],{"class":588},"w",[481,1265,1266],{"class":495}," http",[481,1268,720],{"class":491},[481,1270,1271],{"class":495},"ResponseWriter",[481,1273,592],{"class":491},[481,1275,770],{"class":588},[481,1277,598],{"class":491},[481,1279,1280],{"class":495},"http",[481,1282,720],{"class":491},[481,1284,1285],{"class":495},"Request",[481,1287,616],{"class":491},[481,1289,1035],{"class":491},[481,1291,1293,1296,1298,1301,1303,1306,1308,1311,1313,1315,1318,1321,1323,1326,1328,1330],{"class":483,"line":1292},17,[481,1294,1295],{"class":640},"    page ",[481,1297,714],{"class":491},[481,1299,1300],{"class":581}," atoiPtr",[481,1302,585],{"class":491},[481,1304,1305],{"class":640},"r",[481,1307,720],{"class":491},[481,1309,1310],{"class":640},"URL",[481,1312,720],{"class":491},[481,1314,780],{"class":581},[481,1316,1317],{"class":491},"().",[481,1319,1320],{"class":581},"Get",[481,1322,585],{"class":491},[481,1324,1325],{"class":491},"\"",[481,1327,589],{"class":517},[481,1329,1325],{"class":491},[481,1331,1332],{"class":491},"))\n",[481,1334,1336,1339,1341,1343,1345,1347,1349,1351,1353,1355,1357,1359,1361,1363,1366,1368],{"class":483,"line":1335},18,[481,1337,1338],{"class":640},"    perPage ",[481,1340,714],{"class":491},[481,1342,1300],{"class":581},[481,1344,585],{"class":491},[481,1346,1305],{"class":640},[481,1348,720],{"class":491},[481,1350,1310],{"class":640},[481,1352,720],{"class":491},[481,1354,780],{"class":581},[481,1356,1317],{"class":491},[481,1358,1320],{"class":581},[481,1360,585],{"class":491},[481,1362,1325],{"class":491},[481,1364,1365],{"class":517},"per_page",[481,1367,1325],{"class":491},[481,1369,1332],{"class":491},[481,1371,1373,1376,1378,1380,1382,1384,1386,1388,1390,1392,1394,1396,1398,1400,1402,1404],{"class":483,"line":1372},19,[481,1374,1375],{"class":640},"    p ",[481,1377,714],{"class":491},[481,1379,717],{"class":640},[481,1381,720],{"class":491},[481,1383,567],{"class":581},[481,1385,585],{"class":491},[481,1387,589],{"class":640},[481,1389,592],{"class":491},[481,1391,595],{"class":640},[481,1393,592],{"class":491},[481,1395,717],{"class":640},[481,1397,720],{"class":491},[481,1399,883],{"class":581},[481,1401,585],{"class":491},[481,1403,888],{"class":867},[481,1405,1332],{"class":491},[481,1407,1409],{"class":483,"line":1408},20,[481,1410,625],{"emptyLinePlaceholder":624},[481,1412,1414,1417,1419,1422,1424,1427,1429,1431,1433,1435,1437,1439,1441,1443,1446],{"class":483,"line":1413},21,[481,1415,1416],{"class":640},"    items",[481,1418,592],{"class":491},[481,1420,1421],{"class":640}," total ",[481,1423,714],{"class":491},[481,1425,1426],{"class":581}," fetchProducts",[481,1428,585],{"class":491},[481,1430,447],{"class":640},[481,1432,720],{"class":491},[481,1434,809],{"class":581},[481,1436,812],{"class":491},[481,1438,804],{"class":640},[481,1440,720],{"class":491},[481,1442,819],{"class":581},[481,1444,1445],{"class":491},"())",[481,1447,1448],{"class":524}," \u002F\u002F your own query\n",[481,1450,1452,1455,1457,1460,1462,1464,1467,1470,1472,1474,1476,1479,1481,1483,1485,1487,1489,1491],{"class":483,"line":1451},22,[481,1453,1454],{"class":640},"    json",[481,1456,720],{"class":491},[481,1458,1459],{"class":581},"NewEncoder",[481,1461,585],{"class":491},[481,1463,1263],{"class":640},[481,1465,1466],{"class":491},").",[481,1468,1469],{"class":581},"Encode",[481,1471,585],{"class":491},[481,1473,430],{"class":640},[481,1475,720],{"class":491},[481,1477,1478],{"class":581},"NewPage",[481,1480,585],{"class":491},[481,1482,980],{"class":640},[481,1484,592],{"class":491},[481,1486,990],{"class":640},[481,1488,592],{"class":491},[481,1490,804],{"class":640},[481,1492,1332],{"class":491},[481,1494,1496],{"class":483,"line":1495},23,[481,1497,1077],{"class":491},[481,1499,1501],{"class":483,"line":1500},24,[481,1502,625],{"emptyLinePlaceholder":624},[481,1504,1506,1508,1510,1512,1515,1518,1520,1522,1524],{"class":483,"line":1505},25,[481,1507,578],{"class":491},[481,1509,1300],{"class":581},[481,1511,585],{"class":491},[481,1513,1514],{"class":588},"s",[481,1516,1517],{"class":601}," string",[481,1519,616],{"class":491},[481,1521,598],{"class":491},[481,1523,602],{"class":601},[481,1525,1035],{"class":491},[481,1527,1529,1532,1535,1538,1541],{"class":483,"line":1528},26,[481,1530,1531],{"class":487},"    if",[481,1533,1534],{"class":640}," s ",[481,1536,1537],{"class":491},"==",[481,1539,1540],{"class":491}," \"\"",[481,1542,1035],{"class":491},[481,1544,1546,1549],{"class":483,"line":1545},27,[481,1547,1548],{"class":487},"        return",[481,1550,1551],{"class":491}," nil\n",[481,1553,1555],{"class":483,"line":1554},28,[481,1556,1557],{"class":491},"    }\n",[481,1559,1561,1564,1566,1568,1570,1573,1575,1578,1580,1582],{"class":483,"line":1560},29,[481,1562,1563],{"class":640},"    n",[481,1565,592],{"class":491},[481,1567,765],{"class":640},[481,1569,714],{"class":491},[481,1571,1572],{"class":640}," strconv",[481,1574,720],{"class":491},[481,1576,1577],{"class":581},"Atoi",[481,1579,585],{"class":491},[481,1581,1514],{"class":640},[481,1583,1190],{"class":491},[481,1585,1587,1589,1591,1594,1597],{"class":483,"line":1586},30,[481,1588,1531],{"class":487},[481,1590,765],{"class":640},[481,1592,1593],{"class":491},"!=",[481,1595,1596],{"class":491}," nil",[481,1598,1035],{"class":491},[481,1600,1602,1604],{"class":483,"line":1601},31,[481,1603,1548],{"class":487},[481,1605,1551],{"class":491},[481,1607,1609],{"class":483,"line":1608},32,[481,1610,1557],{"class":491},[481,1612,1614,1617,1620],{"class":483,"line":1613},33,[481,1615,1616],{"class":487},"    return",[481,1618,1619],{"class":491}," &",[481,1621,1622],{"class":640},"n\n",[481,1624,1626],{"class":483,"line":1625},34,[481,1627,1077],{"class":491},[481,1629,1631],{"class":483,"line":1630},35,[481,1632,625],{"emptyLinePlaceholder":624},[481,1634,1636,1638,1640,1642,1645,1647,1650,1652,1654,1657,1660,1662,1664,1666],{"class":483,"line":1635},36,[481,1637,578],{"class":491},[481,1639,1426],{"class":581},[481,1641,585],{"class":491},[481,1643,1644],{"class":588},"limit",[481,1646,592],{"class":491},[481,1648,1649],{"class":588}," offset",[481,1651,676],{"class":601},[481,1653,616],{"class":491},[481,1655,1656],{"class":491}," ([]",[481,1658,1659],{"class":495},"Product",[481,1661,592],{"class":491},[481,1663,993],{"class":601},[481,1665,616],{"class":491},[481,1667,1035],{"class":491},[481,1669,1671,1673,1676,1679],{"class":483,"line":1670},37,[481,1672,1616],{"class":487},[481,1674,1675],{"class":491}," nil,",[481,1677,1678],{"class":867}," 0",[481,1680,1681],{"class":524}," \u002F\u002F your repository call\n",[481,1683,1685],{"class":483,"line":1684},38,[481,1686,1077],{"class":491},[500,1688,1690],{"id":1689},"the-sql-is-yours","The SQL is yours",[447,1692,1693,1694,1696,1697,1700,1701,1704,1705,1708,1709,1711],{},"An important property: ",[450,1695,430],{}," doesn't hide pagination behind a query builder: the SQL is yours, and the module only provides the parameter discipline and the page mechanics (",[450,1698,1699],{},"paginate.Normalize"," for input, ",[450,1702,1703],{},"paginate.NewPage"," for the response). In exchange, the ",[450,1706,1707],{},"LIMIT","\u002F",[450,1710,939],{}," (or, for cursors, the seek predicate and its index) is in your hands.",[500,1713,1715],{"id":1714},"patterns-used","Patterns used",[1717,1718,1719,1736],"ul",{},[1720,1721,1722,659,1725,1727,1728,1731,1732,1735],"li",{},[458,1723,1724],{},"Generic result wrapper",[450,1726,952],{},"): ",[467,1729,238],{"href":1730},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#opaque-tamper-resistant-cursor"," catalogs the cursor sibling, ",[450,1733,1734],{},"CursorPage[T]",", in depth.",[1720,1737,1738,1741,1742,1745,1746,720],{},[458,1739,1740],{},"Functional options"," (the ",[450,1743,1744],{},"With*"," bound tuning): ",[467,1747,238],{"href":1748},"\u002Fen\u002Fconcepts\u002Fdesign-patterns#functional-options",[500,1750,1752],{"id":1751},"where-to-next","Where to next",[1717,1754,1755],{},[1720,1756,1757,1759,1760,943,1763,943,1766,1768],{},[467,1758,438],{"href":439},": ",[450,1761,1762],{},"CursorParams",[450,1764,1765],{},"NormalizeCursor",[450,1767,1734],{},", the seek predicate, and when to reach for it instead of offset.",[1770,1771,1772],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":477,"searchDepth":528,"depth":528,"links":1774},[1775,1776,1777,1778,1779,1780],{"id":502,"depth":528,"text":503},{"id":553,"depth":528,"text":554},{"id":1110,"depth":528,"text":1111},{"id":1689,"depth":528,"text":1690},{"id":1714,"depth":528,"text":1715},{"id":1751,"depth":528,"text":1752},"Offset (page\u002Fper-page) pagination with the paginate module, normalized parameters and a typed page wrapper.","md",null,{},{"icon":55},{"title":52,"description":1781},"Dr5KvBI9gkLSXZsygmfDTHesox9tGaIGLm5slSoMGW0",[1789,1791],{"title":426,"path":427,"stem":428,"description":1790,"icon":317,"children":-1},"Idempotent baseline data loading after migrations, built on first-or-create, with optional guards and multi-tenant support.",{"title":438,"path":439,"stem":440,"description":1792,"icon":19,"children":-1},"Keyset pagination with an opaque cursor and a Postgres tuple-comparison seek, for large or fast-growing tables.",1785445890763]