All files / src/util observableToPromise.ts

88.89% Statements 40/45
77.78% Branches 14/18
100% Functions 7/7
87.18% Lines 34/39
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100  33x 33x 33x 55x   33x 33x 33x 33x 33x 33x 58x     58x 34x 34x   58x 34x 19x     15x       33x   55x 55x 55x 55x         55x             3x 3x 3x 3x         3x               33x           30x 30x 51x   30x                                                        
import { ObservableQuery } from '../../src/core/ObservableQuery';
import { ApolloQueryResult } from '../../src/core/types';
import { Subscription } from '../../src/util/Observable';
 
/**
 *
 * @param observable the observable query to subscribe to
 * @param shouldResolve should we resolve after seeing all our callbacks [default: true]
 *   (use this if you are racing the promise against another)
 * @param wait how long to wait after seeing desired callbacks before resolving
 *   [default: -1 => don't wait]
 * @param errorCallbacks an expected set of errors
 */I
export type Options = {
  observable: ObservableQuery<any>;
  shouldResolve?: boolean;
  wait?: number;
  errorCallbacks?: ((error: Error) => any)[];
};
 
export type ResultCallback = ((result: ApolloQueryResult<any>) => any);
 
// Take an observable and N callbacks, and observe the observable,
// ensuring it is called exactly N times, resolving once it has done so.
// Optionally takes a timeout, which it will wait X ms after the Nth callback
// to ensure it is not called again.
export function observableToPromiseAndSubscription(
  { observable, shouldResolve = true, wait = -1, errorCallbacks = [] }: Options,
  ...cbs: ResultCallback[]
): { promise: Promise<any[]>; subscription: Subscription } {
  let subscription: Subscription = null as never;
  const promise E= new Promise<any[]>((resolve, reject) => {
    let errorIndex = 0;
    let cbIndex = 0;
    const results: any[] = [];
 
    const tryToResolve = () => {
      if (!shouldResolve) {
        return;
      }
 
      const done = () => {
        subscription.unsubscribe();
        // XXX: we could pass a few other things out here?
        resolve(results);
      };
E
      if (cbIndex === cbs.length && errorIndex === errorCallbacks.length) {
        if (wait === -1) {
          done();
        } else {
          setTimeout(done, wait);
        }
      }
    };
 
    subscription = observable.subscribe({
      next(result) {
        const cb = cbs[cbIndex++];
        if (cb) {
          try {
            results.push(cb(result));
          } catch (e) {
            return reject(e);
          }
          tryToResolve();
        } else {
          reject(new Error(`Observable called more than ${cbs.length} times`));
        }
      },
      error(error) {
        const errorCb = errorCallbacks[errorIndex++];
        if (errorCb) {
          try {
            // XXX: should we collect these results too?
            errorCb(error);
          } catch (e) {
            return reject(e);
          }
          tryToResolve();
        } else {
          reject(error);
        }
      },
    });
  });
 
  return {
    promise,
    subscription,
  };
}
 
export default function(
  options: Options,
  ...cbs: ResultCallback[]
): Promise<any[]> {
  return observableToPromiseAndSubscription(options, ...cbs).promise;
}