diff --git a/CHANGELOG.md b/CHANGELOG.md
index d5f3c094..3af2c396 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,8 @@
# Unreleased
+- Support `@alias` fragments.
+
# 3.0.0-rc.9
- Fix client extension enums mixup with `FutureAddedValue`.
diff --git a/packages/relay b/packages/relay
index 72f4958b..7951c17e 160000
--- a/packages/relay
+++ b/packages/relay
@@ -1 +1 @@
-Subproject commit 72f4958b940166a3c9ee9ffd21a0e1d232cb1797
+Subproject commit 7951c17e5dc260bd534c0d512db7159964fa5706
diff --git a/packages/rescript-relay/__tests__/Test_aliasedFragments-tests.js b/packages/rescript-relay/__tests__/Test_aliasedFragments-tests.js
new file mode 100644
index 00000000..b54e6055
--- /dev/null
+++ b/packages/rescript-relay/__tests__/Test_aliasedFragments-tests.js
@@ -0,0 +1,27 @@
+require("@testing-library/jest-dom/extend-expect");
+const t = require("@testing-library/react");
+const React = require("react");
+const queryMock = require("./queryMock");
+
+const { test_aliasedFragments } = require("./Test_aliasedFragments.bs");
+
+describe("Aliased fragments", () => {
+ test("basic fragments work", async () => {
+ queryMock.mockQuery({
+ name: "TestAliasedFragmentsQuery",
+ variables: {
+ skipThing: false,
+ },
+ data: {
+ loggedInUser: {
+ id: "user-1",
+ firstName: "First",
+ lastName: "Last",
+ },
+ },
+ });
+
+ t.render(test_aliasedFragments());
+ await t.screen.findByText("First Last");
+ });
+});
diff --git a/packages/rescript-relay/__tests__/Test_aliasedFragments.res b/packages/rescript-relay/__tests__/Test_aliasedFragments.res
new file mode 100644
index 00000000..acce023c
--- /dev/null
+++ b/packages/rescript-relay/__tests__/Test_aliasedFragments.res
@@ -0,0 +1,58 @@
+module FragmentFirstName = %relay(`
+ fragment TestAliasedFragments_userFirstName on User {
+ firstName
+ }
+`)
+
+module FragmentLastName = %relay(`
+ fragment TestAliasedFragments_userLastName on User {
+ lastName
+ }
+`)
+
+module Query = %relay(`
+ query TestAliasedFragmentsQuery($skipThing: Boolean!) {
+ loggedInUser {
+ ...TestAliasedFragments_userFirstName @alias
+ ...TestAliasedFragments_userLastName @alias @skip(if: $skipThing)
+ }
+ }
+`)
+
+module Test = {
+ @react.component
+ let make = () => {
+ let query = Query.use(~variables={skipThing: false})
+ let firstNameData = FragmentFirstName.use(
+ query.loggedInUser.testAliasedFragments_userFirstName.fragmentRefs,
+ )
+ let lastNameData = FragmentLastName.useOpt(
+ query.loggedInUser.testAliasedFragments_userLastName->Belt.Option.map(f => f.fragmentRefs),
+ )
+
+
+ {React.string(
+ firstNameData.firstName ++
+ " " ++
+ switch lastNameData {
+ | None => "-"
+ | Some({lastName}) => lastName
+ },
+ )}
+
+ }
+}
+
+@live
+let test_aliasedFragments = () => {
+ let network = RescriptRelay.Network.makePromiseBased(~fetchFunction=RelayEnv.fetchQuery)
+
+ let environment = RescriptRelay.Environment.make(
+ ~network,
+ ~store=RescriptRelay.Store.make(~source=RescriptRelay.RecordSource.make()),
+ )
+
+
+
+
+}
diff --git a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragmentsQuery_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragmentsQuery_graphql.res
new file mode 100644
index 00000000..e5f86b28
--- /dev/null
+++ b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragmentsQuery_graphql.res
@@ -0,0 +1,257 @@
+/* @sourceLoc Test_aliasedFragments.res */
+/* @generated */
+%%raw("/* @generated */")
+module Types = {
+ @@warning("-30")
+
+ type rec response_loggedInUser_TestAliasedFragments_userFirstName = {
+ fragmentRefs: RescriptRelay.fragmentRefs<[ | #TestAliasedFragments_userFirstName]>,
+ }
+ and response_loggedInUser_TestAliasedFragments_userLastName = {
+ fragmentRefs: RescriptRelay.fragmentRefs<[ | #TestAliasedFragments_userLastName]>,
+ }
+ and response_loggedInUser = {
+ @as("TestAliasedFragments_userFirstName") testAliasedFragments_userFirstName: response_loggedInUser_TestAliasedFragments_userFirstName,
+ @as("TestAliasedFragments_userLastName") testAliasedFragments_userLastName: option,
+ }
+ type response = {
+ loggedInUser: response_loggedInUser,
+ }
+ @live
+ type rawResponse = response
+ @live
+ type variables = {
+ skipThing: bool,
+ }
+ @live
+ type refetchVariables = {
+ skipThing: option,
+ }
+ @live let makeRefetchVariables = (
+ ~skipThing=?,
+ ): refetchVariables => {
+ skipThing: skipThing
+ }
+
+}
+
+
+type queryRef
+
+module Internal = {
+ @live
+ let variablesConverter: Js.Dict.t>> = %raw(
+ json`{}`
+ )
+ @live
+ let variablesConverterMap = ()
+ @live
+ let convertVariables = v => v->RescriptRelay.convertObj(
+ variablesConverter,
+ variablesConverterMap,
+ Js.undefined
+ )
+ @live
+ type wrapResponseRaw
+ @live
+ let wrapResponseConverter: Js.Dict.t>> = %raw(
+ json`{"__root":{"loggedInUser_TestAliasedFragments_userLastName":{"f":""},"loggedInUser_TestAliasedFragments_userFirstName":{"f":""}}}`
+ )
+ @live
+ let wrapResponseConverterMap = ()
+ @live
+ let convertWrapResponse = v => v->RescriptRelay.convertObj(
+ wrapResponseConverter,
+ wrapResponseConverterMap,
+ Js.null
+ )
+ @live
+ type responseRaw
+ @live
+ let responseConverter: Js.Dict.t>> = %raw(
+ json`{"__root":{"loggedInUser_TestAliasedFragments_userLastName":{"f":""},"loggedInUser_TestAliasedFragments_userFirstName":{"f":""}}}`
+ )
+ @live
+ let responseConverterMap = ()
+ @live
+ let convertResponse = v => v->RescriptRelay.convertObj(
+ responseConverter,
+ responseConverterMap,
+ Js.undefined
+ )
+ type wrapRawResponseRaw = wrapResponseRaw
+ @live
+ let convertWrapRawResponse = convertWrapResponse
+ type rawResponseRaw = responseRaw
+ @live
+ let convertRawResponse = convertResponse
+ type rawPreloadToken<'response> = {source: Js.Nullable.t>}
+ external tokenToRaw: queryRef => rawPreloadToken = "%identity"
+}
+module Utils = {
+ @@warning("-33")
+ open Types
+}
+
+type relayOperationNode
+type operationType = RescriptRelay.queryNode
+
+
+let node: operationType = %raw(json` (function(){
+var v0 = [
+ {
+ "defaultValue": null,
+ "kind": "LocalArgument",
+ "name": "skipThing"
+ }
+];
+return {
+ "fragment": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Fragment",
+ "metadata": null,
+ "name": "TestAliasedFragmentsQuery",
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "concreteType": "User",
+ "kind": "LinkedField",
+ "name": "loggedInUser",
+ "plural": false,
+ "selections": [
+ {
+ "fragment": {
+ "args": null,
+ "kind": "FragmentSpread",
+ "name": "TestAliasedFragments_userFirstName"
+ },
+ "kind": "AliasedFragmentSpread",
+ "name": "TestAliasedFragments_userFirstName",
+ "type": "User",
+ "abstractKey": null
+ },
+ {
+ "condition": "skipThing",
+ "kind": "Condition",
+ "passingValue": false,
+ "selections": [
+ {
+ "fragment": {
+ "args": null,
+ "kind": "FragmentSpread",
+ "name": "TestAliasedFragments_userLastName"
+ },
+ "kind": "AliasedFragmentSpread",
+ "name": "TestAliasedFragments_userLastName",
+ "type": "User",
+ "abstractKey": null
+ }
+ ]
+ }
+ ],
+ "storageKey": null
+ }
+ ],
+ "type": "Query",
+ "abstractKey": null
+ },
+ "kind": "Request",
+ "operation": {
+ "argumentDefinitions": (v0/*: any*/),
+ "kind": "Operation",
+ "name": "TestAliasedFragmentsQuery",
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "concreteType": "User",
+ "kind": "LinkedField",
+ "name": "loggedInUser",
+ "plural": false,
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "firstName",
+ "storageKey": null
+ },
+ {
+ "condition": "skipThing",
+ "kind": "Condition",
+ "passingValue": false,
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "lastName",
+ "storageKey": null
+ }
+ ]
+ },
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "id",
+ "storageKey": null
+ }
+ ],
+ "storageKey": null
+ }
+ ]
+ },
+ "params": {
+ "cacheID": "7904bbabe4aaf72255a7e48d9de20bab",
+ "id": null,
+ "metadata": {},
+ "name": "TestAliasedFragmentsQuery",
+ "operationKind": "query",
+ "text": "query TestAliasedFragmentsQuery(\n $skipThing: Boolean!\n) {\n loggedInUser {\n ...TestAliasedFragments_userFirstName\n ...TestAliasedFragments_userLastName @skip(if: $skipThing)\n id\n }\n}\n\nfragment TestAliasedFragments_userFirstName on User {\n firstName\n}\n\nfragment TestAliasedFragments_userLastName on User {\n lastName\n}\n"
+ }
+};
+})() `)
+
+@live let load: (
+ ~environment: RescriptRelay.Environment.t,
+ ~variables: Types.variables,
+ ~fetchPolicy: RescriptRelay.fetchPolicy=?,
+ ~fetchKey: string=?,
+ ~networkCacheConfig: RescriptRelay.cacheConfig=?,
+) => queryRef = (
+ ~environment,
+ ~variables,
+ ~fetchPolicy=?,
+ ~fetchKey=?,
+ ~networkCacheConfig=?,
+) =>
+ RescriptRelay.loadQuery(
+ environment,
+ node,
+ variables->Internal.convertVariables,
+ {
+ fetchKey,
+ fetchPolicy,
+ networkCacheConfig,
+ },
+ )
+
+@live
+let queryRefToObservable = token => {
+ let raw = token->Internal.tokenToRaw
+ raw.source->Js.Nullable.toOption
+}
+
+@live
+let queryRefToPromise = token => {
+ Js.Promise.make((~resolve, ~reject as _) => {
+ switch token->queryRefToObservable {
+ | None => resolve(Error())
+ | Some(o) =>
+ open RescriptRelay.Observable
+ let _: subscription = o->subscribe(makeObserver(~complete=() => resolve(Ok())))
+ }
+ })
+}
diff --git a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.res
new file mode 100644
index 00000000..5b59184c
--- /dev/null
+++ b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userFirstName_graphql.res
@@ -0,0 +1,60 @@
+/* @sourceLoc Test_aliasedFragments.res */
+/* @generated */
+%%raw("/* @generated */")
+module Types = {
+ @@warning("-30")
+
+ type fragment = {
+ firstName: string,
+ }
+}
+
+module Internal = {
+ @live
+ type fragmentRaw
+ @live
+ let fragmentConverter: Js.Dict.t>> = %raw(
+ json`{}`
+ )
+ @live
+ let fragmentConverterMap = ()
+ @live
+ let convertFragment = v => v->RescriptRelay.convertObj(
+ fragmentConverter,
+ fragmentConverterMap,
+ Js.undefined
+ )
+}
+
+type t
+type fragmentRef
+external getFragmentRef:
+ RescriptRelay.fragmentRefs<[> | #TestAliasedFragments_userFirstName]> => fragmentRef = "%identity"
+
+module Utils = {
+ @@warning("-33")
+ open Types
+}
+
+type relayOperationNode
+type operationType = RescriptRelay.fragmentNode
+
+
+let node: operationType = %raw(json` {
+ "argumentDefinitions": [],
+ "kind": "Fragment",
+ "metadata": null,
+ "name": "TestAliasedFragments_userFirstName",
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "firstName",
+ "storageKey": null
+ }
+ ],
+ "type": "User",
+ "abstractKey": null
+} `)
+
diff --git a/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userLastName_graphql.res b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userLastName_graphql.res
new file mode 100644
index 00000000..8d10772f
--- /dev/null
+++ b/packages/rescript-relay/__tests__/__generated__/TestAliasedFragments_userLastName_graphql.res
@@ -0,0 +1,60 @@
+/* @sourceLoc Test_aliasedFragments.res */
+/* @generated */
+%%raw("/* @generated */")
+module Types = {
+ @@warning("-30")
+
+ type fragment = {
+ lastName: string,
+ }
+}
+
+module Internal = {
+ @live
+ type fragmentRaw
+ @live
+ let fragmentConverter: Js.Dict.t>> = %raw(
+ json`{}`
+ )
+ @live
+ let fragmentConverterMap = ()
+ @live
+ let convertFragment = v => v->RescriptRelay.convertObj(
+ fragmentConverter,
+ fragmentConverterMap,
+ Js.undefined
+ )
+}
+
+type t
+type fragmentRef
+external getFragmentRef:
+ RescriptRelay.fragmentRefs<[> | #TestAliasedFragments_userLastName]> => fragmentRef = "%identity"
+
+module Utils = {
+ @@warning("-33")
+ open Types
+}
+
+type relayOperationNode
+type operationType = RescriptRelay.fragmentNode
+
+
+let node: operationType = %raw(json` {
+ "argumentDefinitions": [],
+ "kind": "Fragment",
+ "metadata": null,
+ "name": "TestAliasedFragments_userLastName",
+ "selections": [
+ {
+ "alias": null,
+ "args": null,
+ "kind": "ScalarField",
+ "name": "lastName",
+ "storageKey": null
+ }
+ ],
+ "type": "User",
+ "abstractKey": null
+} `)
+
diff --git a/packages/rescript-relay/relay.config.js b/packages/rescript-relay/relay.config.js
index 1b126ecd..c3d9e205 100644
--- a/packages/rescript-relay/relay.config.js
+++ b/packages/rescript-relay/relay.config.js
@@ -15,6 +15,9 @@ module.exports = {
},
featureFlags: {
enable_relay_resolver_transform: true,
+ enable_fragment_aliases: {
+ kind: "enabled",
+ },
},
persistConfig: PERSISTING
? {