Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@kamilkisiela
Copy link
Contributor

@kamilkisiela kamilkisiela commented Dec 1, 2021

#2960

Given the schema:

type Purpose @entity {
  id: ID!
  sender: Sender!
  purpose: String!
  createdAt: BigInt!
  transactionHash: String!
}

type Sender @entity {
  id: ID!
  address: Bytes!
  purposes: [Purpose!] @derivedFrom(field: "sender")
  createdAt: BigInt!
  purposeCount: BigInt!
}

The sender_ is added to Purpose_filter input object.

input Purpose_filter {
    ...
+  sender_: Sender_filter
}

The Sender_filter input object is untouched.

Questions

How should I handle @derivedFrom directive?
I see in code that the where argument is not generated for fields with @derivedFrom.

Is it find that I hardcoded c for root table (the one we select columns from)?
I noticed that aliases/prefixes for tables and columns are hard-coded so I guess it's fine to assume that c represents the root tabel.

Filters can be deeply nested, is it a problem?
The logic behind generating the joins is fairly easy and we won't end up with duplicates. It's table <-> table and it starts from "root" table (the one that we select from).

Every table gets its own prefix/alias, the root table gets c. In case of a few level deep filter that adds a condition for Foo entity, it ends up being prefixed in the same way as the condition for Foo in the first or n-th level.

WHERE (c1.createdAt > 19283721 AND ( .... ( ... ( c1.purposeCount > 5 OR ... ) ) ) )

Should a left join contain vid = vid condition?
I used left join to join tables with parent.id = child.column AND parent.vid = child.vid condition. Is it fine? I guess so, because vid represents the version and they should match.

@lutter
Copy link
Collaborator

lutter commented Dec 1, 2021

@kamilkisiela First off, you should base your work off the lutter/gql branch which has the GraphQL refactor that touches quite a bit of code - you definitely don't want to have to rebase across that.

What I would do is define a new variant EntityFilter::Child(String, Box<EntityFilter>) (you have to box to avoid an endless recursive type) where the String contains the name of the field that we want to filter on. The Object that build_filter_from_object gets can contain other objects. The current code in build_filter_from_object will be the leaf of the recursion you'll now need, and you need to detect that recursion is needed before Value::from_query_value is called (~ line 165); if the field indicates that you are dealing with a child filter, you want to return something like EntityFilter::Child(field_name, build_filter_from_object(object.get(field_name)) (there's a bit more to it to make sure that you are passing another Object around, the compiler will yell at you)

In your example, you want build_filter_from_object to return something like vec![EntityFilter::In("id", $list), EntityFilter::Child("notes", EntityFilter::Contains("text", "graphql"))] (I use $list to avoid the very verbose representation of [1,2,3] as a Value::List)

@lutter
Copy link
Collaborator

lutter commented Dec 1, 2021

One downside of what I suggested is that EntityFilter::Child can express arbitrary nesting of child filters, which might become a headache during SQL generation. Another approach would be to rename the current EntityFilter to something else, say BaseEntityFilter, and then define

enum EntityFilter {
   Base(BaseEntityFilter),
   Child(String, BaseEntityFilter)
}

I think either approach would be fine to get started, though this one would be cleaner since it expresses that child filters can only go one level deep cleanly

@kamilkisiela kamilkisiela force-pushed the kamil-filter-by-child branch from 51233c8 to 72fb7fd Compare December 1, 2021 17:16
@kamilkisiela kamilkisiela changed the base branch from master to lutter/gql December 1, 2021 17:16
@dotansimha dotansimha linked an issue Dec 19, 2021 that may be closed by this pull request
@kamilkisiela kamilkisiela force-pushed the kamil-filter-by-child branch 6 times, most recently from f8f1517 to 135a524 Compare December 22, 2021 11:48
@kamilkisiela kamilkisiela marked this pull request as ready for review December 22, 2021 11:49
@kamilkisiela kamilkisiela force-pushed the kamil-filter-by-child branch 3 times, most recently from d073da1 to 786e170 Compare December 22, 2021 13:52
@kamilkisiela kamilkisiela force-pushed the kamil-filter-by-child branch from e3e551a to ad81c2b Compare January 13, 2022 13:28
@lutter lutter force-pushed the lutter/gql branch 2 times, most recently from c98485d to 3727335 Compare January 20, 2022 00:58
@kamilkisiela kamilkisiela force-pushed the kamil-filter-by-child branch from ad81c2b to c288e18 Compare January 20, 2022 13:36
lutter added 23 commits January 20, 2022 12:15
That makes it possible to use the same schema for data nad for
introspection queries
The old name wasn't matching what we use it for any more
No cows were harmed in making this change
That is demanded by the GraphQL spec. We need to have a predictable order
to ensure attestations remain stable, though this change breaks
attestations since it changes the order in which fields appear in the
output from alphabetical (however a `BTreeMap` orders string keys) to the
order in which fields appear in a query.

It also allows us to replace `BTreeMaps`, which are fairly memory
intensive, with cheaper `Vec`.

The test changes all reflect the changed output behavior; they only reorder
fields in the expected output but do not otherwise alter the tests.

Fixes #2943
Rather than use a string name, use the actual object type to identify
types. It's not possible to do this with plain references, for example,
because we pass a reference to a SelectionSet to graph::spawn_blocking, so
we do the next best thing and use an Arc. Unfortunately, because
`graphql_parser` doesn't wrap its object types in an Arc, that means we
need to keep a copy of all of them in ApiSchema.
This just shuffles some code around, but doesn't change anything else, in
preparation for representing the schema in a way that's more useful to us.
Set ENABLE_GRAPHQL_VALIDATIONS to any value in the environment to enable
validations, rather than enabling them by default and disabling them on
demand
Make sure that we handle queries that have a selection from a scalar
field by ignoring the selection or that have no selection for a non-scalar
field by ignoring that field.

The latter differs from the previous behavior where the result would
contain an entry for such a field, but the data for the field would be an
empty object or a list of empty objects.
Instead of immediately reporting an error, treat missing variables as nulls
and let the rest of the execution logic deal with nulls
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.

Filtering on the basis of child entities

3 participants