rescript-relay 3.0.0 → 3.1.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 CHANGED
@@ -1,8 +1,17 @@
1
1
  # master
2
2
 
3
- **All work on version `2.x` is in the [2.x branch](https://github.com/zth/rescript-relay/tree/2.x).**
3
+ # 3.1.0
4
4
 
5
- # **Version 3**
5
+ - **Upgrade versions**: `react-relay` and `relay-runtime` to `18.2.0`.
6
+ - Add support for `Fragment.waitForFragmentData`, a new API in Relay 18.2 that lets you wait for fragment data outside of React.
7
+ - Experimental: Add a "non React" mode to the PPX, which makes sure only APIs that don't rely on React directly are exposed. This is intended to be a way to simplify using RescriptRelay without React. Activate by passing `-non-react` to the PPX, like `"ppx-flags": [["rescript-relay/ppx", "-non-react"]]`.
8
+
9
+ # 3.0.1
10
+
11
+ - Add `Environment.findAllConnectionIds` for finding all IDs of all connection instances for a specific connection, regardless of what configs that connection has been fetched (and cached) with.
12
+ - Add `RecordSourceSelectorProxy.invalidateRecordsByIds` for invalidating multilple records at the same time.
13
+ - Allow configuring input unions via `inputUnions` in `relay.config.js` as an escape hatch for when `@oneOf` support on your server is tricky to set up.
14
+ - Move `@rescript/react` to `>=0.13.0`.
6
15
 
7
16
  # 3.0.0 stable
8
17
 
package/README.md CHANGED
@@ -103,8 +103,8 @@ let make = () => {
103
103
  There's plenty of work ongoing to bring RescriptRelay to full ReScript v11 support, including uncurried mode. Here's the versioning scheme that'll be followed going forward:
104
104
 
105
105
  - 1.x will receive critical bug fixes etc, but new features won't be added
106
- - 2.x will soon ship, and it'll focus on compatibility with ReScript v11, and uncurried mode (uncurried mode will be optional). This is intended to make the transition to v11+ smooth
107
- - 3.x will also soon ship, and that'll fully embrace uncurried mode (no curried mode available), and add a bunch of new stuff + change existing APIs to make them better and more ergonomic
106
+ - 2.x will focus on compatibility with ReScript v11, and uncurried mode (uncurried mode will be optional). This is intended to make the transition to v11+ smooth
107
+ - 3.x is fully embracing uncurried mode (no curried mode available), and adds a bunch of new stuff + change existing APIs to make them better and more ergonomic
108
108
 
109
109
  ## Examples
110
110
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rescript-relay",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "main": "src/RescriptRelay.res",
5
5
  "license": "MIT",
6
6
  "author": "Gabriel Nordeborn",
@@ -49,14 +49,14 @@
49
49
  "node-fetch": "^2.6.0",
50
50
  "react": "18.2.0",
51
51
  "react-dom": "18.2.0",
52
- "react-relay": "17.0.0",
53
- "relay-runtime": "17.0.0",
52
+ "react-relay": "18.2.0",
53
+ "relay-runtime": "18.2.0",
54
54
  "rescript": "11.1.1"
55
55
  },
56
56
  "peerDependencies": {
57
- "@rescript/react": "^0.12.1",
58
- "react-relay": "17.0.0",
59
- "relay-runtime": "17.0.0",
57
+ "@rescript/react": ">=0.13.0",
58
+ "react-relay": "18.2.0",
59
+ "relay-runtime": "18.2.0",
60
60
  "rescript": "^11.0.0"
61
61
  },
62
62
  "dependencies": {
package/ppx-linux CHANGED
Binary file
package/ppx-macos-arm64 CHANGED
Binary file
package/ppx-macos-latest CHANGED
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -3,13 +3,15 @@
3
3
 
4
4
  var React = require("react");
5
5
  var Utils = require("./utils");
6
+ var Js_dict = require("rescript/lib/js/js_dict.js");
6
7
  var Belt_Array = require("rescript/lib/js/belt_Array.js");
8
+ var Belt_Option = require("rescript/lib/js/belt_Option.js");
7
9
  var Caml_option = require("rescript/lib/js/caml_option.js");
8
10
  var ReactRelay = require("react-relay");
9
11
  var RelayRuntime = require("relay-runtime");
10
12
  var Caml_exceptions = require("rescript/lib/js/caml_exceptions.js");
11
- var LiveResolverStore = require("relay-runtime/lib/store/experimental-live-resolvers/LiveResolverStore");
12
- var LiveResolverStore$1 = require("relay-runtime/lib/store/experimental-live-resolvers/LiveResolverStore").default;
13
+ var LiveResolverStore = require("relay-runtime/lib/store/live-resolvers/LiveResolverStore").default;
14
+ var LiveResolverStore$1 = require("relay-runtime/lib/store/live-resolvers/LiveResolverStore");
13
15
 
14
16
  var SuspenseSentinel = {};
15
17
 
@@ -42,8 +44,17 @@ function getPluralRootField(t, fieldName) {
42
44
  return optArrayOfNullableToOptArrayOfOpt(Caml_option.nullable_to_opt(t.getPluralRootField(fieldName)));
43
45
  }
44
46
 
47
+ function invalidateRecordsByIds(store, recordIds) {
48
+ recordIds.forEach(function (dataId) {
49
+ Belt_Option.forEach(Caml_option.nullable_to_opt(store.get(dataId)), (function (r) {
50
+ r.invalidateRecord();
51
+ }));
52
+ });
53
+ }
54
+
45
55
  var RecordSourceSelectorProxy = {
46
- getPluralRootField: getPluralRootField
56
+ getPluralRootField: getPluralRootField,
57
+ invalidateRecordsByIds: invalidateRecordsByIds
47
58
  };
48
59
 
49
60
  var ReadOnlyRecordSourceProxy = {};
@@ -198,14 +209,14 @@ function make(source, gcReleaseBufferSize, queryCacheExpirationTime) {
198
209
  }
199
210
 
200
211
  function makeLiveStore(source, gcReleaseBufferSize, queryCacheExpirationTime) {
201
- return new LiveResolverStore$1(source, {
212
+ return new LiveResolverStore(source, {
202
213
  gcReleaseBufferSize: gcReleaseBufferSize,
203
214
  queryCacheExpirationTime: queryCacheExpirationTime
204
215
  });
205
216
  }
206
217
 
207
218
  function _makeLiveStoreCjs(source, gcReleaseBufferSize, queryCacheExpirationTime) {
208
- return new LiveResolverStore(source, {
219
+ return new LiveResolverStore$1(source, {
209
220
  gcReleaseBufferSize: gcReleaseBufferSize,
210
221
  queryCacheExpirationTime: queryCacheExpirationTime
211
222
  });
@@ -231,8 +242,35 @@ function make$1(network, store, getDataID, treatMissingFieldsAsNull, missingFiel
231
242
  });
232
243
  }
233
244
 
245
+ function findAllConnectionIds(environment, connectionKey, parentId) {
246
+ var ids = [];
247
+ var value = environment.getStore().getSource()._records.get(parentId);
248
+ if (value !== undefined) {
249
+ Js_dict.entries(value).forEach(function (param) {
250
+ if (param[0].startsWith("__" + connectionKey + "_connection")) {
251
+ ids.push(param[1].__ref);
252
+ return ;
253
+ }
254
+
255
+ });
256
+ }
257
+ return ids;
258
+ }
259
+
260
+ function invalidateAllOfConnection(environment, connectionKey, parentId) {
261
+ RelayRuntime.commitLocalUpdate(environment, (function (store) {
262
+ findAllConnectionIds(environment, connectionKey, parentId).forEach(function (dataId) {
263
+ Belt_Option.forEach(Caml_option.nullable_to_opt(store.get(dataId)), (function (r) {
264
+ r.invalidateRecord();
265
+ }));
266
+ });
267
+ }));
268
+ }
269
+
234
270
  var Environment = {
235
- make: make$1
271
+ make: make$1,
272
+ findAllConnectionIds: findAllConnectionIds,
273
+ invalidateAllOfConnection: invalidateAllOfConnection
236
274
  };
237
275
 
238
276
  function RescriptRelay$Context$Provider(props) {
@@ -312,6 +312,12 @@ module RecordSourceSelectorProxy = {
312
312
  getPluralRootField(t, ~fieldName)->optArrayOfNullableToOptArrayOfOpt
313
313
 
314
314
  @send external invalidateStore: t => unit = "invalidateStore"
315
+
316
+ let invalidateRecordsByIds: (t, array<dataId>) => unit = (store, recordIds) => {
317
+ recordIds->Js.Array2.forEach(dataId => {
318
+ store->get(~dataId)->Belt.Option.forEach(r => r->RecordProxy.invalidateRecord)
319
+ })
320
+ }
315
321
  }
316
322
 
317
323
  module ReadOnlyRecordSourceProxy = {
@@ -637,9 +643,9 @@ module Store = {
637
643
 
638
644
  @module @new
639
645
  external makeLiveStoreCjs: (RecordSource.t, storeConfig) => t =
640
- "relay-runtime/lib/store/experimental-live-resolvers/LiveResolverStore"
646
+ "relay-runtime/lib/store/live-resolvers/LiveResolverStore"
641
647
 
642
- @module("relay-runtime/lib/store/experimental-live-resolvers/LiveResolverStore") @new
648
+ @module("relay-runtime/lib/store/live-resolvers/LiveResolverStore") @new
643
649
  external makeLiveStore: (RecordSource.t, storeConfig) => t = "default"
644
650
 
645
651
  @module("relay-runtime") @new
@@ -680,8 +686,19 @@ module Store = {
680
686
  module RelayFieldLogger = {
681
687
  @tag("kind")
682
688
  type arg =
683
- | @as("missing_field.log") MissingFieldLog({owner: string, fieldPath: string})
684
- | @as("missing_field.throw") MissingFieldThrow({owner: string, fieldPath: string})
689
+ | @as("missing_required_field.log") MissingRequiredFieldLog({owner: string, fieldPath: string})
690
+ | @as("missing_required_field.throw")
691
+ MissingRequiredFieldThrow({
692
+ owner: string,
693
+ fieldPath: string,
694
+ })
695
+ | @as("missing_expected_data.log") MissingExpectedData({owner: string, fieldPath: string})
696
+ | @as("missing_expected_data.throw")
697
+ MissingExpectedDataThrow({
698
+ owner: string,
699
+ fieldPath: string,
700
+ handled: bool,
701
+ })
685
702
  | @as("relay_resolver.error")
686
703
  RelayResolverError({
687
704
  owner: string,
@@ -734,6 +751,43 @@ module Environment = {
734
751
  @send
735
752
  external commitPayload: (t, operationDescriptor, 'payload) => unit = "commitPayload"
736
753
  @send external retain: (t, operationDescriptor) => Disposable.t = "retain"
754
+
755
+ @module("relay-runtime")
756
+ external commitLocalUpdate: (t, ~updater: RecordSourceSelectorProxy.t => unit) => unit =
757
+ "commitLocalUpdate"
758
+
759
+ @send external mapGet: (Js.Map.t<'key, 'value>, 'key) => option<'value> = "get"
760
+
761
+ type recordValue = {__ref: dataId}
762
+ @get external _records: RecordSource.t => Js.Map.t<string, Js.Dict.t<recordValue>> = "_records"
763
+
764
+ let findAllConnectionIds = (environment: t, ~connectionKey: string, ~parentId: dataId) => {
765
+ let ids = []
766
+ switch environment->getStore->Store.getSource->_records->mapGet(parentId->dataIdToString) {
767
+ | Some(value) =>
768
+ value
769
+ ->Js.Dict.entries
770
+ ->Js.Array2.forEach(((key, v)) => {
771
+ if key->Js.String2.startsWith("__" ++ connectionKey ++ "_connection") {
772
+ let _ = ids->Js.Array2.push(v.__ref)
773
+ }
774
+ })
775
+ | _ => ()
776
+ }
777
+ ids
778
+ }
779
+
780
+ let invalidateAllOfConnection = (environment: t, ~connectionKey: string, ~parentId: dataId) => {
781
+ environment->commitLocalUpdate(~updater=store => {
782
+ environment
783
+ ->findAllConnectionIds(~connectionKey, ~parentId)
784
+ ->Js.Array2.forEach(dataId => {
785
+ store
786
+ ->RecordSourceSelectorProxy.get(~dataId)
787
+ ->Belt.Option.forEach(r => r->RecordProxy.invalidateRecord)
788
+ })
789
+ })
790
+ }
737
791
  }
738
792
 
739
793
  module Context = {
@@ -399,6 +399,9 @@ module RecordSourceSelectorProxy: {
399
399
  /**Invalidates the entire store. This means that _at the next render_, the entire store will be treated as empty, meaning Relay will refetch everything it needs to show the view it's to show.*/
400
400
  @send
401
401
  external invalidateStore: t => unit = "invalidateStore"
402
+
403
+ /**Invalidates each of the provided records by their ID, if they exist. */
404
+ let invalidateRecordsByIds: (t, array<dataId>) => unit
402
405
  }
403
406
 
404
407
  /**ReadOnlyRecordSourceProxy is the store, but in read-only mode.*/
@@ -741,8 +744,19 @@ module Disposable: {
741
744
  module RelayFieldLogger: {
742
745
  @tag("kind")
743
746
  type arg =
744
- | @as("missing_field.log") MissingFieldLog({owner: string, fieldPath: string})
745
- | @as("missing_field.throw") MissingFieldThrow({owner: string, fieldPath: string})
747
+ | @as("missing_required_field.log") MissingRequiredFieldLog({owner: string, fieldPath: string})
748
+ | @as("missing_required_field.throw")
749
+ MissingRequiredFieldThrow({
750
+ owner: string,
751
+ fieldPath: string,
752
+ })
753
+ | @as("missing_expected_data.log") MissingExpectedData({owner: string, fieldPath: string})
754
+ | @as("missing_expected_data.throw")
755
+ MissingExpectedDataThrow({
756
+ owner: string,
757
+ fieldPath: string,
758
+ handled: bool,
759
+ })
746
760
  | @as("relay_resolver.error")
747
761
  RelayResolverError({
748
762
  owner: string,
@@ -785,6 +799,12 @@ module Environment: {
785
799
  You should use the generated `Query.retain` function on your queries instead of using this directly.*/
786
800
  @send
787
801
  external retain: (t, operationDescriptor) => Disposable.t = "retain"
802
+
803
+ /**Find all connection IDs for a specific connection and on a specific object. Useful together with `@deleteEdge` and similar where you want to remove something from all connection configurations. */
804
+ let findAllConnectionIds: (t, ~connectionKey: string, ~parentId: dataId) => array<dataId>
805
+
806
+ /**Invalidates all connection configurations of `connectionKey` on `parentId`.*/
807
+ let invalidateAllOfConnection: (t, ~connectionKey: string, ~parentId: dataId) => unit
788
808
  }
789
809
 
790
810
  /**fetchPolicy controls how you want Relay to resolve your data.*/
@@ -5,6 +5,7 @@ var React = require("react");
5
5
  var Caml_option = require("rescript/lib/js/caml_option.js");
6
6
  var ReactRelay = require("react-relay");
7
7
  var RescriptRelay_Internal = require("./RescriptRelay_Internal.bs.js");
8
+ var Experimental = require("relay-runtime/experimental");
8
9
  var ResolverFragments = require("relay-runtime/lib/store/ResolverFragments");
9
10
  var UseBlockingPaginationFragment = require("react-relay/lib/relay-hooks/legacy/useBlockingPaginationFragment").default;
10
11
 
@@ -112,6 +113,11 @@ function useRefetchableFragment(node, convertFragment, convertRefetchVariables,
112
113
  ];
113
114
  }
114
115
 
116
+ async function waitForFragmentData(environment, node, convertFragment, fRef) {
117
+ var fragmentData = await Experimental.waitForFragmentData(environment, node, fRef);
118
+ return convertFragment(fragmentData);
119
+ }
120
+
115
121
  exports.useFragment = useFragment;
116
122
  exports.useFragmentOpt = useFragmentOpt;
117
123
  exports.readInlineData = readInlineData;
@@ -119,4 +125,5 @@ exports.read = read;
119
125
  exports.usePaginationFragment = usePaginationFragment;
120
126
  exports.useBlockingPaginationFragment = useBlockingPaginationFragment;
121
127
  exports.useRefetchableFragment = useRefetchableFragment;
128
+ exports.waitForFragmentData = waitForFragmentData;
122
129
  /* react Not a pure module */
@@ -241,3 +241,20 @@ let useRefetchableFragment = (
241
241
  ),
242
242
  )
243
243
  }
244
+
245
+ @module("relay-runtime/experimental")
246
+ external waitForFragmentData_: (
247
+ Environment.t,
248
+ fragmentNode<'node>,
249
+ 'fragmentRef,
250
+ ) => promise<'fragment> = "waitForFragmentData"
251
+
252
+ let waitForFragmentData = async (
253
+ ~environment,
254
+ ~node,
255
+ ~convertFragment: 'fragment => 'fragment,
256
+ ~fRef,
257
+ ) => {
258
+ let fragmentData = await waitForFragmentData_(environment, node, fRef)
259
+ convertFragment(fragmentData)
260
+ }
@@ -83,3 +83,10 @@ let useRefetchableFragment: (
83
83
  ~onComplete: option<Js.Exn.t> => unit=?,
84
84
  ) => Disposable.t,
85
85
  )
86
+
87
+ let waitForFragmentData: (
88
+ ~environment: Environment.t,
89
+ ~node: fragmentNode<'a>,
90
+ ~convertFragment: 'fragment => 'fragment,
91
+ ~fRef: 'b,
92
+ ) => promise<'fragment>