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

[FR] GraphQL: Query by field value #5208

Closed
daltonrooney opened this issue Nov 5, 2019 · 14 comments
Closed

[FR] GraphQL: Query by field value #5208

daltonrooney opened this issue Nov 5, 2019 · 14 comments
Labels
docs 📔 documentation improvements enhancement improvements to existing features graphql ⚙️ features related to the GraphQL API

Comments

@daltonrooney
Copy link

Maybe I'm missing something, but do we have the ability to query elements by field data in GraphQL? For example, I'm building an events module and need to query for three months of entries by startDate. In Twig, we would do something like this:

{% set events = craft.entries.section('events').startDate('and', '>= 2019-11-01', '< 2020-02-01').orderBy('startDate asc') %}

Is there an equivalent in GraphQL? Or is the search directive the best way to do this currently?

@andris-sevcenko
Copy link
Contributor

This is not very feasible in GraphQL, which is much more rigid than regular PHP classes. While, with element queries, it's entirely possible to make sure code just rolls with the punches if something unknown is being set (Craft checks if there's a field with the handle and so on), GraphQL requires all the possible arguments for queries to be listed.

This means that if your Craft install had 100 fields, they would all need to be listed as possible arguments for entry queries. While possible, this would still degrade performance and reduce any GraphQL IDE usability in terms of query auto-completion.

I'd say your options (at the time) are:
a) go with the search query argument
b) as you're rolling your own module, anyway, just add a new GraphQL Query with that module that is more specifically tailored to your needs?

There's no developer documentation for extending GraphQL support, yet, but if you feel like code-diving, then this would be a good place to start: https://github.com/craftcms/cms/blob/develop/src/services/Gql.php#L86-L110

@andris-sevcenko andris-sevcenko added the graphql ⚙️ features related to the GraphQL API label Nov 6, 2019
@brandonkelly brandonkelly added the enhancement improvements to existing features label Nov 7, 2019
@daltonrooney
Copy link
Author

I’d be very interested in option B when more documentation becomes available. I’ve been trying to use the native GraphQL implementation on projects but usually end up going back to CraftQL for anything more than a basic app. We are only going to be doing more GraphQL in the future, so I would love to be able to extend it with our more advanced query requirements.

@andris-sevcenko
Copy link
Contributor

I hope to get the developer documentation in order this year, as it's is sorely needed.

@andris-sevcenko andris-sevcenko added the docs 📔 documentation improvements label Nov 29, 2019
@narration-sd
Copy link
Contributor

Yup, but maybe get a quick and useful start by describing how to add or modify resolvers, as wouldn't that often be a swifter and nicer way to get results, than wholesale creating queries, etc.?

@narration-sd
Copy link
Contributor

narration-sd commented Nov 29, 2019

For reference, here's some code as example of what I'm mentioning, if doing something we don't need any more as Andris has kindly added the transform: argument internally for Assets.

For a special Element query, you'd just write that in as result per your argument/s for it, if present.

I don't know how much easier this might be than arranging a full new Query for GraphQL -- the active part would be similar, but there are the issues of defining arguments, non-collision with stock query for that element, etc..

I also know he has well-formed ideas of what apropos patterns should be, so this will be important as well.

We'll be able to see with the documentation for that process...


    if (Comparator::greaterThanOrEqualTo(
           Craft::$app->getVersion(),
           '3.4')) { // where Andris adds field definition ability
                    Event::on(TypeManager::class,
                        TypeManager::EVENT_DEFINE_GQL_TYPE_FIELDS,
                        [$this, 'addGraphQLFieldDefs']);
    }

    public function addGraphQLFieldDefs(DefineGqlTypeFieldsEvent $event)
    {
        if ($event->typeName === 'AssetInterface') {

            $freshArgsList = \array_merge(
                $event->fields['url']['args'],
                [
                    'transform' => [
                        'name' => 'transform',
                        'type' => Type::string(),
                        'description' => 'The handle of the named transform to use.'
                    ]
                ]);

            $event->fields['url'] = [
                'name' => 'url',
                'type' => Type::string(),
                'args' => $freshArgsList,
                'resolve' => function($source, array $arguments, $context, ResolveInfo $resolveInfo) {
                    if (\array_key_exists('transform', $arguments)) {
                        return $source->getUrl($arguments['transform']);
                    } else if ($resolve = $resolveInfo->parentType->resolveFieldFn) {
                        return $resolve ($source, $arguments, $context, $resolveInfo);
                    } else {
                        return $source->getUrl(); // in case, or better this throws Exception?
                    }
                }
            ];
        }
    }

@andris-sevcenko
Copy link
Contributor

Yup, but maybe get a quick and useful start by describing how to add or modify resolvers, as wouldn't that often be a swifter and nicer way to get results, than wholesale creating queries, etc.?

That's available as of Craft 3.4, though, but yeah. It's possible to use that event and modify query arguments, adding your own conditions.

@narration-sd
Copy link
Contributor

...above corrected to my actual code which has the version compare...

@jamesedmonston
Copy link
Contributor

jamesedmonston commented Dec 9, 2019

@andris-sevcenko do you have an example of how to achieve this with the search query argument? I'm looking to do something similar to the OP: querying past/future events based on a date field.

@andris-sevcenko
Copy link
Contributor

@jamesedmonston huh. On second thought, it's not really possible using search, sorry.

Maybe it's really just worth adding all the custom fields as possible query arguments.

@daltonrooney
Copy link
Author

Maybe it's really just worth adding all the custom fields as possible query arguments.

@andris-sevcenko I've certainly enjoyed that when working with CraftQL but if it there's a potential performance drawback (especially on a large site with hundreds of fields) then I'm more than open to alternatives. One option might be a config file where we specify which fields that we want to enable in GraphQL queries.

But as we move more toward headless sites altogether, some kind of UI in the control panel would be nice. Maybe a list of all available fields when defining your GraphQL schema, which you can select as appropriate?

@andris-sevcenko
Copy link
Contributor

@daltonrooney well it's not really a performance drawback, since it all gets cached by default, but rather can get overwhelming? We'll talk this over internally.

@andris-sevcenko andris-sevcenko added this to the 3.4 milestone Dec 12, 2019
@andris-sevcenko
Copy link
Contributor

Making this a thing for 3.4

Screenshot 2019-12-14 at 16 52 47

@andris-sevcenko
Copy link
Contributor

Just pushed this to the 3.4 branch and it will be a part of the next 3.4 release!

@khalwat
Copy link
Contributor

khalwat commented Dec 17, 2019

Thank you @andris-sevcenko !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs 📔 documentation improvements enhancement improvements to existing features graphql ⚙️ features related to the GraphQL API
Projects
None yet
Development

No branches or pull requests

6 participants