I'm trying to instantiate a new object of my Product model in my service but I got error:
`
ModelNotInitializedError: Model not initialized: Product cannot be instantiated. "Product" needs to be added to a Sequelize instance.
`
There is my sequelize config
I'm ussing repository mode and build the path that contain my models.
import { join } from "path";
import { Config } from "sequelize";
import { Sequelize } from "sequelize-typescript";
const path = join(__dirname, '..', '/entities/models/*.model.ts')
const sequelize = new Sequelize({
repositoryMode: true,
dialect: 'postgres',
host: 'localhost',
database: 'postgres',
port: 5432,
schema: 'store',
username: 'postgres',
password: '123.',
models: [path],
modelMatch: (filename, member) => {
return filename.substring(0, filename.indexOf('.model')).toLowerCase() === member.toLowerCase();
},
hooks: {
afterConnect: async (connection: Sequelize, _config: Config) => {
try {
await connection.query('set search_path = store')
} catch (error) {
console.log('Error at set search path: ', error)
}
}
}
})
export { sequelize }
There are my classes.
Product model, this model I attemp to instantiate.
import { Table, Column, Model, BelongsToMany } from 'sequelize-typescript'
import { Category, CategoryProduct } from './index'
#Table({
timestamps: false,
modelName: 'tal_product',
freezeTableName: true,
underscored: true
})
export class Product extends Model {
#Column({ primaryKey: true })
id!: number
#Column
name!: string
#Column
stock!: number
#Column({ field: 'is_active' })
isActive?: boolean
#BelongsToMany(() => Category, () => CategoryProduct)
categories?: Category[]
}
Product repository, here I have all my querys.
import { Repository } from 'sequelize-typescript'
import { Category, Product } from '../../../entities/models'
import { sequelize } from '../adminModule'
import { ProductRepository } from './product.repository'
export class ProductRepositoryImp implements ProductRepository {
productRepository: Repository<Product>
categoryRepository: Repository<Category>
constructor() {
this.productRepository = sequelize.getRepository(Product)
this.categoryRepository = sequelize.getRepository(Category)
}
create = async (product: Product): Promise<Product> => {
return await this.productRepository.create({ ...product })
}
}
product service, here I call the producRepository and instantiate my model
import { ICreateProduct, IProduct } from '../../../dto/product.dto'
import { Product } from '../../../entities/models'
import { ProductRepository } from '../repositories'
import { ProductServices } from './product.services'
export class ProductServicesImp implements ProductServices {
private productRepository: ProductRepository
public constructor(productRepository: ProductRepository) {
this.productRepository = productRepository
}
create = async (productDto: ICreateProduct): Promise<IProduct> => {
const product = new Product()
product.name = productDto.name
product.stock = productDto.stock
return await this.productRepository.create(product)
}
}
In ProductServicesImp when I instantiate a 'new Product()' I got the error.
Related
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);
}
}
I created a new module in my codebase called as AuditLog, created using nest CLI and i get this error when i compile the code (nest start)
I created it inside src folder (refer screen shot),
here's my ormConfig
module.exports = {
type: 'postgres',
host: host || 'localhost',
username: username || 'postgres',
password: password || 'secret',
port: port || '5432',
database: pathname || 'dbname',
entities: ['src/**/*.entity.ts'],
migrationsTableName: 'migrations',
migrations: [`src/db/${migrationDir}/*.ts`],
cli: {
entitiesDir: 'src/*/',
migrationsDir: `src/db/${migrationDir}`
},
ssl: process.env.NODE_ENV === 'production'
? { rejectUnauthorized: false }
: false
};
Here's my entity definition
import { BaseEntity, Column, Entity, PrimaryColumn } from 'typeorm';
#Entity('auditlog')
export class AuditLogEntity extends BaseEntity {
#PrimaryColumn('uuid')
id: string;
#Column()
entityId: string;
#Column({ type: 'json' })
oldValue: Record<string, any>;
#Column()
entityType: string;
#Column()
updatedAt: Date;
}
Module code
import { Module } from '#nestjs/common';
import { TypeOrmModule } from '#nestjs/typeorm';
import { AuditLogEntity } from './audit-log.entity';
import { AuditLogController } from './audit-log.controller';
import { AuditLogService } from './audit-log.service';
#Module({
imports: [TypeOrmModule.forFeature([AuditLogEntity])],
controllers: [AuditLogController],
providers: [AuditLogService]
})
export class AuditLogModule {}
controller
import { Controller, Get } from '#nestjs/common';
import { AuditLogEntity } from './audit-log.entity';
import { AuditLogService } from './audit-log.service';
#Controller('api/audit-log')
export class AuditLogController {
constructor(private readonly auditLogService: AuditLogService) {}
#Get()
public async createAudit() {
const auditEntity = new AuditLogEntity();
// put this inside a static method that returns AuditLogEntity object taking AuditLogDto
auditEntity.entityId = '01b44c5d-158c-4719-806d-966652d408dc';
auditEntity.entityType = 'order';
auditEntity.oldValue = {
transporterId: '7d07b3e3-bd1f-4209-a1fa-414c5a019f52', // t04
phoneNumber: 9876534201
};
auditEntity.updatedAt = new Date();
return await this.auditLogService.addAuditEntity(auditEntity);
}
}
service file
import { Injectable } from '#nestjs/common';
import { InjectRepository } from '#nestjs/typeorm';
import { Repository } from 'typeorm';
import { AuditLogDto } from './audit-log.dto';
import { AuditLogEntity } from './audit-log.entity';
#Injectable()
export class AuditLogService {
constructor(
#InjectRepository(AuditLogEntity) private readonly auditRepository: Repository<AuditLogEntity>
) {}
public async addAuditEntity(auditEntity: AuditLogEntity): Promise<AuditLogEntity> {
return await this.auditRepository.save(auditEntity);
}
}
i have imported this module in app.module.ts too but still getting this error
Please help me here ...
please refer this file structure if required
Below is the file where I am trying to mock datasource. but Getting error as
TypeError: Cannot set property DataSource of [object Object] which has only a getter
import { AppService } from '../services';
import typeorm = require('typeorm');
describe("Tests for AppService", () => {
beforeAll(() => {
typeorm.DataSource = jest.fn().mockReturnValue({
manager: {
find: jest.fn(),
query: jest.fn(),
}
})
});
it("should call getServices", () => {
const AS = new AppService();
AS.getServices(1);
expect(typeorm.DataSource).toHaveBeenCalled();
});
})
datasource file
import { DataSource } from 'typeorm';
import { services } from '../entity/services';
import { versions } from '../entity/versions';
export const connectDB = new DataSource({
type: 'postgres',
host: 'localhost',
port: 5431,
username: 'postgres',
password: 'password',
database: 'test',
synchronize: true,
logging: true,
entities: [services, versions],
subscribers: [],
migrations: [],
});
connectDB
.initialize()
.then(() => {
console.log(`Data Source has been initialized`);
})
.catch((err) => {
console.error(`Data Source initialization error`, err);
});
export default connectDB;
And I am using it like,
import { Injectable } from '#nestjs/common';
import { Like } from 'typeorm';
import connectDB from '../config/db_connection';
import { services } from '../entity/services';
import { versions } from '../entity/versions';
// handle errors //
// write function description
#Injectable()
export class AppService {
public getServices(id: number): Promise<versions[]> {
return connectDB.manager.find(versions, {
relations: {
service: true,
Is there any better way to mock typeorm datasource in jest.
Thanks
This is the way I implement it in a repo of mine:
import { DataSource } from 'typeorm'
const makeDataSourceMock = (): DataSource => ({
name: 'any_data_source',
options: { database: 'any_database' },
destroy: jest.fn(),
manager: { save: jest.fn() },
getRepository: jest.fn(() => ({
clear: jest.fn()
})),
entityMetadatas: [
{ name: 'any_entity_name' }
]
}) as any
Here is the complete test file if you want to take a look: https://github.com/leal32b/webapi-nodejs/blob/main/test/core/3.infra/persistence/postgres/client/postgres-client.unit.test.ts
No repository for "UserEntity" was found. Looks like
this entity is not registered in current "default" connection? +114ms
RepositoryNotFoundError: No repository for "UserEntity" was found. Looks like this entity is not registered in current "default" connection?
at RepositoryNotFoundError.TypeORMError [as constructor] (E:\Projects\...\src\error\TypeORMError.ts:7:9)
This is a Seed Method. It runs fine and add the data in the database, after adding data, I just get the error.
import { MediaEntity } from '../entities/media.entity';
import { Connection, Equal } from 'typeorm';
import { UserEntity } from '../entities/user.entity';
import { Helper } from '../services/helper';
export default async function UsersSeed(connection: Connection) {
const repository = connection.getRepository(UserEntity);
const data: Partial<UserEntity> = {
firstName: 'tesFName',
lastName: 'testLNsmr',
password: 'fafafa',
email: 'testmail#mail.com',
createdAt: Helper.dateToUTC(new Date())
};
let user = await repository.findOne({ email: data.email });
console.log("19");
console.log(user);
if (!user) {
const entity = Helper.createEntity(UserEntity, data);
console.log("23");
user = await repository.save(entity);
console.log("25");
} else {
console.log("27");
await repository.update(user.id, {
firstName: data.firstName,
lastName: data.lastName
});
console.log("33");
}
console.log("36");
const mediaRepository = connection.getRepository(MediaEntity);
await mediaRepository.update({ user: Equal(null) }, { user: user });
return user;
}
A bit more context:
It is being imported in app.module.ts as this.
#Module({
imports: [
ServeStaticModule.forRoot({
rootPath: join(__dirname, 'uploads')
}),
TypeOrmModule.forRootAsync({
useFactory: async (optionsService: OptionsService) =>
optionsService.typeOrmOptions(),
imports: [OptionsModule],
inject: [OptionsService]
}),
OptionsModule,
MediaModule,
AuthModule,
PlaceModule,
RepositoryModule,
ServicesModule
],
controllers: [],
providers: []
})
And then there is src/entities/entities.module.ts as:
const entities = [
UserEntity,
MediaEntity,
PlaceEntity,
DownloadRestrictionEntity,
MediaInfoEntity
];
#Module({
imports: [TypeOrmModule.forFeature(entities)],
exports: [TypeOrmModule.forFeature(entities)]
})
export class EntitiesModule {
}
Then src/options/options.service.ts as
#Injectable()
export class OptionsService {
constructor(
private service: ConfigService<IEnvironmentVariables>
) {
}
public typeOrmOptions(): TypeOrmModuleOptions {
const environment = process.env.NODE_ENV ? process.env.NODE_ENV : '';
const directory = this.directory();
return {
type: 'postgres',
host: this.service.get('POSTGRES_HOST'),
port: this.service.get('POSTGRES_PORT'),
username: this.service.get('POSTGRES_USER'),
password: this.service.get('POSTGRES_PASSWORD'),
database: this.service.get('POSTGRES_DATABASE'),
synchronize: false,
migrationsRun: this.service.get('RUN_MIGRATIONS'),
keepConnectionAlive: this.isTest(),
entities: [`${directory}/**/*.entity${environment ? '{.ts,.js}' : '{.js, .ts}'}`],
migrationsTableName: 'migrations',
migrations: [`${directory}/migrations/*.ts`],
cli: {
migrationsDir: 'src/migrations'
}
}
}
}
please create UserRepository typeorm-repository-pattern
Method 1:
#Injectable()
export class UsersService {
constructor(
#InjectRepository(User)
private usersRepository: Repository<User>,
) {}
}
Method 2: use BaseRepository from typeorm-transactional-cls-hooked
#EntityRepository(UserAdminEntity)
export class UserAdminRepository extends BaseRepository<UserAdminEntity> {}
I'm working on Backend with TypeGraphQL and NodePostGres.
User will pass database id and table name. I need to send data in JSON Format.
I have tried below code but it doesn't return anything nor does it throw any error.
Service:
import { Service } from 'typedi'
import { Client } from 'pg'
import { databases } from './db'
import { Payload } from './models'
#Service()
export class PayloadService {
fetchPayload(id: number, tableName: string): Payload {
const databaseCredentials = databases.find((d) => d.id && +d.id === id)
if (!databaseCredentials) throw new Error('Invalid ID!')
const client = new Client({
host: databaseCredentials.host,
port: +(databaseCredentials.port || 5432),
user: databaseCredentials.username,
password: databaseCredentials.password,
database: databaseCredentials.database,
ssl: {
rejectUnauthorized: false,
},
})
console.log('before client')
client.query("select * from pg_tables where schemaname='public'", (err, res) => {
if (err) {
console.log(err.stack)
} else {
console.log(res.rows[0])
}
console.log(`callback`)
})
console.log('after client')
return {
id,
data: [],
}
}
}
Resolver:
import { Arg, Query, Resolver } from 'type-graphql'
import { Inject } from 'typedi'
import { Payload } from './models'
import { PayloadService } from './services'
#Resolver(Payload)
export class PayloadResolver {
#Inject()
private PayloadService: PayloadService
#Query((returns) => Payload)
payload(#Arg('databaseId') databaseId: number, #Arg('tableName') tableName: string) {
return this.PayloadService.fetchPayload(databaseId, tableName)
}
}