Skip to content
This repository has been archived by the owner on Apr 14, 2023. It is now read-only.

WIP: Continue work to support new graphql-js #133

Merged
merged 8 commits into from
May 18, 2017

Conversation

dotansimha
Copy link
Contributor

@dotansimha dotansimha commented May 17, 2017

Continue #108

As discussed in the previous PR:

  • Removed inner Observable implementation, and replace it with AsyncIterator, removingObservable code completely.
  • Add support for GraphQL execute return Promise, along with execute that returns AsyncIterator to support reactive data sources.
  • Introduce SubscriptionManager to AsyncIterator to support old graphql-subscriptions API.
  • Added more unit tests to test support of graphql-js with AsyncIterator
  • Apply a fix to support app using upgradeReq (changed since ws@3.0.0).
  • Split some of the server code into smaller files.

Still WIP:

  • More unit tests (for subscribe executor)

@Urigo @DxCx @mistic

TODO:

  • Make sure all of the significant new logic is covered by tests
  • Rebase your changes on master so that they can be merged easily
  • Make sure all tests and linter rules pass
  • Update CHANGELOG.md with your change

@Urigo
Copy link
Contributor

Urigo commented May 17, 2017

@dotansimha awesome!! also adding @NeoPhi for the review

@Urigo Urigo requested review from NeoPhi, Urigo and DxCx May 17, 2017 19:32

return promise
.then(value => ({ value, done: false }))
.catch(error => this.throw(error))
Copy link

@leebyron leebyron May 18, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems pretty strange - are you sure this is doing what you expect? The return() and throw() API on AsyncIterator are intended to be called by the consumer, not internally.

Since an AsyncIterator yields Promises, I would expect that it would simply return the wrapped promise once.

I would expect:

import { $$asyncIterator } from 'iterall';

export function createIterableFromPromise<T>(promise: Promise<T>): AsyncIterator<T> {
  let isComplete = false;

  return {
    next() {
      if (!isComplete) {
        isComplete = true;
        return promise.then(value => { value, done: false });
      }
      return Promise.resolve({ value: undefined, done: true });
    },
    return() {
      isComplete = true;
      return Promise.resolve({ value: undefined, done: true });
    },
    throw(e: Error) {
      isComplete = true;
      return Promise.reject(e);
    },
    [$$asyncIterator]() {
      return this;
    },
  };
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that makes sense. I will change it and added unit tests

return this.throw(error);
},
return() {
return this.throw(error);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be return Promise.resolve({ done: true, value: undefined })

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

export const createRejectionIterable = (error: Error): AsyncIterator<any> => {
return {
next() {
return this.throw(error);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit confusing to have this call itself - perhaps just return Promise.reject(error)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed! Thanks @leebyron

rootValue?: any,
contextValue?: any,
variableValues?: { [key: string]: any },
operationName?: string) => Promise<ExecutionResult> | AsyncIterator<ExecutionResult>;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is attempting to model graphql-js's execute function, that always returns a Promise. Only subscribe returns an AsyncIterator

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@leebyron
Yeah, the original execute of graphql-js returns a Promise.
I talked to @DxCx and we think that if we allow execute to return AsyncIterator in this package, we can also support Hagai's implementation for reactive graphql (#108 (comment))

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@leebyron this is done to allow execution of reactive directives as well (@live) for example, if one uses vanilla graphQL he will get the standard execute..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@leebyron I wanted to make sure that anyone who uses this package and expects graohql-js's execute will get exactly that. It almost won't effect you and the docs will be focused on that. But at the same time, if you want to use a separate, experimental package, it won't block you from it.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds great, just wanted to make sure it wasn't a mistake :)

src/server.ts Outdated
}
}
forAwaitEach(
createAsyncIterator<ExecutionResult>(executionIterable as any) as any,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why so many casting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

export function createIterableFromPromise<T>(promise: Promise<T>): AsyncIterator<T> {
let isResolved = false;

return {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dotansimha since promise have only 1 result anyway,
shouldn't you return value, done: true on next()
and use return as teardown function (which doesn't do anything since promises are not cancelable)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return of AsyncIterator should not return a value, only done=false.
If setting done=true while the Promise is resolved, the value ignored and then the iterator is done.

@Urigo Urigo merged commit 8ed6e88 into apollographql:master May 18, 2017
@dotansimha dotansimha deleted the feature/0.7 branch May 18, 2017 07:20
@NeoPhi
Copy link
Contributor

NeoPhi commented May 18, 2017

This is all looking great.

baconz pushed a commit to PhiloInc/subscriptions-transport-ws that referenced this pull request Apr 24, 2018
* Pass meteor login token in Authorization header

* Use passHeader method

* update changelog

* Fix lint rules
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants