[{"data":1,"prerenderedAt":2221},["ShallowReactive",2],{"navigation_docs_en":3,"-en-examples-mutations-optimistic":342,"-en-examples-mutations-optimistic-surround":2216},[4,45,91,137,195,236,257,291,327],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":44},"Getting Started","i-lucide-rocket","/en/getting-started","en/01.getting-started",[10,15,20,24,29,34,39],{"title":11,"path":12,"stem":13,"icon":14},"What is Qora?","/en/getting-started/what-is-qora","en/01.getting-started/2.what-is-qora","i-lucide-info",{"title":16,"path":17,"stem":18,"icon":19},"Installation","/en/getting-started/installation","en/01.getting-started/3.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":6},"Quick Start","/en/getting-started/quick-start","en/01.getting-started/4.quick-start",{"title":25,"path":26,"stem":27,"icon":28},"Comparison","/en/getting-started/comparison","en/01.getting-started/5.comparison","i-lucide-scale",{"title":30,"path":31,"stem":32,"icon":33},"Coming from TanStack Query","/en/getting-started/coming-from-tanstack-query","en/01.getting-started/6.coming-from-tanstack-query","i-lucide-arrow-left-right",{"title":35,"path":36,"stem":37,"icon":38},"Migrating from Other Libraries","/en/getting-started/migrating-from-other-libraries","en/01.getting-started/7.migrating-from-other-libraries","i-lucide-arrow-right-left",{"title":40,"path":41,"stem":42,"icon":43},"AI Assistants","/en/getting-started/ai-assistants","en/01.getting-started/8.ai-assistants","i-lucide-sparkles",false,{"title":46,"icon":47,"path":48,"stem":49,"children":50,"page":44},"Core Concepts","i-lucide-book-open","/en/core-concepts","en/02.core-concepts",[51,56,61,66,71,76,81,86],{"title":52,"path":53,"stem":54,"icon":55},"Queries","/en/core-concepts/queries","en/02.core-concepts/1.queries","i-lucide-database",{"title":57,"path":58,"stem":59,"icon":60},"Query Keys","/en/core-concepts/query-keys","en/02.core-concepts/2.query-keys","i-lucide-key-round",{"title":62,"path":63,"stem":64,"icon":65},"Query States","/en/core-concepts/query-states","en/02.core-concepts/3.query-states","i-lucide-activity",{"title":67,"path":68,"stem":69,"icon":70},"Caching","/en/core-concepts/caching","en/02.core-concepts/4.caching","i-lucide-layers-3",{"title":72,"path":73,"stem":74,"icon":75},"Stale-While-Revalidate","/en/core-concepts/stale-while-revalidate","en/02.core-concepts/5.stale-while-revalidate","i-lucide-timer-reset",{"title":77,"path":78,"stem":79,"icon":80},"Deduplication","/en/core-concepts/deduplication","en/02.core-concepts/6.deduplication","i-lucide-copy-minus",{"title":82,"path":83,"stem":84,"icon":85},"Mutations & Invalidation","/en/core-concepts/mutations","en/02.core-concepts/7.mutations","i-lucide-pencil-line",{"title":87,"path":88,"stem":89,"icon":90},"Offline & Network","/en/core-concepts/offline","en/02.core-concepts/8.offline","i-lucide-wifi-off",{"title":92,"icon":93,"path":94,"stem":95,"children":96,"page":44},"Flutter Integration","i-lucide-smartphone","/en/flutter-integration","en/03.flutter-integration",[97,102,107,112,117,122,127,132],{"title":98,"path":99,"stem":100,"icon":101},"Setup","/en/flutter-integration/setup","en/03.flutter-integration/1.setup","i-lucide-wrench",{"title":103,"path":104,"stem":105,"icon":106},"QoraScope","/en/flutter-integration/qora-scope","en/03.flutter-integration/2.qora-scope","i-lucide-share-2",{"title":108,"path":109,"stem":110,"icon":111},"QoraBuilder","/en/flutter-integration/qora-builder","en/03.flutter-integration/3.qora-builder","i-lucide-blocks",{"title":113,"path":114,"stem":115,"icon":116},"QoraMutationBuilder","/en/flutter-integration/qora-mutation-builder","en/03.flutter-integration/4.qora-mutation-builder","i-lucide-pencil",{"title":118,"path":119,"stem":120,"icon":121},"InfiniteQueryBuilder","/en/flutter-integration/infinite-query-builder","en/03.flutter-integration/5.infinite-query-builder","i-lucide-infinity",{"title":123,"path":124,"stem":125,"icon":126},"Hooks (flutter_hooks)","/en/flutter-integration/hooks","en/03.flutter-integration/6.hooks","i-lucide-anchor",{"title":128,"path":129,"stem":130,"icon":131},"Network Status Widgets","/en/flutter-integration/network-status","en/03.flutter-integration/7.network-status","i-lucide-wifi",{"title":133,"path":134,"stem":135,"icon":136},"Best Practices","/en/flutter-integration/best-practices","en/03.flutter-integration/8.best-practices","i-lucide-badge-check",{"title":138,"icon":139,"path":140,"stem":141,"children":142,"page":44},"Recipes","i-lucide-chef-hat","/en/recipes","en/04.recipes",[143,147,152,157,162,166,171,176,181,186,191],{"title":144,"path":145,"stem":146,"icon":85},"Mutations","/en/recipes/mutations","en/04.recipes/02.mutations",{"title":148,"path":149,"stem":150,"icon":151},"Optimistic Updates","/en/recipes/optimistic-updates","en/04.recipes/03.optimistic-updates","i-lucide-zap",{"title":153,"path":154,"stem":155,"icon":156},"Persistence","/en/recipes/persistence","en/04.recipes/04.persistence","i-lucide-hard-drive",{"title":158,"path":159,"stem":160,"icon":161},"Network Aware","/en/recipes/network-aware","en/04.recipes/05.network-aware","i-lucide-signal",{"title":163,"path":164,"stem":165,"icon":121},"Infinite Queries","/en/recipes/infinite-queries","en/04.recipes/06.infinite-queries",{"title":167,"path":168,"stem":169,"icon":170},"Dependent Queries","/en/recipes/dependent-queries","en/04.recipes/07.dependent-queries","i-lucide-link-2",{"title":172,"path":173,"stem":174,"icon":175},"Cancellation","/en/recipes/cancel-token","en/04.recipes/08.cancel-token","i-lucide-circle-slash",{"title":177,"path":178,"stem":179,"icon":180},"SSR Hydration","/en/recipes/ssr-hydration","en/04.recipes/09.ssr-hydration","i-lucide-server",{"title":182,"path":183,"stem":184,"icon":185},"Error Handling","/en/recipes/error-handling","en/04.recipes/10.error-handling","i-lucide-shield-alert",{"title":187,"path":188,"stem":189,"icon":190},"Testing","/en/recipes/testing","en/04.recipes/11.testing","i-lucide-flask-conical",{"title":192,"path":193,"stem":194},"Route-Level Prefetching","/en/recipes/prefetch","en/04.recipes/12.prefetch",{"title":196,"icon":197,"path":198,"stem":199,"children":200,"page":44},"API Reference","i-lucide-file-code","/en/api-reference","en/05.api-reference",[201,206,210,214,219,224,228,232],{"title":202,"path":203,"stem":204,"icon":205},"QoraClient","/en/api-reference/qora-client","en/05.api-reference/1.qora-client","i-lucide-cpu",{"title":207,"path":208,"stem":209,"icon":60},"QoraKey","/en/api-reference/qora-key","en/05.api-reference/2.qora-key",{"title":211,"path":212,"stem":213,"icon":65},"QoraState","/en/api-reference/qora-state","en/05.api-reference/3.qora-state",{"title":215,"path":216,"stem":217,"icon":218},"QoraOptions","/en/api-reference/qora-options","en/05.api-reference/4.qora-options","i-lucide-sliders-horizontal",{"title":220,"path":221,"stem":222,"icon":223},"QoraClientConfig","/en/api-reference/qora-client-config","en/05.api-reference/5.qora-client-config","i-lucide-settings-2",{"title":225,"path":226,"stem":227,"icon":85},"Mutation API","/en/api-reference/qora-mutation","en/05.api-reference/6.qora-mutation",{"title":229,"path":230,"stem":231,"icon":156},"PersistQoraClient","/en/api-reference/persist-qora-client","en/05.api-reference/7.persist-qora-client",{"title":233,"path":234,"stem":235,"icon":121},"Infinite Query","/en/api-reference/infinite-query","en/05.api-reference/8.infinite-query",{"title":237,"icon":238,"path":239,"stem":240,"children":241,"page":44},"DevTools","i-lucide-bug","/en/devtools","en/06.devtools",[242,247,252],{"title":243,"path":244,"stem":245,"icon":246},"Overview","/en/devtools/overview","en/06.devtools/1.overview","i-lucide-layout-dashboard",{"title":248,"path":249,"stem":250,"icon":251},"In-App Overlay","/en/devtools/overlay","en/06.devtools/2.overlay","i-lucide-layers",{"title":253,"path":254,"stem":255,"icon":256},"Data Serialization","/en/devtools/data-display","en/06.devtools/4.data-display","i-lucide-eye",{"title":258,"icon":259,"path":260,"stem":261,"children":262,"page":44},"Third Party","i-lucide-puzzle","/en/third-party","en/07.third-party",[263,268,272,277,282,286],{"title":264,"path":265,"stem":266,"icon":267},"With Provider","/en/third-party/with-provider","en/07.third-party/1.with-provider","i-lucide-plug",{"title":269,"path":270,"stem":271,"icon":111},"With BLoC","/en/third-party/with-bloc","en/07.third-party/2.with-bloc",{"title":273,"path":274,"stem":275,"icon":276},"With Riverpod","/en/third-party/with-riverpod","en/07.third-party/3.with-riverpod","i-lucide-droplets",{"title":278,"path":279,"stem":280,"icon":281},"With RxDart","/en/third-party/with-rxdart","en/07.third-party/4.with-rxdart","i-lucide-git-branch",{"title":283,"path":284,"stem":285},"With Dio","/en/third-party/with-dio","en/07.third-party/5.with-dio",{"title":287,"path":288,"stem":289,"icon":290},"With GraphQL","/en/third-party/with-graphql","en/07.third-party/6.with-graphql","i-lucide-binary",{"title":292,"icon":190,"path":293,"stem":294,"children":295,"page":44},"Examples","/en/examples","en/08.examples",[296,301,305,310,314,318,322],{"title":297,"path":298,"stem":299,"icon":300},"Case Study: User List & Detail","/en/examples/basic-query","en/08.examples/1.basic-query","i-lucide-play-circle",{"title":302,"path":303,"stem":304,"icon":151},"Case Study: Optimistic Mutations & Rollback","/en/examples/mutations-optimistic","en/08.examples/2.mutations-optimistic",{"title":306,"path":307,"stem":308,"icon":309},"Case Study: Infinite Scroll Feed","/en/examples/infinite-scroll","en/08.examples/3.infinite-scroll","i-lucide-scroll",{"title":311,"path":312,"stem":313,"icon":90},"Case Study: Offline-First Todo App","/en/examples/offline-first","en/08.examples/4.offline-first",{"title":315,"path":316,"stem":317,"icon":161},"Case Study: Network Awareness","/en/examples/network-awareness","en/08.examples/5.network-awareness",{"title":319,"path":320,"stem":321,"icon":126},"Case Study: Hooks Integration","/en/examples/hooks-integration","en/08.examples/6.hooks-integration",{"title":323,"path":324,"stem":325,"icon":326},"Case Study: Complete Todo App","/en/examples/complete-todo-app","en/08.examples/7.complete-todo-app","i-lucide-check-square",{"title":328,"icon":329,"path":330,"stem":331,"children":332,"page":44},"Help","i-lucide-life-buoy","/en/help","en/09.help",[333,338],{"title":334,"path":335,"stem":336,"icon":337},"FAQ","/en/help/faq","en/09.help/1.faq","i-lucide-circle-help",{"title":339,"path":340,"stem":341,"icon":101},"Troubleshooting","/en/help/troubleshooting","en/09.help/2.troubleshooting",{"id":343,"title":302,"body":344,"description":2207,"extension":2208,"links":2209,"meta":2210,"navigation":2211,"path":303,"seo":2212,"stem":304,"__hash__":2215},"docs_en/en/08.examples/2.mutations-optimistic.md",{"type":345,"value":346,"toc":2191},"minimark",[347,352,360,363,378,381,385,490,492,496,502,512,532,722,724,728,733,740,760,932,958,962,971,1352,1363,1367,1385,1494,1497,1501,1509,1582,1594,1599,1611,2052,2075,2077,2081,2084,2122,2124,2128,2134,2143,2145,2149,2187],[348,349,351],"h2",{"id":350},"objective","Objective",[353,354,355,359],"p",{},[356,357,358],"strong",{},"Context",": Write operations introduce a latency problem. A round-trip to the server takes 1–3 seconds. Blocking the UI until the server responds produces sluggish interactions and breaks the perceived responsiveness of the application.",[353,361,362],{},"Optimistic updates resolve this by applying the expected result to the local cache immediately, before the server responds. If the server confirms the operation, the optimistic data is replaced by the authoritative server response. If the server rejects it, the cache is restored to its pre-mutation state.",[353,364,365,366,369,370,373,374,377],{},"This example implements the full optimistic update protocol using ",[367,368,113],"code",{},", ",[367,371,372],{},"setQueryData",", and ",[367,375,376],{},"restoreQueryData",". The simulated API fails ~30 % of the time to make rollback observable.",[379,380],"hr",{},[348,382,384],{"id":383},"key-features-demonstrated","Key Features Demonstrated",[386,387,388,401,416,430,441,457,479],"ul",{},[389,390,391,396,397,400],"li",{},[356,392,393],{},[367,394,395],{},"QoraMutationBuilder\u003CTData, TVariables, TContext>",": manages ",[367,398,399],{},"MutationController"," lifecycle (create on mount, dispose on unmount), wires offline queue automatically",[389,402,403,408,409,412,413,415],{},[356,404,405],{},[367,406,407],{},"MutationOptions.onMutate",": captures a pre-mutation cache snapshot (",[367,410,411],{},"TContext",") and applies ",[367,414,372],{}," before the server call",[389,417,418,423,424,426,427,429],{},[356,419,420],{},[367,421,422],{},"MutationOptions.onError",": calls ",[367,425,376],{}," with the ",[367,428,411],{}," snapshot to revert both affected cache entries simultaneously",[389,431,432,423,437,440],{},[356,433,434],{},[367,435,436],{},"MutationOptions.onSuccess",[367,438,439],{},"invalidateWhere"," to trigger background refetch and reconcile the cache with the server-confirmed state",[389,442,443,446,447,450,451,454,455],{},[356,444,445],{},"Cross-cache optimistic update",": a single mutation updates two independent cache entries (",[367,448,449],{},"['users', id]"," and ",[367,452,453],{},"['users']",") atomically via ",[367,456,411],{},[389,458,459,465,466,369,469,369,472,369,475,478],{},[356,460,461,464],{},[367,462,463],{},"MutationState"," pattern matching",": four states (",[367,467,468],{},"MutationIdle",[367,470,471],{},"MutationPending",[367,473,474],{},"MutationSuccess",[367,476,477],{},"MutationFailure",") handled exhaustively with Dart 3 switch expressions",[389,480,481,489],{},[356,482,483,485,486,488],{},[367,484,108],{}," + ",[367,487,113],{}," composition",": read and write operations coexist on the same screen without shared mutable state",[379,491],{},[348,493,495],{"id":494},"architecture-highlights","Architecture Highlights",[353,497,498,499,501],{},"The mutation lifecycle is entirely managed by ",[367,500,113],{},". The widget tree declares intent; Qora coordinates cache, network, and state transitions:",[503,504,510],"pre",{"className":505,"code":507,"language":508,"meta":509},[506],"language-text","ex_02_mutations_optimistic/lib/\n├── main.dart                      ← QoraClient + QoraScope at root\n├── models/\n│   └── user.dart                  ← pure data class with copyWith\n├── services/\n│   └── fake_api.dart              ← async API (2 s latency, ~30 % failure on updateUser)\n└── screens/\n    ├── user_list_screen.dart      ← QoraBuilder\u003CList\u003CUser>>, key: ['users']\n    └── rename_user_sheet.dart     ← QoraMutationBuilder + three-step optimistic protocol\n","text","",[367,511,507],{"__ignoreMap":509},[353,513,514,516,517,520,521,523,524,527,528,531],{},[367,515,202],{}," is configured once at the root. ",[367,518,519],{},"UserListScreen"," reads the user list via ",[367,522,108],{},". The edit action captures ",[367,525,526],{},"context.qora"," and passes it explicitly to ",[367,529,530],{},"RenameUserSheet",", since modal routes run in a separate navigator overlay:",[503,533,538],{"className":534,"code":535,"filename":536,"language":537,"meta":509,"style":509},"language-dart shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","Future\u003Cvoid> _showRenameSheet(BuildContext context, User user) {\n  // Capture the client before the sheet opens: modal routes run in a\n  // separate navigator overlay and may not resolve QoraScope on their own.\n  final client = context.qora;\n  return showModalBottomSheet\u003Cvoid>(\n    context: context,\n    isScrollControlled: true,\n    useSafeArea: true,\n    builder: (_) => RenameUserSheet(user: user, client: client),\n  );\n}\n","lib/screens/user_list_screen.dart","dart",[367,539,540,583,590,596,619,636,650,661,671,708,716],{"__ignoreMap":509},[541,542,545,549,553,557,560,564,567,570,573,577,580],"span",{"class":543,"line":544},"line",1,[541,546,548],{"class":547},"sBMFI","Future",[541,550,552],{"class":551},"sTEyZ","\u003C",[541,554,556],{"class":555},"spNyl","void",[541,558,559],{"class":551},"> ",[541,561,563],{"class":562},"s2Zo4","_showRenameSheet",[541,565,566],{"class":551},"(",[541,568,569],{"class":547},"BuildContext",[541,571,572],{"class":551}," context",[541,574,576],{"class":575},"sMK4o",",",[541,578,579],{"class":547}," User",[541,581,582],{"class":551}," user) {\n",[541,584,586],{"class":543,"line":585},2,[541,587,589],{"class":588},"sHwdD","  // Capture the client before the sheet opens: modal routes run in a\n",[541,591,593],{"class":543,"line":592},3,[541,594,595],{"class":588},"  // separate navigator overlay and may not resolve QoraScope on their own.\n",[541,597,599,602,605,608,610,613,616],{"class":543,"line":598},4,[541,600,601],{"class":555},"  final",[541,603,604],{"class":551}," client ",[541,606,607],{"class":575},"=",[541,609,572],{"class":551},[541,611,612],{"class":575},".",[541,614,615],{"class":551},"qora",[541,617,618],{"class":575},";\n",[541,620,622,626,629,631,633],{"class":543,"line":621},5,[541,623,625],{"class":624},"s7zQu","  return",[541,627,628],{"class":562}," showModalBottomSheet",[541,630,552],{"class":551},[541,632,556],{"class":555},[541,634,635],{"class":551},">(\n",[541,637,639,642,645,647],{"class":543,"line":638},6,[541,640,641],{"class":551},"    context",[541,643,644],{"class":575},":",[541,646,572],{"class":551},[541,648,649],{"class":575},",\n",[541,651,653,656,658],{"class":543,"line":652},7,[541,654,655],{"class":551},"    isScrollControlled",[541,657,644],{"class":575},[541,659,660],{"class":575}," true,\n",[541,662,664,667,669],{"class":543,"line":663},8,[541,665,666],{"class":551},"    useSafeArea",[541,668,644],{"class":575},[541,670,660],{"class":575},[541,672,674,677,679,682,685,688,691,693,696,698,701,703,706],{"class":543,"line":673},9,[541,675,676],{"class":551},"    builder",[541,678,644],{"class":575},[541,680,681],{"class":551}," (_) ",[541,683,684],{"class":575},"=>",[541,686,687],{"class":547}," RenameUserSheet",[541,689,690],{"class":551},"(user",[541,692,644],{"class":575},[541,694,695],{"class":551}," user",[541,697,576],{"class":575},[541,699,700],{"class":551}," client",[541,702,644],{"class":575},[541,704,705],{"class":551}," client)",[541,707,649],{"class":575},[541,709,711,714],{"class":543,"line":710},10,[541,712,713],{"class":551},"  )",[541,715,618],{"class":575},[541,717,719],{"class":543,"line":718},11,[541,720,721],{"class":551},"}\n",[379,723],{},[348,725,727],{"id":726},"implementation-details","Implementation Details",[729,730,732],"h3",{"id":731},"the-three-step-optimistic-update-protocol","The three-step optimistic update protocol",[353,734,735,736,739],{},"Every optimistic mutation follows three sequential hooks defined in ",[367,737,738],{},"MutationOptions",". The type parameters encode the domain types precisely:",[386,741,742,748,754],{},[389,743,744,747],{},[367,745,746],{},"TData = User",": value returned by the server on success",[389,749,750,753],{},[367,751,752],{},"TVariables = ({String id, String name})",": input to the mutator",[389,755,756,759],{},[367,757,758],{},"TContext = ({User? user, List\u003CUser>? list})",": pre-mutation snapshot for rollback",[503,761,764],{"className":534,"code":762,"filename":763,"language":537,"meta":509,"style":509},"QoraMutationBuilder\u003CUser, _UpdateVars, _Snapshot>(\n  mutator: (vars) => FakeApi.updateUser(vars.id, name: vars.name),\n  options: MutationOptions\u003CUser, _UpdateVars, _Snapshot>(\n    onMutate: ...,   // Step 1: snapshot + setQueryData\n    onError: ...,    // Step 2: restoreQueryData (rollback)\n    onSuccess: ...,  // Step 3: invalidateWhere (reconciliation)\n  ),\n  builder: (context, state, mutate) { ... },\n)\n","lib/screens/rename_user_sheet.dart",[367,765,766,787,832,856,869,881,893,899,927],{"__ignoreMap":509},[541,767,768,770,772,775,777,780,782,785],{"class":543,"line":544},[541,769,113],{"class":547},[541,771,552],{"class":551},[541,773,774],{"class":547},"User",[541,776,369],{"class":551},[541,778,779],{"class":547},"_UpdateVars",[541,781,369],{"class":551},[541,783,784],{"class":547},"_Snapshot",[541,786,635],{"class":551},[541,788,789,792,794,797,799,802,804,807,810,812,815,817,820,822,825,827,830],{"class":543,"line":585},[541,790,791],{"class":551},"  mutator",[541,793,644],{"class":575},[541,795,796],{"class":551}," (vars) ",[541,798,684],{"class":575},[541,800,801],{"class":547}," FakeApi",[541,803,612],{"class":575},[541,805,806],{"class":562},"updateUser",[541,808,809],{"class":551},"(vars",[541,811,612],{"class":575},[541,813,814],{"class":551},"id",[541,816,576],{"class":575},[541,818,819],{"class":551}," name",[541,821,644],{"class":575},[541,823,824],{"class":551}," vars",[541,826,612],{"class":575},[541,828,829],{"class":551},"name)",[541,831,649],{"class":575},[541,833,834,837,839,842,844,846,848,850,852,854],{"class":543,"line":592},[541,835,836],{"class":551},"  options",[541,838,644],{"class":575},[541,840,841],{"class":547}," MutationOptions",[541,843,552],{"class":551},[541,845,774],{"class":547},[541,847,369],{"class":551},[541,849,779],{"class":547},[541,851,369],{"class":551},[541,853,784],{"class":547},[541,855,635],{"class":551},[541,857,858,861,863,866],{"class":543,"line":598},[541,859,860],{"class":551},"    onMutate",[541,862,644],{"class":575},[541,864,865],{"class":575}," ...,",[541,867,868],{"class":588},"   // Step 1: snapshot + setQueryData\n",[541,870,871,874,876,878],{"class":543,"line":621},[541,872,873],{"class":551},"    onError",[541,875,644],{"class":575},[541,877,865],{"class":575},[541,879,880],{"class":588},"    // Step 2: restoreQueryData (rollback)\n",[541,882,883,886,888,890],{"class":543,"line":638},[541,884,885],{"class":551},"    onSuccess",[541,887,644],{"class":575},[541,889,865],{"class":575},[541,891,892],{"class":588},"  // Step 3: invalidateWhere (reconciliation)\n",[541,894,895,897],{"class":543,"line":652},[541,896,713],{"class":551},[541,898,649],{"class":575},[541,900,901,904,906,909,911,914,916,919,922,925],{"class":543,"line":663},[541,902,903],{"class":551},"  builder",[541,905,644],{"class":575},[541,907,908],{"class":551}," (context",[541,910,576],{"class":575},[541,912,913],{"class":551}," state",[541,915,576],{"class":575},[541,917,918],{"class":551}," mutate) { ",[541,920,921],{"class":575},"...",[541,923,924],{"class":551}," }",[541,926,649],{"class":575},[541,928,929],{"class":543,"line":673},[541,930,931],{"class":551},")\n",[353,933,934,935,938,939,942,943,946,947,949,950,952,953,450,955,957],{},"The hooks execute in sequence: ",[367,936,937],{},"onMutate"," runs before the mutator; ",[367,940,941],{},"onError"," or ",[367,944,945],{},"onSuccess"," run after it settles. The ",[367,948,411],{}," value returned by ",[367,951,937],{}," is forwarded to both ",[367,954,941],{},[367,956,945],{}," as the third parameter.",[729,959,961],{"id":960},"cross-cache-atomic-snapshot","Cross-cache atomic snapshot",[353,963,964,966,967,970],{},[367,965,937],{}," captures two independent cache entries before modifying either. The Dart 3 record type ",[367,968,969],{},"({User? user, List\u003CUser>? list})"," carries both snapshots as a single typed value:",[503,972,974],{"className":534,"code":973,"filename":763,"language":537,"meta":509,"style":509},"onMutate: (vars) async {\n  // Capture the current data for both cache entries before mutating.\n  final prevUser = client.getQueryData\u003CUser>(['users', vars.id]);\n  final prevList = client.getQueryData\u003CList\u003CUser>>(['users']);\n\n  // Apply the optimistic name change to the per-user detail cache.\n  if (prevUser != null) {\n    client.setQueryData\u003CUser>(\n      ['users', vars.id],\n      prevUser.copyWith(name: vars.name),\n    );\n  }\n\n  // Apply the same change to the matching entry inside the list cache.\n  if (prevList != null) {\n    client.setQueryData\u003CList\u003CUser>>(\n      ['users'],\n      prevList\n          .map((u) => u.id == vars.id ? u.copyWith(name: vars.name) : u)\n          .toList(),\n    );\n  }\n\n  // Return both snapshots as the rollback context (TContext).\n  return (user: prevUser, list: prevList);\n},\n",[367,975,976,990,995,1033,1067,1073,1078,1095,1110,1128,1151,1158,1164,1169,1175,1189,1209,1221,1227,1283,1296,1303,1308,1313,1319,1344],{"__ignoreMap":509},[541,977,978,980,982,984,987],{"class":543,"line":544},[541,979,937],{"class":551},[541,981,644],{"class":575},[541,983,796],{"class":551},[541,985,986],{"class":624},"async",[541,988,989],{"class":551}," {\n",[541,991,992],{"class":543,"line":585},[541,993,994],{"class":588},"  // Capture the current data for both cache entries before mutating.\n",[541,996,997,999,1002,1004,1006,1008,1011,1013,1015,1018,1022,1024,1026,1028,1031],{"class":543,"line":592},[541,998,601],{"class":555},[541,1000,1001],{"class":551}," prevUser ",[541,1003,607],{"class":575},[541,1005,700],{"class":551},[541,1007,612],{"class":575},[541,1009,1010],{"class":562},"getQueryData",[541,1012,552],{"class":551},[541,1014,774],{"class":547},[541,1016,1017],{"class":551},">([",[541,1019,1021],{"class":1020},"sfazB","'users'",[541,1023,576],{"class":575},[541,1025,824],{"class":551},[541,1027,612],{"class":575},[541,1029,1030],{"class":551},"id])",[541,1032,618],{"class":575},[541,1034,1035,1037,1040,1042,1044,1046,1048,1050,1053,1055,1057,1060,1062,1065],{"class":543,"line":598},[541,1036,601],{"class":555},[541,1038,1039],{"class":551}," prevList ",[541,1041,607],{"class":575},[541,1043,700],{"class":551},[541,1045,612],{"class":575},[541,1047,1010],{"class":562},[541,1049,552],{"class":551},[541,1051,1052],{"class":547},"List",[541,1054,552],{"class":551},[541,1056,774],{"class":547},[541,1058,1059],{"class":551},">>([",[541,1061,1021],{"class":1020},[541,1063,1064],{"class":551},"])",[541,1066,618],{"class":575},[541,1068,1069],{"class":543,"line":621},[541,1070,1072],{"emptyLinePlaceholder":1071},true,"\n",[541,1074,1075],{"class":543,"line":638},[541,1076,1077],{"class":588},"  // Apply the optimistic name change to the per-user detail cache.\n",[541,1079,1080,1083,1086,1089,1092],{"class":543,"line":652},[541,1081,1082],{"class":624},"  if",[541,1084,1085],{"class":551}," (prevUser ",[541,1087,1088],{"class":575},"!=",[541,1090,1091],{"class":575}," null",[541,1093,1094],{"class":551},") {\n",[541,1096,1097,1100,1102,1104,1106,1108],{"class":543,"line":663},[541,1098,1099],{"class":551},"    client",[541,1101,612],{"class":575},[541,1103,372],{"class":562},[541,1105,552],{"class":551},[541,1107,774],{"class":547},[541,1109,635],{"class":551},[541,1111,1112,1115,1117,1119,1121,1123,1126],{"class":543,"line":673},[541,1113,1114],{"class":551},"      [",[541,1116,1021],{"class":1020},[541,1118,576],{"class":575},[541,1120,824],{"class":551},[541,1122,612],{"class":575},[541,1124,1125],{"class":551},"id]",[541,1127,649],{"class":575},[541,1129,1130,1133,1135,1138,1141,1143,1145,1147,1149],{"class":543,"line":710},[541,1131,1132],{"class":551},"      prevUser",[541,1134,612],{"class":575},[541,1136,1137],{"class":562},"copyWith",[541,1139,1140],{"class":551},"(name",[541,1142,644],{"class":575},[541,1144,824],{"class":551},[541,1146,612],{"class":575},[541,1148,829],{"class":551},[541,1150,649],{"class":575},[541,1152,1153,1156],{"class":543,"line":718},[541,1154,1155],{"class":551},"    )",[541,1157,618],{"class":575},[541,1159,1161],{"class":543,"line":1160},12,[541,1162,1163],{"class":551},"  }\n",[541,1165,1167],{"class":543,"line":1166},13,[541,1168,1072],{"emptyLinePlaceholder":1071},[541,1170,1172],{"class":543,"line":1171},14,[541,1173,1174],{"class":588},"  // Apply the same change to the matching entry inside the list cache.\n",[541,1176,1178,1180,1183,1185,1187],{"class":543,"line":1177},15,[541,1179,1082],{"class":624},[541,1181,1182],{"class":551}," (prevList ",[541,1184,1088],{"class":575},[541,1186,1091],{"class":575},[541,1188,1094],{"class":551},[541,1190,1192,1194,1196,1198,1200,1202,1204,1206],{"class":543,"line":1191},16,[541,1193,1099],{"class":551},[541,1195,612],{"class":575},[541,1197,372],{"class":562},[541,1199,552],{"class":551},[541,1201,1052],{"class":547},[541,1203,552],{"class":551},[541,1205,774],{"class":547},[541,1207,1208],{"class":551},">>(\n",[541,1210,1212,1214,1216,1219],{"class":543,"line":1211},17,[541,1213,1114],{"class":551},[541,1215,1021],{"class":1020},[541,1217,1218],{"class":551},"]",[541,1220,649],{"class":575},[541,1222,1224],{"class":543,"line":1223},18,[541,1225,1226],{"class":551},"      prevList\n",[541,1228,1230,1233,1236,1239,1241,1244,1246,1249,1252,1254,1256,1258,1261,1263,1265,1267,1269,1271,1273,1275,1278,1280],{"class":543,"line":1229},19,[541,1231,1232],{"class":575},"          .",[541,1234,1235],{"class":562},"map",[541,1237,1238],{"class":551},"((u) ",[541,1240,684],{"class":575},[541,1242,1243],{"class":551}," u",[541,1245,612],{"class":575},[541,1247,1248],{"class":551},"id ",[541,1250,1251],{"class":575},"==",[541,1253,824],{"class":551},[541,1255,612],{"class":575},[541,1257,1248],{"class":551},[541,1259,1260],{"class":575},"?",[541,1262,1243],{"class":551},[541,1264,612],{"class":575},[541,1266,1137],{"class":562},[541,1268,1140],{"class":551},[541,1270,644],{"class":575},[541,1272,824],{"class":551},[541,1274,612],{"class":575},[541,1276,1277],{"class":551},"name) ",[541,1279,644],{"class":575},[541,1281,1282],{"class":551}," u)\n",[541,1284,1286,1288,1291,1294],{"class":543,"line":1285},20,[541,1287,1232],{"class":575},[541,1289,1290],{"class":562},"toList",[541,1292,1293],{"class":551},"()",[541,1295,649],{"class":575},[541,1297,1299,1301],{"class":543,"line":1298},21,[541,1300,1155],{"class":551},[541,1302,618],{"class":575},[541,1304,1306],{"class":543,"line":1305},22,[541,1307,1163],{"class":551},[541,1309,1311],{"class":543,"line":1310},23,[541,1312,1072],{"emptyLinePlaceholder":1071},[541,1314,1316],{"class":543,"line":1315},24,[541,1317,1318],{"class":588},"  // Return both snapshots as the rollback context (TContext).\n",[541,1320,1322,1324,1327,1329,1332,1334,1337,1339,1342],{"class":543,"line":1321},25,[541,1323,625],{"class":624},[541,1325,1326],{"class":551}," (user",[541,1328,644],{"class":575},[541,1330,1331],{"class":551}," prevUser",[541,1333,576],{"class":575},[541,1335,1336],{"class":551}," list",[541,1338,644],{"class":575},[541,1340,1341],{"class":551}," prevList)",[541,1343,618],{"class":575},[541,1345,1347,1350],{"class":543,"line":1346},26,[541,1348,1349],{"class":551},"}",[541,1351,649],{"class":575},[353,1353,1354,1356,1357,1359,1360,1362],{},[367,1355,372],{}," pushes the new value to all active ",[367,1358,108],{}," streams subscribed to the matching key. Both ",[367,1361,519],{}," and any open detail widget receive the update on the next frame, before the network call completes.",[729,1364,1366],{"id":1365},"automatic-rollback-on-failure","Automatic rollback on failure",[353,1368,1369,1371,1372,1374,1375,1377,1378,1380,1381,1384],{},[367,1370,941],{}," receives the ",[367,1373,411],{}," snapshot returned by ",[367,1376,937],{},". ",[367,1379,376],{}," is a no-op when the snapshot is ",[367,1382,1383],{},"null",", so null-safety is preserved without defensive branching:",[503,1386,1388],{"className":534,"code":1387,"filename":763,"language":537,"meta":509,"style":509},"onError: (error, vars, ctx) async {\n  // Restore both cache entries from the snapshot returned by onMutate.\n  client.restoreQueryData\u003CUser>(['users', vars.id], ctx?.user);\n  client.restoreQueryData\u003CList\u003CUser>>(['users'], ctx?.list);\n},\n",[367,1389,1390,1412,1417,1455,1488],{"__ignoreMap":509},[541,1391,1392,1394,1396,1399,1401,1403,1405,1408,1410],{"class":543,"line":544},[541,1393,941],{"class":551},[541,1395,644],{"class":575},[541,1397,1398],{"class":551}," (error",[541,1400,576],{"class":575},[541,1402,824],{"class":551},[541,1404,576],{"class":575},[541,1406,1407],{"class":551}," ctx) ",[541,1409,986],{"class":624},[541,1411,989],{"class":551},[541,1413,1414],{"class":543,"line":585},[541,1415,1416],{"class":588},"  // Restore both cache entries from the snapshot returned by onMutate.\n",[541,1418,1419,1422,1424,1426,1428,1430,1432,1434,1436,1438,1440,1442,1444,1447,1450,1453],{"class":543,"line":592},[541,1420,1421],{"class":551},"  client",[541,1423,612],{"class":575},[541,1425,376],{"class":562},[541,1427,552],{"class":551},[541,1429,774],{"class":547},[541,1431,1017],{"class":551},[541,1433,1021],{"class":1020},[541,1435,576],{"class":575},[541,1437,824],{"class":551},[541,1439,612],{"class":575},[541,1441,1125],{"class":551},[541,1443,576],{"class":575},[541,1445,1446],{"class":551}," ctx",[541,1448,1449],{"class":575},"?.",[541,1451,1452],{"class":551},"user)",[541,1454,618],{"class":575},[541,1456,1457,1459,1461,1463,1465,1467,1469,1471,1473,1475,1477,1479,1481,1483,1486],{"class":543,"line":598},[541,1458,1421],{"class":551},[541,1460,612],{"class":575},[541,1462,376],{"class":562},[541,1464,552],{"class":551},[541,1466,1052],{"class":547},[541,1468,552],{"class":551},[541,1470,774],{"class":547},[541,1472,1059],{"class":551},[541,1474,1021],{"class":1020},[541,1476,1218],{"class":551},[541,1478,576],{"class":575},[541,1480,1446],{"class":551},[541,1482,1449],{"class":575},[541,1484,1485],{"class":551},"list)",[541,1487,618],{"class":575},[541,1489,1490,1492],{"class":543,"line":621},[541,1491,1349],{"class":551},[541,1493,649],{"class":575},[353,1495,1496],{},"When the server rejects the mutation, both cache entries revert to their pre-mutation values in a single synchronous operation. All subscribed widgets rebuild immediately, displaying the original data without any user intervention.",[729,1498,1500],{"id":1499},"server-reconciliation-on-success","Server reconciliation on success",[353,1502,1503,1505,1506,1508],{},[367,1504,945],{}," uses ",[367,1507,439],{}," to mark all user-related cache entries as stale. Qora triggers background refetches for every active subscriber, replacing the optimistic data with the server-confirmed state:",[503,1510,1512],{"className":534,"code":1511,"filename":763,"language":537,"meta":509,"style":509},"onSuccess: (user, vars, _) async {\n  // Trigger a background refetch for all user-related entries\n  // so the cache reflects the server-confirmed state.\n  client.invalidateWhere((key) => key.firstOrNull == 'users');\n},\n",[367,1513,1514,1535,1540,1545,1576],{"__ignoreMap":509},[541,1515,1516,1518,1520,1522,1524,1526,1528,1531,1533],{"class":543,"line":544},[541,1517,945],{"class":551},[541,1519,644],{"class":575},[541,1521,1326],{"class":551},[541,1523,576],{"class":575},[541,1525,824],{"class":551},[541,1527,576],{"class":575},[541,1529,1530],{"class":551}," _) ",[541,1532,986],{"class":624},[541,1534,989],{"class":551},[541,1536,1537],{"class":543,"line":585},[541,1538,1539],{"class":588},"  // Trigger a background refetch for all user-related entries\n",[541,1541,1542],{"class":543,"line":592},[541,1543,1544],{"class":588},"  // so the cache reflects the server-confirmed state.\n",[541,1546,1547,1549,1551,1553,1556,1558,1561,1563,1566,1568,1571,1574],{"class":543,"line":598},[541,1548,1421],{"class":551},[541,1550,612],{"class":575},[541,1552,439],{"class":562},[541,1554,1555],{"class":551},"((key) ",[541,1557,684],{"class":575},[541,1559,1560],{"class":551}," key",[541,1562,612],{"class":575},[541,1564,1565],{"class":551},"firstOrNull ",[541,1567,1251],{"class":575},[541,1569,1570],{"class":1020}," 'users'",[541,1572,1573],{"class":551},")",[541,1575,618],{"class":575},[541,1577,1578,1580],{"class":543,"line":621},[541,1579,1349],{"class":551},[541,1581,649],{"class":575},[353,1583,1584,1585,450,1587,1589,1590,1593],{},"The predicate matches both ",[367,1586,453],{},[367,1588,449],{}," simultaneously. Active subscribers transition to ",[367,1591,1592],{},"Loading(previousData: data)",": the optimistic data remains visible during the background fetch, and the final server response replaces it without a blank-screen transition.",[729,1595,1597,464],{"id":1596},"mutationstate-pattern-matching",[367,1598,463],{},[353,1600,1601,1603,1604,1606,1607,1610],{},[367,1602,113],{}," rebuilds whenever the ",[367,1605,399],{}," emits a new state. The ",[367,1608,1609],{},"builder"," maps all four states to UI:",[503,1612,1614],{"className":534,"code":1613,"filename":763,"language":537,"meta":509,"style":509},"builder: (context, state, mutate) {\n  return Column(\n    children: [\n      TextField(\n        controller: _nameController,\n        enabled: !state.isPending,   // disable input while the server call is in flight\n        ...\n      ),\n\n      // Inline status feedback via Dart 3 switch expression\n      switch (state) {\n        MutationFailure(:final error) => _FeedbackBanner(\n            icon: Icons.undo_rounded,\n            message: 'Save failed, name restored. $error',\n            color: Colors.red,\n          ),\n        MutationSuccess() => const _FeedbackBanner(\n            icon: Icons.check_circle_outline,\n            message: 'Saved. Cache updated from server.',\n            color: Colors.green,\n          ),\n        _ => const SizedBox.shrink(),  // MutationIdle, MutationPending\n      },\n\n      FilledButton(\n        onPressed: state.isPending ? null : () => mutate((id: user.id, name: name)),\n        child: state.isPending\n            ? const CircularProgressIndicator(strokeWidth: 2.5)\n            : const Text('Save'),\n      ),\n    ],\n  );\n},\n",[367,1615,1616,1633,1643,1653,1660,1672,1695,1700,1707,1711,1716,1724,1746,1763,1785,1802,1809,1826,1841,1852,1867,1873,1897,1904,1908,1915,1966,1981,2003,2023,2030,2038,2045],{"__ignoreMap":509},[541,1617,1618,1620,1622,1624,1626,1628,1630],{"class":543,"line":544},[541,1619,1609],{"class":551},[541,1621,644],{"class":575},[541,1623,908],{"class":551},[541,1625,576],{"class":575},[541,1627,913],{"class":551},[541,1629,576],{"class":575},[541,1631,1632],{"class":551}," mutate) {\n",[541,1634,1635,1637,1640],{"class":543,"line":585},[541,1636,625],{"class":624},[541,1638,1639],{"class":547}," Column",[541,1641,1642],{"class":551},"(\n",[541,1644,1645,1648,1650],{"class":543,"line":592},[541,1646,1647],{"class":551},"    children",[541,1649,644],{"class":575},[541,1651,1652],{"class":551}," [\n",[541,1654,1655,1658],{"class":543,"line":598},[541,1656,1657],{"class":547},"      TextField",[541,1659,1642],{"class":551},[541,1661,1662,1665,1667,1670],{"class":543,"line":621},[541,1663,1664],{"class":551},"        controller",[541,1666,644],{"class":575},[541,1668,1669],{"class":551}," _nameController",[541,1671,649],{"class":575},[541,1673,1674,1677,1679,1682,1685,1687,1690,1692],{"class":543,"line":638},[541,1675,1676],{"class":551},"        enabled",[541,1678,644],{"class":575},[541,1680,1681],{"class":575}," !",[541,1683,1684],{"class":551},"state",[541,1686,612],{"class":575},[541,1688,1689],{"class":551},"isPending",[541,1691,576],{"class":575},[541,1693,1694],{"class":588},"   // disable input while the server call is in flight\n",[541,1696,1697],{"class":543,"line":652},[541,1698,1699],{"class":575},"        ...\n",[541,1701,1702,1705],{"class":543,"line":663},[541,1703,1704],{"class":551},"      )",[541,1706,649],{"class":575},[541,1708,1709],{"class":543,"line":673},[541,1710,1072],{"emptyLinePlaceholder":1071},[541,1712,1713],{"class":543,"line":710},[541,1714,1715],{"class":588},"      // Inline status feedback via Dart 3 switch expression\n",[541,1717,1718,1721],{"class":543,"line":718},[541,1719,1720],{"class":624},"      switch",[541,1722,1723],{"class":551}," (state) {\n",[541,1725,1726,1729,1731,1733,1736,1739,1741,1744],{"class":543,"line":1160},[541,1727,1728],{"class":547},"        MutationFailure",[541,1730,566],{"class":551},[541,1732,644],{"class":575},[541,1734,1735],{"class":555},"final",[541,1737,1738],{"class":551}," error) ",[541,1740,684],{"class":575},[541,1742,1743],{"class":547}," _FeedbackBanner",[541,1745,1642],{"class":551},[541,1747,1748,1751,1753,1756,1758,1761],{"class":543,"line":1166},[541,1749,1750],{"class":551},"            icon",[541,1752,644],{"class":575},[541,1754,1755],{"class":547}," Icons",[541,1757,612],{"class":575},[541,1759,1760],{"class":551},"undo_rounded",[541,1762,649],{"class":575},[541,1764,1765,1768,1770,1773,1776,1780,1783],{"class":543,"line":1171},[541,1766,1767],{"class":551},"            message",[541,1769,644],{"class":575},[541,1771,1772],{"class":1020}," 'Save failed, name restored. ",[541,1774,1775],{"class":551},"$",[541,1777,1779],{"class":1778},"sHdIc","error",[541,1781,1782],{"class":1020},"'",[541,1784,649],{"class":575},[541,1786,1787,1790,1792,1795,1797,1800],{"class":543,"line":1177},[541,1788,1789],{"class":551},"            color",[541,1791,644],{"class":575},[541,1793,1794],{"class":547}," Colors",[541,1796,612],{"class":575},[541,1798,1799],{"class":551},"red",[541,1801,649],{"class":575},[541,1803,1804,1807],{"class":543,"line":1191},[541,1805,1806],{"class":551},"          )",[541,1808,649],{"class":575},[541,1810,1811,1814,1817,1819,1822,1824],{"class":543,"line":1211},[541,1812,1813],{"class":547},"        MutationSuccess",[541,1815,1816],{"class":551},"() ",[541,1818,684],{"class":575},[541,1820,1821],{"class":555}," const",[541,1823,1743],{"class":547},[541,1825,1642],{"class":551},[541,1827,1828,1830,1832,1834,1836,1839],{"class":543,"line":1223},[541,1829,1750],{"class":551},[541,1831,644],{"class":575},[541,1833,1755],{"class":547},[541,1835,612],{"class":575},[541,1837,1838],{"class":551},"check_circle_outline",[541,1840,649],{"class":575},[541,1842,1843,1845,1847,1850],{"class":543,"line":1229},[541,1844,1767],{"class":551},[541,1846,644],{"class":575},[541,1848,1849],{"class":1020}," 'Saved. Cache updated from server.'",[541,1851,649],{"class":575},[541,1853,1854,1856,1858,1860,1862,1865],{"class":543,"line":1285},[541,1855,1789],{"class":551},[541,1857,644],{"class":575},[541,1859,1794],{"class":547},[541,1861,612],{"class":575},[541,1863,1864],{"class":551},"green",[541,1866,649],{"class":575},[541,1868,1869,1871],{"class":543,"line":1298},[541,1870,1806],{"class":551},[541,1872,649],{"class":575},[541,1874,1875,1878,1880,1882,1885,1887,1890,1892,1894],{"class":543,"line":1305},[541,1876,1877],{"class":551},"        _ ",[541,1879,684],{"class":575},[541,1881,1821],{"class":555},[541,1883,1884],{"class":547}," SizedBox",[541,1886,612],{"class":575},[541,1888,1889],{"class":562},"shrink",[541,1891,1293],{"class":551},[541,1893,576],{"class":575},[541,1895,1896],{"class":588},"  // MutationIdle, MutationPending\n",[541,1898,1899,1902],{"class":543,"line":1310},[541,1900,1901],{"class":551},"      }",[541,1903,649],{"class":575},[541,1905,1906],{"class":543,"line":1315},[541,1907,1072],{"emptyLinePlaceholder":1071},[541,1909,1910,1913],{"class":543,"line":1321},[541,1911,1912],{"class":547},"      FilledButton",[541,1914,1642],{"class":551},[541,1916,1917,1920,1922,1924,1926,1929,1931,1933,1936,1939,1941,1944,1947,1949,1951,1953,1955,1957,1959,1961,1964],{"class":543,"line":1346},[541,1918,1919],{"class":551},"        onPressed",[541,1921,644],{"class":575},[541,1923,913],{"class":551},[541,1925,612],{"class":575},[541,1927,1928],{"class":551},"isPending ",[541,1930,1260],{"class":575},[541,1932,1091],{"class":575},[541,1934,1935],{"class":575}," :",[541,1937,1938],{"class":551}," () ",[541,1940,684],{"class":575},[541,1942,1943],{"class":562}," mutate",[541,1945,1946],{"class":551},"((id",[541,1948,644],{"class":575},[541,1950,695],{"class":551},[541,1952,612],{"class":575},[541,1954,814],{"class":551},[541,1956,576],{"class":575},[541,1958,819],{"class":551},[541,1960,644],{"class":575},[541,1962,1963],{"class":551}," name))",[541,1965,649],{"class":575},[541,1967,1969,1972,1974,1976,1978],{"class":543,"line":1968},27,[541,1970,1971],{"class":551},"        child",[541,1973,644],{"class":575},[541,1975,913],{"class":551},[541,1977,612],{"class":575},[541,1979,1980],{"class":551},"isPending\n",[541,1982,1984,1987,1989,1992,1995,1997,2001],{"class":543,"line":1983},28,[541,1985,1986],{"class":575},"            ?",[541,1988,1821],{"class":555},[541,1990,1991],{"class":547}," CircularProgressIndicator",[541,1993,1994],{"class":551},"(strokeWidth",[541,1996,644],{"class":575},[541,1998,2000],{"class":1999},"sbssI"," 2.5",[541,2002,931],{"class":551},[541,2004,2006,2009,2011,2014,2016,2019,2021],{"class":543,"line":2005},29,[541,2007,2008],{"class":575},"            :",[541,2010,1821],{"class":555},[541,2012,2013],{"class":547}," Text",[541,2015,566],{"class":551},[541,2017,2018],{"class":1020},"'Save'",[541,2020,1573],{"class":551},[541,2022,649],{"class":575},[541,2024,2026,2028],{"class":543,"line":2025},30,[541,2027,1704],{"class":551},[541,2029,649],{"class":575},[541,2031,2033,2036],{"class":543,"line":2032},31,[541,2034,2035],{"class":551},"    ]",[541,2037,649],{"class":575},[541,2039,2041,2043],{"class":543,"line":2040},32,[541,2042,713],{"class":551},[541,2044,618],{"class":575},[541,2046,2048,2050],{"class":543,"line":2047},33,[541,2049,1349],{"class":551},[541,2051,649],{"class":575},[353,2053,2054,450,2056,2058,2059,2062,2063,1377,2066,450,2068,2070,2071,2074],{},[367,2055,468],{},[367,2057,471],{}," share the ",[367,2060,2061],{},"_"," arm: the feedback banner is absent and the button is enabled or disabled by ",[367,2064,2065],{},"state.isPending",[367,2067,477],{},[367,2069,474],{}," each render a distinct inline banner. No boolean flags, no ",[367,2072,2073],{},"setState"," calls.",[379,2076],{},[348,2078,2080],{"id":2079},"validation-steps","Validation Steps",[353,2082,2083],{},"The example ships with an observable failure mode to make rollback visible:",[2085,2086,2087,2094,2097,2108,2119],"ol",{},[389,2088,2089,2090,2093],{},"Open ",[356,2091,2092],{},"User List"," and wait for the initial load",[389,2095,2096],{},"Tap the edit icon on any user",[389,2098,2099,2100,2103,2104,2107],{},"Enter a new name and tap ",[356,2101,2102],{},"Save",": the list updates ",[356,2105,2106],{},"immediately"," in the background",[389,2109,2110,2111],{},"Wait ~2 s for the server response:\n",[386,2112,2113,2116],{},[389,2114,2115],{},"On success (~70 %): the new name persists; a green confirmation appears",[389,2117,2118],{},"On failure (~30 %): the name reverts to the original; a red rollback banner appears",[389,2120,2121],{},"Tap the refresh icon in the app bar to force a full invalidation and observe the server-confirmed state",[379,2123],{},[348,2125,2127],{"id":2126},"source-code","Source Code",[503,2129,2132],{"className":2130,"code":2131,"language":508,"meta":509},[506],"examples/ex_02_mutations_optimistic/\n├── lib/\n│   ├── main.dart                      ← QoraClient + QoraScope setup\n│   ├── models/user.dart               ← pure data class with copyWith\n│   ├── services/fake_api.dart         ← simulated API (2 s delay, ~30 % failure on updateUser)\n│   └── screens/\n│       ├── user_list_screen.dart      ← QoraBuilder + edit trigger\n│       └── rename_user_sheet.dart     ← QoraMutationBuilder + full optimistic protocol\n└── pubspec.yaml\n",[367,2133,2131],{"__ignoreMap":509},[353,2135,2136],{},[2137,2138,2142],"a",{"href":2139,"rel":2140},"https://github.com/meragix/qora/tree/main/examples/ex_02_mutations_optimistic",[2141],"nofollow","View full source code",[379,2144],{},[348,2146,2148],{"id":2147},"related","Related",[386,2150,2151,2158,2170,2176],{},[389,2152,2153,2157],{},[2137,2154,2156],{"href":2155},"../recipes/optimistic-updates","Optimistic Updates Recipe",": step-by-step conceptual walkthrough of the same pattern",[389,2159,2160,2164,2165,450,2167,2169],{},[2137,2161,2163],{"href":2162},"../recipes/mutations","Mutations Recipe",": ",[367,2166,113],{},[367,2168,738],{}," API reference",[389,2171,2172,2175],{},[2137,2173,113],{"href":2174},"../flutter-integration/qora-mutation-builder",": full widget API",[389,2177,2178,2164,2181,2183,2184],{},[2137,2179,297],{"href":2180},"./basic-query",[367,2182,108],{},", SWR caching, and ",[367,2185,2186],{},"FetchStatus",[2188,2189,2190],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}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 .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 .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 .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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":509,"searchDepth":585,"depth":585,"links":2192},[2193,2194,2195,2196,2204,2205,2206],{"id":350,"depth":585,"text":351},{"id":383,"depth":585,"text":384},{"id":494,"depth":585,"text":495},{"id":726,"depth":585,"text":727,"children":2197},[2198,2199,2200,2201,2202],{"id":731,"depth":592,"text":732},{"id":960,"depth":592,"text":961},{"id":1365,"depth":592,"text":1366},{"id":1499,"depth":592,"text":1500},{"id":1596,"depth":592,"text":2203},"MutationState pattern matching",{"id":2079,"depth":585,"text":2080},{"id":2126,"depth":585,"text":2127},{"id":2147,"depth":585,"text":2148},"A complete optimistic update implementation: setQueryData for immediate UI feedback, restoreQueryData for automatic rollback on failure, and invalidateWhere for server reconciliation.","md",null,{},{"icon":151},{"title":2213,"description":2214},"Case Study: Optimistic Mutations & Rollback - Qora","Production-grade optimistic mutations with QoraMutationBuilder. Covers setQueryData, restoreQueryData, cross-cache snapshots, MutationState pattern matching, and server reconciliation.","egv2amR01CBdIyQLvYSeFiJsMjRX5U58Ss8hGBQ8Onw",[2217,2219],{"title":297,"path":298,"stem":299,"description":2218,"icon":300,"children":-1},"A complete list-and-detail feature: SWR caching, FetchStatus two-axis state, per-item query keys, pull-to-refresh, and graceful degradation. Zero boilerplate state management.",{"title":306,"path":307,"stem":308,"description":2220,"icon":309,"children":-1},"Build a high-performance social media-style feed with cursor-based pagination, windowed memory management, and instant optimistic post creation.",1794040402902]