Skip to content

Instantly share code, notes, and snippets.

@savioserra
Created May 1, 2020 23:27
Show Gist options
  • Save savioserra/d0d31836965158b94ec518c9068597fb to your computer and use it in GitHub Desktop.
Save savioserra/d0d31836965158b94ec518c9068597fb to your computer and use it in GitHub Desktop.
Data Loaders
import { ObjectType, DeepPartial, EntityManager, Connection, FindConditions } from 'typeorm';
import { Injectable, Scope } from '@nestjs/common';
import { InjectConnection } from '@nestjs/typeorm';
import DataLoader from 'dataloader';
@Injectable({ scope: Scope.REQUEST })
export abstract class BaseService<M extends { id: string }> {
abstract get type(): ObjectType<M>;
protected loader: DataLoader<string, M>;
constructor(@InjectConnection() protected connection: Connection) {
this.loader = new DataLoader((ids: string[]) => this.connection.manager.findByIds(this.type, ids));
}
getManager(entityManager?: EntityManager) {
return entityManager || this.connection.manager;
}
async create(plainObject: DeepPartial<M>, manager?: EntityManager): Promise<M> {
const entityManager = this.getManager(manager);
const entity = entityManager.create(this.type, { ...plainObject });
await entityManager.save(entity);
this.loader.prime(entity.id, entity);
return entity;
}
async find(find: FindConditions<M>, manager?: EntityManager): Promise<M[]> {
const entityManager = this.getManager(manager);
const entities = await entityManager.find(this.type, { where: find });
entities.forEach((e) => this.loader.prime(e.id, e));
return entities;
}
async findByIds(ids: string[]): Promise<(M | Error)[]> {
return this.loader.loadMany(ids);
}
async findById(id: string): Promise<M> {
return this.loader.load(id);
}
async findOne(find: FindConditions<M>, manager?: EntityManager): Promise<M> {
if (!find) return null;
const entityManager = this.getManager(manager);
const entity = await entityManager.findOne(this.type, { where: { ...find } });
if (entity) this.loader.prime(entity.id, entity);
return entity;
}
async findOrCreate(find: FindConditions<M>, create: DeepPartial<M>, manager?: EntityManager): Promise<M> {
const entityManager = this.getManager(manager);
const findResult = await this.findOne(find, entityManager);
if (findResult) return findResult;
if (!create) throw new Error('Cannot find resource. Make sure to provide "create" data.');
return this.create(create, entityManager);
}
async transaction<T>(callback: (manager: EntityManager) => Promise<T>): Promise<T> {
return this.connection.transaction(callback);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment