The resolver from the example:
defmodule Blog.PostResolver do
def all(_args, _info) do
{:ok, Blog.Repo.all(Post)}
end
end
This will select all fields from database, no matter what fields you request in the query.
Is there any example, how to select only requested fields from the database? Some kind of this:
defmodule Blog.PostResolver do
def all(_args, _info) do
fields = ?
{:ok, Post |> select(fields) |> Blog.Repo.all}
end
end
Hey! You can find the fields under info.definition.fields.
FWIW unless the column contains particularly large amounts of information you don't get a very large speed up from dynamically selecting fields.
@benwilson512 that's one of the problems with graphql.
Everyone says that it's so cool and how it is easy to write stuff, but things like preloading (to avoid lots of queries) are often not even mentioned.
Same with selects - sure, when you have small tables, it may be possible that you don't need it. What about medium or large apps, where you have lots of columns and for example a mobile app wants 2 fields from 30. You know fields, but select all.
I really don't understand it, selects were meant to select necessary fields, not just wildcard all. It would be great to have at least an example in the docs (like with preloads) because people forget this or think that library will do this for them.
I don't think this is an issue with GraphQL itself, but rather just an issue with the fact that as a newer technology there's simply less tooling available so far for adapting it to different scenarios.
GraphQL itself doesn't say anything about preloading or selects because such concerns are very specific to whatever data store you're actually using.
What you'll see is that in each main language that uses GraphQL there has been quite a bit of tooling developed to get the desired functionality out of various kinds of data sources. https://github.com/facebook/dataloader and https://github.com/stems/join-monster come to mind in the JS world, https://github.com/Shopify/graphql-batch in the Ruby world, and we've been working on https://github.com/absinthe-graphql/absinthe_ecto for Elixir users.
To piggy back on @benwilson' comment -- a selection set determines what data to return, not necessarily what data to retrieve from an underlying data store, which may or may not support selection of individual fields, and may or may not even have those fields to begin with (one of GraphQLs greatest uses, in my opinion, as an abstraction layer on top of the underlying data). So, no, you don't get automatic database field selection without having to do some work, but with a bit of tooling you can -- and we're working on making that easier, too.
Yes, I fully agree with you guys. Fine tuning graphql needs some work and knowledge, that's why an official example would be great for devs, who are just starting and have this questions, especially since Absinthe has guides (Ecto Best Practices is a good example).
Thanks @benwilson512 !
@VladShcherbin I use this. Thinks it's pretty generic
defp select_schema_fields(queryable, %Absinthe.Resolution{} = info) do
fields = info.definition.selections
|> Enum.map(&(Map.get(&1, :name)|>String.to_atom))
queryable
|> select(^fields)
end
and:
|> select_schema_fields(info)
|> Repo.all
Think its generic enough.
ps I'm not an elixir expert. And the code where I collect the field atoms seems rather cryptic, perhaps it could be coded better?
I agree with @VladShcherbin that not limiting fields defeats somewhat the purpose of graphql/absinthe. I have rather wide database views large text columns. And the db server is not on the same server as Phoenix. Should make some difference on large row counts.
FYI the options here have come a long way since this original issue. The https://hexdocs.pm/absinthe/Absinthe.Resolution.html#project/1 function makes it much easier to cleanly get subfields under the existing field.
I do think that more selective column retrieval is valuable, but there is literally nothing in Absinthe that prevents people from doing so, it's just a matter of building a mapping from fields (which are easily retrieved) to db columns.
There absolutely could be more tooling there, but it's the kind of tooling we'd be interested in the community stepping up to build, since the core team's focus at the moment has to be stuff like subscriptions or schema refactoring that can't feasibly be done by others.
I've found that this is particularly helpful to use when you have a field that requires preloading of 1 or more relationships in order to compute. project/1 allows you to look to see if that heavy field is requested and modify the preload accordingly.
馃憤
@mgwidmann Yup, definitely an option. I'd also consider experimenting with Batching, you can usually achieve the same thing that way, and it has the plus side of keeping the parent field simpler.
Most helpful comment
FYI the options here have come a long way since this original issue. The https://hexdocs.pm/absinthe/Absinthe.Resolution.html#project/1 function makes it much easier to cleanly get subfields under the existing field.
I do think that more selective column retrieval is valuable, but there is literally nothing in Absinthe that prevents people from doing so, it's just a matter of building a mapping from fields (which are easily retrieved) to db columns.
There absolutely could be more tooling there, but it's the kind of tooling we'd be interested in the community stepping up to build, since the core team's focus at the moment has to be stuff like subscriptions or schema refactoring that can't feasibly be done by others.