import Observable from 'zen-observable-ts'; import { GraphQLRequest, NextLink, Operation, RequestHandler, FetchResult, } from './types'; import { validateOperation, isTerminating, LinkError, transformOperation, createOperation, } from './linkUtils'; const passthrough = (op, forward) => (forward ? forward(op) : Observable.of()); const toLink = (handler: RequestHandler | ApolloLink) => typeof handler === 'function' ? new ApolloLink(handler) : handler; export const empty = (): ApolloLink => new ApolloLink((op, forward) => Observable.of()); export const from = (links: ApolloLink[]): ApolloLink => { if (links.length === 0) return empty(); return links.map(toLink).reduce((x, y) => x.concat(y)); }; export const split = ( test: (op: Operation) => boolean, left: ApolloLink | RequestHandler, right: ApolloLink | RequestHandler = new ApolloLink(passthrough), ): ApolloLink => { const leftLink = toLink(left); const rightLink = toLink(right); if (isTerminating(leftLink) && isTerminating(rightLink)) { return new ApolloLink(operation => { return test(operation) ? leftLink.request(operation) || Observable.of() : rightLink.request(operation) || Observable.of(); }); } else { return new ApolloLink((operation, forward) => { return test(operation) ? leftLink.request(operation, forward) || Observable.of() : rightLink.request(operation, forward) || Observable.of(); }); } }; // join two Links together export const concat = ( first: ApolloLink | RequestHandler, second: ApolloLink | RequestHandler, ) => { const firstLink = toLink(first); if (isTerminating(firstLink)) { console.warn( new LinkError( `You are calling concat on a terminating link, which will have no effect`, firstLink, ), ); return firstLink; } const nextLink = toLink(second); if (isTerminating(nextLink)) { return new ApolloLink( operation => firstLink.request( operation, op => nextLink.request(op) || Observable.of(), ) || Observable.of(), ); } else { return new ApolloLink((operation, forward) => { return ( firstLink.request(operation, op => { return nextLink.request(op, forward) || Observable.of(); }) || Observable.of() ); }); } }; export class ApolloLink { constructor(request?: RequestHandler) { if (request) this.request = request; } public static empty = empty; public static from = from; public static split = split; public static execute = execute; public split( test: (op: Operation) => boolean, left: ApolloLink | RequestHandler, right: ApolloLink | RequestHandler = new ApolloLink(passthrough), ): ApolloLink { return this.concat(split(test, left, right)); } public concat(next: ApolloLink | RequestHandler): ApolloLink { return concat(this, next); } public request( operation: Operation, forward?: NextLink, ): Observable<FetchResult> | null { throw new Error('request is not implemented'); } } export function execute( link: ApolloLink, operation: GraphQLRequest, ): Observable<FetchResult> { return ( link.request( createOperation( operation.context, transformOperation(validateOperation(operation)), ), ) || Observable.of() ); }