// Copyright 2023 The Matrix.org Foundation C.I.C. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import { AnyVariables, CombinedError, OperationContext } from "@urql/core"; import { atom, WritableAtom } from "jotai"; import { useHydrateAtoms } from "jotai/utils"; import { AtomWithQuery, atomWithQuery, clientAtom } from "jotai-urql"; import type { ReactElement } from "react"; import { graphql } from "./gql"; import { client } from "./graphql"; import { err, ok, Result } from "./result"; export type GqlResult = Result; export type GqlAtom = WritableAtom< Promise>, [context?: Partial], void >; /** * Map the result of a query atom to a new value, making it a GqlResult * * @param queryAtom: An atom got from atomWithQuery * @param mapper: A function that takes the data from the query and returns a new value */ export const mapQueryAtom = ( queryAtom: AtomWithQuery, mapper: (data: Data) => NewData ): GqlAtom => { return atom( async (get): Promise> => { const result = await get(queryAtom); if (result.error) { return err(result.error); } if (result.data === undefined) { throw new Error("Query result is undefined"); } return ok(mapper(result.data)); }, (_get, set, context) => { set(queryAtom, context); } ); }; export const HydrateAtoms: React.FC<{ children: ReactElement }> = ({ children, }) => { useHydrateAtoms([[clientAtom, client]]); return children; }; const CURRENT_VIEWER_QUERY = graphql(/* GraphQL */ ` query CurrentViewerQuery { viewer { __typename ... on User { id } ... on Anonymous { id } } } `); const currentViewerAtom = atomWithQuery({ query: CURRENT_VIEWER_QUERY }); export const currentUserIdAtom: GqlAtom = mapQueryAtom( currentViewerAtom, (data) => { if (data.viewer.__typename === "User") { return data.viewer.id; } return null; } ); const CURRENT_VIEWER_SESSION_QUERY = graphql(/* GraphQL */ ` query CurrentViewerSessionQuery { viewerSession { __typename ... on BrowserSession { id } ... on Anonymous { id } } } `); const currentViewerSessionAtom = atomWithQuery({ query: CURRENT_VIEWER_SESSION_QUERY, }); export const currentBrowserSessionIdAtom: GqlAtom = mapQueryAtom( currentViewerSessionAtom, (data) => { if (data.viewerSession.__typename === "BrowserSession") { return data.viewerSession.id; } return null; } );