Skip to content

Enable refining the generic on a Mutation#4253

Merged
rrousselGit merged 17 commits intorrousselGit:masterfrom
TekExplorer:master
Sep 9, 2025
Merged

Enable refining the generic on a Mutation#4253
rrousselGit merged 17 commits intorrousselGit:masterfrom
TekExplorer:master

Conversation

@TekExplorer
Copy link
Copy Markdown
Contributor

@TekExplorer TekExplorer commented Aug 27, 2025

Related Issues

fixes #4252

Checklist

Before you create this PR confirm that it meets all requirements listed below by checking the relevant checkboxes ([x]).

  • I have updated the CHANGELOG.md of the relevant packages.
    Changelog files must be edited under the form:

    ## Unreleased fix/major/minor
    
    - Description of your change. (thanks to @yourGithubId)
  • If this contains new features or behavior changes,
    I have updated the documentation to match those changes.

Summary by CodeRabbit

  • New Features

    • Mutation.call is now generic for keyed mutations, enabling multiple keyed instances with distinct typed results.
  • Documentation

    • Mutation docs refreshed with scoped/keyed and generic-return examples, relocated snippet rendering, and updated reference links.
  • Tests

    • Added tests verifying keyed generic mutations are distinct and listeners observe correctly-typed results.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Aug 27, 2025

Walkthrough

Adds generic support for keyed mutations by making Mutation.call generic over a subtype of the result type, relaxes internal parent typing, updates equality for cross-type safety, and adds tests, docs examples, and a changelog entry reflecting the new keyed generic usage.

Changes

Cohort / File(s) Summary
Core mutation API
packages/riverpod/lib/src/core/mutations.dart
Made Mutation.call generic: call<ChangedT extends ResultT>(Object? key) with @optionalTypeArgs. MutationImpl.call now returns MutationImpl<ChangedT> and delegates to _keyed. Internal _key parent type relaxed to Mutation<Object?>. Added cross-type equality checks to avoid equating keyed mutations with different generic specializations.
Tests
packages/riverpod/test/feature/mutation_test.dart
Added "Supports generic mutations" test exercising keyed generic instances (num, int, double), equality behavior, and type-correct listener notifications.
Documentation / Examples
website/docs/concepts2/mutations.mdx
website/docs/concepts2/mutations/*.dart
Replaced inline examples with snippet rendering and added example snippets demonstrating listening, keyed, generic, triggering, switching, and resetting mutation usage (listening.dart, generic.dart, keyed.dart, triggering.dart, switching.dart, resetting.dart).
Changelog
packages/riverpod/CHANGELOG.md
Added Unreleased note: “Made Mutation.call generic.” with contributor attribution.

Sequence Diagram(s)

sequenceDiagram
  participant Caller as Caller
  participant Mutation as Mutation<ResultT>
  participant Impl as MutationImpl<ChangedT>

  Caller->>Mutation: call<ChangedT extends ResultT>(key)
  Note right of Mutation #E8F8F5: Generic conversion\nproduces a typed keyed mutation
  Mutation->>Impl: MutationImpl<ChangedT>._keyed((key, parent))
  Note right of Impl #F6F8FF: _key stores (value, parent)\nparent typed as Mutation<Object?>
  Impl-->>Caller: Mutation<ChangedT>
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Assessment against linked issues

Objective Addressed Explanation
Make Mutation.call generic to support generics in mutations (#4252)

Assessment — Out-of-scope changes

Code Change Explanation
Documentation examples added (website/docs/concepts2/mutations/*.dart, website/docs/concepts2/mutations.mdx) Docs/examples were added; linked issue requested API change only.
CHANGELOG entry (packages/riverpod/CHANGELOG.md) Changelog update documents the change and is not part of the API implementation requirement.

Possibly related PRs

  • Rework mutations #4170 — Directly overlaps with mutation implementation changes (Mutation.call, keyed/generic behavior).
  • Sync dev with master #4068 — Earlier mutation refactor affecting Mutation types and call behavior; provides relevant context.

Poem

I nibble code beneath the moon,
Made calls more flexible — oh so soon,
Keys and types now hop in line,
Mutations shaped, concise, and fine,
I twitch my nose — the change is mine. 🥕🐇


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ee8c06c and 054c1a0.

📒 Files selected for processing (1)
  • packages/riverpod/CHANGELOG.md (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/riverpod/CHANGELOG.md
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: build (master, packages/flutter_riverpod/example)
  • GitHub Check: build (master, packages/riverpod/example)
  • GitHub Check: build (master, examples/todos)
  • GitHub Check: build (master, packages/flutter_riverpod)
  • GitHub Check: build (master, examples/counter)
  • GitHub Check: build (stable, packages/riverpod_generator)
  • GitHub Check: build (stable, packages/riverpod)
  • GitHub Check: build (stable, packages/riverpod/example)
  • GitHub Check: build (stable, packages/flutter_riverpod)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_lint)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_analyzer_utils)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_lint_flutter_test)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_analyzer_utils_tests)
  • GitHub Check: riverpod_lint (master, packages/riverpod_analyzer_utils_tests)
  • GitHub Check: riverpod_lint (master, packages/riverpod_lint)
  • GitHub Check: riverpod_lint (master, packages/riverpod_lint_flutter_test)
  • GitHub Check: check_generation
  • GitHub Check: riverpod_lint (master, packages/riverpod_analyzer_utils)
  • GitHub Check: changelog
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@TekExplorer TekExplorer marked this pull request as ready for review August 27, 2025 09:27
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/riverpod/lib/src/core/mutations.dart (1)

89-95: Provider equality also blocks reuse across refined generics

_MutationProvider.operator == uses _MutationProvider<ValueT> in the type check, which will be false for different ValueT even if mutation is equal. This causes separate provider entries for the same keyed mutation when ChangedT differs.

Apply this diff:

   @override
   bool operator ==(Object other) {
-    return other is _MutationProvider<ValueT> && mutation == other.mutation;
+    return other is _MutationProvider && mutation == other.mutation;
   }

No change needed to hashCode since it’s already based on mutation.

🧹 Nitpick comments (4)
packages/riverpod/CHANGELOG.md (1)

9-10: Clarify API change with signature and snippet

Recommend documenting the exact signature change and a tiny example for discoverability.

Apply this diff:

-- Made `Mutation.call` generic.
-  This allows for better compatibility with generic-returning functions (thanks to @TekExplorer)
+- Made `Mutation.call` generic: `call<ChangedT extends ResultT>(Object? key) -> Mutation<ChangedT>`.
+  This enables refining a mutation's result type at the call site (thanks to @TekExplorer).
+  Example:
+  ```dart
+  final save = Mutation<Object?>();
+  // Narrow the result type for this keyed usage:
+  final saveUser = save.call<User>(userId);
+  ```
packages/riverpod/lib/src/core/mutations.dart (3)

336-346: Doc grammar fix (“These are”)

Minor wording polish.

-  /// This are passed using [call].
+  /// These are passed using [call].

599-601: Doc typo (“You can also”)

Minor typo.

-/// You cam also manually reset a mutation to its initial state using
+/// You can also manually reset a mutation to its initial state using

411-413: Soundness of _key parent type is fine given covariance, but add an assertion

At runtime, a mismatched parent would be catastrophic. Add a debug assert to ensure this is the parent when creating keyed instances.

 MutationImpl<ChangedT> call<ChangedT extends ResultT>(Object? key) {
-  return MutationImpl<ChangedT>._keyed((key, this), label: label);
+  assert(() {
+    // Sanity: parent must be `this`.
+    final parent = this;
+    return parent is Mutation<Object?>;
+  }());
+  return MutationImpl<ChangedT>._keyed((key, this), label: label);
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 18a2f95 and f43a093.

📒 Files selected for processing (2)
  • packages/riverpod/CHANGELOG.md (1 hunks)
  • packages/riverpod/lib/src/core/mutations.dart (2 hunks)
🔇 Additional comments (1)
packages/riverpod/lib/src/core/mutations.dart (1)

353-355: API: Generic call is a good addition

Signature looks right and aligns with the goal of refining the result type.

Comment thread packages/riverpod/lib/src/core/mutations.dart
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/riverpod/test/feature/mutation_test.dart (2)

41-44: Close subscriptions to avoid lingering listeners.

Not required for correctness here, but closing them is cleaner and mirrors typical usage.

Apply this diff after the last expect:

@@
-    expect(subDouble.read(), isMutationSuccess<double>(3.14));
+    expect(subDouble.read(), isMutationSuccess<double>(3.14));
+    sub.close();
+    subInt.close();
+    subDouble.close();

35-38: Tighten the comment wording.

Clarify intent: it’s about instance equality when generic and key match.

Apply this diff:

-    // shows that using the same generic
-    // with the same key will get the correct value
+    // Using the same generic and the same key yields the same mutation instance
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f43a093 and f0c9723.

📒 Files selected for processing (1)
  • packages/riverpod/test/feature/mutation_test.dart (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (20)
  • GitHub Check: build (master, packages/riverpod)
  • GitHub Check: build (master, packages/riverpod_annotation)
  • GitHub Check: build (master, packages/flutter_riverpod/example)
  • GitHub Check: build (master, examples/pub)
  • GitHub Check: build (master, packages/riverpod_generator)
  • GitHub Check: build (master, examples/marvel)
  • GitHub Check: build (master, packages/flutter_riverpod)
  • GitHub Check: build (stable, packages/flutter_riverpod/example)
  • GitHub Check: build (master, examples/counter)
  • GitHub Check: build (stable, packages/flutter_riverpod)
  • GitHub Check: build (stable, examples/todos)
  • GitHub Check: build (stable, packages/riverpod)
  • GitHub Check: riverpod_lint (master, packages/riverpod_lint_flutter_test)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_analyzer_utils_tests)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_lint_flutter_test)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_lint)
  • GitHub Check: riverpod_lint (master, packages/riverpod_lint)
  • GitHub Check: riverpod_lint (master, packages/riverpod_analyzer_utils_tests)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_analyzer_utils)
  • GitHub Check: check_generation
🔇 Additional comments (1)
packages/riverpod/test/feature/mutation_test.dart (1)

26-38: Nice coverage for generic/key identity.

Good assertions showing distinct instances across generics and same-instance equality for identical generic+key.

Comment thread packages/riverpod/test/feature/mutation_test.dart Outdated
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Comment thread packages/riverpod/test/feature/mutation_test.dart Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
website/docs/concepts2/mutations.mdx (1)

309-321: Fix variable name and incorrect run invocation in keyed example

  • Variable used in ref.watch is deleteMutation, but declared as deleteTodoMutation.
  • Calling run on deleteTodo(todo.id) is incorrect since deleteTodo is the watched state, not the mutation. Call run on the mutation instance with the same key.
-/// final deleteTodoMutation = Mutation<void>();
+/// final deleteTodoMutation = Mutation<void>();
 /// ...
 ///
 /// // You can pass a unique object to the mutation upon watching it.
-/// final deleteTodo = ref.watch(deleteMutation(todo.id));
+/// final deleteTodo = ref.watch(deleteTodoMutation(todo.id));
 /// ...
 ///
 /// onPressed: () {
 ///   // Upon calling `run`, you will have to pass the same key as when
 ///   // watching the mutation.
-///   deleteTodo(todo.id).run(ref, (tsx) async { /* ... */ });
+///   deleteTodoMutation(todo.id).run(ref, (tsx) async { /* ... */ });
 /// }
♻️ Duplicate comments (1)
packages/riverpod/lib/src/core/mutations.dart (1)

519-526: Equality currently blocks cross-generic keyed equality; consider ignoring type parameter in == for keyed instances

As written, operator == requires other is MutationImpl<ResultT> and _matchesT, so two keyed mutations with the same (parent, key) but different ChangedT won’t be equal. This undermines the idea of “refining” the same keyed mutation across types (e.g., mut<num>('k') vs mut<int>('k')), and may fragment caches/observers keyed by the mutation.

Proposed change (keyed instances equal by (parent,key) regardless of generic; unkeyed fallback remains identity):

-  bool _matchesT(Mutation<Object?> other) => other is Mutation<ResultT>;
+  // No longer needed if equality ignores generic for keyed instances.
   @override
   bool operator ==(Object other) {
-    if (other is! MutationImpl<ResultT> || !other._matchesT(this)) return false;
-    if (_key != null) return _key == other._key;
+    if (identical(this, other)) return true;
+    if (other is! MutationImpl) return false;
+    if (_key != null) return _key == (other as MutationImpl)._key;
 
     return super == other;
   }

No change needed to hashCode since it already derives from _key when present.

Note: To fully share provider instances across refined generics, _MutationProvider.operator == may also need to drop its generic constraint:

-  @override
-  bool operator ==(Object other) {
-    return other is _MutationProvider<ValueT> && mutation == other.mutation;
-  }
+  @override
+  bool operator ==(Object other) {
+    return other is _MutationProvider && mutation == other.mutation;
+  }

If the intended design is to keep refined generics distinct, please confirm and we can drop this suggestion and add docs/tests clarifying the behavior.

🧹 Nitpick comments (3)
website/docs/concepts2/mutations.mdx (3)

40-48: Keyed mutation example: consider showing the watch/run flow

The snippet defines a keyed mutation instance but doesn’t illustrate how to listen/run it. Adding one line clarifies usage.

 final removeTodo = Mutation<void>();
-final removeTodoWithId = removeTodo(todo.id);
+final removeTodoWithId = removeTodo(todo.id);
+// Later in a widget:
+final state = ref.watch(removeTodoWithId);
+// And when triggering:
+removeTodoWithId.run(ref, (tsx) async { /* ... */ });

50-61: Grammar and casing tweaks; tighten example prose

  • “api” → “API”
  • “such as if” → “such as when”
-Sometimes, these mutations have a generic return type,
-such as if an api response may have different response types
+Sometimes, these mutations have a generic return type,
+such as when an API response may have different response types
 based on the input parameters.

65-68: Wording nit: “our choice” → “your choice”

Minor tone fix in user-facing docs.

-For this, we will need a <Link documentID="concepts2/refs" /> and pick a listening method of our choice
+For this, we will need a <Link documentID="concepts2/refs" /> and pick a listening method of your choice
 (typically [Ref.watch]).
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 925d3d5 and 72fbeef.

📒 Files selected for processing (3)
  • packages/riverpod/lib/src/core/mutations.dart (3 hunks)
  • packages/riverpod/test/feature/mutation_test.dart (1 hunks)
  • website/docs/concepts2/mutations.mdx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/riverpod/test/feature/mutation_test.dart
🧰 Additional context used
🪛 LanguageTool
website/docs/concepts2/mutations.mdx

[grammar] ~43-~43: There might be a mistake here.
Context: ...multiple instances of the same mutation, such as deleting a specific item in a li...

(QB_NEW_EN)


[grammar] ~50-~50: There might be a mistake here.
Context: ...se mutations have a generic return type, such as if an api response may have diff...

(QB_NEW_EN)


[grammar] ~51-~51: There might be a mistake here.
Context: ...sponse may have different response types based on the input parameters. ```dart f...

(QB_NEW_EN)


[grammar] ~66-~66: There might be a mistake here.
Context: ...nd pick a listening method of our choice (typically [Ref.watch]). A typical exa...

(QB_NEW_EN)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: build (master, packages/flutter_riverpod/example)
  • GitHub Check: build (master, packages/flutter_riverpod)
  • GitHub Check: build (master, examples/pub)
  • GitHub Check: build (master, examples/random_number)
  • GitHub Check: build (master, examples/stackoverflow)
  • GitHub Check: build (stable, packages/riverpod_generator/integration/build_yaml)
  • GitHub Check: build (stable, packages/riverpod)
  • GitHub Check: build (master, examples/counter)
  • GitHub Check: build (stable, examples/todos)
  • GitHub Check: build (stable, packages/riverpod_generator)
  • GitHub Check: build (stable, examples/marvel)
  • GitHub Check: build (stable, examples/counter)
  • GitHub Check: build (stable, examples/stackoverflow)
  • GitHub Check: check_generation
  • GitHub Check: riverpod_lint (master, packages/riverpod_analyzer_utils_tests)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_analyzer_utils_tests)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_lint_flutter_test)
  • GitHub Check: riverpod_lint (master, packages/riverpod_lint_flutter_test)
  • GitHub Check: riverpod_lint (master, packages/riverpod_analyzer_utils)
🔇 Additional comments (3)
packages/riverpod/lib/src/core/mutations.dart (3)

354-355: API: Making Mutation.call generic is a good move

Allows refining the result type per key; annotation with @optionalTypeArgs is appropriate.


408-408: Internal key now stores parent as Mutation<Object?>

This widens parent typing so keyed instances can originate from any parent mutation. Looks correct; ensure all tuple usages access $1/$2 consistently to avoid named-field drift.

Would you like a quick grep script to verify only $1/$2 are used with _key across the file?


411-413: Generic call implementation LGTM

Returning MutationImpl<ChangedT>._keyed((key, this), ...) preserves parent identity and label; no unnecessary casts.

Comment thread website/docs/concepts2/mutations.mdx Outdated
Comment thread website/docs/concepts2/mutations.mdx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
website/docs/concepts2/mutations.mdx (1)

101-102: Fix duplicated word and clarify

Minor grammar fix.

-// We perform a perform request using a Notifier.
+// We perform a request using a Notifier.
♻️ Duplicate comments (1)
website/docs/concepts2/mutations.mdx (1)

52-52: Nice: snippet extracted and inlined via raw-loader

This addresses the prior request to externalize code samples for compilation safety.

🧹 Nitpick comments (5)
website/docs/concepts2/mutations/listening.dart (1)

24-27: Verify WidgetStatePropertyAll vs MaterialStatePropertyAll compatibility

WidgetStatePropertyAll requires newer Flutter. If your min Flutter SDK is older, ButtonStyle.backgroundColor expects MaterialStateProperty<Color?>. Consider this fallback.

-            backgroundColor: switch (addTodoState) {
-              MutationError() => const WidgetStatePropertyAll(Colors.red),
-              _ => null,
-            },
+            backgroundColor: switch (addTodoState) {
+              MutationError() => const MaterialStatePropertyAll(Colors.red),
+              _ => null,
+            },
website/docs/concepts2/mutations.mdx (4)

18-25: Polish punctuation and stray character

Remove the extra “!” and fix spacing before the semicolon.

-![Submit progress indicator](/img/concepts2/mutations/spinner.gif)!
+![Submit progress indicator](/img/concepts2/mutations/spinner.gif)

-...with UI concerns ; and it involves a lot of boilerplate code
+...with UI concerns; and it involves a lot of boilerplate code

69-72: Tighten wording and capitalization

Use API (caps) and avoid the duplicated “such as”.

-Sometimes, these mutations have a generic return type,
-such as if an api response may have different response types
-based on the input parameters, such as with deserialization.
+Sometimes, these mutations have a generic return type,
+for example when an API response varies based on input parameters,
+such as during deserialization.

87-89: Clarify: run is an instance method

The narrative suggests passing a mutation to a static function. It’s invoked on the instance.

-To trigger a mutation, we can use [Mutation.run], pass our mutation, and provide an asynchronous callback
+To trigger a mutation, call [Mutation.run] on your instance (e.g., addTodo.run) and provide an asynchronous callback

153-161: Confirm doc version pinning

All API links are pinned to 3.0.0‑dev.17. If the dev tag bumps, these will stale. Consider using latest or a shared version constant if that matches project conventions.

-[MutationPending]: https://pub.dev/documentation/riverpod/3.0.0-dev.17/experimental_mutation/MutationPending-class.html
+[MutationPending]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/MutationPending-class.html
...
-[Ref.watch]: https://pub.dev/documentation/riverpod/3.0.0-dev.17/riverpod/Ref/watch.html
+[Ref.watch]: https://pub.dev/documentation/riverpod/latest/riverpod/Ref/watch.html
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4636d15 and 280a465.

📒 Files selected for processing (2)
  • website/docs/concepts2/mutations.mdx (4 hunks)
  • website/docs/concepts2/mutations/listening.dart (1 hunks)
🧰 Additional context used
🪛 LanguageTool
website/docs/concepts2/mutations.mdx

[grammar] ~5-~5: There might be a mistake here.
Context: ...mport CodeBlock from "@theme/CodeBlock"; import { trimSnippet } from "/src/compon...

(QB_NEW_EN)


[grammar] ~6-~6: There might be a mistake here.
Context: ...et } from "/src/components/CodeSnippet"; import listener from 'raw-loader!./mutat...

(QB_NEW_EN)


[grammar] ~60-~60: There might be a mistake here.
Context: ...multiple instances of the same mutation, such as deleting a specific item in a li...

(QB_NEW_EN)


[grammar] ~69-~69: There might be a mistake here.
Context: ...se mutations have a generic return type, such as if an api response may have diff...

(QB_NEW_EN)


[grammar] ~70-~70: There might be a mistake here.
Context: ...sponse may have different response types based on the input parameters, such as w...

(QB_NEW_EN)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: build (master, packages/hooks_riverpod/example)
  • GitHub Check: build (master, packages/flutter_riverpod)
  • GitHub Check: build (master, packages/riverpod_annotation)
  • GitHub Check: build (master, examples/pub)
  • GitHub Check: build (master, packages/flutter_riverpod/example)
  • GitHub Check: build (master, examples/random_number)
  • GitHub Check: build (master, examples/counter)
  • GitHub Check: build (master, packages/riverpod)
  • GitHub Check: build (master, examples/todos)
  • GitHub Check: build (stable, packages/riverpod_annotation)
  • GitHub Check: build (stable, packages/flutter_riverpod/example)
  • GitHub Check: build (stable, examples/random_number)
  • GitHub Check: build (stable, examples/pub)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_lint)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_lint_flutter_test)
  • GitHub Check: riverpod_lint (master, packages/riverpod_lint_flutter_test)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_analyzer_utils_tests)
  • GitHub Check: check_generation
  • GitHub Check: riverpod_lint (master, packages/riverpod_analyzer_utils_tests)
🔇 Additional comments (2)
website/docs/concepts2/mutations/listening.dart (2)

16-17: Good use of Ref.watch for mutation state

Clear, side‑effect free subscription to the mutation state.


39-42: Pending-state UI is succinct and correct

Conditional progress indicator based on MutationPending reads well.

Comment thread website/docs/concepts2/mutations.mdx Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

♻️ Duplicate comments (1)
website/docs/concepts2/mutations.mdx (1)

5-12: Snippets extracted and imported correctly; listener path fix looks good

The raw-loader imports point to dedicated .dart snippets, and the previous listener.dart → listening.dart issue is resolved.

Run to verify snippet files exist and imports match:

#!/bin/bash
set -euo pipefail
base="website/docs/concepts2/mutations"
for f in listening.dart keyed.dart generic.dart triggering.dart switching.dart resetting.dart; do
  test -f "$base/$f" || { echo "Missing: $base/$f"; exit 1; }
done
# Ensure imports reference the exact filenames
rg -nP $'^import\\s+\\w+\\s+from\\s+\\\'raw-loader!\\./mutations/(listening|keyed|generic|triggering|switching|resetting)\\.dart\\\';$' website/docs/concepts2/mutations.mdx
🧹 Nitpick comments (8)
website/docs/concepts2/mutations/triggering.dart (2)

45-45: Fix typo in comment.

-          // We perform a perform request using a Notifier.
+          // We perform a request using a Notifier.

35-54: Optionally await run to avoid re-entrancy and surface errors.

Making onPressed async and awaiting run helps prevent double-taps during pending and propagates exceptions to Flutter’s error handler.

-    return ElevatedButton(
-      onPressed: () {
+    return ElevatedButton(
+      onPressed: () async {
         // Trigger the mutation, and run the callback.
         // During the callback, we obtain a MutationTransaction (tsx) object
         // which we can use to access providers and perform operations.
-        addTodo.run(ref, (tsx) async {
+        await addTodo.run(ref, (tsx) async {
           // We use tsx.get to access providers within mutations.
           // This will keep the provider alive for the duration of the operation.
           final todoNotifier = tsx.get(todoNotifierProvider.notifier);
 
-          // We perform a perform request using a Notifier.
+          // We perform a request using a Notifier.
           final createdTodo = await todoNotifier.addTodo('Eat a cookie');
 
           // We return the created todo. This enables our UI to show information
           // about the created todo, such as its ID/creation date/etc.
           return createdTodo;
         });
       },
website/docs/concepts2/mutations/generic.dart (1)

42-48: Return the created value to showcase generic return types.

Returning the CreatedResponse from executeCreateTodo better demonstrates the new generic capability.

-Future<void> executeCreateTodo(MutationTarget ref) async {
-  await createTodo.run(ref, (tsx) async {
+Future<CreatedResponse<Todo>> executeCreateTodo(MutationTarget ref) async {
+  return await createTodo.run(ref, (tsx) async {
     final client = tsx.get(apiProvider);
     final response = client.post('/todos', data: {'title': 'Eat a cookie'});
     return CreatedResponse<Todo>.fromJson(response.data, Todo.fromJson);
   });
 }
website/docs/concepts2/mutations.mdx (5)

57-57: Specify code language for proper syntax highlighting

Add language="dart" to CodeBlock.

-<CodeBlock>{trimSnippet(listener)}</CodeBlock>
+<CodeBlock language="dart">{trimSnippet(listener)}</CodeBlock>

59-76: Tighten phrasing, fix capitalization, and add code language; minor copyedits

  • Capitalize “API”.
  • Remove repetition (“such as … such as”).
  • Minor grammar/punctuation.
  • Add language="dart" to CodeBlock elements.
-### Scoping a mutation
+### Scoping a mutation
@@
-Sometimes, you may want to have multiple instances of the same mutation.
+Sometimes, you may want multiple instances of the same mutation.
@@
-This can include things like an id, or any other parameter that makes the mutation unique.
+This can include an ID or any other parameter that makes the mutation unique.
@@
-This is useful if you want to have multiple instances of the same mutation,
-such as deleting a specific item in a list
+This is useful when you want multiple instances of the same mutation,
+such as deleting a specific item in a list.
@@
-Simply call the mutation with the unique key:
+Call the mutation with a unique key:
@@
-<CodeBlock>{trimSnippet(keyed)}</CodeBlock>
+<CodeBlock language="dart">{trimSnippet(keyed)}</CodeBlock>
@@
-Sometimes, these mutations have a generic return type,
-such as if an api response may have different response types
-based on the input parameters, such as with deserialization.
+Sometimes, mutations have a generic return type. For example, an API response
+may deserialize into different types based on the input parameters.
@@
-<CodeBlock>{trimSnippet(generic)}</CodeBlock>
+<CodeBlock language="dart">{trimSnippet(generic)}</CodeBlock>

85-85: Add language to CodeBlock

Consistent highlighting across snippets.

-<CodeBlock>{trimSnippet(triggering)}</CodeBlock>
+<CodeBlock language="dart">{trimSnippet(triggering)}</CodeBlock>

97-97: Add language to CodeBlock

-<CodeBlock>{trimSnippet(switching)}</CodeBlock>
+<CodeBlock language="dart">{trimSnippet(switching)}</CodeBlock>

110-110: Add language to CodeBlock

-<CodeBlock>{trimSnippet(resetting)}</CodeBlock>
+<CodeBlock language="dart">{trimSnippet(resetting)}</CodeBlock>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 280a465 and d4bdb21.

📒 Files selected for processing (6)
  • website/docs/concepts2/mutations.mdx (5 hunks)
  • website/docs/concepts2/mutations/generic.dart (1 hunks)
  • website/docs/concepts2/mutations/keyed.dart (1 hunks)
  • website/docs/concepts2/mutations/resetting.dart (1 hunks)
  • website/docs/concepts2/mutations/switching.dart (1 hunks)
  • website/docs/concepts2/mutations/triggering.dart (1 hunks)
🧰 Additional context used
🪛 LanguageTool
website/docs/concepts2/mutations.mdx

[grammar] ~5-~5: There might be a mistake here.
Context: ...mport CodeBlock from "@theme/CodeBlock"; import { trimSnippet } from "/src/compon...

(QB_NEW_EN)


[grammar] ~6-~6: There might be a mistake here.
Context: ...et } from "/src/components/CodeSnippet"; import listener from 'raw-loader!./mutat...

(QB_NEW_EN)


[grammar] ~7-~7: There might be a mistake here.
Context: ...'raw-loader!./mutations/listening.dart'; import keyed from 'raw-loader!./mutation...

(QB_NEW_EN)


[grammar] ~8-~8: There might be a mistake here.
Context: ...rom 'raw-loader!./mutations/keyed.dart'; import generic from 'raw-loader!./mutati...

(QB_NEW_EN)


[grammar] ~9-~9: There might be a mistake here.
Context: ...m 'raw-loader!./mutations/generic.dart'; import triggering from 'raw-loader!./mut...

(QB_NEW_EN)


[grammar] ~10-~10: There might be a mistake here.
Context: ...raw-loader!./mutations/triggering.dart'; import switching from 'raw-loader!./muta...

(QB_NEW_EN)


[grammar] ~11-~11: There might be a mistake here.
Context: ...'raw-loader!./mutations/switching.dart'; import resetting from 'raw-loader!./muta...

(QB_NEW_EN)


[grammar] ~65-~65: There might be a mistake here.
Context: ...multiple instances of the same mutation, such as deleting a specific item in a li...

(QB_NEW_EN)


[grammar] ~72-~72: There might be a mistake here.
Context: ...se mutations have a generic return type, such as if an api response may have diff...

(QB_NEW_EN)


[grammar] ~73-~73: There might be a mistake here.
Context: ...sponse may have different response types based on the input parameters, such as w...

(QB_NEW_EN)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Redirect rules - river-pod
  • GitHub Check: Header rules - river-pod
  • GitHub Check: Pages changed - river-pod
  • GitHub Check: riverpod_lint (stable, packages/riverpod_lint)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_analyzer_utils_tests)
  • GitHub Check: riverpod_lint (master, packages/riverpod_analyzer_utils_tests)
  • GitHub Check: riverpod_lint (master, packages/riverpod_analyzer_utils)
  • GitHub Check: check_generation
🔇 Additional comments (4)
website/docs/concepts2/mutations/resetting.dart (1)

13-21: LGTM.

Clear, minimal reset example consistent with the other snippets.

website/docs/concepts2/mutations.mdx (3)

53-53: Anchor reference clarified

The “typically [Ref.watch]” addition improves discoverability; link anchor is defined below. No changes needed.


120-120: Ref.watch anchor added

Good addition for direct API lookup. No action needed.


117-117: All pub.dev links are consistently using version 3.0.0-dev.17

I’ve verified that every https://pub.dev/documentation/riverpod/… link in website/docs/concepts2/mutations.mdx points to version 3.0.0-dev.17. No updates are needed here.

Comment on lines +9 to +14
factory CreatedResponse.fromJson(
Map<String, Object?> json,
ValueT Function(Map<String, Object?>) fromJson,
) {
return CreatedResponse(fromJson(json['data']! as Map<String, Object?>));
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix CreatedResponse.fromJson: currently reads a nested 'data' that isn’t present.

You pass response.data (already the payload), but fromJson tries to read json['data'] again—this will fail.

   factory CreatedResponse.fromJson(
     Map<String, Object?> json,
     ValueT Function(Map<String, Object?>) fromJson,
   ) {
-    return CreatedResponse(fromJson(json['data']! as Map<String, Object?>));
+    return CreatedResponse(fromJson(json));
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
factory CreatedResponse.fromJson(
Map<String, Object?> json,
ValueT Function(Map<String, Object?>) fromJson,
) {
return CreatedResponse(fromJson(json['data']! as Map<String, Object?>));
}
factory CreatedResponse.fromJson(
Map<String, Object?> json,
ValueT Function(Map<String, Object?>) fromJson,
) {
return CreatedResponse(fromJson(json));
}
🤖 Prompt for AI Agents
In website/docs/concepts2/mutations/generic.dart around lines 9 to 14, the
CreatedResponse.fromJson factory incorrectly attempts to read json['data'] (a
nested key that doesn't exist because the caller already passes response.data);
change it to pass the supplied json directly to the fromJson converter (e.g.
call fromJson(json as Map<String, Object?>) or fromJson(json) with an
appropriate cast) and remove the ['data'] lookup so the factory uses the payload
already provided.

Comment on lines +5 to +7
/* SNIPPET START */
final removeTodo = Mutation<void>();
final removeTodoWithId = removeTodo(todo.id);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Close the snippet block.

Missing SNIPPET END will break docs extraction.

 /* SNIPPET START */
 final removeTodo = Mutation<void>();
 final removeTodoWithId = removeTodo(todo.id);
+/* SNIPPET END */
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* SNIPPET START */
final removeTodo = Mutation<void>();
final removeTodoWithId = removeTodo(todo.id);
/* SNIPPET START */
final removeTodo = Mutation<void>();
final removeTodoWithId = removeTodo(todo.id);
/* SNIPPET END */
🤖 Prompt for AI Agents
In website/docs/concepts2/mutations/keyed.dart around lines 5 to 7, the snippet
block is not closed—there's a "SNIPPET START" but no corresponding "SNIPPET
END", which breaks docs extraction; add the missing "/* SNIPPET END */" (or the
project's expected snippet end marker) immediately after the shown code block to
properly close the snippet.

Comment thread website/docs/concepts2/mutations/switching.dart
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (2)
website/docs/concepts2/mutations.mdx (2)

5-12: Snippets extracted and imports wired correctly.

Raw-loader imports match the new .dart snippets. This addresses the earlier ask to extract snippets to dedicated files.


59-66: Good: new dedicated “Scoping a mutation” section placed under Listening.

This implements the earlier suggestion to move this content into its own section under “Listening to mutations.”

🧹 Nitpick comments (4)
website/docs/concepts2/mutations.mdx (4)

23-24: Trailing “!” after image and awkward phrasing.

Remove the extra exclamation and tighten the sentence.

-In short, mutations are to achieve effects such as this:
-![Submit progress indicator](/img/concepts2/mutations/spinner.gif)!
+In short, mutations are used to achieve effects like this:
+![Submit progress indicator](/img/concepts2/mutations/spinner.gif)

27-29: Fix punctuation spacing.

There should be no space before a semicolon.

-state of your provider with UI concerns ; and it involves a lot of boilerplate code
+state of your provider with UI concerns; and it involves a lot of boilerplate code

72-75: Clarify wording and capitalize API; reduce repetition.

“Simplify” the sentence and reflect the new ability to refine generics at call-site.

-Sometimes, these mutations have a generic return type,
-such as if an api response may have different response types
-based on the input parameters, such as with deserialization.
+Sometimes, these mutations have a generic return type. For example, an API response may vary based on input parameters (deserialization), and you can refine the mutation’s generic at the call-site accordingly.

112-120: Prefer /latest docs links and add a link for Mutation.call.

Hardcoding dev.17 makes the page stale quickly. Switch to /latest and add the missing [Mutation.call] reference to match the new feature.

-[MutationPending]: https://pub.dev/documentation/riverpod/3.0.0-dev.17/experimental_mutation/MutationPending-class.html
-[MutationError]: https://pub.dev/documentation/riverpod/3.0.0-dev.17/experimental_mutation/MutationError-class.html
-[MutationSuccess]: https://pub.dev/documentation/riverpod/3.0.0-dev.17/experimental_mutation/MutationSuccess-class.html
-[MutationIdle]: https://pub.dev/documentation/riverpod/3.0.0-dev.17/experimental_mutation/MutationIdle-class.html
-[Mutation.reset]: https://pub.dev/documentation/riverpod/3.0.0-dev.17/experimental_mutation/Mutation/reset.html
-[Mutation.run]: https://pub.dev/documentation/riverpod/3.0.0-dev.17/experimental_mutation/Mutation/run.html
-[Mutation]: https://pub.dev/documentation/riverpod/3.0.0-dev.17/experimental_mutation/Mutation-class.html
-[Notifier]: https://pub.dev/documentation/riverpod/3.0.0-dev.17/riverpod/Notifier-class.html
-[Ref.watch]: https://pub.dev/documentation/riverpod/3.0.0-dev.17/riverpod/Ref/watch.html
+[MutationPending]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/MutationPending-class.html
+[MutationError]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/MutationError-class.html
+[MutationSuccess]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/MutationSuccess-class.html
+[MutationIdle]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/MutationIdle-class.html
+[Mutation.reset]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/Mutation/reset.html
+[Mutation.run]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/Mutation/run.html
+[Mutation.call]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/Mutation/call.html
+[Mutation]: https://pub.dev/documentation/riverpod/latest/experimental_mutation/Mutation-class.html
+[Notifier]: https://pub.dev/documentation/riverpod/latest/riverpod/Notifier-class.html
+[Ref.watch]: https://pub.dev/documentation/riverpod/latest/riverpod/Ref/watch.html

Run a quick docs-link check to ensure /latest works across the site before merging.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d4bdb21 and a921ada.

📒 Files selected for processing (3)
  • website/docs/concepts2/mutations.mdx (5 hunks)
  • website/docs/concepts2/mutations/switching.dart (1 hunks)
  • website/docs/concepts2/mutations/triggering.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • website/docs/concepts2/mutations/switching.dart
  • website/docs/concepts2/mutations/triggering.dart
🧰 Additional context used
🪛 LanguageTool
website/docs/concepts2/mutations.mdx

[grammar] ~5-~5: There might be a mistake here.
Context: ...mport CodeBlock from "@theme/CodeBlock"; import { trimSnippet } from "/src/compon...

(QB_NEW_EN)


[grammar] ~6-~6: There might be a mistake here.
Context: ...et } from "/src/components/CodeSnippet"; import listener from 'raw-loader!./mutat...

(QB_NEW_EN)


[grammar] ~7-~7: There might be a mistake here.
Context: ...'raw-loader!./mutations/listening.dart'; import keyed from 'raw-loader!./mutation...

(QB_NEW_EN)


[grammar] ~8-~8: There might be a mistake here.
Context: ...rom 'raw-loader!./mutations/keyed.dart'; import generic from 'raw-loader!./mutati...

(QB_NEW_EN)


[grammar] ~9-~9: There might be a mistake here.
Context: ...m 'raw-loader!./mutations/generic.dart'; import triggering from 'raw-loader!./mut...

(QB_NEW_EN)


[grammar] ~10-~10: There might be a mistake here.
Context: ...raw-loader!./mutations/triggering.dart'; import switching from 'raw-loader!./muta...

(QB_NEW_EN)


[grammar] ~11-~11: There might be a mistake here.
Context: ...'raw-loader!./mutations/switching.dart'; import resetting from 'raw-loader!./muta...

(QB_NEW_EN)


[grammar] ~19-~19: There might be a mistake here.
Context: ... objects which enable the user interface to react to state changes. A common use-...

(QB_NEW_EN)


[grammar] ~20-~20: There might be a mistake here.
Context: ...ser interface to react to state changes. A common use-case is displaying a loadin...

(QB_NEW_EN)


[grammar] ~23-~23: There might be a mistake here.
Context: ...ons are to achieve effects such as this: ![Submit progress indicator](/img/concep...

(QB_NEW_EN)


[style] ~23-~23: Using many exclamation marks might seem excessive (in this case: 8 exclamation marks for a text that’s 3819 characters long)
Context: ...ns are to achieve effects such as this: Submit progress indicator! Without mutations, you would have to s...

(EN_EXCESSIVE_EXCLAMATION)


[grammar] ~65-~65: There might be a mistake here.
Context: ...multiple instances of the same mutation, such as deleting a specific item in a li...

(QB_NEW_EN)


[grammar] ~72-~72: There might be a mistake here.
Context: ...se mutations have a generic return type, such as if an api response may have diff...

(QB_NEW_EN)


[grammar] ~73-~73: There might be a mistake here.
Context: ...sponse may have different response types based on the input parameters, such as w...

(QB_NEW_EN)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: build (master, examples/todos)
  • GitHub Check: build (stable, packages/riverpod_annotation)
  • GitHub Check: build (stable, packages/riverpod_generator)
  • GitHub Check: build (master, packages/riverpod/example)
  • GitHub Check: build (master, packages/riverpod_generator)
  • GitHub Check: build (master, packages/flutter_riverpod/example)
  • GitHub Check: build (master, packages/riverpod)
  • GitHub Check: build (master, packages/hooks_riverpod/example)
  • GitHub Check: build (stable, packages/hooks_riverpod/example)
  • GitHub Check: build (stable, packages/flutter_riverpod/example)
  • GitHub Check: build (stable, packages/flutter_riverpod)
  • GitHub Check: check_generation
  • GitHub Check: build (stable, examples/todos)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_analyzer_utils_tests)
  • GitHub Check: riverpod_lint (master, packages/riverpod_analyzer_utils_tests)
  • GitHub Check: riverpod_lint (master, packages/riverpod_lint_flutter_test)
  • GitHub Check: riverpod_lint (master, packages/riverpod_lint)
  • GitHub Check: riverpod_lint (stable, packages/riverpod_lint_flutter_test)
🔇 Additional comments (1)
website/docs/concepts2/mutations.mdx (1)

5-12: All mutation snippet files present and correctly referenced.
Verified that each of the six Dart snippets under website/docs/concepts2/mutations/ exists and is imported exactly once in mutations.mdx.

@rrousselGit
Copy link
Copy Markdown
Owner

LGTM thanks!

@rrousselGit rrousselGit merged commit bc36aa9 into rrousselGit:master Sep 9, 2025
44 of 45 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mutations cannot be generic

2 participants