Base Service
You can inject BaseService
into Services
or Resolvers
.
BaseService
can be thought of as a wrapper of mongoose
Model
.
It provides basic CRUD operations with context
and Hooks
.
Interface
Below is the type of BaseService
, which shows the methods and their parameters.
class BaseService<T = any, Context = any> {
model: PaginateModel<T>;
create(ctx: Context, input: Partial<T>): Promise<T>;
update(ctx: Context, input: Partial<T> & { id: ObjectId }): Promise<T>;
findById(ctx: Context, filter: { _id: ObjectId }): Promise<T>;
findByIdNullable(ctx: Context, filter: { _id: ObjectId }): Promise<T | null>;
findOne(ctx: Context, filter: FilterQuery<T>): Promise<T>;
findOneNullable(ctx: Context, filter: FilterQuery<T>): Promise<T | null>;
findOne(ctx: Context, filter: mongoose.FilterQuery<T>): Promise<T>;
findAll(ctx: Context, filter: mongoose.FilterQuery<T>, sort: object): Promise<T[]>;
remove(ctx: Context, id: ObjectId, options?: RemoveOptions): Promise<SuccessResponse>;
paginate(ctx: Context, filter: FilterQuery<T>, sort: object, page: number, limit: number): PaginateResult;
}
update
and remove
methods use findOne
under the hood.
Inject BaseService
Below is an example of how to inject BaseService
import { BaseService, InjectBaseService } from 'dryerjs';
type Context = { user: { id: ObjectId, role: 'admin' | 'user' } }
@Injectable()
class AuthService {
constructor(@InjectBaseService(User) public userService: BaseService<User, Context>) {}
async refreshToken(ctx: Context) {
const user = await this.userService.findOne(ctx, { _id: ctx.user.id });
// fake function to generate token
return getTokenFromUser(user);
}
}
Use Mongoose Model
BaseService
only covers the basic CRUD operations with context, if you want to use more advanced features or context free,
you can use mongoose
Model
directly by accessing model
property of BaseService
.
@Injectable()
class AuthService {
constructor(@InjectBaseService(User) public userService: BaseService<User, Context>) {}
async isEmailTaken(email: string) {
return await this.userService.model.exists({ email });
}
}
Context object
Context
normally comes from the Resolvers
, but you can also create your own context object to pass into BaseService
methods.
@Injectable()
class AuthService {
async cron() {
const adminContext: Context = { user: { id: '000000000000000000000000', role: 'admin' } };
const oneYearAgo = new Date(Date.now() - 365 * 86400 * 1000);
const users = await this.userService.findAll(ctx, { lastLoggedInAt: { $lt: oneYearAgo } });
for (const user of users) {
await this.userService.update(adminContext, { id: user.id, status: 'inactive' });
}
}
}
Compare with using mongoose
Model
directly, calling update
method with BaseService
will trigger beforeUpdateHook
and afterUpdateHook
.
Which could be extremely important if you have some logic in the hooks.