Filter on reference fields
UlyssesTech opened this issue · comments
I am wondering if it is to filter based on fields of a reference scheme(s)?
Let's say we have the following schemas:
var company = schema.Schema{
"id": schema.IDField,
"name": {
Filterable: true,
Sortable: true,
Validator: &schema.String{},
},
}
var machine = schema.Schema{
"id": schema.IDField,
"name": {
Filterable: true,
Sortable: true,
Validator: &schema.String{},
"user": {
Filterable: true,
Sortable: true,
Validator: &schema.Reference{Path: "users"},
},
},
}
var measurement = schema.Schema{
"id": schema.IDField,
"name": {
Filterable: true,
Sortable: true,
Validator: &schema.String{},
"machine": {
Filterable: true,
Sortable: true,
Validator: &schema.Reference{Path: "machines"},
},
},
}
In this case a company can have different machines, and each machine can have different measurements. If we want to get all the measurements done by a specific machine, then we can use a filter request, as follows:
$ http GET :8080/measurements filter='{machine: "machine_id"}'
But what if we want to get all the measurements for a specific company? It looks like the following syntax does not work:
$ http GET :8080/measurements filter='{machine.company: "company_id"}'
nor
$ http GET :8080/measurements fields='machine{company(filter: "{id: \"company_id\"}")}'
I know that we can go around it by creating sub-resources or applying a request on "/companies" with proper fields set, but it will be nice if we can filter directly on reference fields as we do on sub-documents.
The following syntax seems really neat to apply:
$ http GET :8080/measurements filter='{machine.company.id: "company_id"}'
Where we can filter on nested reference fields and can choose the field (i.e. the "id", but it can be also "name").
In my case, I solve this by adding company as a reference to measurements as well:
var measurement = schema.Schema{
"id": schema.IDField,
"name": {
Filterable: true,
Sortable: true,
Validator: &schema.String{},
"machine": {
Filterable: true,
Sortable: true,
Validator: &schema.Reference{Path: "machines"},
},
"company": {
Filterable: true,
Sortable: true,
Validator: &schema.Reference{Path: "companies"},
},
},
}
This is not optimal as "machine" already includes a reference to the company, but this solves the problem of filtering as we can filter directly on company field from measurements. This makes it easier as well to implement authorization logic in the resource hooks. For example, if a user has just permission to see measurements related to a specific company, I can easily add a filter predicate to the query.
As a first warning, there isn't much active development of rest-layer. We for one have decided to use it more or less, as-is, and the original author, @rs, is not using this project in production.
That said, you are welcome to attempt to create a PR four your use-case. Before you start on the code though, there are some considerations to take:
- How do you find the related resource for Filter validation in the schema package (with no knowledge of the resource package)? Do you define a better interface for finding related resources?
- Do you always allow filtering of related resources, or do need to configure it in the schema?
- How do you implement this within the resource pacakge and/or within the resource Storer implementations?
Implementation wise, as there are no joins available in the rest-layer abstraction, there would need to be two distinct queries when doing related lookup. E.g. first get all companies, then extract the IDs, and then do the final query.
For example, if a user has just permission to see measurements related to a specific company, I can easily add a filter predicate to the query.
As for permissions, then you can do this with resource hooks today, as your own extension to rest-layer. Within the hooks, you can do as many sub-queries as you need. We have a permission system where we do perform related queries, compile the result into a new query for the target resource (usually an $in
query), and finally join the permission query with the user query with an explicit AND.