How to fix this Implementation that doesn't work? - node.js

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!

Related

ERROR [ExceptionsHandler] Cannot query across many-to-many for property permissions

I have a project that I have made the project with nestjs and now I have a problem in method's update and the relation is Many-To-Many when I call Put Api nest gives me below error Note: I have 2 entity Role and Permission that they have many-to-many relation together.
I have a update method in role-service that I commented on it that works well but I have made a abstract class and role-service extended it but the method update doesn't work and give me bellow error
request api => url/api/role/id Body => {name:"admin",permissions:[{"id":1},{"id":2}]}
ERROR [ExceptionsHandler] Cannot query across many-to-many for property permissions
-Role Entity
import { Permission } from 'src/permission/model/permission.entity';
import {
Column,
Entity,
JoinTable,
ManyToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
#Entity('roles')
export class Role {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
#ManyToMany((_Type) => Permission, { cascade: true })
#JoinTable({
name: 'role_permissions',
joinColumn: { name: 'role_id', referencedColumnName: 'id' },
inverseJoinColumn: { name: 'permission_id', referencedColumnName: 'id' },
})
permissions: Permission[];
}
Permission Entity
#Entity('permissions')
export class Permission {
#PrimaryGeneratedColumn()
id: number;
#Column()
name: string;
}
Role Controller
import {
Body,
Controller,
Delete,
Get,
Param,
Post,
Put,
UseGuards,
} from '#nestjs/common';
import { AuthGuard } from 'src/auth/auth.guard';
import { RoleCreateDto } from './models/role-create.dto';
import { RoleUpdateDto } from './models/role-update.dto';
import { Role } from './models/role.entity';
import { RoleService } from './role.service';
#UseGuards(AuthGuard)
#Controller('roles')
export class RoleController {
constructor(private roleService: RoleService) {}
#Put(':id')
async update(#Param('id') id: number, #Body() body: RoleUpdateDto) {
await this.roleService.update(id,body);
return await this.roleService.findOne({ id });
}
}
Role service
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { AbstractService } from 'src/common/abstract.service';
import { Repository } from 'typeorm';
import { RoleCreateDto } from './models/role-create.dto';
import { Role } from './models/role.entity';
#Injectable()
export class RoleService extends AbstractService {
constructor(
#InjectRepository(Role) private readonly roleRepository: Repository<Role>,
) {
super(roleRepository)
}
async findOne(condition): Promise<Role> {
return await this.roleRepository.findOne({ where: condition , relations:["permissions"]});
}
// async update(id: number, data:any): Promise<any> {
// console.log(id);
// const role = await this.findOne({id});
// console.log(role);
// role.name = data.name;
// role.permissions= data.permissions;
// const r = await this.roleRepository.preload(role)
// console.log("role",r);
// return await this.roleRepository.save(r);
// }
// async delete(id: number): Promise<any> {
// return await this.roleRepository.delete(id);
// }
}
abstract service
import { Injectable } from '#nestjs/common';
import { Repository } from 'typeorm';
import { PaginatedResult } from './pagibated-result.interface';
#Injectable()
export abstract class AbstractService {
protected constructor(protected readonly repository: Repository<any>) {}
async all(): Promise<any[]> {
return await this.repository.find();
}
async paginate(page = 1): Promise<PaginatedResult> {
const take = 1;
const [data, total] = await this.repository.findAndCount({
take,
skip: (page - 1) * take,
});
return {
data: data,
meta: {
total,
page,
last_page: Math.ceil(total / take),
},
};
}
async create(data): Promise<any> {
return await this.repository.save(data);
}
async findOne(condition): Promise<any> {
return await this.repository.findOne({ where: condition });
}
async update(id: number, data): Promise<any> {
return await this.repository.update({id},data);
}
async delete(id: number): Promise<any> {
return await this.repository.delete(id);
}
}

How should I create a PrismaAdapter

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.

NestJS y TypeORM: built in Repository undefined

i did Inject Repository(User) but it did not work for me .
i want to call : this.users Repository.create
but give this error :
Type Error: this.users Repository.create is not a function
......
i did Inject Repository(User) but it did not work for me .
i want to call : this.users Repository.create
but give this error :
Type Error: this.users Repository.create is not a function
Service :
import { HttpException, HttpStatus, Inject, Injectable,forwardRef } from '#nestjs/common';
import { AuthenticationService } from 'src/authentication/authentication.service';
import { Repository } from 'typeorm';
import CreateUserDto from './dto/create-user.dto';
import { InjectRepository } from '#nestjs/typeorm';
import User from './entities/user.entity';
#Injectable()
export class UserService {
constructor(
#Inject(forwardRef(() => AuthenticationService))
// #Inject(User)
// private usersRepository: Repository<User>
#InjectRepository(User) private usersRepository: Repository<User>,
private readonly authenticationService: AuthenticationService,
) {}
async getByEmail(email: string) {
const user = await this.usersRepository.findOne({ email });
if (user) {
return user;
}
throw new HttpException('User with this email does not exist', HttpStatus.NOT_FOUND);
}
async getById(id: number) {
const user = await this.usersRepository.findOne({ id });
if (user) {
return user;
}
throw new HttpException('User with this id does not exist', HttpStatus.NOT_FOUND);
}
async create(userData: CreateUserDto) {
const newUser = await this.usersRepository.create(userData);
await this.usersRepository.save(newUser);
return newUser;
}
}
Module :
import { Module,forwardRef } from '#nestjs/common';
import { UserService } from './users.service';
import { TypeOrmModule } from '#nestjs/typeorm';
import User from './entities/user.entity';
import { UsersController } from './users.controller';
import { AuthenticationService } from 'src/authentication/authentication.service';
import { ConfigModule, ConfigService } from '#nestjs/config';
import { JwtModule, JwtService } from '#nestjs/jwt';
#Module({
imports: [TypeOrmModule.forFeature([User]),JwtModule.register({})],
providers: [UserService,AuthenticationService,ConfigService],
exports: [UserService,AuthenticationService,ConfigService],
controllers:[UsersController]
})
export class UsersModule {}
Entity :
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
#Entity('User')
class User {
#PrimaryGeneratedColumn()
public id?: number;
#Column({ unique: true })
public email: string;
#Column()
public name: string;
#Column()
public password: string;
}
export default User;
I found a solution by creating a custom repository and extend it with built in works fine.
Here is link :
https://clownhacker.tistory.com/250
I think it happened because I did changes with my entity class, I hope it will help someone.
In my case in this.repository, this was not pointing to correct instance. Used bind to fix it.

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) {}

How to pool postgresql connections in nodejs with facade design pattern?

Hello i am writing simple web application using design similar to facade design pattern. Application is written in Typescript using nodejs, expressjs, node-postres and inversify. Let say i have this simple example
Router.ts
router.get('/test', testController.test);
TestController.ts
import { Request, Response } from 'express';
import { ITestUC } from '../usecase/TestUC';
import { di } from '../core/Di';
import { TYPES } from '../core/Types';
class TestController {
public async test(req: Request, res: Response, next: Function) {
const uc = di.get<ITestUC>(TYPES.ITestUC);
await uc.run();
res.send({ data:1 });
}
}
export const testController = new TestController();
TestUC.ts
import "reflect-metadata";
import { injectable, interfaces } from "inversify";
import { di } from "../core/Di";
import { TYPES } from "../core/Types";
import { ITestManager1 } from "../library/Test/TestManager1";
import { ITestManager2 } from "../library/Test/TestManager2";
import { PoolClient } from "pg";
import { PostgresClient, IPostgresClient } from "../core/PostgresClient";
import { IPostgresPool } from "../core/PostgresPool";
function db(transaction: boolean) {
return (target: any, property: string, descriptor: TypedPropertyDescriptor<() => void>) => {
const fn = descriptor.value;
if(!fn) return;
descriptor.value = async function (){
let poolClient: PoolClient,
postgresClient: PostgresClient = new PostgresClient();
try {
poolClient = await di.get<IPostgresPool>(TYPES.IPostgresPool).pool.connect();
postgresClient.set(poolClient);
di.rebind<IPostgresClient>(TYPES.IPostgresClient).toDynamicValue((context: interfaces.Context) => { return postgresClient });
if (transaction) postgresClient.begin();
await fn.apply(this);
if (transaction) postgresClient.commit();
} catch (e) {
if (transaction) postgresClient.rollback();
throw e;
} finally {
postgresClient.get().release();
}
}
}
}
#injectable()
export class TestUC implements ITestUC {
#db(true)
public async run(): Promise<void> {
const manager1 = await di.get<ITestManager1>(TYPES.ITestManager1);
manager1.test1('m1');
const manager2 = await di.get<ITestManager2>(TYPES.ITestManager2);
manager2.test1('m2');
}
}
export interface ITestUC {
run(): Promise<void>
}
TestManager1.ts
import { injectable, inject} from "inversify";
import "reflect-metadata";
import { TYPES } from "../../core/Types";
import { ITestSql1 } from "./TestSql1";
#injectable()
export class TestManager1 implements ITestManager1 {
#inject(TYPES.ITestSql1) private sql: ITestSql1;
public async test1(value: string) {
await this.sql.test1(value);
}
}
export interface ITestManager1 {
test1(value: string)
}
TestSql1.ts
import { injectable, inject } from "inversify";
import "reflect-metadata";
import { IPostgresClient } from "../../core/PostgresClient";
import { TYPES } from "../../core/Types";
#injectable()
export class TestSql1 implements ITestSql1{
#inject(TYPES.IPostgresClient) db: IPostgresClient;
public async test1(value: string) {
const query = {
name: 'insert-test',
text: `
INSERT INTO pr.test (
process,
operation,
key
) VALUES (
$1,
$2,
$3
)`,
values: [
this.db.get()['processID'],
1,
value
]
};
await this.db.get().query(query);
}
}
export interface ITestSql1 {
test1(value: string)
}
PostgresClient.ts
import { PoolClient } from "pg";
export class PostgresClient implements IPostgresClient {
private client: PoolClient;
get(): PoolClient {
return this.client;
}
set(client: PoolClient) {
this.client = client;
}
async begin() {
await this.client.query('BEGIN');
}
async commit() {
await this.client.query('COMMIT');
}
async rollback() {
await this.client.query('ROLLBACK');
}
}
export interface IPostgresClient {
get(): PoolClient;
set(client: PoolClient);
commit();
rollback();
begin();
}
TestManager2.ts and TestSql2.ts are basically same as TestManager1.ts and TestSql1.ts
My problem is that every request seems to use only one same postgresql connection from pool (Tested with JMeter) and serialize all api request.
Pool doesn't even create other connections to postgresql. It looks like other requests waits for previous request end or postgresql connection release.
How to instantiate one connection (transaction) for every request using node-postgres pool and at the same time don't block other requests?
Is this code blocking? Or i misunderstood somthing in documentation? Or simply this design isn't suitable for nodejs? I really don't now and stuck for week.

Resources