Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

allow the filter function to be async #41

Merged
merged 7 commits into from
Feb 5, 2017
Merged

allow the filter function to be async #41

merged 7 commits into from
Feb 5, 2017

Conversation

NeoPhi
Copy link
Contributor

@NeoPhi NeoPhi commented Jan 30, 2017

@helfer This was the changed I mentioned to allow the filter function to be async.

@NeoPhi NeoPhi requested a review from helfer January 30, 2017 16:23
const query = `subscription Filter2($filterBoolean: Boolean){
testFilter(filterBoolean: $filterBoolean)
}`;
const callback = function(err, payload){
Copy link

Choose a reason for hiding this comment

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

you are ignoring err, is this intended?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As the test case is structured an err would be unexpected but easy enough to check.

@@ -234,6 +241,31 @@ describe('SubscriptionManager', function() {
});
});

it('can use an async filter function', function(done) {
Copy link

Choose a reason for hiding this comment

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

i might be missing something, how do you test async here?

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 publish below is for Filter2 which as defined above uses setTimeout to delay returning the result.

Copy link

Choose a reason for hiding this comment

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

yeah i've seen it, but it means the test is actually making sure promises work,
and not that things are running in parallel..
name is abit confusing.. 🗡

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't see it as that. If you revert the changes to pubsub.ts this test will fail since and async filter is always truthy even if it ultimately returns a false value. If you have a suggestion about how to restructure the test please let me know.

Copy link

Choose a reason for hiding this comment

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

oh no, i don't mind at all that this is what you are testing.
i would just rename the test abit to something like "can use promise inside filter function"
or something like that.. since usually when testing 'async', the testing is about being run in parallel

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated the test name.

src/pubsub.ts Outdated
}
contextPromise.then((context) => {
if (!filter(rootValue, context)) {
Promise.resolve().then(() => {
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can optimize this code and do a better use of Promise chaining - this way you can avoid the inner promises and the empty resolve(). you can also merge the two catch that does the same thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I wasn't able to see an easy way to do that since the context needs to be in the closure for two unrelated calls.

Copy link
Contributor

@Urigo Urigo Feb 2, 2017

Choose a reason for hiding this comment

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

@NeoPhi, I see, but you think that something like this won't do the trick?

const onMessage = (rootValue) => {
    const contextResult = typeof options.context === 'function' ? options.context() : context;

    return Promise
        .resolve(contextResult)
        .then(context => { filterResult: filter(rootValue, context), context: context} )
        .then(prev=> {
            const {filterResult, context} = prev;

            if (!filterResult) return;

            return execute(
                this.schema,
                parsedQuery,
                rootValue,
                context,
                options.variables,
                options.operationName
            );
        })
        .then(executionResult => {
            options.callback(null, executionResult);
        })
        .catch((error) => {
            options.callback(error);
        });
}

Copy link
Contributor Author

@NeoPhi NeoPhi Feb 2, 2017

Choose a reason for hiding this comment

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

If filter returns a Promise it will not be resolved.

Copy link
Contributor

Choose a reason for hiding this comment

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

@NeoPhi , so we can resolve it any way, and do the same for context, and then use Promise.all... something like that:

const onMessage = (rootValue) => {
    const contextResult = typeof options.context === 'function' ? options.context() : context;

    return Promise
        .resolve(contextResult)
        .then(context => Promise.all([ Promise.resolve(filter(rootValue, context)), Promise.resolve(context) ]) )
        .then(promisesResults=> {
            const filterResult = promisesResults[0];
            const context = promisesResults[1];

            if (!filterResult) return;

            return execute(
                this.schema,
                parsedQuery,
                rootValue,
                context,
                options.variables,
                options.operationName
            );
        })
        .then(executionResult => {
            options.callback(null, executionResult);
        })
        .catch((error) => {
            options.callback(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.

Woke up with the same thought. Although you can't unnest the executionResult otherwise the callback will be called with (null, undefined) unless that is desired.

@NeoPhi NeoPhi removed the request for review from helfer February 3, 2017 08:30
@Urigo Urigo merged commit c60cf98 into master Feb 5, 2017
@Urigo
Copy link
Contributor

Urigo commented Feb 5, 2017

thank you @NeoPhi !

@NeoPhi NeoPhi deleted the neophi-async-filter branch March 11, 2017 20:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants