Can't update relation n:m - javascript

I have two entities with relation n:m
#ObjectType()
#Entity("tags")
export class TagEntity extends BaseEntity {
#Field(() => ID)
#PrimaryGeneratedColumn()
id: number;
#Field(() => [PostEntity])
#ManyToMany(() => PostEntity, post => post.tags)
posts: PostEntity[];
}
#ObjectType()
#Entity("posts")
export class PostEntity extends BaseEntity {
#Field(() => ID)
#PrimaryGeneratedColumn()
id: number;
#Field(() => [TagEntity])
#ManyToMany(() => TagEntity, tag => tag.posts)
#JoinTable()
tags: TagEntity[];
}
When I try to update post with new tag emit error:
"column "postsId" of relation "posts" does not exist"
Update logic:
await this.postsRepository.update({ id }, postData);
postData:
{ id: '1',
title: 'new post title',
url: 'new post url',
tags:
[ TagEntity {
id: 2,
title: 'tag title 2',
url: 'tag url 2',
createdAt: 2019-03-04T08:56:50.531Z,
updatedAt: 2019-03-04T08:56:50.531Z } ] }
Generated sql:
UPDATE "posts" SET "id" = $2, "title" = $3, "url" = $4, "postsId" = $5, "updatedAt" = CURRENT_TIMESTAMP WHERE "id" = $1 -- PARAMETERS: ["1","1","new post title","new post url",null]

Related

How to initialize typeorm entity by considering its nullable columns

I would like to set value to typeorm entity and insert them to DB.
import { PricingPatternElement } from file
const Element:PricingPatternElement = {
displayOrder : 10,
elementName : "test",
createdAt : getCurrentDate(),
createdBy : "test"
}
When I set above value to PricingPatternElement it returned following error.
Type '{ displayOrder: number; elementName: string; createdAt: Date; createdBy: string; }' is missing the following properties from type 'PricingPatternElement': pricingPatternElementId, minPrice, maxPrice, priceInterval, and 15 more.
it shows 15 members are not set . but actually, I set nullable as follows
so that I need not set nullable values.
my desired goal is to set value avoiding to set nullable columns.
I must set only 5 columnsaccording to its entity definitions.
import {
BaseEntity,
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
} from "typeorm";
import { PricingPattern } from "./pricingPattern";
import { InputPricingElement } from "./inputPricingElement";
#Index("pricing_pattern_element_pkc", ["pricingPatternElementId"], {
unique: true,
})
#Entity("pricing_pattern_element", { schema: "atai" })
export class PricingPatternElement extends BaseEntity {
#PrimaryGeneratedColumn({
type: "bigint",
name: "pricing_pattern_element_id",
})
pricingPatternElementId: string;
#Column("integer", { name: "display_order" })
displayOrder: number;
#Column("text", { name: "element_name" })
elementName: string;
#Column("integer", { name: "min_price", nullable: true })
minPrice: number | null;
#Column("integer", { name: "max_price", nullable: true })
maxPrice: number | null;
#Column("integer", { name: "price_interval", nullable: true })
priceInterval: number | null;
#Column("character varying", {
name: "icon_image",
nullable: true,
length: 256,
})
iconImage: string | null;
#Column("text", { name: "additional_explanation", nullable: true })
additionalExplanation: string | null;
#Column("integer", { name: "default_element_price", nullable: true })
defaultElementPrice: number | null;
#Column("timestamp without time zone", { name: "created_at" })
createdAt: Date;
#Column("character varying", { name: "created_by", length: 256 })
createdBy: string;
#Column("timestamp without time zone", { name: "updated_at", nullable: true })
updatedAt: Date | null;
#Column("character varying", {
name: "updated_by",
nullable: true,
length: 256,
})
updatedBy: string | null;
#Column("timestamp without time zone", { name: "revoked_at", nullable: true })
revokedAt: Date | null;
#Column("character varying", {
name: "revoked_by",
nullable: true,
length: 256,
})
revokedBy: string | null;
#ManyToOne(
() => PricingPattern,
(pricingPattern) => pricingPattern.pricingPatternElements
)
#JoinColumn([
{ name: "pricing_pattern_id", referencedColumnName: "pricingPatternId" },
])
pricingPattern: PricingPattern;
#OneToMany(
() => InputPricingElement,
(inputPricingElement) => inputPricingElement.pricingPatternElement
)
inputPricingElements: InputPricingElement[];
}
How can I set value avoiding to set nullable columns ?
Thanks
Well, one of the way is to use "as":
const Element = {
displayOrder : 10,
elementName : "test",
createdAt : getCurrentDate(),
createdBy : "test"
} as PricingPatternElement;
But you should understand that if there will be default params it will not exists in this object (but it could be used in tests, for example)
Probably you trying to find https://orkhan.gitbook.io/typeorm/docs/repository-api:
const user = repository.create({
id: 1,
firstName: "Timber",
lastName: "Saw",
});
This will create an entity without inserting it into db

Validate array object - Swagger/NestJS

I am wondering if there's a way to create a dto to validate array of object?
Example array:
[
{
"name": "Tag 1",
"description": "This is the first tag"
},
{
"name": "Tag 2",
"description": "This is the second tag"
}
]
At the moment I have this, while it works, it isn't what I am after.
export class Tags {
#ApiProperty({
description: 'The name of the tag',
example: 'Tag 1',
required: true
})
#IsString()
#MaxLength(30)
#MinLength(1)
name: string;
#ApiProperty({
description: 'The description of the tag',
example: 'This is the first tag',
required: true
})
#IsString()
#MinLength(3)
description: string;
}
export class CreateTagDto {
#ApiProperty({ type: [Tags] })
#Type(() => Tags)
#ArrayMinSize(1)
#ValidateNested({ each: true })
tags: Tags[];
}
Just use ParseArrayPipe:
Update your Controller:
#Post()
createExample(#Body(new ParseArrayPipe({ items: Tags, whitelist: true })) body: Tags[]) {
...
}
Ensure to have items and whitelist set.
Update your DTO:
import { IsString, Length } from "class-validator";
export class Tags {
#IsString()
#Length(1, 30)
name: string;
#IsString()
#Length(3)
description: string;
}

How to check that argument key is listed in generic type?

I just started to use TypeScript with ReactJS. I want to declare component props in this way:
type TProps<T> = {
data: {
[key in T]: string // key should be listed on <T>
}[]
columns: {
header: string
name: // should be listed in <T>
}[]
}
const Component = <T extends string[]>(props: TProps<T>) => {
//some code here
}
In this case I receive an error about T is not assignable to type 'string | number | symbol'
How can I define it? The main idea is that user should pass array of names for columns as generic, and then if he passes props for component with name which is not listed in generic it should show an error.
Example:
const Table = <T extends string[]>(props) => {
// code
}
// valid
Table<["name", "email"]>({
data: [
{
name: "Alex",
email: "alex#mail.com"
},
{
name: "George",
email: "george#mail.com"
}
],
columns: [
{
header: 'Name',
dataColumn: 'name'
},
{
header: 'E-Mail',
dataColumn: 'email'
}
]
});
// not valid
Table<["name", "email"]>({
data: [
{
name: "Alex",
email: "alex#mail.com"
},
{
name: "George", // no email property
}
],
columns: [
{
header: 'Name',
dataColumn: 'name'
},
{
header: 'Phone',
dataColumn: 'phone' // phone property not listed in generic type
}
]
});
You need to add constraint to generic type parameter so it will only accept list of valid key types:
type TProps<T extends PropertyKey[]> = {
data: {
[key in T[number]]: string
}[]
columns: {
header: string
dataColumn: T[number]
}[]
}
Now it behaves as expected:
Table<["name", "email"]>({
data: [
{
name: "Alex",
email: "alex#mail.com"
},
{
name: "George", // Property 'email' is missing in type ...
}
],
columns: [
{
header: 'Name',
dataColumn: 'name'
},
{
header: 'Phone',
dataColumn: 'phone' // Type '"phone"' is not assignable to type '"name" | "email"'
}
]
});
Playground
We use T[number] to get union type of allowed keys (array/tuple item type)
data definition can be simplified using Record utility
type TProps<T extends PropertyKey[]> = {
data: Record<T[number], string>[]
columns: {
header: string
dataColumn: T[number]
}[]
}

how to define location in an entity using mongodb

I am using nest js in my sample application. I define the entity of my application .Entity means a document. But I struck at one place to define the location.
using mongoose I define the schema of my document like this see link
https://raw.githubusercontent.com/webmakaka/Node.js-API-Masterclass-With-Express-MongoDB/master/api/models/Bootcamp.js
location: {
// GeoJSON Point
type: {
type: String,
enum: ['Point']
},
coordinates: {
type: [Number],
index: '2dsphere'
},
formattedAddress: String,
street: String,
city: String,
state: String,
zipcode: String,
country: String
},
careers: {
// Array of strings
type: [String],
required: true,
enum: [
'Web Development',
'Mobile Development',
'UI/UX',
'Data Science',
'Business',
'Other'
]
},
same thing I want to do using typeorm using mongoDB without mongoos .can you please help me how I will do that.
here is my entity class
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, ManyToOne, ObjectID, ObjectIdColumn } from 'typeorm';
import { IsNotEmpty, MaxLength } from 'class-validator';
#Entity('bootcamp')
export class BootcampEntity extends BaseEntity {
#ObjectIdColumn() id: ObjectID;
#Column({type:'text',unique:true,length:50,nullable: false})
name:string;
#Column({type:'text'})
slug: string;
#Column({type:'text',length:500,nullable: false})
description: string;
#Column({type:'text'})
website: string;
#Column({type:'text',length:20})
phone: string;
#Column({type:'text',})
email: string;
#Column({type:'text',nullable: false})
address: string;
#Column({type:'text',array: true })
careers: string[];
#Column({type:'int'})
averageRating:number
#Column({type:'int'})
averageCost:number
//
#Column({type:'string',default:'no-photo.jpg'})
photo: string;
//
#Column({type:'boolean',default:false})
housing: boolean;
#Column({type:'boolean',default:false})
jobAssistance: boolean;
#Column({type:'boolean',default:false})
jobGuarantee: boolean;
#Column({type:'boolean',default:false})
acceptGi: boolean;
#Column({type:'date',default:Date.now()})
createdAt: Date;
}
I am using this framework
https://docs.nestjs.com/
typeorm link
https://typeorm.io/#/entities
there is schema
https://raw.githubusercontent.com/webmakaka/Node.js-API-Masterclass-With-Express-MongoDB/master/api/models/Bootcamp.js
I want make same schema using typeorm .I struck only defining the location attribute ?
how to define ?could you please tell me how I will define location in my entity class ?
I think location would have similar structure to code below.
source 1
source 2
enum GeoJSONPoint {
Point = "Point"
}
enum Careers {
WebDevelopment = 'Web Development',
MobileDevelopment = 'Mobile Development',
UIUX = 'UI/UX',
DataScience = 'Data Science',
Business = 'Business',
Other = 'Other'
}
#Entity('location')
export class LocationEntity extends BaseEntity {
#Column({
type: "enum",
enum: GeoJSONPoint
})
type: GeoJSONPoint;
#Column({type:'int'})
coordinates: number;
#Column({type:'text'})
formattedAddress: string;
#Column({type:'text'})
street: string;
#Column({type:'text'})
city: string;
#Column({type:'text'})
state: string;
#Column({type:'text'})
zipcode: string;
#Column({type:'text'})
country: string;
#Column({type:'simple-array'})
careers: Careers[];
}

Laravel programmatically commands will not work with users

Hi I am trying to run commands with buttons I created. Some commands must send an email to a user, but I keep getting 500 internal server errors. Also, how do I filter the user data to retrieve email address of currently logged in user?
Here is my route:
Route::get('/admin/systemadmin/index', 'CommandsController#index')->middleware('permission:page-view-admin-systemadmin')->middleware('Analyse');
Route::post('/admin/artisan/commands/run', 'CommandsController#runCommand')->middleware('Analyse');
Here is my controller:
public function index() {
$users = User::all();
$commands = [
[
'id' => 1,
'signature' => 'sync:whatever',
'user' =>'',
'title' =>'Sync Whatever',
'groupID' => 1,
'groupName' => 'First Group'
],
[
'id' => 2,
'signature' => 'send:smsNotification',
'user' =>'users',
'title' =>'Send SMS',
'groupID' => 3,
'groupName' => 'Notification'
],
];
return view('admin.systemadmin.test')->with(
[
'users' => $users,
'commands' => collect($commands)
]
);
}
public function runCommand(Request $request){
$users = User::all();
$signature = $request->input('signature');
$command = Artisan::call($signature);
return response($command);
}
Here is my blade.php:
<div v-for="(commands, groupName) in groupedCommands">
<h4>#{{ groupName }}</h4>
<div class="btn-group" v-for="command in commands">
<commands-component
:entity-config="commandConfig(command.id, command.signature, command.user, command.title, command.groupID, command.groupName)">
<input style="margin-right:10px;margin-bottom:10px;" type="button" class="btn btn-primary" v-bind:value="command.title">
</commands-component>
</div>
</div>
My Vue:
commandConfig: function(ident, signature, user, title, groupId, groupName){
$data = {
id: { text: 'commandModal' + ident, id: null },
modalTitle: title,
buttons: [
{
buttonTitle: 'Run Command',
buttonClass: 'btn btn-success pull-right',
submitUrl: {
url: '/admin/artisan/commands/run',
},
}
],
attributes: [
{name: "message", displayName: "Are you sure you want to proceed with the command?", type: "action-text", col: "12" },
{name: "signature", displayName: "Command Signature", type:'text', col:"12"}
],
data: {
signature:signature + ' ' + this.users[0].email,
user: user
}
}
return $data;
}
}

Categories

Resources