Skip to content

Commit 166a737

Browse files
Update migration guide with findings
1 parent 6ddcc7c commit 166a737

File tree

1 file changed

+72
-3
lines changed

1 file changed

+72
-3
lines changed

website/src/docs/hotchocolate/v14/migrating/migrate-from-13-to-14.md

Lines changed: 72 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,20 @@ builder.Services
8888
.AddGlobalObjectIdentification();
8989
```
9090

91+
## IIdSerializer replaced by INodeIdSerializer
92+
93+
Previously, you could grab the `IIdSerializer` from your dependency injection container to manually parse and serialize globally unique identifiers (GID).
94+
As part of the changes to the GID format mentioned above, the `IIdSerializer` interface has been renamed to `INodeIdSerializer`.
95+
96+
The methods used for parsing and serialization have also been renamed:
97+
98+
| Before | After |
99+
| ---------------------------------- | ---------------------------------------------------------------------------------------- |
100+
| `.Deserialize("<gid-value>")` | `.Parse("<gid-value>", typeof(string))` where `string` is the underlying type of the GID |
101+
| `.Serialize("MyType", "<raw-id>")` | `.Format("MyType", "<raw-id>")` |
102+
103+
The `Parse()` (previously `Deserialize()`) method has also changed its return type from `IdValue` to `NodeId`. The parsed Id value can now be accessed through the `NodeId.InternalId` instead of the `IdValue.Value` property.
104+
91105
## Node Resolver validation
92106

93107
We now enforce that each object type implementing the `Node` interface also defines a resolver, so that the object can be refetched through the `node(id: ID!)` field.
@@ -100,6 +114,19 @@ builder.Services
100114
.ModifyOptions(o => o.EnsureAllNodesCanBeResolved = false)
101115
```
102116

117+
## IDataLoader<TKey, TValue> arguments now need to be marked as service
118+
119+
Previously, you could inject `IDataLoader<TKey, TValue>` without any attribute. Now you need to mark it as a service.
120+
121+
```csharp
122+
public string GetMyType([Service] IDataLoader<int, MyType?> dataLoader)
123+
```
124+
125+
## DataLoader.LoadAsync always returns nullable type
126+
127+
Previously, the `LoadAsync` method on a DataLoader was typed as non-nullable, even though `null` could be returned.
128+
This release changes the return type of `LoadAsync` to always be nullable.
129+
103130
## Builder APIs
104131

105132
We have aligned all builder APIs to be more consistent and easier to use. Builders can now be created by using the static method `Builder.New()` and the `Build()` method to create the final object.
@@ -108,17 +135,27 @@ We have aligned all builder APIs to be more consistent and easier to use. Builde
108135

109136
The interface `IQueryRequestBuilder` and its implementations were replaced with `OperationRequestBuilder` which now supports building standard GraphQL operation requests as well as variable batch requests.
110137

111-
The `Build()` method returns now a `IOperationRequest` which is implemented by `OperationRequest` and `VariableBatchRequest`.
138+
The `Build()` method now returns a `IOperationRequest` which is implemented by `OperationRequest` and `VariableBatchRequest`.
139+
140+
We've also renamed and consolidated some methods on the `OperationRequestBuilder`:
112141

113-
We have also simplified what the builder does and removed a lot of the convenience methods that allowed to add single variables to it. This has todo with the support of variable batching. Now, you have to provide the variable map directly.
142+
| Before | After |
143+
| ----------------------------------- | --------------------------------------------------------------------------- |
144+
| `SetQuery("{ __typename }")` | `SetDocument("{ __typename }")` |
145+
| `AddVariableValue("name", "value")` | `AddVariableValues(new Dictionary<string, object?> { ["name"] = "value" })` |
114146

115147
### IQueryResultBuilder replaced by OperationResultBuilder
116148

117149
The interface `IQueryResultBuilder` and its implementations were replaced with `OperationResultBuilder` which produces an `OperationResult` on `Build()`.
118150

119151
### IQueryResult replaced by OperationResult
120152

121-
The interface `IQueryResultBuilder` and its implementations were replaced with `OperationResultBuilder` which produces an `OperationResult` on `Build()`.
153+
The interface `IQueryResult` has been replaced by `OperationResult`.
154+
155+
### IExecutionResult.ExpectQueryResult replaced by .ExpectOperationResult
156+
157+
In your unit tests you might have been using `result.ExpectQueryResult()` to assert that a result is not a streamed response and rather a completed result.
158+
This assertion method has been renamed to `ExpectOperationResult()`.
122159

123160
## Operation complexity analyzer replaced
124161

@@ -197,6 +234,38 @@ Accessing a keyed service that has not been registered will now throw, instead o
197234

198235
This change aligns the API with the regular (non-keyed) service access API.
199236

237+
## Connection getTotalCount constructor argument replaced with totalCount
238+
239+
Previously, you could supply an async method to the `getTotalCount` constructor argument when instantiating a `Connection<T>`. This method would only be evaluated to calculate the total count, if the `totalCount` field was selected on that Connection in a query.
240+
241+
```csharp
242+
return new Connection<MyType>(
243+
edges: [/* ... */],
244+
info: new ConnectionPageInfo(/* ... */),
245+
getTotalCount: async cancellationToken => 123)
246+
```
247+
248+
In this release the constructor argument was renamed to `totalCount` and now only accepts an `int` for the total count, no longer a method to compute the total count.
249+
If you want to re-create the old behavior, you can use the new `[IsSelected]` attribute to conditionally compute the total count.
250+
251+
```csharp
252+
public Connection<MyType> GetMyTypes(
253+
[IsSelected("totalCount")] bool hasSelectedTotalCount,
254+
CancellationToken cancellationToken)
255+
{
256+
var totalCount = 0;
257+
if (hasSelectedTotalCount)
258+
{
259+
totalCount = /* ... */;
260+
}
261+
262+
return new Connection<MyType>(
263+
edges: [/* ... */],
264+
info: new ConnectionPageInfo(/* ... */),
265+
totalCount: totalCount)
266+
}
267+
```
268+
200269
# Deprecations
201270

202271
Things that will continue to function this release, but we encourage you to move away from.

0 commit comments

Comments
 (0)