Validation for array objects using class-validator in node js - node.js

i want to validate alcoholeId and alcoholeName if it is empty.here is my format:
{
"barId": "string",
"barName": "string",
"drinksItems": [
{
"alcoholId": "string",
"alcoholName": "string",
"mixerList": [
{
"mixerId": "string"
}
],
"modifierList": [
{
"modifierId": "string"
}
]
}]
}

For this you need to have an entity and to use #ValidateNested and #Type to cast it correctly (only in case of you use class-transformer).
class Alcohol {
#IsNotEmpty()
alcoholId: string;
#IsNotEmpty()
alcoholName: string;
}
class Bar {
#IsNotEmpty() // <- requires the array to be present
#ValidateNested()
// #Type(() => Alcohol) // <- add only if you use class-transformer
alcohols: Array<Alcohol>;
}

Related

How to query and filtering with multiple elements in typeorm - nest js

What is the best way to query and filtering relation entity / many to many field in typeorm. For example in my case i have books with 2 categories:
action & adventure.
Then i want filtering by that categories.
so the url e.g:
..../books?categories='action,adventure'.
My problem i can only filter with only 1 or i must use orWhere in my querybuilder but if i add the categories to
'action,adventure,scifi'
is still got the result not filtering of all of them categories
book.entity.ts
#Entity()
export class Book {
#PrimaryGeneratedColumn()
id: number;
#Column()
title: string;
#Column()
description: string;
#Column()
thumbnail: string;
#ManyToMany(() => BooksCategory, {
cascade: true,
})
#JoinTable()
category: BooksCategory[];
#Column({
nullable: false,
default: () => 'CURRENT_TIMESTAMP',
type: 'timestamp',
})
created_at: Date;
#Column({
nullable: false,
default: () => 'CURRENT_TIMESTAMP',
type: 'timestamp',
})
updated_at: Date;
}
Here my service function
books.service.ts
async findAll(query: GetBooksQueryDto): Promise<Book[]> {
const booksQuery = await this.booksRepository.createQueryBuilder('book');
const joins = await booksQuery.leftJoinAndSelect(
'book.category',
'category',
);
const titleFilter = await joins.andWhere('book.title LIKE :title', {
title: `%${query.title}%`,
});
const categoryFilter = titleFilter
.andWhere('category.name LIKE :category', {
category: `action`,
})
.andWhere('category.name LIKE :category', {
category: `adventure`,
});
return await categoryFilter.getMany();
}
got return like this
[
{
"id": 1,
"title": "Love is war",
"description": "One piece is real",
"thumbnail": "file://",
"created_at": "2022-11-20T16:36:11.000Z",
"updated_at": "2022-11-20T16:36:11.000Z",
"category": [
{
"id": 2,
"name": "adventure"
}
]
}
]
My expection is like this
[
{
"id": 1,
"title": "Love is war",
"description": "One piece is real",
"thumbnail": "file://",
"created_at": "2022-11-20T16:36:11.000Z",
"updated_at": "2022-11-20T16:36:11.000Z",
"category": [
{
"id": 1,
"name": "action"
},
{
"id": 2,
"name": "adventure"
}
]
}
]
the problem the second argument or the next argument of andWhere() in categoryFilter is overwriting the previous value of categories array.
Im not sure why are you using filtering in this way.
You should be using better naming convention for variables. You dont need all those variables because if dont have any conditions.
Based on your code above i would write something like this.
return this.booksRepository.createQueryBuilder('book').leftJoinAndSelect(
'book.category',
'category',
).where('book.title LIKE :title', {
title: `%${query.title}%`,
}).andWhere('category.name IN (:...categories)', {
categories: query.categories,
}).getMany();
You could even can use Typerorm find method for this query.

setting type of index in for of loop in Typescript

I am trying to set the type of an item when I loop through a response which is an array of objects, however, I am not sure how to declare the type.
I have the following type:
export type Movie = {
title: string;
director: string;
year: string;
};
I get the following response from an api
const movies = [{
"movie": {
"title": 'The Dark Knight',
"director": 'Christofer Nolan',
},
"details": {
"year": 2008,
"rating": 4.5
}
},
{
"movie": {
"title": 'The Joker',
"director": 'Todd Phillips',
},
"details": {
"year": 2019,
"rating": 4.7
}
}
}]
I want to map the response to xml which I have the following function for
function mapToMoviesXML(movies: Movie[]) {
let data = `<?xml version="1.0" encoding="UTF-8"?>`;
data += `<movies>`;
for (let item of movies) {
data += `<movies>
<title>${item.movie.title}</title>
<director>${item.movie.director}</director>
<year>${item.details.year}</year>
<rating>${item.details.rating}</rating>
</movies>`;
}
however, I get the following error for item.movie and item.details within the loop
Property 'movie' does not exist on type 'Movie'
Property 'details' does not exist on type 'Movie'
I thought because I am getting the final value i.e. item.movie.title which is defined in the Movie type I would not need to declare a type for item. Any ideas what I need to change or update my type to?
To satisfy the way movies: Movie[] is being used (and to mirror what the API is actually sending) the type definition would need to be something along the lines of this:
export type Movie = {
movie: {
title: string;
director: string;
}
details: {
year: number;
rating: number;
};
};
or potentially more useful would be to break the nested objects into their own types and reference them from the parent object, i.e.
export interface MovieOverview {
title: string;
director: string;
}
export interface MovieDetails {
year: number;
rating: number;
}
export interface Movie {
movie: MovieOverview;
details: MovieDetails;
}

GraphQL custom Schema

I want to link an custom GraphQL type from frontmatter to a team member with #link
{
"members": [
{
"name": "String",
"id": "String",
...
}
]
}
In the frontmatter, I have a authors array field with the team member id
type Author {
name: String
positon: String
}
type Frontmatter {
title: String
authors: [TeamJson] #link(by: "members.id" )
}

Nestjs - Validating and Converting Query params [duplicate]

I'm trying to validate the parameters that come in the query of a get request, but for some reason, the validation pipe is unable to identify the elements of the query.
import {
Controller,
Post,
Query,
Body,
UseInterceptors,
Param,
Res,
Logger,
} from '#nestjs/common';
import { Crud, CrudController, Override } from '#nestjsx/crud';
import { OpenScheduleDto } from './open-schedule.dto';
#Crud(Schedule)
export class ScheduleController
implements CrudController<ScheduleService, Schedule> {
constructor(public service: ScheduleService) {}
get base(): CrudController<ScheduleService, Schedule> {
return this;
}
#Override()
async getMany(#Query() query: OpenScheduleDto) {
return query;
}
}
OpenSchedule.dto
import { IsNumber, IsOptional, IsString } from 'class-validator';
export class OpenScheduleDto {
#IsNumber()
companyId: number;
#IsNumber()
#IsOptional()
professionalId: number;
#IsString()
#IsOptional()
scheduleDate: string;
}
When I make a get request to http://localhost:3000/schedules?companyId=3&professionalId=1
I get unexpected errors:
{
"statusCode": 400,
"error": "Bad Request",
"message": [
{
"target": {
"companyId": "3",
"professionalId": "1"
},
"value": "3",
"property": "companyId",
"children": [],
"constraints": {
"isNumber": "companyId must be a number"
}
},
{
"target": {
"companyId": "3",
"professionalId": "1"
},
"value": "1",
"property": "professionalId",
"children": [],
"constraints": {
"isNumber": "professionalId must be a number"
}
}
]
}
That is because when you use #Query parameters, everything is a string. It does not have number or boolean as data types like json. So you have to transform your value to a number first. For that, you can use class-transformer's #Transform:
import { IsNumber, IsOptional, IsString } from 'class-validator';
import { Transform } from 'class-transformer';
export class OpenScheduleDto {
#Transform(id => parseInt(id))
#IsNumber()
companyId: number;
#Transform(id => id ? parseInt(id) : id)
#IsNumber()
#IsOptional()
professionalId?: number;
#IsString()
#IsOptional()
scheduleDate?: string;
}
Note though, that this is unsafe because e.g. parseInt('5abc010') is 5. So you might want to do additional checks in your transformation function.

Elasticsearch create join field (Nodejs)

I have the following docs:
export class CustomerServiceResultType{
id: string;
body:{customerRelation: string};
}
export class CustomerType{
id: string;
body:{name: string};
}
I want CustomerServiceResultType to have a relation to CustomerType with the field: customerRelation.
this is my mapping:
await this.elasticsearchService.indices.putMapping({
"index": "db",
"type": "CustomerServiceResultType",
"body" : {
"properties": {
"customerRelation": {
"type": "join",
"relations": {
"CustomerServiceResultType": "CustomerType"
}
}
}
}
});
This is the error I get:
[Nest] 421512 - 11/21/2020, 6:40:42 PM [ExceptionsHandler] illegal_argument_exception +96414ms
ResponseError: illegal_argument_exception
There are no details about this error...
Thanks
There's nothing wrong with your request per-se -- I think it just requires one extra option: include_type_name: true.
It's undefined by default in nodejs but is required in ES 7.x on the server side. More reasoning behind this is here.
So this should do the trick:
await client.indices.putMapping({
include_type_name: true,
index: "db",
type: "CustomerServiceResultType",
body : {
properties: {
customerRelation: {
type: "join",
relations: {
CustomerServiceResultType: "CustomerType"
}
}
}
}
});
Typed indexes will be removed in 8.x so the best approach would actually be:
await client.indices.putMapping({
index: "db",
body : {
properties: {
customerRelation: {
type: "join",
relations: {
CustomerServiceResultType: "CustomerType"
}
}
}
}
});
BTW: your typescript types don't really play a role here because ES is a JSON-only interface and while there's the deprecated type aspect to ES, the two concepts are very distant.

Resources