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

Proposal: Generic Filter Functionality #76

Closed
ajnavarro opened this issue Aug 1, 2024 · 3 comments
Closed

Proposal: Generic Filter Functionality #76

ajnavarro opened this issue Aug 1, 2024 · 3 comments
Assignees

Comments

@ajnavarro
Copy link
Collaborator

ajnavarro commented Aug 1, 2024

Description

We are suffering from Feature Creep on the filtering side of GraphQL API implementation, and we can still not cover most of the use cases (we cannot filter blocks by the proposer, for example).

I did a quick research and it is possible to implement a plugin on gqlgen that can generate the filter objects we need to be able to filter by all the fields we want.

Proposal

Implement a gqlgen plugin

We can create a plugin implementing CodeGenerator interface:

type CodeGenerator interface {
	GenerateCode(cfg *codegen.Data) error
}

That will allow us to scan all existing objects in the schema, get their fields with their types, and generate the needed objects for applying the filtering.

Proposed Filter structure

A filter will contain And filters, Or filters, Not filter, and field filters. They will be composed as follows (we are using Block filter as an example):

type FilterBlock struct {
	And []*FilterBlock
	Or []*FilterBlock
	Not *FilterBlock

	hash *FilterString

	num_txs *FilterNumber
   
	txs *NestedFilterBlockTransaction
}

type FilterString struct {
	Exists bool
    Eq       string
    Neq    string

    Like    string
    Nlike  string

	// TODO: maybe there are more useful ones?
}

That will allow us to create filters like:

{
   "_and":[
      {
         "num_txs":{
            "gt":10,
            "lt":100
         }
      },
      {
         "proposer_address_raw":{
            "eq":"ADDR"
         },
         "_or":[
            {
               "tx":{
                  "hash":{
                     "eq":"TXHASH"
                  }
               }
            }
         ]
      }
   ],
   "_or":[
      {
         "consensus_hash":{
            "eq":"HASH"
         }
      }
   ]
}

That will be the same as:

WHERE (((num_txs > 10 AND num_txs < 100) AND proposer_address_raw = "ADDR") OR tx_hash="TXHASH") OR consensus_hash = "HASH"

Schema tagging for filter creation

We can scan the existing graphql schema to find specific annotations, and from that, generate the needed filters. Example:

# plugin:filter
type Block {

  # plugin:filter
  hash: String!

  # plugin:filter
  height: Int!

  version: String!

  # plugin:filter
  chain_id: String!

  # plugin:filter
  time: Time!
	
[...]

That will allow us to create filters only from the types and fields we want/need. In the future we can be more specific, like only creating eq filter for a field: (# plugin:filter(types:[eq])))

Special cases

We have filters that are used outside the filtering logic, for example, to query the storage (block height). We need to expose this values to retrieve them. One idea (still thinking if it is the best) will be add a special tag to these values to expose a method to retrieve the max and min values from the filters, something like:

  # plugin:filter(expose:[minmax])
  height: Int!

Generating the following method in the generated filter struct:

func (f *FilterBlock) GetMinMaxHeight()(min int, max int) {
	// TODO check height filters values (eq, gt, lt and so on) in a recursive way, and return the min value and max value
}
@zivkovicmilos
Copy link
Member

I love this, I think it's great 💯

I was bummed to find out we need to directly modify the existing objects in order to index specific block fields, like the proposer, but if this is a long term solution then I'm all for it

@jinoosss what do you think?

@jinoosss
Copy link
Member

jinoosss commented Aug 5, 2024

@zivkovicmilos @ajnavarro ,
I think that's a really good suggestion, too.
We can provide consistent and intuitive filters.

@zivkovicmilos
Copy link
Member

Closed by #90

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

No branches or pull requests

3 participants