Skip to content

Commit

Permalink
feat(objection): fixup PR based on comments
Browse files Browse the repository at this point in the history
  • Loading branch information
Ross MacPhee committed Sep 7, 2022
1 parent 3099485 commit f8b7661
Show file tree
Hide file tree
Showing 12 changed files with 53 additions and 38 deletions.
15 changes: 12 additions & 3 deletions docs/tutorials/objection.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,27 +124,32 @@ When used in conjunction with @@Entity@@ and @@IdColumn@@, Ts.ED attempts to pro
In the instance of @@BelongsToOne@@, the default join keys will be:

```json
// (e.g.: `movie.ownerId` and `user.id`)
{
"from": "<sourceModelTable>.<foreignModelProperty>Id",
"to": "<foreignModelTable>.<foreignModelIdColumn>"
}
```

::: tip
An example of the keys outputted above could be `movie.ownerId` and `user.id` respectively.
:::

In the instances of @@HasMany@@ and @@HasOne@@, the default join keys will be:

```json
// (e.g.: `user.id` and `authentication.userId`)
{
"from": "<sourceModelTable>.<sourceModelIdColumn>",
"to": "<foreignModelTable>.<sourceModelTable>Id"
}
```

::: tip
An example of the keys outputted above could be `user.id` and `authentication.userId` respectively.
:::

In the instances of @@ManyToMany@@ and @@HasOneThroughRelation@@, the default join key will be:

```json
// (e.g.: `user.id`, `user_authentication.userId`, `user_authentication.authenticationId` `authentication.id`)
{
"from": "<sourceModelTable>.<sourceModelIdColumn>",
"through": {
Expand All @@ -155,6 +160,10 @@ In the instances of @@ManyToMany@@ and @@HasOneThroughRelation@@, the default jo
}
```

::: tip
An example of the keys outputted above could be `user.id`, `user_authentication.userId`, `user_authentication.authenticationId` and `authentication.id` respectively.
:::

## Get connection

```typescript
Expand Down
4 changes: 2 additions & 2 deletions packages/orm/objection/src/decorators/belongsToOne.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {Model} from "objection";
import {RelatesTo} from "./relatesTo";
import {SingularRelationshipOpts} from "../domain/RelationshipOpts";
import {RelationshipOptsWithoutThrough} from "../domain/RelationshipOpts";

/**
*
* @param opts
* @decorator
* @objection
*/
export function BelongsToOne(opts?: SingularRelationshipOpts): PropertyDecorator {
export function BelongsToOne(opts?: RelationshipOptsWithoutThrough): PropertyDecorator {
return RelatesTo(Model.BelongsToOneRelation, opts);
}
4 changes: 2 additions & 2 deletions packages/orm/objection/src/decorators/hasMany.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe("@HasMany", () => {
class User extends Model {
@IdColumn()
id!: string;
@HasMany({modelClass: Pet})
@HasMany(Pet)
pets?: Pet[];
}
expect(User.relationMappings).toEqual({
Expand All @@ -40,7 +40,7 @@ describe("@HasMany", () => {
@IdColumn()
id!: string;
userId!: string;
@HasMany({modelClass: Pet, from: "userId", to: "ownerId"})
@HasMany(Pet, {from: "userId", to: "ownerId"})
pets?: Pet[];
}
expect(User.relationMappings).toEqual({
Expand Down
9 changes: 5 additions & 4 deletions packages/orm/objection/src/decorators/hasMany.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {Model} from "objection";
import {PluralRelationshipOptsWithThrough} from "../domain/RelationshipOpts";
import {Model, ModelClassSpecifier} from "objection";

import {RelatesTo} from "./relatesTo";
import {RelationshipOptsWithThrough} from "../domain/RelationshipOpts";

/**
*
* @param opts
* @decorator
* @objection
*/
export function HasMany(opts: PluralRelationshipOptsWithThrough): PropertyDecorator {
return RelatesTo(Model.HasManyRelation, opts);
export function HasMany(type: ModelClassSpecifier, opts?: RelationshipOptsWithThrough): PropertyDecorator {
return RelatesTo(Model.HasManyRelation, {...opts, type});
}
4 changes: 2 additions & 2 deletions packages/orm/objection/src/decorators/hasOne.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {Model} from "objection";
import {RelatesTo} from "./relatesTo";
import {SingularRelationshipOpts} from "../domain/RelationshipOpts";
import {RelationshipOptsWithoutThrough} from "../domain/RelationshipOpts";

/**
*
* @param opts
* @decorator
* @objection
*/
export function HasOne(opts?: SingularRelationshipOpts): PropertyDecorator {
export function HasOne(opts?: RelationshipOptsWithoutThrough): PropertyDecorator {
return RelatesTo(Model.HasOneRelation, opts);
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {RelationshipOptsWithThrough, RelationshipOptsWithoutThrough} from "../domain/RelationshipOpts";

import {Model} from "objection";
import {RelatesTo} from "./relatesTo";
import {SingularRelationshipOptsWithThrough} from "../domain/RelationshipOpts";

/**
*
* @param opts
* @decorator
* @objection
*/
export function HasOneThroughRelation(opts?: SingularRelationshipOptsWithThrough): PropertyDecorator {
export function HasOneThroughRelation(opts?: RelationshipOptsWithThrough): PropertyDecorator {
return RelatesTo(Model.HasOneThroughRelation, opts);
}
7 changes: 3 additions & 4 deletions packages/orm/objection/src/decorators/manyToMany.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ describe("@ManyToMany", () => {
class User extends Model {
@IdColumn()
id!: string;
@ManyToMany({modelClass: Pet})
@ManyToMany(Pet)
pets?: Pet[];
}
expect(User.relationMappings).toEqual({
Expand Down Expand Up @@ -44,11 +44,10 @@ describe("@ManyToMany", () => {
@IdColumn()
id!: string;
userId!: string;
@ManyToMany({
@ManyToMany(Pet, {
from: "userId",
through: {from: "user_pet.ownerId", to: "user_pet.petId"},
to: "petId",
modelClass: Pet
to: "petId"
})
pets?: Pet[];
}
Expand Down
9 changes: 5 additions & 4 deletions packages/orm/objection/src/decorators/manyToMany.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import {Model} from "objection";
import {PluralRelationshipOptsWithThrough} from "../domain/RelationshipOpts";
import {Model, ModelClassSpecifier} from "objection";

import {RelatesTo} from "./relatesTo";
import {RelationshipOptsWithThrough} from "../domain/RelationshipOpts";

/**
*
* @param opts
* @decorator
* @objection
*/
export function ManyToMany(opts: PluralRelationshipOptsWithThrough): PropertyDecorator {
return RelatesTo(Model.ManyToManyRelation, opts);
export function ManyToMany(type: ModelClassSpecifier, opts?: RelationshipOptsWithThrough): PropertyDecorator {
return RelatesTo(Model.ManyToManyRelation, {...opts, type});
}
8 changes: 5 additions & 3 deletions packages/orm/objection/src/decorators/relatesTo.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import {CollectionOf, Property} from "@tsed/schema";
import {RelationshipOpts, isModelClassFactory} from "../domain/RelationshipOpts";
import {StoreFn, useDecorators} from "@tsed/core";

import {OBJECTION_RELATIONSHIP_KEY} from "../utils/getJsonEntityRelationships";
import {RelationType} from "objection";
import {RelationshipOpts} from "../domain/RelationshipOpts";
import {createRelationshipMapping} from "../utils/createRelationshipMapping";

/**
Expand All @@ -15,9 +15,11 @@ import {createRelationshipMapping} from "../utils/createRelationshipMapping";
*/
export function RelatesTo(relation: RelationType, opts?: RelationshipOpts): PropertyDecorator {
return useDecorators(
Property(),
...(opts && "modelClass" in opts ? [CollectionOf(opts!.modelClass)] : []),
opts?.type ? CollectionOf(opts.type) : Property(),
StoreFn((store, params) => {
if (opts && isModelClassFactory(opts.type)) {
opts.type = opts.type();
}
store.set(OBJECTION_RELATIONSHIP_KEY, createRelationshipMapping(params, relation, opts));
})
);
Expand Down
16 changes: 9 additions & 7 deletions packages/orm/objection/src/domain/RelationshipOpts.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import {RelationJoin, RelationMapping} from "objection";
import {isFunction, isString} from "@tsed/core";
import {ModelClassFactory, ModelClassSpecifier, RelationJoin, RelationMapping} from "objection";

import {Type} from "@tsed/core";
export type RelationshipOptsWithThrough = Partial<RelationJoin> & Omit<RelationMapping<any>, "relation" | "join" | "modelClass">;

export type PluralRelationshipOptsWithThrough = Partial<RelationJoin> &
Omit<RelationMapping<any>, "relation" | "join" | "modelClass"> & {modelClass: Type<any>};
export type RelationshipOptsWithoutThrough = Omit<RelationshipOptsWithThrough, "through">;

export type SingularRelationshipOptsWithThrough = Omit<PluralRelationshipOptsWithThrough, "modelClass">;
export type RelationshipOpts = (RelationshipOptsWithThrough | RelationshipOptsWithoutThrough) & {type?: ModelClassSpecifier};

export type SingularRelationshipOpts = Omit<SingularRelationshipOptsWithThrough, "through">;
export const isRelationshipOptsWithThrough = (opts?: RelationshipOpts): opts is RelationshipOptsWithThrough =>
opts !== undefined && (<RelationshipOptsWithThrough>opts).through !== undefined;

export type RelationshipOpts = PluralRelationshipOptsWithThrough | SingularRelationshipOptsWithThrough | SingularRelationshipOpts;
export const isModelClassFactory = (type?: ModelClassSpecifier): type is ModelClassFactory =>
type !== undefined && !isString(type) && isFunction(type) && !("prototype" in type);
8 changes: 4 additions & 4 deletions packages/orm/objection/src/utils/createJoinKeys.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import {Model, RelationType} from "objection";
import {RelationshipOpts, isRelationshipOptsWithThrough} from "../domain/RelationshipOpts";

import {Metadata} from "@tsed/core";
import {RelationshipOpts} from "../domain/RelationshipOpts";

/**
* @ignore
*/
export function createJoinKeys(targetClass: any, target: any, propertyKey: string, relation: RelationType, opts?: RelationshipOpts) {
const FOREIGN_MODEL = (opts && "modelClass" in opts && opts.modelClass) || Metadata.getType(target, propertyKey);
export function createJoinKeys(targetClass: any, targetSuper: any, propertyKey: string, relation: RelationType, opts?: RelationshipOpts) {
const FOREIGN_MODEL = opts?.type || Metadata.getType(targetSuper, propertyKey);
const SOURCE_MODEL_KEY = `${targetClass.tableName}.${opts?.from || targetClass.idColumn}`;
const FOREIGN_MODEL_KEY = `${FOREIGN_MODEL.tableName}.${opts?.to || FOREIGN_MODEL.idColumn}`;

Expand All @@ -22,7 +22,7 @@ export function createJoinKeys(targetClass: any, target: any, propertyKey: strin
case Model.HasOneThroughRelation:
return {
from: SOURCE_MODEL_KEY,
through: (opts && "through" in opts && opts.through) || {
through: (isRelationshipOptsWithThrough(opts) && opts.through) || {
from: `${targetClass.tableName}_${FOREIGN_MODEL.tableName}.${targetClass.tableName}Id`,
to: `${targetClass.tableName}_${FOREIGN_MODEL.tableName}.${FOREIGN_MODEL.tableName}Id`
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function createRelationshipMapping([target, propertyKey]: DecoratorParame
return (targetClass: any) => ({
[propertyKey]: {
relation,
modelClass: (opts && "modelClass" in opts && opts.modelClass) || Metadata.getType(target, propertyKey),
modelClass: opts?.type || Metadata.getType(target, propertyKey),
join: createJoinKeys(targetClass, target, String(propertyKey), relation, opts),
modify: opts?.modify,
filter: opts?.filter,
Expand Down

0 comments on commit f8b7661

Please sign in to comment.