objection.js: Graph typings are incompatible with eager relation properties
UPDATE: This is actually a Typescript-specific usage problem whose solution is not currently modeled in the examples.
The typings for insertGraph()
and upsertGraph()
don’t allow graphs that include eager relation properties.
The problem is that these methods take Partial<T extends Model>
as input parameters, but this only makes the eager relation properties optional and not also their properties, recursively. In particular, they expect an eager relation property to have all the methods of Objection.Model.
Here are some examples and their errors:
import * as Objection from 'objection';
class Person extends Objection.Model {
id?: number;
firstName: string;
lastName: string;
// Commenting the following out doesn't help, as then movies wouldn't be valid in Partial<T>
movies?: Movie[];
}
class Movie extends Objection.Model {
id?: number
name: string;
}
Person
.query()
.insertGraph({
firstName: 'Jennifer',
lastName: 'Lawrence',
movies: [{ // ERROR: missing all of Model's properties
// id: 32 (adding this wouldn't help)
name: 'American Hustle'
}]
});
Person
.query()
.insertGraph({
firstName: 'Jennifer',
lastName: 'Lawrence',
movies: [{ // ERROR: missing all of Model's properties
id: 32
// name: 'American Hustle' (adding this wouldn't help)
}]
}, {
relate: true
});
Person
.query()
.insertGraph([{
firstName: 'Jennifer',
lastName: 'Lawrence',
movies: [{ // ERROR: does not match movies property
"#id": 'silverLiningsPlaybook'
name: 'Silver Linings Playbook'
}]
}, {
firstName: 'Bradley',
lastName: 'Cooper',
movies: [{ // ERROR: does not match movies property
"#ref": 'silverLiningsPlaybook'
}]
}]);
Person
.query()
.upsertGraph({
id: 1,
firstName: 'Jonnifer',
movies: [{ // ERROR: missing all of Model's properties
id: 1
//name: 'American Hustle' (adding this wouldn't help)
}, { // ERROR: missing all of Model's properties
id: 1253
// name: 'Passengers' (adding this wouldn't help)
}]
});
I’ve been exploring ways to improve these typings in #714, but have not found anything that works other than the any
type.
I looked at adding [key: string]: any
to the Partial<T>
parameter of insertGraph()
and upsertGraph()
, but then if the model ever defines an eager relation property, TS expect that property to match the model definition, not [key: string]: any
. However, this approach works fine if the models simply do not define types for their eager relation properties.
cc @mceachen
About this issue
- Original URL
- State: closed
- Created 6 years ago
- Comments: 18 (10 by maintainers)
With Conditional types introduced in TypeScript 2.8, we can update typings as follows:
Then there’s no need to type model’s relation properties with
Partial
.Would you be willing to accept a PR with this change? @koskimas
I spent a huge amount of time trying to figure out how to handle eager relations within Typescript because there were no examples of properly typed eager relations. The only example was of a
Person
-type property, which I copied by addingAnimal
andMovies
, but which we’ve now decided should bePartial<Person>
, etc., for non-cyclic graphs.So the question is whether to have an example that’ll save others the same headache. At a minimum, we’d need to change the relation types to partials. A more thorough example would demo model references in cyclic graphs.
As I’ve said in other comments, I think there’s value in keeping the
express-*
trees consistent, so the only difference betweenexpress-es7
andexpress-ts
is what is required by TypeScript to compile in strict mode.IOW, @koskimas, is it OK to add
pick
andomit
examples to all the express-* APIs? (It seems reasonable to me)You need to ask @mceachen about changing the example project.
I guess this would be more accurate:
UPDATE: This works fine on insert or upsert, but eager loads are expecting every eagerly-loaded model to match each of these model alternatives, which is impossible. I guess I’m stuck with the prior version of
EagerModel
, which I now callEagerRelation
in my code (I’m also using it on interfaces used to define models).If you use
#id
,#ref
or#dbRef
. Very few people actually do.This should work: