Skip to content

Commit

Permalink
feat(repository): hasManyThrough - implement DefaultHasManyThroughRep…
Browse files Browse the repository at this point in the history
…ository
  • Loading branch information
derdeka committed Mar 3, 2020
1 parent 97b976f commit e251996
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,24 +1,68 @@
import {Entity, EntityCrudRepository, Getter, HasManyThroughDefinition} from "../..";
import {DefaultHasManyThroughRepository, HasManyThroughRepository} from "./has-many-through.repository";
import {
DataObject,
Entity,
EntityCrudRepository,
Getter,
HasManyThroughDefinition,
} from '../..';
import {
createTargetConstraint,
createThroughConstraint,
resolveHasManyThroughMetadata,
} from './has-many-through.helpers';
import {
DefaultHasManyThroughRepository,
HasManyThroughRepository,
} from './has-many-through.repository';

export type HasManyThroughRepositoryFactory<
TargetEntity extends Entity,
TargetID,
ThroughEntity extends Entity,
ThroughID,
> = (fkValue: ThroughID) => HasManyThroughRepository<TargetEntity, TargetID, ThroughEntity>;
ForeignKeyType
> = (
fkValue: ForeignKeyType,
) => HasManyThroughRepository<TargetEntity, TargetID, ThroughEntity>;

export function createHasManyThroughRepositoryFactory<
TargetEntity extends Entity,
TargetID,
ThroughEntity extends Entity,
ThroughID,
ForeignKeyType
>(
relationMetadata: HasManyThroughDefinition,
targetRepositoryGetter: Getter<EntityCrudRepository<TargetEntity, TargetID>>,
throughRepositoryGetter: Getter<EntityCrudRepository<ThroughEntity, ThroughID>>,
): HasManyThroughRepositoryFactory<TargetEntity, TargetID, ThroughEntity, ThroughID> {
return (fkValue?: ThroughID) => {
throughRepositoryGetter: Getter<
EntityCrudRepository<ThroughEntity, ThroughID>
>,
): HasManyThroughRepositoryFactory<
TargetEntity,
TargetID,
ThroughEntity,
ForeignKeyType
> {
const meta = resolveHasManyThroughMetadata(relationMetadata);
return (fkValue?: ForeignKeyType) => {
const getTargetContraint = (
throughInstances: ThroughEntity[],
): DataObject<TargetEntity> => {
return createTargetConstraint<TargetEntity, ThroughEntity>(
meta,
throughInstances,
);
};
const getThroughConstraint = (
targetInstance?: TargetEntity,
): DataObject<ThroughEntity> => {
const constriant: DataObject<ThroughEntity> = createThroughConstraint<
TargetEntity,
ThroughEntity,
ForeignKeyType
>(meta, fkValue, targetInstance);
return constriant;
};

return new DefaultHasManyThroughRepository<
TargetEntity,
TargetID,
Expand All @@ -29,6 +73,8 @@ export function createHasManyThroughRepositoryFactory<
>(
targetRepositoryGetter,
throughRepositoryGetter,
getTargetContraint,
getThroughConstraint,
);
}
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import {DataObject, Entity, HasManyThroughDefinition} from '../..';

export type HasManyThroughResolvedDefinition = HasManyThroughDefinition;

/**
* Creates constraint used to query target
* @param relationMeta - hasManyThrough metadata to resolve
* @param throughInstances - Instances of through entities used to constrain the target
* @internal
*/
export function createTargetConstraint<
Target extends Entity,
Through extends Entity
>(
relationMeta: HasManyThroughResolvedDefinition,
throughInstances: Through[],
): DataObject<Target> {
throw new Error('Not implemented');
}

/**
* Creates constraint used to query through
* @param relationMeta - hasManyThrough metadata to resolve
* @param fkValue - Value of the foreign key used to constrain through
* @param targetInstance - Instance of target entity used to constrain through
* @internal
*/
export function createThroughConstraint<
Target extends Entity,
Through extends Entity,
ForeignKeyType
>(
relationMeta: HasManyThroughResolvedDefinition,
fkValue?: ForeignKeyType,
targetInstance?: Target,
): DataObject<Through> {
throw new Error('Not implemented');
}

/**
* Resolves given hasMany metadata if target is specified to be a resolver.
* Mainly used to infer what the `keyTo` property should be from the target's
* belongsTo metadata
* @param relationMeta - hasManyThrough metadata to resolve
* @internal
*/
export function resolveHasManyThroughMetadata(
relationMeta: HasManyThroughDefinition,
): HasManyThroughResolvedDefinition {
throw new Error('Not implemented');
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@

import {Getter} from '@loopback/core';
import {Count, DataObject, Entity, Filter, Options, Where} from '../..';
import {EntityCrudRepository} from '../../repositories';
import {
constrainDataObject,
constrainFilter,
constrainWhere,
EntityCrudRepository,
} from '../../repositories';

/**
* CRUD operations for a target repository of a HasManyThrough relation
Expand Down Expand Up @@ -107,12 +112,17 @@ export class DefaultHasManyThroughRepository<
TargetRepository extends EntityCrudRepository<TargetEntity, TargetID>,
ThroughEntity extends Entity,
ThroughID,
ThroughRepository extends EntityCrudRepository<ThroughEntity, ThroughID>,
> implements HasManyThroughRepository<TargetEntity, TargetID, ThroughEntity> {

ThroughRepository extends EntityCrudRepository<ThroughEntity, ThroughID>
> implements HasManyThroughRepository<TargetEntity, TargetID, ThroughEntity> {
constructor(
public targetRepositoryGetter: Getter<TargetRepository>,
public throughRepositoryGetter: Getter<ThroughRepository>,
public getTargetRepository: Getter<TargetRepository>,
public getThroughRepository: Getter<ThroughRepository>,
public getTargetConstraint: (
throughInstances: ThroughEntity[],
) => DataObject<TargetEntity>,
public getThroughConstraint: (
targetInstance?: TargetEntity,
) => DataObject<ThroughEntity>,
) {}

async create(
Expand All @@ -122,7 +132,21 @@ export class DefaultHasManyThroughRepository<
throughOptions?: Options;
},
): Promise<TargetEntity> {
throw new Error("Method not implemented.");
const targetRepository = await this.getTargetRepository();
const throughRepository = await this.getThroughRepository();
const targetInstance = await targetRepository.create(
targetModelData,
options,
);
const throughConstraint = this.getThroughConstraint(targetInstance);
await throughRepository.create(
constrainDataObject(
options?.throughData ?? {},
throughConstraint as DataObject<ThroughEntity>,
),
options?.throughOptions,
);
return targetInstance;
}

async find(
Expand All @@ -131,7 +155,18 @@ export class DefaultHasManyThroughRepository<
throughOptions?: Options;
},
): Promise<TargetEntity[]> {
throw new Error("Method not implemented.");
const targetRepository = await this.getTargetRepository();
const throughRepository = await this.getThroughRepository();
const throughConstraint = this.getThroughConstraint();
const throughInstances = await throughRepository.find(
constrainFilter(undefined, throughConstraint),
options?.throughOptions,
);
const targetConstraint = this.getTargetConstraint(throughInstances);
return targetRepository.find(
constrainFilter(filter, targetConstraint),
options,
);
}

async delete(
Expand All @@ -140,7 +175,19 @@ export class DefaultHasManyThroughRepository<
throughOptions?: Options;
},
): Promise<Count> {
throw new Error("Method not implemented.");
const targetRepository = await this.getTargetRepository();
const throughRepository = await this.getThroughRepository();
const throughConstraint = this.getThroughConstraint();
// TODO(derdeka): How to delete throughInstances?
const throughInstances = await throughRepository.find(
constrainFilter(undefined, throughConstraint),
options?.throughOptions,
);
const targetConstraint = this.getTargetConstraint(throughInstances);
return targetRepository.deleteAll(
constrainWhere(where, targetConstraint as Where<TargetEntity>),
options,
);
}

async patch(
Expand All @@ -150,7 +197,19 @@ export class DefaultHasManyThroughRepository<
throughOptions?: Options;
},
): Promise<Count> {
throw new Error("Method not implemented.");
const targetRepository = await this.getTargetRepository();
const throughRepository = await this.getThroughRepository();
const throughConstraint = this.getThroughConstraint();
const throughInstances = await throughRepository.find(
constrainFilter(undefined, throughConstraint),
options?.throughOptions,
);
const targetConstraint = this.getTargetConstraint(throughInstances);
return targetRepository.updateAll(
constrainDataObject(dataObject, targetConstraint),
constrainWhere(where, targetConstraint as Where<TargetEntity>),
options,
);
}

async link(
Expand All @@ -160,7 +219,7 @@ export class DefaultHasManyThroughRepository<
throughOptions?: Options;
},
): Promise<TargetEntity> {
throw new Error("Method not implemented.");
throw new Error('Method not implemented.');
}

async unlink(
Expand All @@ -169,6 +228,6 @@ export class DefaultHasManyThroughRepository<
throughOptions?: Options;
},
): Promise<void> {
throw new Error("Method not implemented.");
throw new Error('Method not implemented.');
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@

import {Entity, EntityResolver} from '../../model';
import {relation} from '../relation.decorator';
import {HasManyDefinition, RelationType, HasManyThroughDefinition} from '../relation.types';
import {
HasManyDefinition,
RelationType,
HasManyThroughDefinition,
} from '../relation.types';

/**
* Decorator for hasMany
Expand Down
13 changes: 10 additions & 3 deletions packages/repository/src/repositories/legacy-juggler-bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,19 @@ export class DefaultCrudRepository<
TargetEntiy extends Entity,
TargetID,
ThroughEntity extends Entity,
ThroughID,
ThroughID
>(
relationName: string,
targetRepositoryGetter: Getter<EntityCrudRepository<TargetEntiy, TargetID>>,
throughRepositoryGetter: Getter<EntityCrudRepository<ThroughEntity, ThroughID>>,
): HasManyThroughRepositoryFactory<TargetEntiy, TargetID, ThroughEntity, ThroughID> {
throughRepositoryGetter: Getter<
EntityCrudRepository<ThroughEntity, ThroughID>
>,
): HasManyThroughRepositoryFactory<
TargetEntiy,
TargetID,
ThroughEntity,
ThroughID
> {
const meta = this.entityClass.definition.relations[relationName];
return createHasManyThroughRepositoryFactory<
TargetEntiy,
Expand Down

0 comments on commit e251996

Please sign in to comment.