Polymorphic splats in QB
- Dominant language
- Python
- Stars
- 415
- Forks
- 50
- PR merge metrics
- No merged PRs in 30d
Description
Polymorphic types are not friendly to plain `*` splats, as those will only include the common fields. So when dealing with polymorphic types we need to be able to use subtype-specific splats.
Consider this schema:
```
abstract type Foo {
prop: str;
}
type Bar extending Foo {
bar_prop: str;
}
type Baz extending Foo {
baz_prop: str;
}
type Kek {
pek: Foo;
}
```
Let's say we want the equivalent to `select Kek{**}`. In EdgeQL it would be something like this:
```
select Kek {
*,
pek: {
*,
[is Bar].*,
[is Baz].*,
}
}
```
We can't omit the `*` in `pek`, because without it both of the polymorphic splats try to include the common properties and that causes a clash and an error.
So the QB equivalent is:
```
from models import default
q = default.Kek.select(
"*",
pek=lambda k: k.pek.select(
"*",
*default.Bar,
*default.Baz,
)
)
```
This works OK for the above case, but not in general. This form only works when the sub-types don't share any property names and thus don't cause clashes.
If we had a slightly different schema:
```
abstract type Foo {
prop: str;
}
type Bar extending Foo {
extra_prop: str;
}
type Baz extending Foo {
extra_prop: str;
}
type Kek {
pek: Foo;
}
```
We would have an issue with `extra_prop` clashing and so we cannot use a splat here. In EdgeQL, we would have to resolve this manually with a coalesce:
```
select Kek {
*,
pek: {
*,
extra_prop :=
[is Bar].extra_prop ??
[is Baz].extra_prop,
}
}
```
This means that the QB needs to support referring to polymorpshic fields individually as part of expressions or as fields included in the `select`. I propose that we need a method for type intersection `[is Bar]` and we can call it `when_type` as a shorter and more intuitive form of "type intersection".
So this clash can be resolved like this:
```
q = default.Kek.select(
"*",
pek=lambda k: k.pek.select(
"*",
extra_prop=lambda foo: std.coalesce(
foo.when_type(default.Bar).extra_prop,
foo.when_type(default.Baz).extra_prop,
),
)
)
```
For the original schema, the query can be rewritten without splats:
```
q = default.Kek.select(
"*",
pek=lambda k: k.pek.select(
"*",
default.Bar.bar_prop,
default.Baz.baz_prop,
)
)
```
However, if we have `when_type`, then maybe we can also write this instead:
```
q = default.Kek.select(
"*",
pek=lambda k: k.pek.select(
"*",
k.when_type(default.Bar).bar_prop,
k.when_type(default.Baz).baz_prop,
)
)
```
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.