Merge pull request #1 from alloy/voxmatt-relay-modern

[WIP] More work on Relay Modern typings.
This commit is contained in:
Matt Martin
2017-10-17 09:26:14 -07:00
committed by GitHub
12 changed files with 472 additions and 723 deletions
@@ -1,5 +1,5 @@
import * as React from 'react';
import { RelayCommonTypes } from 'relay-runtime';
import * as React from "react";
import { RelayCommonTypes } from "relay-runtime";
// ~~~~~~~~~~~~~~~~~~~~~
// Maybe Fix
@@ -7,7 +7,11 @@ import { RelayCommonTypes } from 'relay-runtime';
export type StoreReaderData = any;
export type StoreReaderOptions = any;
export type RelayStoreData = any;
export interface RelayQuery { Fragment: any; Node: any; Root: any; }
export interface RelayQuery {
Fragment: any;
Node: any;
Root: any;
}
// ~~~~~~~~~~~~~~~~~~~~~
// Environment
@@ -16,33 +20,27 @@ export interface FragmentResolver {
dispose(): void;
resolve(
fragment: RelayQuery["Fragment"],
dataIDs: RelayCommonTypes.DataID | RelayCommonTypes.DataID[],
dataIDs: RelayCommonTypes.DataID | RelayCommonTypes.DataID[]
): StoreReaderData | StoreReaderData[] | undefined | null;
}
export interface RelayEnvironmentInterface {
forceFetch(
querySet: RelayCommonTypes.RelayQuerySet,
onReadyStateChange: RelayCommonTypes.ReadyStateChangeCallback,
onReadyStateChange: RelayCommonTypes.ReadyStateChangeCallback
): RelayCommonTypes.Abortable;
getFragmentResolver(
fragment: RelayQuery["Fragment"],
onNext: () => void,
): FragmentResolver;
getFragmentResolver(fragment: RelayQuery["Fragment"], onNext: () => void): FragmentResolver;
getStoreData(): RelayStoreData;
primeCache(
querySet: RelayCommonTypes.RelayQuerySet,
onReadyStateChange: RelayCommonTypes.ReadyStateChangeCallback,
onReadyStateChange: RelayCommonTypes.ReadyStateChangeCallback
): RelayCommonTypes.Abortable;
read(
node: RelayQuery["Node"],
dataID: RelayCommonTypes.DataID,
options?: StoreReaderOptions,
options?: StoreReaderOptions
): StoreReaderData | void;
readQuery(
root: RelayQuery["Root"],
options?: StoreReaderOptions,
): StoreReaderData[] | void;
readQuery(root: RelayQuery["Root"], options?: StoreReaderOptions): StoreReaderData[] | void;
}
// ~~~~~~~~~~~~~~~~~~~~~
@@ -75,12 +73,12 @@ export interface RelayQueryRequestResolve {
}
export type RelayMutationStatus =
'UNCOMMITTED' | // Transaction hasn't yet been sent to the server. Transaction can be committed or rolled back.
'COMMIT_QUEUED' | // Transaction was committed but another transaction with the same collision key is pending, so the transaction has been queued to send to the server.
'COLLISION_COMMIT_FAILED' | // Transaction was queued for commit but another transaction with the same collision key failed. All transactions in the collision queue,
| "UNCOMMITTED" // Transaction hasn't yet been sent to the server. Transaction can be committed or rolled back.
| "COMMIT_QUEUED" // Transaction was committed but another transaction with the same collision key is pending, so the transaction has been queued to send to the server.
| "COLLISION_COMMIT_FAILED" // Transaction was queued for commit but another transaction with the same collision key failed. All transactions in the collision queue,
// including this one, have been failed. Transaction can be recommitted or rolled back.
'COMMITTING' | // Transaction is waiting for the server to respond.
'COMMIT_FAILED';
| "COMMITTING" // Transaction is waiting for the server to respond.
| "COMMIT_FAILED";
export class RelayMutationTransaction {
applyOptimistic(): RelayMutationTransaction;
@@ -118,13 +116,16 @@ export class DefaultNetworkLayer implements RelayNetworkLayer {
supports(...options: string[]): boolean;
}
export function createContainer<T>(component: React.ComponentClass<T> | React.StatelessComponent<T>, params?: CreateContainerOpts): RelayContainerClass<T>;
export function createContainer<T>(
component: React.ComponentClass<T> | React.StatelessComponent<T>,
params?: CreateContainerOpts
): RelayContainerClass<T>;
export function injectNetworkLayer(networkLayer: RelayNetworkLayer): any;
export function isContainer(component: React.ComponentClass<any>): boolean;
export function QL(...args: any[]): string;
export class Route {
constructor(params?: RelayVariables)
constructor(params?: RelayVariables);
}
/**
@@ -155,7 +156,7 @@ export interface Store {
export const Store: Store;
export class RootContainer extends React.Component<RootContainerProps, any> { }
export class RootContainer extends React.Component<RootContainerProps, any> {}
export interface RootContainerProps extends React.Props<RootContainer> {
Component: RelayContainerClass<any>;
@@ -165,13 +166,13 @@ export interface RootContainerProps extends React.Props<RootContainer> {
renderFailure?(error: Error, retry: (...args: any[]) => any): JSX.Element;
}
export class Renderer extends React.Component<RendererProps, any> { }
export class Renderer extends React.Component<RendererProps, any> {}
export interface RendererProps {
Container: RelayContainerClass<any>; // Relay container that defines fragments and the view to render.
forceFetch?: boolean; // Whether to send a server request regardless of data available on the client.
queryConfig: Route; // `QueryConfig` or `Relay.Route` that defines the query roots.
environment: Store; // An instance of `Relay.Environment` or any object that implements the `RelayEnvironment` interface.
environment: Store; // An instance of `Relay.Environment` or any object that implements the `RelayEnvironment` interface.
render?: RenderCallback; // Called to render when data requirements are being fulfilled.
onReadyStateChange?: OnReadyStateChange;
}
@@ -186,28 +187,30 @@ export interface RenderStateConfig {
export type RenderCallback = (renderState: RenderStateConfig) => any;
export type ReadyStateEvent =
'ABORT' |
'CACHE_RESTORED_REQUIRED' |
'CACHE_RESTORE_FAILED' |
'CACHE_RESTORE_START' |
'NETWORK_QUERY_ERROR' |
'NETWORK_QUERY_RECEIVED_ALL' |
'NETWORK_QUERY_RECEIVED_REQUIRED' |
'NETWORK_QUERY_START' |
'STORE_FOUND_ALL' |
'STORE_FOUND_REQUIRED';
| "ABORT"
| "CACHE_RESTORED_REQUIRED"
| "CACHE_RESTORE_FAILED"
| "CACHE_RESTORE_START"
| "NETWORK_QUERY_ERROR"
| "NETWORK_QUERY_RECEIVED_ALL"
| "NETWORK_QUERY_RECEIVED_REQUIRED"
| "NETWORK_QUERY_START"
| "STORE_FOUND_ALL"
| "STORE_FOUND_REQUIRED";
export type OnReadyStateChange = (readyState: {
ready: boolean,
done: boolean,
stale: boolean,
error?: Error,
events: ReadyStateEvent[],
aborted: boolean
}) => void;
export type OnReadyStateChange = (
readyState: {
ready: boolean;
done: boolean;
stale: boolean;
error?: Error;
events: ReadyStateEvent[];
aborted: boolean;
}
) => void;
export interface RelayProp {
readonly route: { name: string; }; // incomplete, also has params and queries
readonly route: { name: string }; // incomplete, also has params and queries
readonly variables: any;
readonly pendingVariables?: any;
setVariables(variables: any, onReadyStateChange?: OnReadyStateChange): void;
@@ -1,6 +1,6 @@
import { RelayRuntimeTypes, RelayCommonTypes } from 'relay-runtime';
import { RelayEnvironmentInterface } from './react-relay-classic';
import {} from './react-relay-modern';
import { RelayRuntimeTypes, RelayCommonTypes } from "relay-runtime";
import { RelayEnvironmentInterface } from "react-relay/classic";
import {} from "react-relay/modern";
// ~~~~~~~~~~~~~~~~~~~~~
// Maybe Fix
@@ -34,20 +34,22 @@ export type CompatEnvironment = RelayRuntimeTypes.Environment | RelayClassicEnvi
// ~~~~~~~~~~~~~~~~~~~~~
export function commitUpdate(
environment: CompatEnvironment,
config: RelayRuntimeTypes.MutationConfig<any>,
config: RelayRuntimeTypes.MutationConfig<any>
): RelayCommonTypes.Disposable;
export function applyUpdate(
environment: CompatEnvironment,
config: RelayRuntimeTypes.OptimisticMutationConfig,
config: RelayRuntimeTypes.OptimisticMutationConfig
): RelayCommonTypes.Disposable;
// ~~~~~~~~~~~~~~~~~~~~~
// RelayCompatContainer
// ~~~~~~~~~~~~~~~~~~~~~
export interface GeneratedNodeMap { [key: string]: RelayCommonTypes.GraphQLTaggedNode; }
export interface GeneratedNodeMap {
[key: string]: RelayCommonTypes.GraphQLTaggedNode;
}
export function createContainer<T>(
Component: ReactBaseComponent<T>,
fragmentSpec: RelayCommonTypes.GraphQLTaggedNode | GeneratedNodeMap,
fragmentSpec: RelayCommonTypes.GraphQLTaggedNode | GeneratedNodeMap
): ReactFragmentComponent<T>;
// ~~~~~~~~~~~~~~~~~~~~~
+20 -155
View File
@@ -1,160 +1,25 @@
// Type definitions for react-relay 0.9.2
// Type definitions for react-relay 1.3
// Project: https://github.com/facebook/relay
// Definitions by: Johannes Schickling <https://github.com/graphcool>
// Matt Martin <https://github.com/voxmatt>
// Eloy Durán <https://github.com/alloy>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.3
// TypeScript Version: 2.4
declare module "react-relay" {
import * as React from "react";
import { RelayRuntimeTypes } from "relay-runtime";
import * as ReactRelayModernTypes from "react-relay/modern";
type ClientMutationID = string;
/** Fragments are a hash of functions */
interface Fragments {
[query: string]: ((variables?: RelayVariables) => string)
}
interface CreateContainerOpts {
initialVariables?: any
fragments: Fragments
prepareVariables?(prevVariables: RelayVariables): RelayVariables
}
interface RelayVariables {
[name: string]: any
}
/** add static getFragment method to the component constructor */
interface RelayContainerClass<T> extends React.ComponentClass<T> {
getFragment: ((q: string, v?: RelayVariables) => string)
}
interface RelayQueryRequestResolve {
response: any
}
type RelayMutationStatus =
'UNCOMMITTED' | // Transaction hasn't yet been sent to the server. Transaction can be committed or rolled back.
'COMMIT_QUEUED' | // Transaction was committed but another transaction with the same collision key is pending, so the transaction has been queued to send to the server.
'COLLISION_COMMIT_FAILED' | //Transaction was queued for commit but another transaction with the same collision key failed. All transactions in the collision queue, including this one, have been failed. Transaction can be recommitted or rolled back.
'COMMITTING' | // Transaction is waiting for the server to respond.
'COMMIT_FAILED';
class RelayMutationTransaction {
applyOptimistic(): RelayMutationTransaction;
commit(): RelayMutationTransaction | null;
recommit(): void;
rollback(): void;
getError(): Error;
getStatus(): RelayMutationStatus;
getHash(): string;
getID(): ClientMutationID;
}
interface RelayMutationRequest {
getQueryString(): string
getVariables(): RelayVariables
resolve(result: RelayQueryRequestResolve): any
reject(errors: any): any
}
interface RelayQueryRequest {
resolve(result: RelayQueryRequestResolve): any
reject(errors: any): any
getQueryString(): string
getVariables(): RelayVariables
getID(): string
getDebugName(): string
}
interface RelayNetworkLayer {
supports(...options: string[]): boolean
}
class DefaultNetworkLayer implements RelayNetworkLayer {
constructor(host: string, options?: any)
supports(...options: string[]): boolean
}
function createContainer<T>(component: React.ComponentClass<T> | React.StatelessComponent<T>, params?: CreateContainerOpts): RelayContainerClass<T>
function injectNetworkLayer(networkLayer: RelayNetworkLayer): any
function isContainer(component: React.ComponentClass<any>): boolean
function QL(...args: any[]): string
class Route {
constructor(params?: RelayVariables)
}
/**
* Relay Mutation class, where T are the props it takes and S is the returned payload from Relay.Store.update.
* S is typically dynamic as it depends on the data the app is currently using, but it's possible to always
* return some data in the payload using REQUIRED_CHILDREN which is where specifying S is the most useful.
*/
class Mutation<T,S> {
props: T
constructor(props: T)
static getFragment(q: string): string
}
interface Transaction {
getError(): Error
Status(): number
}
interface StoreUpdateCallbacks<T> {
onFailure?(transaction: Transaction): any
onSuccess?(response: T): any
}
interface Store {
commitUpdate(mutation: Mutation<any,any>, callbacks?: StoreUpdateCallbacks<any>): any
}
var Store: Store
class RootContainer extends React.Component<RootContainerProps,any> {}
interface RootContainerProps extends React.Props<RootContainer>{
Component: RelayContainerClass<any>
route: Route
renderLoading?(): JSX.Element
renderFetched?(data: any): JSX.Element
renderFailure?(error: Error, retry: Function): JSX.Element
}
type ReadyStateEvent =
'ABORT' |
'CACHE_RESTORED_REQUIRED' |
'CACHE_RESTORE_FAILED' |
'CACHE_RESTORE_START' |
'NETWORK_QUERY_ERROR' |
'NETWORK_QUERY_RECEIVED_ALL' |
'NETWORK_QUERY_RECEIVED_REQUIRED' |
'NETWORK_QUERY_START' |
'STORE_FOUND_ALL' |
'STORE_FOUND_REQUIRED';
interface OnReadyStateChange {
(readyState: {
ready: boolean,
done: boolean,
stale: boolean,
error?: Error,
events: Array<ReadyStateEvent>,
aborted: boolean
}): void
}
interface RelayProp {
readonly route: { name: string; }; // incomplete, also has params and queries
readonly variables: any;
readonly pendingVariables?: any | null;
setVariables(variables: any, onReadyStateChange?: OnReadyStateChange): void;
forceFetch(variables: any, onReadyStateChange?: OnReadyStateChange): void;
hasOptimisticUpdate(record: any): boolean;
getPendingTransactions(record: any): RelayMutationTransaction[];
commitUpdate: (mutation: Mutation<any,any>, callbacks?: StoreUpdateCallbacks<any>) => any;
}
}
// ~~~~~~~~~~~~~~~~~~~~~
// React-Relay Modern
// ~~~~~~~~~~~~~~~~~~~~~
export import QueryRenderer = ReactRelayModernTypes.ReactRelayQueryRenderer;
export import createFragmentContainer = ReactRelayModernTypes.createFragmentContainer;
export import createPaginationContainer = ReactRelayModernTypes.createPaginationContainer;
export import createRefetchContainer = ReactRelayModernTypes.createRefetchContainer;
export import graphql = ReactRelayModernTypes.graphql;
export import commitLocalUpdate = RelayRuntimeTypes.commitLocalUpdate;
export import commitMutation = RelayRuntimeTypes.commitRelayModernMutation;
export import fetchQuery = RelayRuntimeTypes.fetchRelayModernQuery;
export import requestSubscription = RelayRuntimeTypes.requestRelaySubscription;
// exported for convenience
export import ModernTypes = ReactRelayModernTypes;
@@ -1,5 +1,5 @@
import * as React from 'react';
import { RelayCommonTypes, RelayRuntimeTypes } from 'relay-runtime';
import * as React from "react";
import { RelayCommonTypes, RelayRuntimeTypes } from "relay-runtime";
// ~~~~~~~~~~~~~~~~~~~~~
// Maybe Fix
@@ -21,23 +21,20 @@ export interface RelayProp {
// ~~~~~~~~~~~~~~~~~~~~~
// RelayQL
// ~~~~~~~~~~~~~~~~~~~~~
export function RelayQL(
strings: string[],
...substitutions: any[]
): RelayCommonTypes.RelayConcreteNode;
export function RelayQL(strings: string[], ...substitutions: any[]): RelayCommonTypes.RelayConcreteNode;
// ~~~~~~~~~~~~~~~~~~~~~
// RelayModernGraphQLTag
// ~~~~~~~~~~~~~~~~~~~~~
export interface GeneratedNodeMap { [key: string]: GraphQLTaggedNode; }
export interface GeneratedNodeMap {
[key: string]: GraphQLTaggedNode;
}
export type GraphQLTaggedNode =
(() => ConcreteFragment | ConcreteBatch)
| (() => ConcreteFragment | ConcreteBatch)
| {
modern(): ConcreteFragment | ConcreteBatch,
classic(relayQL: typeof RelayQL):
| ConcreteFragmentDefinition
| ConcreteOperationDefinition,
};
modern(): ConcreteFragment | ConcreteBatch;
classic(relayQL: typeof RelayQL): ConcreteFragmentDefinition | ConcreteOperationDefinition;
};
/**
* Runtime function to correspond to the `graphql` tagged template function.
* All calls to this function should be transformed by the plugin.
@@ -67,14 +64,14 @@ export interface ReadyState {
export interface QueryRendererState {
readyState: ReadyState;
}
export class ReactRelayQueryRenderer extends React.Component<QueryRendererProps, QueryRendererState> { }
export class ReactRelayQueryRenderer extends React.Component<QueryRendererProps, QueryRendererState> {}
// ~~~~~~~~~~~~~~~~~~~~~
// createFragmentContainer
// ~~~~~~~~~~~~~~~~~~~~~
export function createFragmentContainer<T>(
Component: ReactBaseComponent<T>,
fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap,
fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap
): ReactBaseComponent<T>;
// ~~~~~~~~~~~~~~~~~~~~~
@@ -91,38 +88,38 @@ export interface ConnectionData {
pageInfo?: PageInfo;
}
export type RelayPaginationProp = RelayProp & {
hasMore(): boolean,
isLoading(): boolean,
hasMore(): boolean;
isLoading(): boolean;
loadMore(
pageSize: number,
callback: (error?: Error) => void,
options?: RefetchOptions,
): RelayCommonTypes.Disposable | undefined | null,
options?: RefetchOptions
): RelayCommonTypes.Disposable | undefined | null;
refetchConnection(
totalCount: number,
callback: (error?: Error) => void,
refetchVariables?: RelayCommonTypes.Variables,
): RelayCommonTypes.Disposable | undefined | null,
refetchVariables?: RelayCommonTypes.Variables
): RelayCommonTypes.Disposable | undefined | null;
};
export function FragmentVariablesGetter(
prevVars: RelayCommonTypes.Variables,
totalCount: number,
totalCount: number
): RelayCommonTypes.Variables;
export interface ConnectionConfig {
direction?: 'backward' | 'forward';
getConnectionFromProps?(props: object): ConnectionData | undefined | null;
export interface ConnectionConfig<T> {
direction?: "backward" | "forward";
getConnectionFromProps?(props: T): ConnectionData | undefined | null;
getFragmentVariables?: typeof FragmentVariablesGetter;
getVariables(
props: { [propName: string]: any },
paginationInfo: { count: number, cursor?: string },
fragmentVariables: RelayCommonTypes.Variables,
paginationInfo: { count: number; cursor?: string },
fragmentVariables: RelayCommonTypes.Variables
): RelayCommonTypes.Variables;
query: GraphQLTaggedNode;
}
export function createPaginationContainer<T>(
Component: ReactBaseComponent<T>,
fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap,
connectionConfig: ConnectionConfig,
connectionConfig: ConnectionConfig<T>
): ReactBaseComponent<T>;
// ~~~~~~~~~~~~~~~~~~~~~
@@ -134,14 +131,16 @@ export interface RefetchOptions {
}
export type RelayRefetchProp = RelayProp & {
refetch(
refetchVariables: RelayCommonTypes.Variables | ((fragmentVariables: RelayCommonTypes.Variables) => RelayCommonTypes.Variables),
refetchVariables:
| RelayCommonTypes.Variables
| ((fragmentVariables: RelayCommonTypes.Variables) => RelayCommonTypes.Variables),
renderVariables?: RelayCommonTypes.Variables,
callback?: (error?: Error) => void,
options?: RefetchOptions,
): RelayCommonTypes.Disposable,
options?: RefetchOptions
): RelayCommonTypes.Disposable;
};
export function createRefetchContainer<T>(
Component: ReactBaseComponent<T>,
fragmentSpec: GraphQLTaggedNode | GeneratedNodeMap,
taggedNode: GraphQLTaggedNode,
taggedNode: GraphQLTaggedNode
): ReactBaseComponent<T>;
@@ -1,61 +1,58 @@
import * as React from "react"
import * as Relay from "react-relay"
import * as React from "react";
import * as Relay from "react-relay/classic";
interface Props {
text: string
userId: string
text: string;
userId: string;
}
interface Response {
}
// tslint:disable-next-line no-empty-interface
interface Response {}
export default class AddTweetMutation extends Relay.Mutation<Props, Response> {
getMutation () {
return Relay.QL`mutation{addTweet}`
getMutation() {
return Relay.QL`mutation{addTweet}`;
}
getFatQuery () {
getFatQuery() {
return Relay.QL`
fragment on AddTweetPayload {
tweetEdge
user
}
`
`;
}
getConfigs () {
return [{
type: "RANGE_ADD",
parentName: "user",
parentID: this.props.userId,
connectionName: "tweets",
edgeName: "tweetEdge",
rangeBehaviors: {
"": "append",
getConfigs() {
return [
{
type: "RANGE_ADD",
parentName: "user",
parentID: this.props.userId,
connectionName: "tweets",
edgeName: "tweetEdge",
rangeBehaviors: {
"": "append",
},
},
}]
];
}
getVariables () {
return this.props
getVariables() {
return this.props;
}
}
interface ArtworkProps {
artwork: {
title: string
},
relay: Relay.RelayProp,
title: string;
};
relay: Relay.RelayProp;
}
class Artwork extends React.Component<ArtworkProps> {
render() {
return (
<a href={`/artworks/${this.props.relay.variables.artworkID}`}>
{this.props.artwork.title}
</a>
)
return <a href={`/artworks/${this.props.relay.variables.artworkID}`}>{this.props.artwork.title}</a>;
}
}
@@ -65,9 +62,9 @@ const ArtworkContainer = Relay.createContainer(Artwork, {
fragment on Artwork {
title
}
`
}
})
`,
},
});
class StubbedArtwork extends React.Component {
render() {
@@ -75,7 +72,7 @@ class StubbedArtwork extends React.Component {
artwork: { title: "CHAMPAGNE FORMICA FLAG" },
relay: {
route: {
name: "champagne"
name: "champagne",
},
variables: {
artworkID: "champagne-formica-flag",
@@ -83,10 +80,10 @@ class StubbedArtwork extends React.Component {
setVariables: () => {},
forceFetch: () => {},
hasOptimisticUpdate: () => false,
getPendingTransactions: (): Relay.RelayMutationTransaction[] => undefined,
getPendingTransactions: (): Relay.RelayMutationTransaction[] => [],
commitUpdate: () => {},
}
}
return <ArtworkContainer {...props} />
},
};
return <ArtworkContainer {...props} />;
}
}
@@ -1,11 +1,5 @@
import * as React from "react";
import {
Environment,
Network,
RecordSource,
Store,
ConnectionHandler,
} from 'relay-runtime';
import { Environment, Network, RecordSource, Store, ConnectionHandler } from "relay-runtime";
////////////////////////////
// RELAY MODERN TESTS
@@ -25,7 +19,7 @@ import {
// Modern Environment
// ~~~~~~~~~~~~~~~~~~~~~
function fetchQuery(operation: any, variables: any, cacheConfig: {}) {
return fetch('/graphql');
return fetch("/graphql");
}
const network = Network.create(fetchQuery);
const source = new RecordSource();
@@ -35,28 +29,28 @@ const modernEnvironment = new Environment({ network, store });
// ~~~~~~~~~~~~~~~~~~~~~
// Modern QueryRenderer
// ~~~~~~~~~~~~~~~~~~~~~
const MyQueryRenderer = (props: { name: string}) => (
<QueryRenderer
environment={ modernEnvironment }
query={graphql`
query ExampleQuery($pageID: ID!) {
page(id: $pageID) {
name
}
}
`}
variables={{
pageID: '110798995619330',
}}
render={({error, props}) => {
if (error) {
return <div>{error.message}</div>;
} else if (props) {
return <div>{props.name} is great!</div>;
}
return <div>Loading</div>;
}}
/>
const MyQueryRenderer = (props: { name: string }) => (
<QueryRenderer
environment={modernEnvironment}
query={graphql`
query ExampleQuery($pageID: ID!) {
page(id: $pageID) {
name
}
}
`}
variables={{
pageID: "110798995619330",
}}
render={({ error, props }) => {
if (error) {
return <div>{error.message}</div>;
} else if (props) {
return <div>{props.name} is great!</div>;
}
return <div>Loading</div>;
}}
/>
);
// ~~~~~~~~~~~~~~~~~~~~~
@@ -65,14 +59,14 @@ const MyQueryRenderer = (props: { name: string}) => (
const MyFragmentContainer = createFragmentContainer(
class TodoListView extends React.Component {
render() {
return <div/>;
return <div />;
}
},
{
item: graphql`
fragment TodoItem_item on Todo {
text
isComplete
text
isComplete
}
`,
}
@@ -81,84 +75,75 @@ const MyFragmentContainer = createFragmentContainer(
// ~~~~~~~~~~~~~~~~~~~~~
// Modern RefetchContainer
// ~~~~~~~~~~~~~~~~~~~~~
interface StoryInterface { id: string; }
interface StoryInterface {
id: string;
}
interface FeedStoriesProps {
relay: ModernTypes.RelayRefetchProp;
feed: {
stories: { edges: Array<{ node: StoryInterface }> }
stories: { edges: Array<{ node: StoryInterface }> };
};
}
class Story extends React.Component<{ story: StoryInterface }> {}
class FeedStories extends React.Component<FeedStoriesProps> {
render() {
return (
<div>
{this.props.feed.stories.edges.map(
edge => <Story story={edge.node} key={edge.node.id} />
)}
<button
onClick={() => this._loadMore}
title="Load More"
/>
</div>
);
return (
<div>
{this.props.feed.stories.edges.map(edge => <Story story={edge.node} key={edge.node.id} />)}
<button onClick={() => this._loadMore} title="Load More" />
</div>
);
}
_loadMore() {
// Increments the number of stories being rendered by 10.
const refetchVariables = (fragmentVariables: {count: number }) => ({
count: fragmentVariables.count + 10,
});
this.props.relay.refetch(refetchVariables);
// Increments the number of stories being rendered by 10.
const refetchVariables = (fragmentVariables: { count: number }) => ({
count: fragmentVariables.count + 10,
});
this.props.relay.refetch(refetchVariables);
}
}
}
const FeedRefetchContainer = createRefetchContainer(
FeedStories,
{
feed: graphql.experimental`
fragment FeedStories_feed on Feed
@argumentDefinitions(
count: {type: "Int", defaultValue: 10}
) {
stories(first: $count) {
edges {
node {
id
...Story_story
}
feed: graphql.experimental`
fragment FeedStories_feed on Feed @argumentDefinitions(count: { type: "Int", defaultValue: 10 }) {
stories(first: $count) {
edges {
node {
id
...Story_story
}
}
}
}
}
}
`
`,
},
graphql.experimental`
query FeedStoriesRefetchQuery($count: Int) {
feed {
...FeedStories_feed @arguments(count: $count)
query FeedStoriesRefetchQuery($count: Int) {
feed {
...FeedStories_feed @arguments(count: $count)
}
}
}
`,
);
`
);
// ~~~~~~~~~~~~~~~~~~~~~
// Modern PaginationContainer
// ~~~~~~~~~~~~~~~~~~~~~
interface FeedProps {
user: { feed: { edges: Array<{ node: StoryInterface}>}};
user: { feed: { edges: Array<{ node: StoryInterface }> } };
relay: ModernTypes.RelayPaginationProp;
}
class Feed extends React.Component<FeedProps> {
render() {
return (<div>
{this.props.user.feed.edges.map(
edge => <Story story={edge.node} key={edge.node.id} />
)}
<button
onClick={() => this._loadMore()}
title="Load More"
/>
</div>);
return (
<div>
{this.props.user.feed.edges.map(edge => <Story story={edge.node} key={edge.node.id} />)}
<button onClick={() => this._loadMore()} title="Load More" />
</div>
);
}
_loadMore() {
@@ -170,7 +155,7 @@ class Feed extends React.Component<FeedProps> {
10, // Fetch the next 10 feed items
e => {
console.log(e);
},
}
);
}
}
@@ -179,25 +164,25 @@ const FeedPaginationContainer = createPaginationContainer(
Feed,
{
user: graphql`
fragment Feed_user on User {
feed(
first: $count
after: $cursor
orderby: $orderBy # other variables
) @connection(key: "Feed_feed") {
edges {
node {
id
...Story_story
fragment Feed_user on User {
feed(
first: $count
after: $cursor
orderby: $orderBy # other variables
) @connection(key: "Feed_feed") {
edges {
node {
id
...Story_story
}
}
}
}
}
}
`,
},
{
direction: 'forward',
getConnectionFromProps(props: { user: {feed: any}}) {
direction: "forward",
getConnectionFromProps(props) {
return props.user && props.user.feed;
},
getFragmentVariables(prevVars, totalCount) {
@@ -206,7 +191,7 @@ const FeedPaginationContainer = createPaginationContainer(
count: totalCount,
};
},
getVariables(props, {count, cursor}, fragmentVariables) {
getVariables(props, { count, cursor }, fragmentVariables) {
return {
count,
cursor,
@@ -216,17 +201,13 @@ const FeedPaginationContainer = createPaginationContainer(
};
},
query: graphql`
query FeedPaginationQuery(
$count: Int!
$cursor: String
$orderby: String!
) {
user {
# You could reference the fragment defined previously.
...Feed_user
query FeedPaginationQuery($count: Int!, $cursor: String, $orderby: String!) {
user {
# You could reference the fragment defined previously.
...Feed_user
}
}
}
`
`,
}
);
@@ -234,46 +215,52 @@ const FeedPaginationContainer = createPaginationContainer(
// Modern Mutations
// ~~~~~~~~~~~~~~~~~~~~~
const mutation = graphql`
mutation MarkReadNotificationMutation(
$input: MarkReadNotificationData!
) {
markReadNotification(data: $input) {
notification {
seenState
mutation MarkReadNotificationMutation($input: MarkReadNotificationData!) {
markReadNotification(data: $input) {
notification {
seenState
}
}
}
}
`;
const optimisticResponse = {
markReadNotification: {
notification: {
seenState: 'SEEN',
seenState: "SEEN",
},
},
};
const configs = [{
type: 'NODE_DELETE' as 'NODE_DELETE',
deletedIDFieldName: 'destroyedShipId',
}, {
type: 'RANGE_ADD' as 'RANGE_ADD',
parentID: 'shipId',
connectionInfo: [{
key: 'AddShip_ships',
rangeBehavior: 'append',
}],
edgeName: 'newShipEdge',
}, {
type: 'RANGE_DELETE' as 'RANGE_DELETE',
parentID: 'todoId',
connectionKeys: [{
key: 'RemoveTags_tags',
rangeBehavior: 'append',
}],
pathToConnection: ['todo', 'tags'],
deletedIDFieldName: 'removedTagId'
}];
const configs = [
{
type: "NODE_DELETE" as "NODE_DELETE",
deletedIDFieldName: "destroyedShipId",
},
{
type: "RANGE_ADD" as "RANGE_ADD",
parentID: "shipId",
connectionInfo: [
{
key: "AddShip_ships",
rangeBehavior: "append",
},
],
edgeName: "newShipEdge",
},
{
type: "RANGE_DELETE" as "RANGE_DELETE",
parentID: "todoId",
connectionKeys: [
{
key: "RemoveTags_tags",
rangeBehavior: "append",
},
],
pathToConnection: ["todo", "tags"],
deletedIDFieldName: "removedTagId",
},
];
function markNotificationAsRead(source: string, storyID: string) {
const variables = {
@@ -283,37 +270,38 @@ function markNotificationAsRead(source: string, storyID: string) {
},
};
commitMutation(
modernEnvironment,
{
configs,
mutation,
optimisticResponse,
variables,
onCompleted: (response, errors) => {
console.log('Response received from server.');
},
onError: err => console.error(err),
commitMutation(modernEnvironment, {
configs,
mutation,
optimisticResponse,
variables,
onCompleted: (response, errors) => {
console.log("Response received from server.");
},
);
onError: err => console.error(err),
updater: (store, data) => {
const field = store.get(storyID);
if (field) {
field.setValue(data.story, "story");
}
}
});
}
// ~~~~~~~~~~~~~~~~~~~~~
// Modern Subscriptions
// ~~~~~~~~~~~~~~~~~~~~~
const subscription = graphql`
subscription MarkReadNotificationSubscription(
$storyID: ID!
) {
markReadNotification(storyID: $storyID) {
notification {
seenState
subscription MarkReadNotificationSubscription($storyID: ID!) {
markReadNotification(storyID: $storyID) {
notification {
seenState
}
}
}
}
`;
const variables = {
storyID: '123',
storyID: "123",
};
requestSubscription(
modernEnvironment, // see Environment docs
@@ -326,18 +314,12 @@ requestSubscription(
// example of a custom updater
updater: store => {
// Get the notification
const rootField = store.getRootField('markReadNotification');
const notification = !!rootField && rootField.getLinkedRecord('notification');
const rootField = store.getRootField("markReadNotification");
const notification = !!rootField && rootField.getLinkedRecord("notification");
// Add it to a connection
const viewer = store.getRoot().getLinkedRecord('viewer');
const notifications =
ConnectionHandler.getConnection(viewer, 'notifications');
const edge = ConnectionHandler.createEdge(
store,
notifications,
notification,
'<TypeOfNotificationsEdge>',
);
const viewer = store.getRoot().getLinkedRecord("viewer");
const notifications = ConnectionHandler.getConnection(viewer, "notifications");
const edge = ConnectionHandler.createEdge(store, notifications, notification, "<TypeOfNotificationsEdge>");
ConnectionHandler.insertEdgeAfter(notifications, edge);
},
}
@@ -348,7 +330,7 @@ requestSubscription(
///////////////////////////
import {
QueryRenderer as CompatQueryRenderer,
createFragmentContainer as createFragmentContainerCompat
createFragmentContainer as createFragmentContainerCompat,
} from "react-relay/compat";
// TODO? This is all more or less identical to modern...
@@ -378,16 +360,18 @@ export default class AddTweetMutation extends Relay.Mutation<Props, {}> {
}
getConfigs() {
return [{
type: "RANGE_ADD",
parentName: "user",
parentID: this.props.userId,
connectionName: "tweets",
edgeName: "tweetEdge",
rangeBehaviors: {
"": "append",
return [
{
type: "RANGE_ADD",
parentName: "user",
parentID: this.props.userId,
connectionName: "tweets",
edgeName: "tweetEdge",
rangeBehaviors: {
"": "append",
},
},
}];
];
}
getVariables() {
@@ -397,18 +381,14 @@ export default class AddTweetMutation extends Relay.Mutation<Props, {}> {
interface ArtworkProps {
artwork: {
title: string
title: string;
};
relay: Relay.RelayProp;
}
class Artwork extends React.Component<ArtworkProps> {
render() {
return (
<a href={`/artworks/${this.props.relay.variables.artworkID}`}>
{this.props.artwork.title}
</a>
);
return <a href={`/artworks/${this.props.relay.variables.artworkID}`}>{this.props.artwork.title}</a>;
}
}
@@ -418,8 +398,8 @@ const ArtworkContainer = Relay.createContainer(Artwork, {
fragment on Artwork {
title
}
`
}
`,
},
});
class StubbedArtwork extends React.Component {
@@ -428,7 +408,7 @@ class StubbedArtwork extends React.Component {
artwork: { title: "CHAMPAGNE FORMICA FLAG" },
relay: {
route: {
name: "champagne"
name: "champagne",
},
variables: {
artworkID: "champagne-formica-flag",
@@ -438,7 +418,7 @@ class StubbedArtwork extends React.Component {
hasOptimisticUpdate: () => false,
getPendingTransactions: (): any => undefined,
commitUpdate: () => {},
}
},
};
return <ArtworkContainer {...props} />;
}
+7 -3
View File
@@ -7,7 +7,7 @@
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": false,
"strictNullChecks": true,
"baseUrl": "../",
"typeRoots": [
"../"
@@ -19,6 +19,10 @@
},
"files": [
"index.d.ts",
"react-relay-tests.tsx"
"classic.d.ts",
"modern.d.ts",
"compat.d.ts",
"test/react-relay-tests.tsx",
"test/react-relay-classic-tests.tsx"
]
}
}
-23
View File
@@ -1,23 +0,0 @@
// Type definitions for react-relay 1.3
// Project: https://github.com/facebook/relay
// Definitions by: Johannes Schickling <https://github.com/graphcool>, Matt Martin <https://github.com/voxmatt>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4
import { RelayRuntimeTypes } from 'relay-runtime';
import * as ReactRelayModernTypes from './lib/react-relay-modern';
// ~~~~~~~~~~~~~~~~~~~~~
// React-Relay Modern
// ~~~~~~~~~~~~~~~~~~~~~
export import QueryRenderer = ReactRelayModernTypes.ReactRelayQueryRenderer;
export import createFragmentContainer = ReactRelayModernTypes.createFragmentContainer;
export import createPaginationContainer = ReactRelayModernTypes.createPaginationContainer;
export import createRefetchContainer = ReactRelayModernTypes.createRefetchContainer;
export import graphql = ReactRelayModernTypes.graphql;
export import commitLocalUpdate = RelayRuntimeTypes.commitLocalUpdate;
export import commitMutation = RelayRuntimeTypes.commitRelayModernMutation;
export import fetchQuery = RelayRuntimeTypes.fetchRelayModernQuery;
export import requestSubscription = RelayRuntimeTypes.requestRelaySubscription;
// exported for convenience
export import ModernTypes = ReactRelayModernTypes;
-33
View File
@@ -1,33 +0,0 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6",
"dom"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": true,
"baseUrl": "../../",
"typeRoots": [
"../../"
],
"types": [],
"noEmit": true,
"forceConsistentCasingInFileNames": true,
"jsx": "react",
"paths": {
"react-relay": ["react-relay/v1"],
"react-relay/*": ["react-relay/v1/*"],
"react-relay/classic": ["react-relay/v1/classic.d"],
"react-relay/compat": ["react-relay/v1/compat.d"]
}
},
"files": [
"index.d.ts",
"react-relay-tests.tsx",
"lib/react-relay-classic.d.ts",
"lib/react-relay-modern.d.ts",
"lib/react-relay-compat.d.ts"
]
}
+145 -179
View File
@@ -1,6 +1,7 @@
// Type definitions for relay-runtime 1.3
// Project: https://github.com/facebook/relay
// Definitions by: Matt Martin <https://github.com/voxmatt>
// Eloy Durán <https://github.com/alloy>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.4
@@ -36,10 +37,7 @@ export namespace RelayCommonTypes {
// ~~~~~~~~~~~~~~~~~~~~~
// RelayQL
// ~~~~~~~~~~~~~~~~~~~~~
type RelayQL = (
strings: string[],
...substitutions: any[]
) => RelayConcreteNode;
type RelayQL = (strings: string[], ...substitutions: any[]) => RelayConcreteNode;
// ~~~~~~~~~~~~~~~~~~~~~
// RelayModernGraphQLTag
@@ -48,13 +46,11 @@ export namespace RelayCommonTypes {
[key: string]: GraphQLTaggedNode;
}
type GraphQLTaggedNode =
(() => ConcreteFragment | ConcreteBatch) |
{
modern(): ConcreteFragment | ConcreteBatch,
classic(relayQL: RelayQL):
| ConcreteFragmentDefinition
| ConcreteOperationDefinition,
};
| (() => ConcreteFragment | ConcreteBatch)
| {
modern(): ConcreteFragment | ConcreteBatch;
classic(relayQL: RelayQL): ConcreteFragmentDefinition | ConcreteOperationDefinition;
};
// ~~~~~~~~~~~~~~~~~~~~~
// General Usage
// ~~~~~~~~~~~~~~~~~~~~~
@@ -81,8 +77,8 @@ export namespace RelayCommonTypes {
interface PayloadError {
message: string;
locations?: Array<{
line: number,
column: number,
line: number;
column: number;
}>;
}
/**
@@ -94,8 +90,8 @@ export namespace RelayCommonTypes {
operation: ConcreteBatch,
variables: Variables,
cacheConfig: CacheConfig,
uploadables?: UploadableMap,
): Runtime.ObservableFromValue<QueryPayload>;
uploadables?: UploadableMap
): RelayRuntimeTypes.ObservableFromValue<QueryPayload>;
/**
* A function that executes a GraphQL subscription operation, returning one or
@@ -108,8 +104,8 @@ export namespace RelayCommonTypes {
operation: ConcreteBatch,
variables: Variables,
cacheConfig: CacheConfig,
observer: LegacyObserver<QueryPayload>,
) => Runtime.RelayObservable<QueryPayload> | Disposable;
observer: LegacyObserver<QueryPayload>
) => RelayRuntimeTypes.RelayObservable<QueryPayload> | Disposable;
// ~~~~~~~~~~~~~~~~~~~~~
// RelayStoreTypes
@@ -131,7 +127,7 @@ export namespace RelayCommonTypes {
store: RecordSourceSelectorProxy,
// Actually RelayCombinedEnvironmentTypes#SelectorData, but mixed is
// inconvenient to access deeply in product code.
data: any, // FLOW FIXME
data: any // FLOW FIXME
) => void;
/**
@@ -141,33 +137,25 @@ export namespace RelayCommonTypes {
interface RecordSourceSelectorProxy {
create(dataID: DataID, typeName: string): RecordProxy;
delete(dataID: DataID): void;
get(dataID: DataID): RecordProxy | void;
get(dataID: DataID): RecordProxy | null;
getRoot(): RecordProxy;
getRootField(fieldName: string): RecordProxy | void;
getPluralRootField(fieldName: string): RecordProxy[] | void;
getRootField(fieldName: string): RecordProxy | null;
getPluralRootField(fieldName: string): RecordProxy[] | null;
}
interface RecordProxy {
copyFieldsFrom(source: RecordProxy): void;
getDataID(): DataID;
getLinkedRecord(name: string, args?: Variables): RecordProxy | void;
getLinkedRecords(name: string, args?: Variables): Array<RecordProxy | null> | void;
getOrCreateLinkedRecord(
name: string,
typeName: string,
args?: Variables,
): RecordProxy;
getLinkedRecord(name: string, args?: Variables): RecordProxy | null;
getLinkedRecords(name: string, args?: Variables): Array<RecordProxy | null> | null;
getOrCreateLinkedRecord(name: string, typeName: string, args?: Variables): RecordProxy;
getType(): string;
getValue(name: string, args?: Variables): any;
setLinkedRecord(
record: RecordProxy,
name: string,
args?: Variables,
): RecordProxy;
setLinkedRecord(record: RecordProxy, name: string, args?: Variables): RecordProxy;
setLinkedRecords(
records: Array<RecordProxy | null> | undefined | null,
name: string,
args?: Variables,
args?: Variables
): RecordProxy;
setValue(value: any, name: string, args?: Variables): RecordProxy;
}
@@ -175,7 +163,7 @@ export namespace RelayCommonTypes {
interface RecordSourceProxy {
create(dataID: DataID, typeName: string): RecordProxy;
delete(dataID: DataID): void;
get(dataID: DataID): Array<RecordProxy | null> | void;
get(dataID: DataID): Array<RecordProxy | null> | null;
getRoot(): RecordProxy;
}
@@ -228,17 +216,23 @@ export namespace RelayCommonTypes {
/**
* Arbitrary data e.g. received by a container as props.
*/
interface Props { [key: string]: any; }
interface Props {
[key: string]: any;
}
/*
* An individual cached graph object.
*/
interface Record { [key: string]: any; }
interface Record {
[key: string]: any;
}
/**
* A collection of records keyed by id.
*/
interface RecordMap { [dataID: string]: Record | null | undefined; }
interface RecordMap {
[dataID: string]: Record | null | undefined;
}
/**
* A selector defines the starting point for a traversal into the graph for the
@@ -254,20 +248,24 @@ export namespace RelayCommonTypes {
* A representation of a selector and its results at a particular point in time.
*/
type CSnapshot<TNode> = CSelector<TNode> & {
data: SelectorData | null | undefined,
seenRecords: RecordMap,
data: SelectorData | null | undefined;
seenRecords: RecordMap;
};
/**
* The results of a selector given a store/RecordSource.
*/
interface SelectorData { [key: string]: any; }
interface SelectorData {
[key: string]: any;
}
/**
* The results of reading the results of a FragmentMap given some input
* `Props`.
*/
interface FragmentSpecResults { [key: string]: any; }
interface FragmentSpecResults {
[key: string]: any;
}
/**
* A utility for resolving and subscribing to the results of a fragment spec
@@ -304,7 +302,9 @@ export namespace RelayCommonTypes {
setVariables(variables: Variables): void;
}
interface CFragmentMap<TFragment> { [key: string]: TFragment; }
interface CFragmentMap<TFragment> {
[key: string]: TFragment;
}
/**
* An operation selector describes a specific instance of a GraphQL operation
@@ -326,14 +326,7 @@ export namespace RelayCommonTypes {
* The public API of Relay core. Represents an encapsulated environment with its
* own in-memory cache.
*/
interface CEnvironment<
TEnvironment,
TFragment,
TGraphQLTaggedNode,
TNode,
TOperation,
TPayload,
> {
interface CEnvironment<TEnvironment, TFragment, TGraphQLTaggedNode, TNode, TOperation, TPayload> {
/**
* Read the results of a selector from in-memory records in the store.
*/
@@ -344,10 +337,7 @@ export namespace RelayCommonTypes {
* when data has been committed to the store that would cause the results of
* the snapshot's selector to change.
*/
subscribe(
snapshot: CSnapshot<TNode>,
callback: (snapshot: CSnapshot<TNode>) => void,
): Disposable;
subscribe(snapshot: CSnapshot<TNode>, callback: (snapshot: CSnapshot<TNode>) => void): Disposable;
/**
* Ensure that all the records necessary to fulfill the given selector are
@@ -370,11 +360,11 @@ export namespace RelayCommonTypes {
* after receving the first `onNext` result.
*/
sendQuery(config: {
cacheConfig?: CacheConfig,
onCompleted?(): void,
onError?(error: Error): void,
onNext?(payload: TPayload): void,
operation: COperationSelector<TNode, TOperation>,
cacheConfig?: CacheConfig;
onCompleted?(): void;
onError?(error: Error): void;
onNext?(payload: TPayload): void;
operation: COperationSelector<TNode, TOperation>;
}): Disposable;
/**
@@ -386,29 +376,17 @@ export namespace RelayCommonTypes {
* subscription open indefinitely such that `onCompleted` is not called.
*/
streamQuery(config: {
cacheConfig?: CacheConfig,
onCompleted?(): void,
onError?(error: Error): void,
onNext?(payload: TPayload): void,
operation: COperationSelector<TNode, TOperation>,
cacheConfig?: CacheConfig;
onCompleted?(): void;
onError?(error: Error): void;
onNext?(payload: TPayload): void;
operation: COperationSelector<TNode, TOperation>;
}): Disposable;
unstable_internal: CUnstableEnvironmentCore<
TEnvironment,
TFragment,
TGraphQLTaggedNode,
TNode,
TOperation
>;
unstable_internal: CUnstableEnvironmentCore<TEnvironment, TFragment, TGraphQLTaggedNode, TNode, TOperation>;
}
interface CUnstableEnvironmentCore<
TEnvironment,
TFragment,
TGraphQLTaggedNode,
TNode,
TOperation,
> {
interface CUnstableEnvironmentCore<TEnvironment, TFragment, TGraphQLTaggedNode, TNode, TOperation> {
/**
* Create an instance of a FragmentSpecResolver.
*
@@ -421,7 +399,7 @@ export namespace RelayCommonTypes {
containerName: string,
fragments: CFragmentMap<TFragment>,
props: Props,
callback: () => void,
callback: () => void
): FragmentSpecResolver;
/**
@@ -430,10 +408,7 @@ export namespace RelayCommonTypes {
* filtered to exclude variables that do not matche defined arguments on the
* operation, and default values are populated for null values.
*/
createOperationSelector(
operation: TOperation,
variables: Variables,
): COperationSelector<TNode, TOperation>;
createOperationSelector(operation: TOperation, variables: Variables): COperationSelector<TNode, TOperation>;
/**
* Given a graphql`...` tagged template, extract a fragment definition usable
@@ -482,11 +457,7 @@ export namespace RelayCommonTypes {
* const childData = environment.lookup(childSelector).data;
* ```
*/
getSelector(
operationVariables: Variables,
fragment: TFragment,
prop: any,
): CSelector<TNode> | void;
getSelector(operationVariables: Variables, fragment: TFragment, prop: any): CSelector<TNode> | null;
/**
* Given the result `items` from a parent that fetched `fragment`, creates a
@@ -497,8 +468,8 @@ export namespace RelayCommonTypes {
getSelectorList(
operationVariables: Variables,
fragment: TFragment,
props: any[],
): Array<CSelector<TNode>> | void;
props: any[]
): Array<CSelector<TNode>> | null;
/**
* Given a mapping of keys -> results and a mapping of keys -> fragments,
@@ -511,7 +482,7 @@ export namespace RelayCommonTypes {
getSelectorsFromObject(
operationVariables: Variables,
fragments: CFragmentMap<TFragment>,
props: Props,
props: Props
): { [key: string]: CSelector<TNode> | Array<CSelector<TNode>> | null | undefined };
/**
@@ -523,7 +494,7 @@ export namespace RelayCommonTypes {
*/
getDataIDsFromObject(
fragments: CFragmentMap<TFragment>,
props: Props,
props: Props
): { [key: string]: DataID | DataID[] | null | undefined };
/**
@@ -537,7 +508,7 @@ export namespace RelayCommonTypes {
getVariablesFromObject(
operationVariables: Variables,
fragments: CFragmentMap<TFragment>,
props: Props,
props: Props
): Variables;
}
@@ -564,51 +535,46 @@ export namespace RelayCommonTypes {
max_runs: number;
}
interface FIELDS_CHANGE {
type: 'FIELDS_CHANGE';
fieldIDs: { [fieldName: string]: DataID | DataID[]; };
type: "FIELDS_CHANGE";
fieldIDs: { [fieldName: string]: DataID | DataID[] };
}
interface RANGE_ADD {
type: 'RANGE_ADD';
type: "RANGE_ADD";
parentName?: string;
parentID?: string;
connectionInfo?: Array<{
key: string,
filters?: Variables,
rangeBehavior: string,
key: string;
filters?: Variables;
rangeBehavior: string;
}>;
connectionName?: string;
edgeName: string;
rangeBehaviors?: RangeBehaviors;
}
interface NODE_DELETE {
type: 'NODE_DELETE';
type: "NODE_DELETE";
parentName?: string;
parentID?: string;
connectionName?: string;
deletedIDFieldName: string;
}
interface RANGE_DELETE {
type: 'RANGE_DELETE';
type: "RANGE_DELETE";
parentName?: string;
parentID?: string;
connectionKeys?: Array<{
key: string,
filters?: Variables,
key: string;
filters?: Variables;
}>;
connectionName?: string;
deletedIDFieldName: string | string[];
pathToConnection: string[];
}
interface REQUIRED_CHILDREN {
type: 'REQUIRED_CHILDREN';
type: "REQUIRED_CHILDREN";
children: RelayConcreteNode[];
}
type RelayMutationConfig =
FIELDS_CHANGE |
RANGE_ADD |
NODE_DELETE |
RANGE_DELETE |
REQUIRED_CHILDREN;
type RelayMutationConfig = FIELDS_CHANGE | RANGE_ADD | NODE_DELETE | RANGE_DELETE | REQUIRED_CHILDREN;
interface RelayMutationTransactionCommitCallbacks {
onFailure?: RelayMutationTransactionCommitFailureCallback;
@@ -616,14 +582,16 @@ export namespace RelayCommonTypes {
}
type RelayMutationTransactionCommitFailureCallback = (
transaction: RelayMutationTransaction,
preventAutoRollback: () => void,
preventAutoRollback: () => void
) => void;
type RelayMutationTransactionCommitSuccessCallback = (
response: {
[key: string]: any;
}
) => void;
type RelayMutationTransactionCommitSuccessCallback = (response: {
[key: string]: any,
}) => void;
interface NetworkLayer {
sendMutation(request: RelayMutationRequest): Promise<any> | void;
sendQueries(requests: RelayQueryRequest[]): Promise<any> | void;
sendMutation(request: RelayMutationRequest): Promise<any> | null;
sendQueries(requests: RelayQueryRequest[]): Promise<any> | null;
supports(...options: string[]): boolean;
}
interface QueryResult {
@@ -639,18 +607,16 @@ export namespace RelayCommonTypes {
ready: boolean;
stale: boolean;
}
type RelayContainerErrorEventType =
| 'CACHE_RESTORE_FAILED'
| 'NETWORK_QUERY_ERROR';
type RelayContainerErrorEventType = "CACHE_RESTORE_FAILED" | "NETWORK_QUERY_ERROR";
type RelayContainerLoadingEventType =
| 'ABORT'
| 'CACHE_RESTORED_REQUIRED'
| 'CACHE_RESTORE_START'
| 'NETWORK_QUERY_RECEIVED_ALL'
| 'NETWORK_QUERY_RECEIVED_REQUIRED'
| 'NETWORK_QUERY_START'
| 'STORE_FOUND_ALL'
| 'STORE_FOUND_REQUIRED';
| "ABORT"
| "CACHE_RESTORED_REQUIRED"
| "CACHE_RESTORE_START"
| "NETWORK_QUERY_RECEIVED_ALL"
| "NETWORK_QUERY_RECEIVED_REQUIRED"
| "NETWORK_QUERY_START"
| "STORE_FOUND_ALL"
| "STORE_FOUND_REQUIRED";
type ReadyStateChangeCallback = (readyState: ReadyState) => void;
interface ReadyStateEvent {
type: RelayContainerLoadingEventType | RelayContainerErrorEventType;
@@ -668,13 +634,19 @@ export namespace RelayCommonTypes {
* https://github.com/facebook/relay/blob/master/packages/react-relay/classic/tools/RelayInternalTypes.js
*/
// ~~~~~~~~~~~~~~~~~~~~~
interface QueryPayload { [key: string]: any; }
interface RelayQuerySet { [queryName: string]: any; }
type RangeBehaviorsFunction = (connectionArgs: {
[argName: string]: any,
}) => 'APPEND' | 'IGNORE' | 'PREPEND' | 'REFETCH' | 'REMOVE';
interface QueryPayload {
[key: string]: any;
}
interface RelayQuerySet {
[queryName: string]: any;
}
type RangeBehaviorsFunction = (
connectionArgs: {
[argName: string]: any;
}
) => "APPEND" | "IGNORE" | "PREPEND" | "REFETCH" | "REMOVE";
interface RangeBehaviorsObject {
[key: string]: 'APPEND' | 'IGNORE' | 'PREPEND' | 'REFETCH' | 'REMOVE';
[key: string]: "APPEND" | "IGNORE" | "PREPEND" | "REFETCH" | "REMOVE";
}
type RangeBehaviors = RangeBehaviorsFunction | RangeBehaviorsObject;
}
@@ -700,7 +672,7 @@ export namespace RelayRuntimeTypes {
operation: object,
variables: RelayCommonTypes.Variables,
cacheConfig: RelayCommonTypes.CacheConfig,
uploadables?: RelayCommonTypes.UploadableMap,
uploadables?: RelayCommonTypes.UploadableMap
) => Promise<any>;
interface RelayNetwork {
execute: ExecuteFunction;
@@ -709,7 +681,7 @@ export namespace RelayRuntimeTypes {
// ~~~~~~~~~~~~~~~~~~~~~
// RelayDefaultHandlerProvider
// ~~~~~~~~~~~~~~~~~~~~~
function HandlerProvider(name: string): typeof RelayCommonTypes.Handler | void;
function HandlerProvider(name: string): typeof RelayCommonTypes.Handler | null;
// ~~~~~~~~~~~~~~~~~~~~~
// RelayModernEnvironment
@@ -728,41 +700,39 @@ export namespace RelayRuntimeTypes {
revertUpdate(update: OptimisticUpdate): void;
replaceUpdate(update: OptimisticUpdate, newUpdate: OptimisticUpdate): void;
applyMutation(config: {
operation: OperationSelector,
optimisticUpdater?: RelayCommonTypes.SelectorStoreUpdater,
optimisticResponse?: object,
operation: OperationSelector;
optimisticUpdater?: RelayCommonTypes.SelectorStoreUpdater;
optimisticResponse?: object;
}): RelayCommonTypes.Disposable;
check(readSelector: Selector): boolean;
commitPayload(
operationSelector: OperationSelector,
payload: PayloadData,
): void;
commitPayload(operationSelector: OperationSelector, payload: PayloadData): void;
commitUpdate(updater: RelayCommonTypes.StoreUpdater): void;
lookup(readSelector: Selector): Snapshot;
subscribe(
snapshot: Snapshot,
callback: (snapshot: Snapshot) => void,
): RelayCommonTypes.Disposable;
subscribe(snapshot: Snapshot, callback: (snapshot: Snapshot) => void): RelayCommonTypes.Disposable;
retain(selector: Selector): RelayCommonTypes.Disposable;
execute(config: {
operation: OperationSelector,
cacheConfig?: RelayCommonTypes.CacheConfig,
updater?: RelayCommonTypes.SelectorStoreUpdater,
operation: OperationSelector;
cacheConfig?: RelayCommonTypes.CacheConfig;
updater?: RelayCommonTypes.SelectorStoreUpdater;
}): RelayObservable<RelayResponsePayload>;
executeMutation(config: {
operation: OperationSelector,
optimisticUpdater?: RelayCommonTypes.SelectorStoreUpdater,
optimisticResponse?: object,
updater?: RelayCommonTypes.SelectorStoreUpdater,
uploadables?: RelayCommonTypes.UploadableMap,
operation: OperationSelector;
optimisticUpdater?: RelayCommonTypes.SelectorStoreUpdater;
optimisticResponse?: object;
updater?: RelayCommonTypes.SelectorStoreUpdater;
uploadables?: RelayCommonTypes.UploadableMap;
}): RelayObservable<RelayResponsePayload>;
}
// ~~~~~~~~~~~~~~~~~~~~~
// RelayInMemoryRecordSource
// ~~~~~~~~~~~~~~~~~~~~~
interface Record { [key: string]: any; }
interface RecordMap { [dataID: string]: Record | null | undefined; }
interface Record {
[key: string]: any;
}
interface RecordMap {
[dataID: string]: Record | null | undefined;
}
// ~~~~~~~~~~~~~~~~~~~~~
// Network
@@ -772,7 +742,10 @@ export namespace RelayRuntimeTypes {
* Creates an implementation of the `Network` interface defined in
* `RelayNetworkTypes` given `fetch` and `subscribe` functions.
*/
static create(fetchFn: typeof RelayCommonTypes.FetchFunction, subscribeFn?: RelayCommonTypes.SubscribeFunction): RelayNetwork;
static create(
fetchFn: typeof RelayCommonTypes.FetchFunction,
subscribeFn?: RelayCommonTypes.SubscribeFunction
): RelayNetwork;
}
// ~~~~~~~~~~~~~~~~~~~~~
@@ -782,14 +755,11 @@ export namespace RelayRuntimeTypes {
constructor(records?: RecordMap);
clear(): void;
delete(dataID: RelayCommonTypes.DataID): void;
get(dataID: RelayCommonTypes.DataID): Record | void;
get(dataID: RelayCommonTypes.DataID): Record | null;
getRecordIDs(): RelayCommonTypes.DataID[];
getStatus(dataID: RelayCommonTypes.DataID): 'EXISTENT' | 'NONEXISTENT' | 'UNKNOWN';
getStatus(dataID: RelayCommonTypes.DataID): "EXISTENT" | "NONEXISTENT" | "UNKNOWN";
has(dataID: RelayCommonTypes.DataID): boolean;
load(
dataID: RelayCommonTypes.DataID,
callback: (error: Error | null, record: Record | null) => void,
): void;
load(dataID: RelayCommonTypes.DataID, callback: (error: Error | null, record: Record | null) => void): void;
remove(dataID: RelayCommonTypes.DataID): void;
set(dataID: RelayCommonTypes.DataID, record: Record): void;
size(): number;
@@ -807,10 +777,7 @@ export namespace RelayRuntimeTypes {
lookup(selector: Selector): Snapshot;
notify(): void;
publish(source: RecordSource): void;
subscribe(
snapshot: Snapshot,
callback: (snapshot: Snapshot) => void,
): RelayCommonTypes.Disposable;
subscribe(snapshot: Snapshot, callback: (snapshot: Snapshot) => void): RelayCommonTypes.Disposable;
}
// ~~~~~~~~~~~~~~~~~~~~~
@@ -866,14 +833,14 @@ export namespace RelayRuntimeTypes {
* value is another Record instead of a scalar). May throw if the field is
* present but not a scalar linked record.
*/
getLinkedRecord(name: string, args?: RelayCommonTypes.Variables): RecordInspector | void;
getLinkedRecord(name: string, args?: RelayCommonTypes.Variables): RecordInspector | null;
/**
* Returns an array of inspectors for the given plural "linked" field (a field
* whose value is an array of Records instead of a scalar). May throw if the
* field is present but not a plural linked record.
*/
getLinkedRecords(name: string, args?: RelayCommonTypes.Variables): RecordInspector[] | void;
getLinkedRecords(name: string, args?: RelayCommonTypes.Variables): RecordInspector[] | null;
}
class RelayRecordSourceInspector {
@@ -883,7 +850,7 @@ export namespace RelayRuntimeTypes {
* Returns an inspector for the record with the given id, or null/undefined if
* that record is deleted/unfetched.
*/
get(dataID: RelayCommonTypes.DataID): RecordInspector | void;
get(dataID: RelayCommonTypes.DataID): RecordInspector | null;
/**
* Returns a list of "<id>: <type>" for each record in the store that has an
* `id`.
@@ -955,7 +922,9 @@ export namespace RelayRuntimeTypes {
* legacy Relay observer and directly return an Observable instead.
*/
static fromLegacy<V>(
callback: (legacyObserver: RelayCommonTypes.LegacyObserver<V>) => RelayCommonTypes.Disposable | RelayObservable<V>,
callback: (
legacyObserver: RelayCommonTypes.LegacyObserver<V>
) => RelayCommonTypes.Disposable | RelayObservable<V>
): RelayObservable<V>;
/**
@@ -1036,10 +1005,7 @@ export namespace RelayRuntimeTypes {
// commitLocalUpdate
// ~~~~~~~~~~~~~~~~~~~~~
// exposed through RelayModern, not Runtime directly
type commitLocalUpdate = (
environment: Environment,
updater: RelayCommonTypes.StoreUpdater,
) => void;
type commitLocalUpdate = (environment: Environment, updater: RelayCommonTypes.StoreUpdater) => void;
// ~~~~~~~~~~~~~~~~~~~~~
// commitRelayModernMutation
@@ -1058,7 +1024,7 @@ export namespace RelayRuntimeTypes {
}
function commitRelayModernMutation(
environment: Environment,
config: MutationConfig<any>,
config: MutationConfig<any>
): RelayCommonTypes.Disposable;
// ~~~~~~~~~~~~~~~~~~~~~
@@ -1094,7 +1060,7 @@ export namespace RelayRuntimeTypes {
environment: any, // FIXME - $FlowFixMe in facebook source code
taggedNode: RelayCommonTypes.GraphQLTaggedNode,
variables: RelayCommonTypes.Variables,
cacheConfig?: RelayCommonTypes.CacheConfig,
cacheConfig?: RelayCommonTypes.CacheConfig
): Promise<any>; // FIXME - $FlowFixMe in facebook source code
// ~~~~~~~~~~~~~~~~~~~~~
@@ -1112,7 +1078,7 @@ export namespace RelayRuntimeTypes {
}
function requestRelaySubscription(
environment: Environment,
config: GraphQLSubscriptionConfig,
config: GraphQLSubscriptionConfig
): RelayCommonTypes.Disposable;
}
+9 -20
View File
@@ -1,11 +1,4 @@
import {
Environment,
Network,
RecordSource,
Store,
ConnectionHandler,
ViewerHandler,
} from 'relay-runtime';
import { Environment, Network, RecordSource, Store, ConnectionHandler, ViewerHandler } from "relay-runtime";
const source = new RecordSource();
const store = new Store(source);
@@ -15,13 +8,9 @@ const store = new Store(source);
// ~~~~~~~~~~~~~~~~~~~~~
// Define a function that fetches the results of an operation (query/mutation/etc)
// and returns its results as a Promise:
function fetchQuery(
operation: any,
variables: { [key: string]: string },
cacheConfig: {},
) {
return fetch('/graphql', {
method: 'POST',
function fetchQuery(operation: any, variables: { [key: string]: string }, cacheConfig: {}) {
return fetch("/graphql", {
method: "POST",
body: JSON.stringify({
query: operation.text, // GraphQL text from input
variables,
@@ -50,10 +39,10 @@ const environment = new Environment({
function handlerProvider(handle: any) {
switch (handle) {
// Augment (or remove from) this list:
case 'connection': return ConnectionHandler;
case 'viewer': return ViewerHandler;
case "connection":
return ConnectionHandler;
case "viewer":
return ViewerHandler;
}
throw new Error(
`handlerProvider: No handler provided for ${handle}`
);
throw new Error(`handlerProvider: No handler provided for ${handle}`);
}