edgedb-js
edgedb-js copied to clipboard
Query-builder cardinality inference error
I'm getting an error over address and image when trying to filter them through an ID. Seems like a cardinality inference error which I don't think it should be the case since I am filter by uuid.
const query_employer = e.insert(e.Employer, {
name: EMPLOYER,
address: e.select(e.Address, address => ({
filter: e.op(address.id, '=', e.cast(e.uuid, result_address.id)),
})),
guild: e.select(e.Guild, guild => ({
filter: e.op(guild.name, '=', GUILD),
})),
image: e.select(e.Employer_image, image => ({
filter: e.op(image.id, '=', e.cast(e.uuid, result_image.id)),
})),
});
const result_employer = await query_employer.run(client);
console.log(result_employer);
The typescript error:
Type '$expr_Select<{ __element__: ObjectType<"default::Employer_image", { id: PropertyDesc<$uuid, Cardinality.One, true, false, true, true>; __type__: LinkDesc<$Type, Cardinality.One, ... 4 more ..., false>; ... 4 more ...; "<image": LinkDesc<...>; }, Omit<...>>; __cardinality__: Cardinality.Many; }>' is not assignable to type 'TypeSet<ObjectType<string, { id: PropertyDesc<$uuid, Cardinality.One, true, false, true, true>; __type__: LinkDesc<$Type, Cardinality.One, {}, false, false, true, false>; ... 4 more ...; "<image": LinkDesc<...>; }, any>, Cardinality.AtMostOne | ... 1 more ... | Cardinality.Empty>'.
Types of property '__cardinality__' are incompatible.
Type 'Cardinality.Many' is not assignable to type 'Cardinality.AtMostOne | Cardinality.One | Cardinality.Empty'.ts(2322)
typeutil.d.ts(5, 32): The expected type comes from property 'image' which is declared here on type '{ [x: `@${string}`]: TypeSet<BaseType, Cardinality> | scalarLiterals; image: TypeSet<ObjectType<string, { id: PropertyDesc<$uuid, Cardinality.One, true, false, true, true>; ... 5 more ...; "<image": LinkDesc<...>; }, any>, Cardinality.AtMostOne | ... 1 more ... | Cardinality.Empty>; guild: TypeSet<...>; address: Typ...'
Relevant schema:
type Employer {
required property name -> str;
required link address -> Address;
required link guild -> Guild;
required link image -> Employer_image;
constraint exclusive on ((.name, .address))
}
type Guild extending Named {}
type Employer_image {
required property name -> str;
required property orig_link -> str;
required property s3_link -> str;
}
type Address {
property street -> str;
required link city -> City;
required link state -> State;
required link country -> Country;
constraint exclusive on ((.city, .state, .country))
}
type City extending Named {}
type State extending Named {}
type Country extending Named {}
For now I'm fixing it up by wrapping image and address with e.assert_single
Seems this is a problem with inferring cardinality from e.cast
. Either of these approaches will work:
e.cast(e.uuid, e.str("c900312b-2b8d-4d8d-b491-0761ecbb72e1")); // works
e.uuid("c900312b-2b8d-4d8d-b491-0761ecbb72e1"); // works
e.cast(e.uuid, "c900312b-2b8d-4d8d-b491-0761ecbb72e1"); // doesn't work
Use one of the working forms for now. I'll look into fixing this soon.
Using the 2nd approach was my go to! Thanks.
For folks googling this, assert_single might be a good alternative where you're not actually filtering on exclusive but limiting or otherwise sure it's Cardinality.AtMostOne | Cardinality.One | Cardinality.Empty
.
btw, inferring the cardinality based on the filter was removed in https://github.com/edgedb/edgedb-js/pull/460 ostensibly due to TypeScript recursion depth issues on the type that inferred the cardinality from the filter itself.
We'll revisit here and see if we can make it work well.