How should I create a PrismaAdapter - node.js

I would like to create a PrismaAdapter,the model should be a string or the PrismaModel (i dont know how to type it) but I am struggling and I don't know if it is even possible. Here is my failed attempt.
thx for your help
import { PrismaClient } from '#prisma/client'
//type PrismaModel = keyof PrismaClient<PrismaClientOptions>
//type PrismaModel = keyof Prisma.userDelegate<GlobalReject>
//type PrismaUserModel = Prisma.userDelegate<GlobalReject>;
class PrismaAdapter {
private prisma: PrismaClient
private user: PrismaUserModel
constructor() {
this.prisma = new PrismaClient()
this.user = this.prisma.user
}
async findOne(model: PrismaModel, where: object): Promise<any> {
return await this.prisma[model].findOne({ where })
}
async findMany(model: string): Promise<any[]> {
return await this.prisma[model].findMany()
}
async create(model: PrismaModel, data: object): Promise<any> {
return await this.prisma[model].create({ data })
}
async update(model: string, where: object, data: object): Promise<any> {
return await this.prisma[model].update({ where, data })
}
async delete(model: string, where: object): Promise<any> {
return await this.prisma[model].delete({ where })
}
}
export default PrismaAdapter
I am expecting to use it in a Database service class.
import PrismaAdapter from "./PrismaAdapter";
class DatabaseAdapter {
private database: PrismaAdapter;
private model: PrismaModel;
constructor({database, model}: {database: PrismaAdapter, model: PrismaModel}) {
this.database = database;
}
async findOne(model :PrismaModel,id: number): Promise<any> {
return this.database.findOne(model,where: {id})
}
async findMany(model: string): Promise<any[]> {
return await this.database.findMany(model)
}
}
export default DatabaseAdapter
And use this database Adapter in for exemple a UserRepository.

Related

How to fix this Implementation that doesn't work?

The users repository implements IUsersRepository, although i cant get the values from IUsersRepository
The error that is shown
UserRepository implementing the IUserRepository Interface
import { getRepository, Repository } from "typeorm";
import { IUsersRepository } from "../IUsersRepository";
import { User } from "../../entities/User";
import { ICreateUserDTO } from "../../../../dtos/usersDto";
class UsersRepository implements IUsersRepository {
private repository: Repository<User>;
constructor() {
this.repository = getRepository (User);
}
async create({ name, email, password, age }: ICreateUserDto): Promise<void> {
const user = this.repository.create({
name,
email,
password,
age
});
await this.repository.save(user);
}
async findBy Email(email: string): Promise<User> {
const user = this.repository.findByEmail({ email });
return user;
}
async findById(id: string): Promise<User> {
const user = this.repository.findById(id);
return user;
}
export { Users Repository }
IUserRepository Interface:
import { ICreateUserDTO } from "../../../dtos/usersDto",
import { User } from "../entities/User";
interface IUsersRepository {
create (data: ICreateUserDTO): Promise<void>;
findByEmail(email: string): Promise<User>;
findById(id: string): Promise<User>;
}
export { IUsersRepository }
How could I fix it?
findByEmail is not function of typeorm's Repository class.
It is even marked with a red line in your screenshot.
You need to write the proper query there!

Using Fastify preHandler middleware

Passing a middleware to authenticate user before accessing this route.
When I'm passing tokenController.authUser as a middleware tokenService inside tokenController is undefined. However when I run this method as a function inside the route instead of a middleware it works fine.
server.post('/api/admin/test', { preHandler: [tokenController.authUser] }, async (request: any, reply: any) => {
return null
});
Token Controller :-
import { Users } from "#prisma/client";
import ITokenService from "../../services/tokenService/ITokenService";
import ITokenController from "./ITokenController";
export default class TokenController implements ITokenController {
private readonly tokenService: ITokenService;
constructor(_tokenService: ITokenService) {
this.tokenService = _tokenService;
}
async authUser(request: any, reply: any): Promise<Users | Error> {
const authHeader = request.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (token === null)
return reply.code(401);
try {
const result = await this.tokenService.verifyToken(token);
console.log(result);
return result;
}
catch (e) {
reply.code(401);
return new Error("Error");
}
}
}
Token Service :-
import { Users } from "#prisma/client";
import ITokenService from "./ITokenService";
export default class TokenService implements ITokenService {
private readonly sign: Function;
private readonly verify: Function;
private readonly secretKey: string;
constructor(sign: Function, verify: Function, _secretKey: string) {
this.sign = sign;
this.verify = verify;
this.secretKey = _secretKey;
}
public async generateToken(user: Users): Promise<string> {
return await this.sign({ user }, this.secretKey);
}
public async verifyToken(token: string): Promise<Users | Error> {
const result = await this.verify(token, this.secretKey);
return result;
}
}
For some reason making a separate middleware function and calling tokenController.authUser inside that method works fine.
const middleware = (_req, _res, next) => {
console.log('middleware');
next()
}
server.post('/api/admin/test', { preHandler: [middleware] }, async (request: any, reply: any) => {
return null
});

Is there a way to insert current user into fields in base entity before inserting data

How to to insert current logged in user to createdBy & lastChangedBy fields after creating/updating entity?
In my BaseEntity i've tried
#BeforeInsert()
async insertUser(#GetAuthUserPayload() userPayload: User) {
const user = await this.usersService.findOne({
where: { username: userPayload.username },
});
this.createdBy = user;
this.lastChangedBy = user;
}
But i've found out decorators work only in controllers(in entity they return undefined). Is there any other way than updating DTO in controller or using session?
Since i am using #nestjsx/crud i haven't found any other method than updating DTO. I've managed to solve this issue by creating BaseService:
import { TypeOrmCrudService } from '#nestjsx/crud-typeorm';
import { InjectRepository } from '#nestjs/typeorm';
import { Inject, Injectable, Scope, Type } from '#nestjs/common';
import { CrudRequest, Override } from '#nestjsx/crud';
import { DeepPartial } from 'typeorm';
import { REQUEST } from '#nestjs/core';
import { User } from '../users/entities/user.entity';
export interface IBaseService<T> {}
type Constructor<I> = new (...args: any[]) => I;
export function BaseService<T>(entity: Constructor<T>): Type<IBaseService<T>> {
#Injectable({
scope: Scope.REQUEST,
})
class BaseServiceHost extends TypeOrmCrudService<T> implements IBaseService<T> {
constructor(#InjectRepository(entity) repo, #Inject(REQUEST) readonly request: any) {
super(repo);
}
#Override()
createOne(req: CrudRequest, dto: DeepPartial<T>): Promise<T> {
return super.createOne(req, this.addCreatedByToDTO(dto));
}
#Override()
replaceOne(req: CrudRequest, dto: DeepPartial<T>): Promise<T> {
return super.replaceOne(req, this.addLastChangedByToDTO(dto));
}
#Override()
updateOne(req: CrudRequest, dto: DeepPartial<T>): Promise<T> {
return super.updateOne(req, this.addLastChangedByToDTO(dto));
}
private addCreatedByToDTO(dto: DeepPartial<T>): DeepPartial<T> {
const userUUID: Partial<User> = this.request.user.userUUID;
return { ...dto, createdBy: userUUID };
}
private addLastChangedByToDTO(dto: DeepPartial<T>): DeepPartial<T> {
const userUUID: Partial<User> = this.request.user.userUUID;
return { ...dto, lastChangedBy: userUUID };
}
}
return BaseServiceHost;
}
Later on i just extend my service like:
#Injectable()
export class ExampleService extends BaseService(ExampleEntity) {}

Trying to call by Enum (NestJS)

I'm coding on NestJS and I'm trying to call my database info by enumeration.
Example: I want all of motherboard (motherboard is an enum). I'm having many options for this.
I would like your opinion and for you, what is the best option?
This is my Entity :
#Entity('component')
export class Component {
static idComponent(idComponent: any): Component[] | PromiseLike<Component[]> {
throw new Error('Method not implemented.');
}
#PrimaryGeneratedColumn()
idComponent: number;
#Column()
name: string;
#Column()
brand: string;
#Column()
availability: string;
#Column()
price: string;
#Column('enum', { enum: ComponentType })
type: ComponentType;
service_type: ComponentType;
#Column('datetime', { default: () => 'CURRENT_TIMESTAMP' })
date: string;
#ApiProperty({ enum: () => Configurateur })
#OneToMany(() => Configurateur, configurateur => configurateur.component)
ComponentType: Configurateur[];
}
My Controller :
#ApiTags('component')
#Controller('component')
export class ComponentController {
constructor(private componentService: ComponentService) { }
#Get('all')
async findAll(#Res() res) {
const lists = await this.componentService.findAll();
return res.status(HttpStatus.OK).json(lists);
}
#Get('id')
async findById(#Res() res, #Query('id') id: string) {
const lists = await this.componentService.findById(id);
if (!lists) throw new NotFoundException('Id does not exist!');
return res.status(HttpStatus.OK).json(lists);
}
#Get('type')
async findByType(#Res() res, #Query('type') ComponentType: string) {
const listsType = await this.componentService.findByType(ComponentType);
if (!listsType) throw new NotFoundException('Id does not exist!');
return res.status(HttpStatus.OK).json(listsType);
}
}
And my Service :
#Injectable()
export class ComponentService {
constructor(
#InjectRepository(Component)
private readonly componentRepository: Repository<Component>,
) { }
async findAll(): Promise<Component[]> {
return await this.componentRepository.find();
}
async findById(id): Promise<Component[]> {
const customer = await this.componentRepository.findByIds(id);
return customer;
}
async findByType(ComponentType): Promise<any> {
const customerType = await this.componentRepository.find(ComponentType);
return customerType;
}
// Have Error and is a test
getType(ByType): Promise<any> {
let Type = String(ByType);
return new Promise(resolve => {
const type = this.componentRepository.find(type => type.Type === Type);
if (!type) {
throw new HttpException('Course does not exist', 404)
}
resolve(Type)
});
}
}
Edit : CompentType is my Enums file.
Thank you for your time.

typeorm convert EntitySchema to Entity

I'm using typescript and typeorm. I have this Entity:
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
#Entity()
export class Sample {
#PrimaryGeneratedColumn()
id: number;
#Column({ length: 50 })
name: string;
#Column('text', { nullable: true })
description: string;
}
I query a single result like this:
const connection = await this.getConnection();
const sampleRepo = await connection.getRepository(Sample);
const sample = await sampleRepo.createQueryBuilder('sample')
.where('sample.id = :id', { id: id })
.getOne();
Now, I need to do some stuff with the result columns, but the sample object is of type EntitySchema. So, in typescript, I can't do sample.id because the error:
Property 'id' does not exist on type 'EntitySchema<any>'
Is there anyway to convert the EntitySchema into an actual Sample object?
As it turns out, this is due to a bad implementation. I moved the creation of the repository to a separate class:
export default class Database {
private connectionManager: ConnectionManager
constructor() {
this.connectionManager = getConnectionManager();
}
public getRepository<T extends EntitySchema>(type: ObjectType<T> | EntitySchema<T> | string): Promise<Repository<T>> {
const connection = await this.getConnection();
return connection.getRepository(type);
}
public async getConnection(connectionName = 'default'): Promise<Connection> {
let connection: Connection;
if (this.connectionManager.has(connectionName)) {
connection = this.connectionManager.get(connectionName);
if (!connection.isConnected) {
connection = await connection.connect();
}
}
else {
const connectionOptions: ConnectionOptions = Object
.assign({ name: connection }, connectionProperties);
connection = await createConnection(connectionOptions);
}
return connection;
}
}
It looks like connection.getRepository doesn't return a promise. As well, the T generic shouldn't be extending EntitySchema. To make the function work as intended, I had to write it like this:
public getRepository<T>(type: ObjectType<T> | EntitySchema<T> | string): Promise<Repository<T>> {
return new Promise((resolve, reject) => {
this.getConnection().then(conn => {
resolve(conn.getRepository(type));
}).catch(reject);
});
}

Resources