-
Notifications
You must be signed in to change notification settings - Fork 638
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Graph typings are incompatible with eager relation properties #724
Comments
I'll shortly be exploring ways to capture graphs in domain-specific interfaces, so there's a chance I might discover a way to get some static type checking. Meantime, if you can think of anything better than |
This should work: class Person extends Objection.Model {
id?: number;
firstName: string;
lastName: string;
movies?: Partial<Movie>[];
} |
Oh cool! Just need a small addition to make the errors go away: declare module 'objection' {
export interface Model {
'#id'?: string;
'#ref'?: string;
'#dbRef'?: number;
}
} But there is a serious drawback for eager loading: TS will require the app to check (or bang-override) the presence of every single model property. |
Or do this to avoid adding graph model ref properties to Model: type EagerModel<T extends Objection.Model> = Partial<T> & {
'#id'?: string;
'#ref'?: string;
'#dbRef'?: number;
};
class Person extends Objection.Model {
id?: number;
firstName: string;
lastName: string;
movies?: EagerModel<Movie>[];
} But this is still potentially annoying for eager loading. |
What do you mean by that? You can also create a base class and define the |
I think |
Ah perfect!
I missed that. So the app would have to either add them to its models or define something like |
If you use |
I guess none of these changes are actually needed for the They should probably be in some example though, maybe even |
How are you restricting the columns returned in eager queries? The relation expression only seems to filter for eager properties (whole models). |
I guess this would be more accurate: type EagerModel<T extends Objection.Model> =
{'#id'?: string;} & Partial<T> |
{'#ref': string;} |
{'#dbRef': number;}; 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 |
I got my answer: Only question is, should we revise the |
You need to ask @mceachen about changing the example project. |
As I've said in other comments, I think there's value in keeping the IOW, @koskimas, is it OK to add |
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 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. |
With Conditional types introduced in TypeScript 2.8, we can update typings as follows: type GraphModel<T> =
| ({'#id'?: string; '#ref'?: never; '#dbRef'?: never} & T)
| ({'#id'?: never; '#ref': string; '#dbRef'?: never} & {
[P in keyof T]?: never
})
| ({'#id'?: never; '#ref'?: never; '#dbRef': number} & {
[P in keyof T]?: never
});
type NonFunctionPropertyNames<T> = {
[K in keyof T]: T[K] extends Function ? never : K
}[keyof T];
interface DeepPartialGraphArray<T> extends Array<DeepPartialGraph<T>> {}
type DeepPartialGraphModel<T> =
| GraphModel<{[P in NonFunctionPropertyNames<T>]?: DeepPartialGraph<T[P]>}>
| Partial<T>;
type DeepPartialGraph<T> =
T extends (any[] | ReadonlyArray<any>) ? DeepPartialGraphArray<T[number]> :
T extends Model ? DeepPartialGraphModel<T> :
T;
interface InsertGraph<QM extends Model> {
(
modelsOrObjects?: DeepPartialGraph<QM>[],
options?: InsertGraphOptions,
): QueryBuilder<QM, QM[]>;
(
modelOrObject?: DeepPartialGraph<QM>,
options?: InsertGraphOptions,
): QueryBuilder<QM, QM>;
(): this;
} Then there's no need to type model's relation properties with Would you be willing to accept a PR with this change? @koskimas |
Ping @koskimas |
@yenbekbay your types LGTM, thanks for taking the time to do that. A PR would be great! |
Update TypeScript typings for `QueryBuilder#insertGraph` and `QueryBuilder#upsertGraph` methods to support nested 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()
andupsertGraph()
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:
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 thePartial<T>
parameter ofinsertGraph()
andupsertGraph()
, 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
The text was updated successfully, but these errors were encountered: