Open sphuber opened 4 years ago
Oh come on, the error message could not be clearer ;) type is not a valid attribute to query by (=column) for this relationship. You are filtering for the type of an ancestor-descendant relationship to have a certain value. However, the type is not defined for this relationship (it is defined for links). Therefore, filtering by that column has to raise an error. The problem is not using edge_filters as a keyword, but the argument you passed. IMO (and if I understood correctly) this is not a bug, but the expected behavior (of course the error message could be improved).
Oh come on, the error message could not be clearer ;) type is not a valid attribute to query by (=column) for this relationship. You are filtering for the type of an ancestor-descendant relationship to have a certain value. However, the type is not defined for this relationship (it is defined for links). Therefore, filtering by that column has to raise an error. The problem is not using edge_filters as a keyword, but the argument you passed. IMO (and if I understood correctly) this is not a bug, but the expected behavior (of course the error message could be improved).
I understand that that is the problem, where the exception is raised and what it is saying. However, the question is whether it should raise for the query that I defined. The query:
builder = orm.QueryBuilder()
builder.append(orm.CalculationNode, tag='calculation')
builder.append(orm.Data, with_ancestors='calculation', edge_filters={'type': LinkType.CREATE.value})
to me makes perfect sense. It says:
get all
Data
nodes that have aCalculationNode
as an ancestor that is reachable by followingCREATE
links exclusively
for this trivial example, using with_ancestors
does not make a lot of sense as one could just use with_incoming
for the same effect, since the only link between CalculationNode
and Data
is a CREATE
anyway. However, one could also think about a query like:
builder = orm.QueryBuilder()
builder.append(orm.CalculationNode, tag='calculation')
builder.append(orm.Data, with_ancestors='calculation', edge_filters={'type': {'in': [LinkType.CREATE.value, LinkType.INPUT_CALC.value]})
These queries make sense right? Or am I missing something?
The reason I ran into this is because in the scope of PR #4306 we are thinking of adding the with_ancestors_extended
keyword that would also follow INPUT_WORK
and the CALL_CALC/CALL_WORK
links. For advanced usage, it might be useful to be able to restrict the set of links that are followed, for example do follow CALL_CALC
but do not follow CALL_WORK
. I felt the most natural way in terms of API was to use the edge_filters
for this. But I found out that this is not supported even for the existing with_ancestors
.
In principle, it would make sense to augment the links that are traversed, but this will be tough. To explain: the ancestor/descendant relationship is queried via a common table expression (CTE), which creates a new table (in memory) on demand, containing ancestor_id and descendant_id (you can also ask for the traversed nodes to be put in a list, that would be another column, not done by default because the query-time goes up x10). This table does not contain info over which types of links were traversed. And that CTE is hardcoded with the types of links that are allowed, so if you want the user to define it you'd have to implement this. Caution however: if you query something with a cycle you end up in an infinite loop.
Code snippet that will trigger it:
the exception that is raised:
Note that I had to adapt the exception message of
get_column
itself, because it would also try to address an attribute of thealias
variable, but the whole problem is thatalias
is not an instance ofAlias
but ofsqlalchemy.sql.base.ImmutableColumnCollection
.@lekah I tried looking into this, but could really use your help here.