rescript-relay 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/ppx-linux +0 -0
- package/ppx-macos-arm64 +0 -0
- package/ppx-macos-latest +0 -0
- package/ppx-windows-latest +0 -0
- package/relay-compiler-linux-musl/relay +0 -0
- package/relay-compiler-linux-x64/relay +0 -0
- package/relay-compiler-macos-arm64/relay +0 -0
- package/relay-compiler-macos-x64/relay +0 -0
- package/relay-compiler-win-x64/relay.exe +0 -0
- package/src/RescriptRelay.bs.js +8 -4
- package/src/RescriptRelay.res +13 -6
- package/src/RescriptRelay.resi +812 -58
- package/src/utils.js +6 -0
- package/src/utils.mjs +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# master
|
|
2
2
|
|
|
3
|
+
# 3.3.0
|
|
4
|
+
|
|
5
|
+
- Add support for top level `@catch` on fragments on unions.
|
|
6
|
+
- Add parameter `excludedIds: array<dataId>` to `invalidateRecordsByIds` to allow excluding a list of connection IDs from invalidation.
|
|
7
|
+
- **BREAKING:** `operation.text` and `operation.id` are now nullable, which better reflects what values they can actually have in runtime.
|
|
8
|
+
- fix bug where custom scalars would error when set to null in refetch variables.
|
|
9
|
+
|
|
3
10
|
# 3.2.0
|
|
4
11
|
|
|
5
12
|
- Add support for the new Relay `@catch` directive. https://github.com/zth/rescript-relay/pull/549
|
package/package.json
CHANGED
package/ppx-linux
CHANGED
|
Binary file
|
package/ppx-macos-arm64
CHANGED
|
Binary file
|
package/ppx-macos-latest
CHANGED
|
Binary file
|
package/ppx-windows-latest
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/src/RescriptRelay.bs.js
CHANGED
|
@@ -283,12 +283,16 @@ function findAllConnectionIds(environment, connectionKey, parentId) {
|
|
|
283
283
|
return ids;
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
-
function invalidateAllOfConnection(environment, connectionKey, parentId) {
|
|
286
|
+
function invalidateAllOfConnection(environment, connectionKey, parentId, excludedIdsOpt) {
|
|
287
|
+
var excludedIds = excludedIdsOpt !== undefined ? excludedIdsOpt : [];
|
|
287
288
|
RelayRuntime.commitLocalUpdate(environment, (function (store) {
|
|
288
289
|
findAllConnectionIds(environment, connectionKey, parentId).forEach(function (dataId) {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
290
|
+
if (!excludedIds.includes(dataId)) {
|
|
291
|
+
return Belt_Option.forEach(Caml_option.nullable_to_opt(store.get(dataId)), (function (r) {
|
|
292
|
+
r.invalidateRecord();
|
|
293
|
+
}));
|
|
294
|
+
}
|
|
295
|
+
|
|
292
296
|
});
|
|
293
297
|
}));
|
|
294
298
|
}
|
package/src/RescriptRelay.res
CHANGED
|
@@ -534,8 +534,8 @@ module Network = {
|
|
|
534
534
|
type operationMetadata = {codesplits?: array<codesplitsMetadata>}
|
|
535
535
|
|
|
536
536
|
type operation = {
|
|
537
|
-
id: string
|
|
538
|
-
text: string
|
|
537
|
+
id: Js.Nullable.t<string>,
|
|
538
|
+
text: Js.Nullable.t<string>,
|
|
539
539
|
name: string,
|
|
540
540
|
operationKind: string,
|
|
541
541
|
metadata: Js.Nullable.t<operationMetadata>,
|
|
@@ -796,14 +796,21 @@ module Environment = {
|
|
|
796
796
|
ids
|
|
797
797
|
}
|
|
798
798
|
|
|
799
|
-
let invalidateAllOfConnection = (
|
|
799
|
+
let invalidateAllOfConnection = (
|
|
800
|
+
environment: t,
|
|
801
|
+
~connectionKey: string,
|
|
802
|
+
~parentId: dataId,
|
|
803
|
+
~excludedIds=[],
|
|
804
|
+
) => {
|
|
800
805
|
environment->commitLocalUpdate(~updater=store => {
|
|
801
806
|
environment
|
|
802
807
|
->findAllConnectionIds(~connectionKey, ~parentId)
|
|
803
808
|
->Js.Array2.forEach(dataId => {
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
809
|
+
if !(excludedIds->Js.Array2.includes(dataId)) {
|
|
810
|
+
store
|
|
811
|
+
->RecordSourceSelectorProxy.get(~dataId)
|
|
812
|
+
->Belt.Option.forEach(r => r->RecordProxy.invalidateRecord)
|
|
813
|
+
}
|
|
807
814
|
})
|
|
808
815
|
})
|
|
809
816
|
}
|
package/src/RescriptRelay.resi
CHANGED
|
@@ -94,12 +94,56 @@ external makeUploadables: Js.Dict.t<'file> => uploadables = "%identity"
|
|
|
94
94
|
/**Unwraps `uploadables` into a Js.Dict.t with your expected file type, so you can use that dict to attach the provided files to your request.*/
|
|
95
95
|
external unwrapUploadables: uploadables => Js.Dict.t<'file> = "%identity"
|
|
96
96
|
|
|
97
|
-
/**
|
|
97
|
+
/**
|
|
98
|
+
Generates a client-side `dataId` derived from an existing record.
|
|
99
|
+
|
|
100
|
+
This is a low-level function for creating deterministic client IDs. For most use cases,
|
|
101
|
+
prefer `generateUniqueClientID` which creates globally unique identifiers.
|
|
102
|
+
|
|
103
|
+
## Parameters
|
|
104
|
+
- `dataId`: The base record ID to derive from
|
|
105
|
+
- `storageKey`: A unique key for this derived record
|
|
106
|
+
- `index`: Optional index for array-like derived records
|
|
107
|
+
|
|
108
|
+
## Examples
|
|
109
|
+
|
|
110
|
+
```rescript
|
|
111
|
+
// Create a client ID for a cached query result
|
|
112
|
+
let derivedId = RescriptRelay.generateClientID(
|
|
113
|
+
~dataId=user.__id,
|
|
114
|
+
~storageKey="cached_search_results",
|
|
115
|
+
)
|
|
116
|
+
```
|
|
117
|
+
*/
|
|
98
118
|
@module("relay-runtime")
|
|
99
119
|
external generateClientID: (~dataId: dataId, ~storageKey: string, ~index: int=?) => dataId =
|
|
100
120
|
"generateClientID"
|
|
101
121
|
|
|
102
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
Generates a globally unique client-side `dataId`.
|
|
124
|
+
|
|
125
|
+
Creates a new unique identifier safe for client-side records. Primarily used for
|
|
126
|
+
optimistic updates where you need temporary IDs before server confirmation.
|
|
127
|
+
|
|
128
|
+
## Examples
|
|
129
|
+
|
|
130
|
+
```rescript
|
|
131
|
+
// Use in optimistic response
|
|
132
|
+
mutate(
|
|
133
|
+
~variables={...},
|
|
134
|
+
~optimisticResponse={
|
|
135
|
+
userCreated: Some({
|
|
136
|
+
user: {
|
|
137
|
+
id: RescriptRelay.generateUniqueClientID(),
|
|
138
|
+
name: "New User",
|
|
139
|
+
__typename: #User,
|
|
140
|
+
}
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
*/
|
|
103
147
|
@module("relay-runtime")
|
|
104
148
|
external generateUniqueClientID: unit => dataId = "generateUniqueClientID"
|
|
105
149
|
|
|
@@ -171,15 +215,70 @@ module RecordProxy: {
|
|
|
171
215
|
/**Read the following section on working with the Relay store: https://relay.dev/docs/en/relay-store*/
|
|
172
216
|
type t
|
|
173
217
|
|
|
174
|
-
/**
|
|
218
|
+
/**
|
|
219
|
+
Copies all fields from a source record to the current record.
|
|
220
|
+
|
|
221
|
+
Performs a shallow copy of all field values from the source record to the target record.
|
|
222
|
+
Useful for duplicating record data or applying bulk updates.
|
|
223
|
+
|
|
224
|
+
⚠️ **Note**: This is a low-level, non-type-safe API. Use with caution and prefer higher-level operations when possible.
|
|
225
|
+
|
|
226
|
+
## Parameters
|
|
227
|
+
- `sourceRecord`: The record to copy fields from
|
|
228
|
+
|
|
229
|
+
## Examples
|
|
230
|
+
|
|
231
|
+
```rescript
|
|
232
|
+
// Copy from newUser to existing user record
|
|
233
|
+
userRecord->RescriptRelay.RecordProxy.copyFieldsFrom(~sourceRecord=newUser)
|
|
234
|
+
```
|
|
235
|
+
*/
|
|
175
236
|
@send
|
|
176
237
|
external copyFieldsFrom: (t, ~sourceRecord: t) => unit = "copyFieldsFrom"
|
|
177
238
|
|
|
178
|
-
/**
|
|
239
|
+
/**
|
|
240
|
+
Gets the unique identifier for this record.
|
|
241
|
+
|
|
242
|
+
Returns the `dataId` that Relay uses to identify this record in the store.
|
|
243
|
+
Every record in Relay has a unique `dataId`.
|
|
244
|
+
|
|
245
|
+
⚠️ **Note**: This is a low-level, non-type-safe API. Use with caution and prefer higher-level operations when possible.
|
|
246
|
+
|
|
247
|
+
## Examples
|
|
248
|
+
|
|
249
|
+
```rescript
|
|
250
|
+
let userId = userRecord->RescriptRelay.RecordProxy.getDataId
|
|
251
|
+
Console.log("User ID: " ++ RescriptRelay.dataIdToString(userId))
|
|
252
|
+
```
|
|
253
|
+
*/
|
|
179
254
|
@send
|
|
180
255
|
external getDataId: t => dataId = "getDataID"
|
|
181
256
|
|
|
182
|
-
/**
|
|
257
|
+
/**
|
|
258
|
+
Gets a linked record (object) field.
|
|
259
|
+
|
|
260
|
+
Retrieves another record that is linked from this record. Returns `None` if
|
|
261
|
+
the field doesn't exist or is null.
|
|
262
|
+
|
|
263
|
+
⚠️ **Note**: This is a low-level, non-type-safe API. Use with caution and prefer higher-level operations when possible.
|
|
264
|
+
|
|
265
|
+
## Parameters
|
|
266
|
+
- `name`: The field name to retrieve
|
|
267
|
+
- `arguments`: Optional arguments for parameterized fields
|
|
268
|
+
|
|
269
|
+
## Examples
|
|
270
|
+
|
|
271
|
+
```rescript
|
|
272
|
+
// Get user's profile
|
|
273
|
+
let profile = userRecord->RescriptRelay.RecordProxy.getLinkedRecord(~name="profile")
|
|
274
|
+
|
|
275
|
+
// Get user's post with specific ID
|
|
276
|
+
let post = userRecord->RescriptRelay.RecordProxy.getLinkedRecord(
|
|
277
|
+
~name="post",
|
|
278
|
+
~arguments=RescriptRelay.makeArguments({"id": postId})
|
|
279
|
+
)
|
|
280
|
+
```
|
|
281
|
+
*/
|
|
183
282
|
@send
|
|
184
283
|
@return(nullable)
|
|
185
284
|
external getLinkedRecord: (t, ~name: string, ~arguments: arguments=?) => option<t> =
|
|
@@ -258,12 +357,56 @@ module RecordProxy: {
|
|
|
258
357
|
~arguments: arguments=?,
|
|
259
358
|
) => option<array<option<bool>>> = "getValue"
|
|
260
359
|
|
|
261
|
-
/**
|
|
360
|
+
/**
|
|
361
|
+
Sets a linked record for a field.
|
|
362
|
+
|
|
363
|
+
Links another record to this record at the specified field. The linked record
|
|
364
|
+
must already exist in the store.
|
|
365
|
+
|
|
366
|
+
⚠️ **Note**: This is a low-level, non-type-safe API. Use with caution and prefer higher-level operations when possible.
|
|
367
|
+
|
|
368
|
+
## Parameters
|
|
369
|
+
- `record`: The record to link
|
|
370
|
+
- `name`: The field name to set
|
|
371
|
+
- `arguments`: Optional arguments for parameterized fields
|
|
372
|
+
|
|
373
|
+
## Examples
|
|
374
|
+
|
|
375
|
+
```rescript
|
|
376
|
+
// Link a profile to a user
|
|
377
|
+
let _ = userRecord->RescriptRelay.RecordProxy.setLinkedRecord(
|
|
378
|
+
~record=profileRecord,
|
|
379
|
+
~name="profile"
|
|
380
|
+
)
|
|
381
|
+
```
|
|
382
|
+
*/
|
|
262
383
|
@send
|
|
263
384
|
external setLinkedRecord: (t, ~record: t, ~name: string, ~arguments: arguments=?) => t =
|
|
264
385
|
"setLinkedRecord"
|
|
265
386
|
|
|
266
|
-
/**
|
|
387
|
+
/**
|
|
388
|
+
Sets an array of linked records for a field.
|
|
389
|
+
|
|
390
|
+
Links multiple records to this record at the specified field. Use `None` for
|
|
391
|
+
null entries in the array.
|
|
392
|
+
|
|
393
|
+
⚠️ **Note**: This is a low-level, non-type-safe API. Use with caution and prefer higher-level operations when possible.
|
|
394
|
+
|
|
395
|
+
## Parameters
|
|
396
|
+
- `records`: Array of records to link (with optional null entries)
|
|
397
|
+
- `name`: The field name to set
|
|
398
|
+
- `arguments`: Optional arguments for parameterized fields
|
|
399
|
+
|
|
400
|
+
## Examples
|
|
401
|
+
|
|
402
|
+
```rescript
|
|
403
|
+
// Set user's posts
|
|
404
|
+
let _ = userRecord->RescriptRelay.RecordProxy.setLinkedRecords(
|
|
405
|
+
~records=[Some(post1), None, Some(post3)],
|
|
406
|
+
~name="posts"
|
|
407
|
+
)
|
|
408
|
+
```
|
|
409
|
+
*/
|
|
267
410
|
@send
|
|
268
411
|
external setLinkedRecords: (
|
|
269
412
|
t,
|
|
@@ -389,15 +532,78 @@ module RecordSourceSelectorProxy: {
|
|
|
389
532
|
@send
|
|
390
533
|
external batchLiveStateUpdates: (t, unit => unit) => unit = "batchLiveStateUpdates"
|
|
391
534
|
|
|
392
|
-
/**
|
|
535
|
+
/**
|
|
536
|
+
Creates a new record in the store.
|
|
537
|
+
|
|
538
|
+
Creates a new record with the specified ID and type. The record will be empty
|
|
539
|
+
initially - use `RecordProxy` methods to populate its fields.
|
|
540
|
+
|
|
541
|
+
⚠️ **Note**: This is a low-level, non-type-safe API. Use with caution and prefer higher-level operations when possible.
|
|
542
|
+
|
|
543
|
+
## Parameters
|
|
544
|
+
- `dataId`: Unique identifier for the new record
|
|
545
|
+
- `typeName`: GraphQL type name for the record
|
|
546
|
+
|
|
547
|
+
## Examples
|
|
548
|
+
|
|
549
|
+
```rescript
|
|
550
|
+
// Create optimistic user record
|
|
551
|
+
let newUser = store->RescriptRelay.RecordSourceSelectorProxy.create(
|
|
552
|
+
~dataId=RescriptRelay.generateUniqueClientID(),
|
|
553
|
+
~typeName="User"
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
let _ = newUser->RescriptRelay.RecordProxy.setValueString(~value="John Doe", ~name="name")
|
|
557
|
+
```
|
|
558
|
+
*/
|
|
393
559
|
@send
|
|
394
560
|
external create: (t, ~dataId: dataId, ~typeName: string) => RecordProxy.t = "create"
|
|
395
561
|
|
|
396
|
-
/**
|
|
562
|
+
/**
|
|
563
|
+
Deletes a record from the store.
|
|
564
|
+
|
|
565
|
+
Removes the record with the specified ID from the store. Any references to
|
|
566
|
+
this record from other records will become null.
|
|
567
|
+
|
|
568
|
+
⚠️ **Note**: This is a low-level, non-type-safe API. Use with caution and prefer higher-level operations when possible.
|
|
569
|
+
|
|
570
|
+
## Parameters
|
|
571
|
+
- `dataId`: The ID of the record to delete
|
|
572
|
+
|
|
573
|
+
## Examples
|
|
574
|
+
|
|
575
|
+
```rescript
|
|
576
|
+
// Delete a user record
|
|
577
|
+
store->RescriptRelay.RecordSourceSelectorProxy.delete(~dataId=userId)
|
|
578
|
+
```
|
|
579
|
+
*/
|
|
397
580
|
@send
|
|
398
581
|
external delete: (t, ~dataId: dataId) => unit = "delete"
|
|
399
582
|
|
|
400
|
-
/**
|
|
583
|
+
/**
|
|
584
|
+
Gets a record from the store by ID.
|
|
585
|
+
|
|
586
|
+
Retrieves an existing record from the store. Returns `None` if the record
|
|
587
|
+
doesn't exist.
|
|
588
|
+
|
|
589
|
+
⚠️ **Note**: This is a low-level, non-type-safe API. Use with caution and prefer higher-level operations when possible.
|
|
590
|
+
|
|
591
|
+
## Parameters
|
|
592
|
+
- `dataId`: The ID of the record to retrieve
|
|
593
|
+
|
|
594
|
+
## Examples
|
|
595
|
+
|
|
596
|
+
```rescript
|
|
597
|
+
switch store->RescriptRelay.RecordSourceSelectorProxy.get(~dataId=userId) {
|
|
598
|
+
| Some(userRecord) =>
|
|
599
|
+
// Work with the user record
|
|
600
|
+
let _ = userRecord->RescriptRelay.RecordProxy.setValueBool(~value=true, ~name="isActive")
|
|
601
|
+
| None =>
|
|
602
|
+
// Record doesn't exist
|
|
603
|
+
()
|
|
604
|
+
}
|
|
605
|
+
```
|
|
606
|
+
*/
|
|
401
607
|
@send
|
|
402
608
|
@return(nullable)
|
|
403
609
|
external get: (t, ~dataId: dataId) => option<RecordProxy.t> = "get"
|
|
@@ -523,9 +729,37 @@ module MissingFieldHandler: {
|
|
|
523
729
|
) => t
|
|
524
730
|
}
|
|
525
731
|
|
|
526
|
-
/**
|
|
732
|
+
/**
|
|
733
|
+
Utilities for working with Relay connections.
|
|
734
|
+
|
|
735
|
+
Connections are Relay's way of handling paginated lists. These utilities help you
|
|
736
|
+
manipulate connection data in the store, such as adding/removing edges and getting
|
|
737
|
+
connection records.
|
|
738
|
+
|
|
739
|
+
Read the [Relay ConnectionHandler docs](https://relay.dev/docs/en/relay-store#connectionhandler) for more details.
|
|
740
|
+
*/
|
|
527
741
|
module ConnectionHandler: {
|
|
528
|
-
/**
|
|
742
|
+
/**
|
|
743
|
+
Gets a connection record from a parent record.
|
|
744
|
+
|
|
745
|
+
Retrieves the connection record for a specific connection key and optional filters.
|
|
746
|
+
Returns `None` if the connection doesn't exist.
|
|
747
|
+
|
|
748
|
+
## Parameters
|
|
749
|
+
- `record`: The parent record containing the connection
|
|
750
|
+
- `key`: The connection key (from `@connection(key: "...")`)
|
|
751
|
+
- `filters`: Optional filter arguments used in the connection
|
|
752
|
+
|
|
753
|
+
## Examples
|
|
754
|
+
|
|
755
|
+
```rescript
|
|
756
|
+
// Get user's friends connection
|
|
757
|
+
let friendsConnection = RescriptRelay.ConnectionHandler.getConnection(
|
|
758
|
+
~record=userRecord,
|
|
759
|
+
~key=UserFriends_user_graphql.connectionKey,
|
|
760
|
+
)
|
|
761
|
+
```
|
|
762
|
+
*/
|
|
529
763
|
@module("relay-runtime")
|
|
530
764
|
@scope("ConnectionHandler")
|
|
531
765
|
@return(nullable)
|
|
@@ -535,7 +769,32 @@ module ConnectionHandler: {
|
|
|
535
769
|
~filters: arguments=?,
|
|
536
770
|
) => option<RecordProxy.t> = "getConnection"
|
|
537
771
|
|
|
538
|
-
/**
|
|
772
|
+
/**
|
|
773
|
+
Creates an edge record for a connection.
|
|
774
|
+
|
|
775
|
+
Creates a new edge that can be inserted into a connection. The edge wraps
|
|
776
|
+
a node and provides cursor information for pagination.
|
|
777
|
+
|
|
778
|
+
💡 **Tip**: For most cases, prefer using declarative directives like `@appendNode` or `@prependNode` in your mutations instead of manually managing edges.
|
|
779
|
+
|
|
780
|
+
## Parameters
|
|
781
|
+
- `store`: The store to create the edge in
|
|
782
|
+
- `connection`: The connection this edge belongs to
|
|
783
|
+
- `node`: The node (record) to wrap in this edge
|
|
784
|
+
- `edgeType`: The GraphQL type name for the edge
|
|
785
|
+
|
|
786
|
+
## Examples
|
|
787
|
+
|
|
788
|
+
```rescript
|
|
789
|
+
// Create edge for new friend
|
|
790
|
+
let newEdge = RescriptRelay.ConnectionHandler.createEdge(
|
|
791
|
+
~store,
|
|
792
|
+
~connection=friendsConnection,
|
|
793
|
+
~node=newFriendRecord,
|
|
794
|
+
~edgeType="UserEdge"
|
|
795
|
+
)
|
|
796
|
+
```
|
|
797
|
+
*/
|
|
539
798
|
@module("relay-runtime")
|
|
540
799
|
@scope("ConnectionHandler")
|
|
541
800
|
external createEdge: (
|
|
@@ -545,7 +804,36 @@ module ConnectionHandler: {
|
|
|
545
804
|
~edgeType: string,
|
|
546
805
|
) => RecordProxy.t = "createEdge"
|
|
547
806
|
|
|
548
|
-
/**
|
|
807
|
+
/**
|
|
808
|
+
Inserts an edge before a specific cursor or at the beginning.
|
|
809
|
+
|
|
810
|
+
Adds an edge to the connection before the specified cursor position.
|
|
811
|
+
If no cursor is provided, the edge is inserted at the start of the list.
|
|
812
|
+
|
|
813
|
+
💡 **Tip**: For most cases, prefer using declarative directives like `@prependEdge` in your mutations instead of manually inserting edges.
|
|
814
|
+
|
|
815
|
+
## Parameters
|
|
816
|
+
- `connection`: The connection to insert into
|
|
817
|
+
- `newEdge`: The edge to insert
|
|
818
|
+
- `cursor`: Optional cursor to insert before
|
|
819
|
+
|
|
820
|
+
## Examples
|
|
821
|
+
|
|
822
|
+
```rescript
|
|
823
|
+
// Insert at beginning
|
|
824
|
+
RescriptRelay.ConnectionHandler.insertEdgeBefore(
|
|
825
|
+
~connection=friendsConnection,
|
|
826
|
+
~newEdge=friendEdge
|
|
827
|
+
)
|
|
828
|
+
|
|
829
|
+
// Insert before specific cursor
|
|
830
|
+
RescriptRelay.ConnectionHandler.insertEdgeBefore(
|
|
831
|
+
~connection=friendsConnection,
|
|
832
|
+
~newEdge=friendEdge,
|
|
833
|
+
~cursor="cursor123"
|
|
834
|
+
)
|
|
835
|
+
```
|
|
836
|
+
*/
|
|
549
837
|
@module("relay-runtime")
|
|
550
838
|
@scope("ConnectionHandler")
|
|
551
839
|
external insertEdgeBefore: (
|
|
@@ -554,7 +842,29 @@ module ConnectionHandler: {
|
|
|
554
842
|
~cursor: string=?,
|
|
555
843
|
) => unit = "insertEdgeBefore"
|
|
556
844
|
|
|
557
|
-
/**
|
|
845
|
+
/**
|
|
846
|
+
Inserts an edge after a specific cursor or at the end.
|
|
847
|
+
|
|
848
|
+
Adds an edge to the connection after the specified cursor position.
|
|
849
|
+
If no cursor is provided, the edge is inserted at the end of the list.
|
|
850
|
+
|
|
851
|
+
💡 **Tip**: For most cases, prefer using declarative directives like `@appendEdge` in your mutations instead of manually inserting edges.
|
|
852
|
+
|
|
853
|
+
## Parameters
|
|
854
|
+
- `connection`: The connection to insert into
|
|
855
|
+
- `newEdge`: The edge to insert
|
|
856
|
+
- `cursor`: Optional cursor to insert after
|
|
857
|
+
|
|
858
|
+
## Examples
|
|
859
|
+
|
|
860
|
+
```rescript
|
|
861
|
+
// Insert at end
|
|
862
|
+
RescriptRelay.ConnectionHandler.insertEdgeAfter(
|
|
863
|
+
~connection=friendsConnection,
|
|
864
|
+
~newEdge=friendEdge
|
|
865
|
+
)
|
|
866
|
+
```
|
|
867
|
+
*/
|
|
558
868
|
@module("relay-runtime")
|
|
559
869
|
@scope("ConnectionHandler")
|
|
560
870
|
external insertEdgeAfter: (
|
|
@@ -563,12 +873,59 @@ module ConnectionHandler: {
|
|
|
563
873
|
~cursor: string=?,
|
|
564
874
|
) => unit = "insertEdgeAfter"
|
|
565
875
|
|
|
566
|
-
/**
|
|
876
|
+
/**
|
|
877
|
+
Removes a node from a connection by its ID.
|
|
878
|
+
|
|
879
|
+
Deletes any edge from the connection where the edge's node has the specified ID.
|
|
880
|
+
Note: This only removes the edge, not the actual node record from the store.
|
|
881
|
+
|
|
882
|
+
💡 **Tip**: For most cases, prefer using declarative directives like `@deleteEdge` in your mutations instead of manually removing edges.
|
|
883
|
+
|
|
884
|
+
## Parameters
|
|
885
|
+
- `connection`: The connection to remove from
|
|
886
|
+
- `nodeId`: The ID of the node to remove
|
|
887
|
+
|
|
888
|
+
## Examples
|
|
889
|
+
|
|
890
|
+
```rescript
|
|
891
|
+
// Remove friend from connection
|
|
892
|
+
RescriptRelay.ConnectionHandler.deleteNode(
|
|
893
|
+
~connection=friendsConnection,
|
|
894
|
+
~nodeId=friendId
|
|
895
|
+
)
|
|
896
|
+
```
|
|
897
|
+
*/
|
|
567
898
|
@module("relay-runtime")
|
|
568
899
|
@scope("ConnectionHandler")
|
|
569
900
|
external deleteNode: (~connection: RecordProxy.t, ~nodeId: dataId) => unit = "deleteNode"
|
|
570
901
|
|
|
571
|
-
/**
|
|
902
|
+
/**
|
|
903
|
+
Generates a connection's unique data ID.
|
|
904
|
+
|
|
905
|
+
Constructs the internal ID that Relay uses to identify a specific connection
|
|
906
|
+
on a specific parent with specific filters.
|
|
907
|
+
|
|
908
|
+
💡 **Tip**: For connections with arguments, the generated fragment module includes a type-safe `getConnectionId` function. For example, `UserPosts_user_graphql.getConnectionId(~status="PUBLISHED")`.
|
|
909
|
+
|
|
910
|
+
## Parameters
|
|
911
|
+
- Parent record's data ID
|
|
912
|
+
- Connection key string
|
|
913
|
+
- Filter arguments object
|
|
914
|
+
|
|
915
|
+
## Examples
|
|
916
|
+
|
|
917
|
+
```rescript
|
|
918
|
+
// Get connection ID for user's filtered posts
|
|
919
|
+
let connectionId = RescriptRelay.ConnectionHandler.getConnectionID(
|
|
920
|
+
userId,
|
|
921
|
+
UserPosts_user_graphql.connectionKey,
|
|
922
|
+
{"status": "PUBLISHED"}
|
|
923
|
+
)
|
|
924
|
+
|
|
925
|
+
// A type-safe version is also available for each fragment defined. Prefer using that.
|
|
926
|
+
let connectionId = UserPosts_user_graphql.getConnectionId(~status=PUBLISHED)
|
|
927
|
+
```
|
|
928
|
+
*/
|
|
572
929
|
@module("relay-runtime")
|
|
573
930
|
@scope("ConnectionHandler")
|
|
574
931
|
external getConnectionID: (dataId, string, 'filters) => dataId = "getConnectionID"
|
|
@@ -630,28 +987,73 @@ module Observable: {
|
|
|
630
987
|
/**Ignore this subscription.*/ external ignoreSubscription: subscription => unit = "%ignore"
|
|
631
988
|
}
|
|
632
989
|
|
|
633
|
-
/**
|
|
990
|
+
/**
|
|
991
|
+
Network layer configuration for Relay.
|
|
992
|
+
|
|
993
|
+
The network layer defines how Relay makes requests to your GraphQL server.
|
|
994
|
+
You must provide fetch and optionally subscription functions to handle
|
|
995
|
+
queries, mutations, and subscriptions.
|
|
996
|
+
*/
|
|
634
997
|
module Network: {
|
|
635
998
|
type codesplitsMetadata = (string, unit => unit)
|
|
636
999
|
|
|
637
1000
|
type operationMetadata = {codesplits?: array<codesplitsMetadata>}
|
|
638
1001
|
|
|
639
|
-
/**The type representing an instantiated
|
|
1002
|
+
/**The type representing an instantiated network layer.*/
|
|
640
1003
|
type t
|
|
641
1004
|
|
|
642
|
-
/**
|
|
1005
|
+
/**
|
|
1006
|
+
Information about a GraphQL operation being executed.
|
|
1007
|
+
|
|
1008
|
+
Contains the operation details that your fetch function will receive.
|
|
1009
|
+
For persisted queries, `id` exists but `text` is empty. For regular queries,
|
|
1010
|
+
`text` contains the query string but `id` is empty.
|
|
1011
|
+
|
|
1012
|
+
## Fields
|
|
1013
|
+
- `id`: Persisted query ID (if using persisted queries)
|
|
1014
|
+
- `text`: GraphQL query text (if not using persisted queries)
|
|
1015
|
+
- `name`: Operation name
|
|
1016
|
+
- `operationKind`: "query", "mutation", or "subscription"
|
|
1017
|
+
- `metadata`: Optional operation metadata
|
|
1018
|
+
*/
|
|
643
1019
|
type operation = {
|
|
644
|
-
|
|
645
|
-
|
|
1020
|
+
/** The operation ID. Set if persisted queries are enabled, otherwise not set. */
|
|
1021
|
+
id: Js.Nullable.t<string>,
|
|
1022
|
+
/** The operation text. Not set for persisted queries, or if this is a client-only query that will not make a network request. */
|
|
1023
|
+
text: Js.Nullable.t<string>,
|
|
1024
|
+
/** The operation name. */
|
|
646
1025
|
name: string,
|
|
1026
|
+
/** The operation kind. */
|
|
647
1027
|
operationKind: string,
|
|
1028
|
+
/** Optional operation metadata. */
|
|
648
1029
|
metadata: Js.Nullable.t<operationMetadata>,
|
|
649
1030
|
}
|
|
650
1031
|
|
|
651
|
-
/**
|
|
1032
|
+
/**
|
|
1033
|
+
Function signature for handling GraphQL subscriptions.
|
|
1034
|
+
|
|
1035
|
+
## Parameters
|
|
1036
|
+
- `operation`: The subscription operation details
|
|
1037
|
+
- `variables`: JSON variables for the subscription
|
|
1038
|
+
- `cacheConfig`: Cache configuration options
|
|
1039
|
+
|
|
1040
|
+
## Returns
|
|
1041
|
+
Observable that emits subscription data over time
|
|
1042
|
+
*/
|
|
652
1043
|
type subscribeFn = (operation, Js.Json.t, cacheConfig) => Observable.t<Js.Json.t>
|
|
653
1044
|
|
|
654
|
-
/**
|
|
1045
|
+
/**
|
|
1046
|
+
Function signature for fetching data using promises.
|
|
1047
|
+
|
|
1048
|
+
## Parameters
|
|
1049
|
+
- `operation`: The operation details
|
|
1050
|
+
- `variables`: JSON variables for the operation
|
|
1051
|
+
- `cacheConfig`: Cache configuration options
|
|
1052
|
+
- `uploadables`: Optional file uploads
|
|
1053
|
+
|
|
1054
|
+
## Returns
|
|
1055
|
+
Promise that resolves to the GraphQL response
|
|
1056
|
+
*/
|
|
655
1057
|
type fetchFunctionPromise = (
|
|
656
1058
|
operation,
|
|
657
1059
|
Js.Json.t,
|
|
@@ -659,7 +1061,18 @@ module Network: {
|
|
|
659
1061
|
Js.Nullable.t<uploadables>,
|
|
660
1062
|
) => Js.Promise.t<Js.Json.t>
|
|
661
1063
|
|
|
662
|
-
/**
|
|
1064
|
+
/**
|
|
1065
|
+
Function signature for fetching data using observables.
|
|
1066
|
+
|
|
1067
|
+
## Parameters
|
|
1068
|
+
- `operation`: The operation details
|
|
1069
|
+
- `variables`: JSON variables for the operation
|
|
1070
|
+
- `cacheConfig`: Cache configuration options
|
|
1071
|
+
- `uploadables`: Optional file uploads
|
|
1072
|
+
|
|
1073
|
+
## Returns
|
|
1074
|
+
Observable that emits the GraphQL response
|
|
1075
|
+
*/
|
|
663
1076
|
type fetchFunctionObservable = (
|
|
664
1077
|
operation,
|
|
665
1078
|
Js.Json.t,
|
|
@@ -667,7 +1080,16 @@ module Network: {
|
|
|
667
1080
|
Js.Nullable.t<uploadables>,
|
|
668
1081
|
) => Observable.t<Js.Json.t>
|
|
669
1082
|
|
|
670
|
-
/**
|
|
1083
|
+
/**
|
|
1084
|
+
Creates a network layer using a promise-based fetch function.
|
|
1085
|
+
|
|
1086
|
+
Most common way to create a network layer. Your fetch function should
|
|
1087
|
+
make HTTP requests to your GraphQL endpoint and return promises.
|
|
1088
|
+
|
|
1089
|
+
## Parameters
|
|
1090
|
+
- `fetchFunction`: Function that returns promises for GraphQL requests
|
|
1091
|
+
- `subscriptionFunction`: Optional function for handling subscriptions
|
|
1092
|
+
*/
|
|
671
1093
|
@module("relay-runtime")
|
|
672
1094
|
@scope("Network")
|
|
673
1095
|
external makePromiseBased: (
|
|
@@ -675,7 +1097,16 @@ module Network: {
|
|
|
675
1097
|
~subscriptionFunction: subscribeFn=?,
|
|
676
1098
|
) => t = "create"
|
|
677
1099
|
|
|
678
|
-
/**
|
|
1100
|
+
/**
|
|
1101
|
+
Creates a network layer using an observable-based fetch function.
|
|
1102
|
+
|
|
1103
|
+
Use this when you need more control over the request lifecycle or want to
|
|
1104
|
+
handle streaming responses like `@defer` and `@stream`.
|
|
1105
|
+
|
|
1106
|
+
## Parameters
|
|
1107
|
+
- `observableFunction`: Function that returns observables for GraphQL requests
|
|
1108
|
+
- `subscriptionFunction`: Optional function for handling subscriptions
|
|
1109
|
+
*/
|
|
679
1110
|
@module("relay-runtime")
|
|
680
1111
|
@scope("Network")
|
|
681
1112
|
external makeObservableBased: (
|
|
@@ -683,62 +1114,200 @@ module Network: {
|
|
|
683
1114
|
~subscriptionFunction: subscribeFn=?,
|
|
684
1115
|
) => t = "create"
|
|
685
1116
|
|
|
1117
|
+
/**
|
|
1118
|
+
Preloads resources based on operation response.
|
|
1119
|
+
|
|
1120
|
+
Internal function for resource preloading. Used by Relay's code splitting
|
|
1121
|
+
and resource preloading features.
|
|
1122
|
+
*/
|
|
686
1123
|
let preloadResources: (~operation: operation, ~variables: Js.Json.t, ~response: Js.Json.t) => unit
|
|
687
1124
|
}
|
|
688
1125
|
|
|
689
|
-
/**
|
|
1126
|
+
/**
|
|
1127
|
+
The RecordSource - storage for normalized GraphQL records.
|
|
1128
|
+
|
|
1129
|
+
RecordSource is the underlying storage mechanism that holds normalized GraphQL
|
|
1130
|
+
records. It can be initialized empty or with existing data for hydration scenarios
|
|
1131
|
+
like SSR. The store uses a RecordSource to persist and retrieve cached data.
|
|
1132
|
+
*/
|
|
690
1133
|
module RecordSource: {
|
|
691
|
-
/**The type representing
|
|
1134
|
+
/**The type representing a RecordSource instance.*/
|
|
692
1135
|
type t
|
|
693
1136
|
|
|
694
|
-
/**
|
|
1137
|
+
/**
|
|
1138
|
+
Creates a new RecordSource.
|
|
1139
|
+
|
|
1140
|
+
Can be initialized empty or with existing record data for hydration.
|
|
1141
|
+
When doing SSR, you'll typically create an empty RecordSource on the server,
|
|
1142
|
+
populate it with data, serialize it, and then recreate it on the client.
|
|
1143
|
+
|
|
1144
|
+
## Parameters
|
|
1145
|
+
- `records`: Optional existing records to initialize with
|
|
1146
|
+
|
|
1147
|
+
## Examples
|
|
1148
|
+
|
|
1149
|
+
```rescript
|
|
1150
|
+
// Create empty RecordSource
|
|
1151
|
+
let source = RescriptRelay.RecordSource.make()
|
|
1152
|
+
|
|
1153
|
+
// Create RecordSource with existing data (e.g., from SSR)
|
|
1154
|
+
let hydratedSource = RescriptRelay.RecordSource.make(
|
|
1155
|
+
~records=serverSideRecords
|
|
1156
|
+
)
|
|
1157
|
+
```
|
|
1158
|
+
*/
|
|
695
1159
|
@module("relay-runtime")
|
|
696
1160
|
@new
|
|
697
1161
|
external make: (~records: recordSourceRecords=?) => t = "RecordSource"
|
|
698
1162
|
|
|
699
|
-
/**
|
|
1163
|
+
/**
|
|
1164
|
+
Serializes the RecordSource to JSON.
|
|
1165
|
+
|
|
1166
|
+
Converts all records in the source to a JSON representation that can be
|
|
1167
|
+
transmitted or stored. Commonly used for SSR to send server-side cached
|
|
1168
|
+
data to the client.
|
|
1169
|
+
|
|
1170
|
+
## Returns
|
|
1171
|
+
JSON object containing all normalized records
|
|
1172
|
+
|
|
1173
|
+
## Examples
|
|
1174
|
+
|
|
1175
|
+
```rescript
|
|
1176
|
+
// Serialize for SSR
|
|
1177
|
+
let serverRecords = recordSource->RescriptRelay.RecordSource.toJSON
|
|
1178
|
+
|
|
1179
|
+
// Send to client or store in localStorage
|
|
1180
|
+
let serialized = Js.Json.stringify(serverRecords)
|
|
1181
|
+
```
|
|
1182
|
+
*/
|
|
700
1183
|
@send
|
|
701
1184
|
external toJSON: t => recordSourceRecords = "toJSON"
|
|
702
1185
|
}
|
|
703
1186
|
|
|
704
|
-
/**
|
|
1187
|
+
/**
|
|
1188
|
+
The Relay Store - manages normalized GraphQL data caching.
|
|
1189
|
+
|
|
1190
|
+
The Store handles data normalization, caching, garbage collection, and provides
|
|
1191
|
+
interfaces for reading and writing data. It works with a RecordSource to persist
|
|
1192
|
+
the actual record data.
|
|
1193
|
+
*/
|
|
705
1194
|
module Store: {
|
|
706
|
-
/**The type representing
|
|
1195
|
+
/**The type representing a Relay store instance.*/
|
|
707
1196
|
type t
|
|
708
1197
|
|
|
709
|
-
/**
|
|
1198
|
+
/**
|
|
1199
|
+
Creates a new standard Relay store.
|
|
1200
|
+
|
|
1201
|
+
The store manages normalized data and provides caching with configurable
|
|
1202
|
+
garbage collection and TTL settings.
|
|
1203
|
+
|
|
1204
|
+
## Parameters
|
|
1205
|
+
- `source`: RecordSource containing the initial data
|
|
1206
|
+
- `gcReleaseBufferSize`: Number of queries to keep cached (default: 10)
|
|
1207
|
+
- `queryCacheExpirationTime`: TTL in milliseconds for cached queries (default: no TTL)
|
|
1208
|
+
|
|
1209
|
+
## Examples
|
|
1210
|
+
|
|
1211
|
+
```rescript
|
|
1212
|
+
let store = RescriptRelay.Store.make(
|
|
1213
|
+
~source=RescriptRelay.RecordSource.make(),
|
|
1214
|
+
~gcReleaseBufferSize=20, // Keep 20 queries cached
|
|
1215
|
+
~queryCacheExpirationTime=5 * 60 * 1000, // 5 minute TTL
|
|
1216
|
+
)
|
|
1217
|
+
```
|
|
1218
|
+
*/
|
|
710
1219
|
let make: (
|
|
711
1220
|
~source: RecordSource.t,
|
|
712
|
-
~gcReleaseBufferSize:
|
|
713
|
-
int=?,
|
|
1221
|
+
~gcReleaseBufferSize: int=?,
|
|
714
1222
|
~queryCacheExpirationTime: int=?,
|
|
715
|
-
) =>
|
|
716
|
-
|
|
1223
|
+
) => t
|
|
1224
|
+
|
|
1225
|
+
/**
|
|
1226
|
+
Creates a new live store with real-time capabilities.
|
|
1227
|
+
|
|
1228
|
+
Similar to the standard store but with enhanced support for live queries
|
|
1229
|
+
and real-time data updates. Only needed if you're using Relay Resolvers.
|
|
1230
|
+
|
|
1231
|
+
ℹ️ **Note**: Use this only when you need Relay Resolvers. For most applications, the standard `make` function is sufficient.
|
|
717
1232
|
|
|
718
|
-
|
|
1233
|
+
## Parameters
|
|
1234
|
+
- `source`: RecordSource containing the initial data
|
|
1235
|
+
- `gcReleaseBufferSize`: Number of queries to keep cached (default: 10)
|
|
1236
|
+
- `queryCacheExpirationTime`: TTL in milliseconds for cached queries (default: no TTL)
|
|
1237
|
+
|
|
1238
|
+
## Examples
|
|
1239
|
+
|
|
1240
|
+
```rescript
|
|
1241
|
+
let liveStore = RescriptRelay.Store.makeLiveStore(
|
|
1242
|
+
~source=RescriptRelay.RecordSource.make(),
|
|
1243
|
+
~gcReleaseBufferSize=15,
|
|
1244
|
+
)
|
|
1245
|
+
```
|
|
1246
|
+
*/
|
|
719
1247
|
let makeLiveStore: (
|
|
720
1248
|
~source: RecordSource.t,
|
|
721
|
-
~gcReleaseBufferSize:
|
|
722
|
-
int=?,
|
|
1249
|
+
~gcReleaseBufferSize: int=?,
|
|
723
1250
|
~queryCacheExpirationTime: int=?,
|
|
724
|
-
) =>
|
|
725
|
-
t
|
|
1251
|
+
) => t
|
|
726
1252
|
|
|
1253
|
+
/**Internal CommonJS version of makeLiveStore. Use `makeLiveStore` instead.*/
|
|
727
1254
|
let _makeLiveStoreCjs: (
|
|
728
1255
|
~source: RecordSource.t,
|
|
729
1256
|
~gcReleaseBufferSize: int=?,
|
|
730
1257
|
~queryCacheExpirationTime: int=?,
|
|
731
1258
|
) => t
|
|
732
1259
|
|
|
733
|
-
/**
|
|
1260
|
+
/**
|
|
1261
|
+
Gets the RecordSource from this store.
|
|
1262
|
+
|
|
1263
|
+
Provides access to the underlying record source for advanced operations
|
|
1264
|
+
like serialization or direct record access.
|
|
1265
|
+
|
|
1266
|
+
## Examples
|
|
1267
|
+
|
|
1268
|
+
```rescript
|
|
1269
|
+
let source = store->RescriptRelay.Store.getSource
|
|
1270
|
+
let serialized = source->RescriptRelay.RecordSource.toJSON
|
|
1271
|
+
```
|
|
1272
|
+
*/
|
|
734
1273
|
@send
|
|
735
1274
|
external getSource: t => RecordSource.t = "getSource"
|
|
736
1275
|
|
|
737
|
-
/**
|
|
1276
|
+
/**
|
|
1277
|
+
Publishes new records to the store.
|
|
1278
|
+
|
|
1279
|
+
Merges new record data into the existing store. Particularly useful for
|
|
1280
|
+
SSR scenarios where you need to hydrate client-side stores with server data.
|
|
1281
|
+
|
|
1282
|
+
## Parameters
|
|
1283
|
+
- `source`: RecordSource containing new records to publish
|
|
1284
|
+
|
|
1285
|
+
## Examples
|
|
1286
|
+
|
|
1287
|
+
```rescript
|
|
1288
|
+
// Hydrate client store with server data
|
|
1289
|
+
let serverRecords = RescriptRelay.RecordSource.make(~records=serverData)
|
|
1290
|
+
store->RescriptRelay.Store.publish(serverRecords)
|
|
1291
|
+
```
|
|
1292
|
+
*/
|
|
738
1293
|
@send
|
|
739
1294
|
external publish: (t, RecordSource.t) => unit = "publish"
|
|
740
1295
|
|
|
741
|
-
/**
|
|
1296
|
+
/**
|
|
1297
|
+
Temporarily disables garbage collection.
|
|
1298
|
+
|
|
1299
|
+
Prevents the store from cleaning up cached data. Useful when you need to
|
|
1300
|
+
ensure data persistence during operations like serialization.
|
|
1301
|
+
|
|
1302
|
+
## Examples
|
|
1303
|
+
|
|
1304
|
+
```rescript
|
|
1305
|
+
// Hold GC during serialization
|
|
1306
|
+
store->RescriptRelay.Store.holdGC
|
|
1307
|
+
let serialized = store->RescriptRelay.Store.getSource->RescriptRelay.RecordSource.toJSON
|
|
1308
|
+
// GC will resume automatically
|
|
1309
|
+
```
|
|
1310
|
+
*/
|
|
742
1311
|
@send
|
|
743
1312
|
external holdGC: t => unit = "holdGC"
|
|
744
1313
|
}
|
|
@@ -786,12 +1355,45 @@ module RelayFieldLogger: {
|
|
|
786
1355
|
type t = arg => unit
|
|
787
1356
|
}
|
|
788
1357
|
|
|
789
|
-
/**
|
|
1358
|
+
/**
|
|
1359
|
+
The Relay Environment - the central hub for Relay operations.
|
|
1360
|
+
|
|
1361
|
+
The Environment coordinates between the network layer, store, and other Relay
|
|
1362
|
+
components. It manages data fetching, caching, and normalization. You typically
|
|
1363
|
+
create one Environment per application and pass it to Relay components.
|
|
1364
|
+
*/
|
|
790
1365
|
module Environment: {
|
|
791
|
-
/**The type representing
|
|
1366
|
+
/**The type representing a Relay environment instance.*/
|
|
792
1367
|
type t
|
|
793
1368
|
|
|
794
|
-
/**
|
|
1369
|
+
/**
|
|
1370
|
+
Creates a new Relay Environment.
|
|
1371
|
+
|
|
1372
|
+
The Environment requires a network layer and store at minimum. Additional
|
|
1373
|
+
configuration options allow you to customize caching, error handling,
|
|
1374
|
+
and data normalization behavior.
|
|
1375
|
+
|
|
1376
|
+
## Parameters
|
|
1377
|
+
- `network`: Network layer for making GraphQL requests
|
|
1378
|
+
- `store`: Store for caching normalized data
|
|
1379
|
+
- `getDataID`: Optional custom function for generating record IDs
|
|
1380
|
+
- `treatMissingFieldsAsNull`: Whether missing fields should be treated as null
|
|
1381
|
+
- `missingFieldHandlers`: Array of handlers for filling in missing data
|
|
1382
|
+
- `relayFieldLogger`: Optional logger for field-level events
|
|
1383
|
+
- `isServer`: Whether this environment is running on the server
|
|
1384
|
+
|
|
1385
|
+
## Examples
|
|
1386
|
+
|
|
1387
|
+
```rescript
|
|
1388
|
+
let environment = RescriptRelay.Environment.make(
|
|
1389
|
+
~network=myNetworkLayer,
|
|
1390
|
+
~store=RescriptRelay.Store.make(
|
|
1391
|
+
~source=RescriptRelay.RecordSource.make()
|
|
1392
|
+
),
|
|
1393
|
+
~treatMissingFieldsAsNull=false,
|
|
1394
|
+
)
|
|
1395
|
+
```
|
|
1396
|
+
*/
|
|
795
1397
|
let make: (
|
|
796
1398
|
~network: Network.t,
|
|
797
1399
|
~store: Store.t,
|
|
@@ -805,24 +1407,118 @@ module Environment: {
|
|
|
805
1407
|
~isServer: bool=?,
|
|
806
1408
|
) => t
|
|
807
1409
|
|
|
808
|
-
/**
|
|
1410
|
+
/**
|
|
1411
|
+
Gets the store instance from this environment.
|
|
1412
|
+
|
|
1413
|
+
Provides access to the underlying store for advanced store operations
|
|
1414
|
+
like publishing records or holding garbage collection.
|
|
1415
|
+
|
|
1416
|
+
## Examples
|
|
1417
|
+
|
|
1418
|
+
```rescript
|
|
1419
|
+
let store = environment->RescriptRelay.Environment.getStore
|
|
1420
|
+
store->RescriptRelay.Store.holdGC // Prevent garbage collection
|
|
1421
|
+
```
|
|
1422
|
+
*/
|
|
809
1423
|
@send
|
|
810
1424
|
external getStore: t => Store.t = "getStore"
|
|
811
1425
|
|
|
812
|
-
/**
|
|
1426
|
+
/**
|
|
1427
|
+
Commits a GraphQL response payload to the store.
|
|
1428
|
+
|
|
1429
|
+
Low-level function for manually committing operation results. Most users
|
|
1430
|
+
should use higher-level APIs like queries and mutations instead.
|
|
1431
|
+
|
|
1432
|
+
## Parameters
|
|
1433
|
+
- `operationDescriptor`: The operation that produced this payload
|
|
1434
|
+
- `payload`: The GraphQL response data to commit
|
|
1435
|
+
*/
|
|
813
1436
|
@send
|
|
814
1437
|
external commitPayload: (t, operationDescriptor, 'payload) => unit = "commitPayload"
|
|
815
1438
|
|
|
816
|
-
/**
|
|
817
|
-
|
|
1439
|
+
/**
|
|
1440
|
+
Retains an operation to prevent garbage collection.
|
|
1441
|
+
|
|
1442
|
+
Keeps the data for an operation in the store by preventing Relay's garbage
|
|
1443
|
+
collector from cleaning it up. Returns a disposable that releases the retain
|
|
1444
|
+
when disposed.
|
|
1445
|
+
|
|
1446
|
+
Note: Use the generated `Query.retain` functions instead of calling this directly.
|
|
1447
|
+
|
|
1448
|
+
## Parameters
|
|
1449
|
+
- `operationDescriptor`: The operation to retain
|
|
1450
|
+
|
|
1451
|
+
## Returns
|
|
1452
|
+
Disposable that releases the retain when disposed
|
|
1453
|
+
*/
|
|
818
1454
|
@send
|
|
819
1455
|
external retain: (t, operationDescriptor) => Disposable.t = "retain"
|
|
820
1456
|
|
|
821
|
-
/**
|
|
1457
|
+
/**
|
|
1458
|
+
Finds all connection IDs for a specific connection key on a parent record.
|
|
1459
|
+
|
|
1460
|
+
Useful for operations that need to affect all instances of a connection,
|
|
1461
|
+
such as when using `@deleteEdge` or bulk connection updates.
|
|
1462
|
+
|
|
1463
|
+
## Parameters
|
|
1464
|
+
- `connectionKey`: The connection key to search for
|
|
1465
|
+
- `parentId`: The parent record containing the connections
|
|
1466
|
+
|
|
1467
|
+
## Returns
|
|
1468
|
+
Array of connection data IDs
|
|
1469
|
+
|
|
1470
|
+
## Examples
|
|
1471
|
+
|
|
1472
|
+
```rescript
|
|
1473
|
+
// Find all friend list connections for a user
|
|
1474
|
+
let connectionIds = environment->RescriptRelay.Environment.findAllConnectionIds(
|
|
1475
|
+
~connectionKey=UserFriends_user_graphql.connectionKey,
|
|
1476
|
+
~parentId=userId
|
|
1477
|
+
)
|
|
1478
|
+
```
|
|
1479
|
+
*/
|
|
822
1480
|
let findAllConnectionIds: (t, ~connectionKey: string, ~parentId: dataId) => array<dataId>
|
|
823
1481
|
|
|
824
|
-
/**
|
|
825
|
-
|
|
1482
|
+
/**
|
|
1483
|
+
Invalidates all connection configurations of `connectionKey` on `parentId`.
|
|
1484
|
+
|
|
1485
|
+
This function invalidates all cached data for connections with the specified key on the given parent record.
|
|
1486
|
+
When connections are invalidated, any queries that depend on this connection data will be considered stale
|
|
1487
|
+
and will need to be refetched the next time they are accessed.
|
|
1488
|
+
|
|
1489
|
+
## Parameters
|
|
1490
|
+
- `environment`: The Relay environment
|
|
1491
|
+
- `connectionKey`: The connection key used in the `@connection(key: "...")` directive
|
|
1492
|
+
- `parentId`: The data ID of the parent record that holds the connection
|
|
1493
|
+
- `excludedIds`: Optional array of connection data IDs to exclude from invalidation
|
|
1494
|
+
|
|
1495
|
+
## Examples
|
|
1496
|
+
|
|
1497
|
+
### Basic Usage
|
|
1498
|
+
```rescript
|
|
1499
|
+
// Invalidate all connections for a user's friends
|
|
1500
|
+
environment->RescriptRelay.Environment.invalidateAllOfConnection(
|
|
1501
|
+
~connectionKey=UserProfile_friends_graphql.connectionKey,
|
|
1502
|
+
~parentId=user.__id,
|
|
1503
|
+
)
|
|
1504
|
+
```
|
|
1505
|
+
|
|
1506
|
+
### With Excluded IDs
|
|
1507
|
+
```rescript
|
|
1508
|
+
environment->RescriptRelay.Environment.invalidateAllOfConnection(
|
|
1509
|
+
~connectionKey=UserProfile_friends_graphql.connectionKey,
|
|
1510
|
+
~parentId=user.__id,
|
|
1511
|
+
// Invalidate all of this connection except for the currently rendered one.
|
|
1512
|
+
~excludedIds=[currentConnection.__id],
|
|
1513
|
+
)
|
|
1514
|
+
```
|
|
1515
|
+
*/
|
|
1516
|
+
let invalidateAllOfConnection: (
|
|
1517
|
+
t,
|
|
1518
|
+
~connectionKey: string,
|
|
1519
|
+
~parentId: dataId,
|
|
1520
|
+
~excludedIds: array<dataId>=?,
|
|
1521
|
+
) => unit
|
|
826
1522
|
}
|
|
827
1523
|
|
|
828
1524
|
/**fetchPolicy controls how you want Relay to resolve your data.*/
|
|
@@ -883,14 +1579,72 @@ let useEnvironmentFromContext: unit => Environment.t
|
|
|
883
1579
|
|
|
884
1580
|
/**An exception detailing that a mutation failed.*/ exception Mutation_failed(array<mutationError>)
|
|
885
1581
|
|
|
886
|
-
/**
|
|
1582
|
+
/**
|
|
1583
|
+
Commits a local update to the Relay store.
|
|
1584
|
+
|
|
1585
|
+
Performs imperative updates to the store without triggering network requests.
|
|
1586
|
+
Use this for client-side only changes like toggling UI state or updating
|
|
1587
|
+
local fields that don't need server synchronization.
|
|
1588
|
+
|
|
1589
|
+
## Parameters
|
|
1590
|
+
- `environment`: The Relay environment
|
|
1591
|
+
- `updater`: Function that receives the store and performs updates
|
|
1592
|
+
|
|
1593
|
+
## Examples
|
|
1594
|
+
|
|
1595
|
+
```rescript
|
|
1596
|
+
// Toggle a local UI state
|
|
1597
|
+
RescriptRelay.commitLocalUpdate(
|
|
1598
|
+
~environment,
|
|
1599
|
+
~updater=store => {
|
|
1600
|
+
let user = store->RescriptRelay.RecordSourceSelectorProxy.get(~dataId=userId)
|
|
1601
|
+
switch user {
|
|
1602
|
+
| Some(userRecord) =>
|
|
1603
|
+
let _ = userRecord->RescriptRelay.RecordProxy.setValueBool(
|
|
1604
|
+
~value=!isExpanded,
|
|
1605
|
+
~name="isExpanded"
|
|
1606
|
+
)
|
|
1607
|
+
| None => ()
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
)
|
|
1611
|
+
```
|
|
1612
|
+
*/
|
|
887
1613
|
@module("relay-runtime")
|
|
888
1614
|
external commitLocalUpdate: (
|
|
889
1615
|
~environment: Environment.t,
|
|
890
1616
|
~updater: RecordSourceSelectorProxy.t => unit,
|
|
891
1617
|
) => unit = "commitLocalUpdate"
|
|
892
1618
|
|
|
893
|
-
/**
|
|
1619
|
+
/**
|
|
1620
|
+
Subscribes to invalidation events for specific records.
|
|
1621
|
+
|
|
1622
|
+
Executes a callback whenever any of the specified records are invalidated.
|
|
1623
|
+
Useful for triggering refetches or UI updates when cached data becomes stale.
|
|
1624
|
+
|
|
1625
|
+
## Parameters
|
|
1626
|
+
- Array of `dataId`s to watch for invalidation
|
|
1627
|
+
- Callback function executed when any watched record is invalidated
|
|
1628
|
+
|
|
1629
|
+
## Examples
|
|
1630
|
+
|
|
1631
|
+
```rescript
|
|
1632
|
+
// Watch for user invalidation and refetch
|
|
1633
|
+
let disposable = RescriptRelay.useSubscribeToInvalidationState(
|
|
1634
|
+
[user.__id],
|
|
1635
|
+
() => {
|
|
1636
|
+
// Refetch user data when invalidated
|
|
1637
|
+
UserQuery.fetchPromised(~environment, ~variables={id: user.id})
|
|
1638
|
+
->Promise.done
|
|
1639
|
+
}
|
|
1640
|
+
)
|
|
1641
|
+
|
|
1642
|
+
// Clean up subscription
|
|
1643
|
+
React.useEffect1(() => {
|
|
1644
|
+
Some(() => disposable->RescriptRelay.Disposable.dispose)
|
|
1645
|
+
}, [disposable])
|
|
1646
|
+
```
|
|
1647
|
+
*/
|
|
894
1648
|
@module("react-relay")
|
|
895
1649
|
external useSubscribeToInvalidationState: (array<dataId>, unit => unit) => Disposable.t =
|
|
896
1650
|
"useSubscribeToInvalidationState"
|
package/src/utils.js
CHANGED
|
@@ -79,6 +79,12 @@ function traverse(
|
|
|
79
79
|
continue;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
if (currentObj[key] && currentObj[key].BS_PRIVATE_NESTED_SOME_NONE >= 0) {
|
|
83
|
+
newObj = getNewObj(newObj, currentObj);
|
|
84
|
+
newObj[key] = currentObj[key];
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
82
88
|
var shouldConvertRootObj =
|
|
83
89
|
typeof instructions["r"] === "string" &&
|
|
84
90
|
fullInstructionMap[instructions["r"]];
|
package/src/utils.mjs
CHANGED
|
@@ -79,6 +79,12 @@ function traverse(
|
|
|
79
79
|
continue;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
+
if (currentObj[key] && currentObj[key].BS_PRIVATE_NESTED_SOME_NONE >= 0) {
|
|
83
|
+
newObj = getNewObj(newObj, currentObj);
|
|
84
|
+
newObj[key] = currentObj[key];
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
|
|
82
88
|
var shouldConvertRootObj =
|
|
83
89
|
typeof instructions["r"] === "string" &&
|
|
84
90
|
fullInstructionMap[instructions["r"]];
|