I have a Parent Child (One-To-One) Relationship like this:
model Account {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
billingAddress Address?
name String
##map("Accounts")
}
model Address {
id Int #id #default(autoincrement())
city String?
country String?
postalCode Int?
state String?
street String?
accountId Int #unique
account Account #relation(fields: [accountId], references: [id])
}
I want to be able to Update the Parent Record without the need of updating also the Child Record. Furthermore, it would be great, if I can update the Parent Record and the Child Record at the same time. Right now I am getting an Error when only trying to send the Data for the Parent Record.
Here are my DTOs to Create and Edit the Entities:
Create / Edit Account:
export class CreateAccountDto {
#IsString()
#IsOptional()
name: string;
#IsOptional()
billingAddress?: CreateAddressDto;
}
Create / Edit Addresss:
export class EditAddressDto {
#IsString()
#IsOptional()
city?: string;
#IsString()
#IsOptional()
country?: string;
#IsNumber()
#IsOptional()
postalCode?: number;
#IsString()
#IsOptional()
state?: string;
#IsString()
#IsOptional()
street?: string;
#IsInt()
#IsOptional()
accountId: number;
}
I'm creating and editing the Account like this:
async editAccount(accountId: number, dto: EditAccountDto) {
let account;
console.log({dto})
account = await this.prisma.account.update({
where: {
id: accountId
},
data: {
...dto,
billingAddress: {
update: {
...dto.billingAddress
}
}
},
include: {
billingAddress: true
}
});
console.log(account)
return account;
}
When i try to Edit the Account with the following Data
{
"name": "Test Account Create2",
"billingAddress": {
"id": 2,
"city": "Dortmund",
"state": "NRW",
"postalCode": 44442,
"country": "Germany",
"street": "Benninghofer Heide 63",
"accountId": 10000001
}
}
i am getting the following Error:
Unknown arg `accountId` in data.billingAddress.update.accountId for type AddressUncheckedUpdateWithoutAccountInput. Did you mean `country`? Available args:
type AddressUncheckedUpdateWithoutAccountInput {
id?: Int | IntFieldUpdateOperationsInput
city?: String | NullableStringFieldUpdateOperationsInput | Null
country?: String | NullableStringFieldUpdateOperationsInput | Null
latitude?: Decimal | NullableDecimalFieldUpdateOperationsInput | Null
longitude?: Decimal | NullableDecimalFieldUpdateOperationsInput | Null
postalCode?: Int | NullableIntFieldUpdateOperationsInput | Null
state?: String | NullableStringFieldUpdateOperationsInput | Null
street?: String | NullableStringFieldUpdateOperationsInput | Null
}
at Document.validate (C:\Users\Simon\IdeaProjects\crm-tool\crm-backend\node_modules\#prisma\client\runtime\index.js:29297:20)
at serializationFn (C:\Users\Simon\IdeaProjects\crm-tool\crm-backend\node_modules\#prisma\client\runtime\index.js:31876:19)
at runInChildSpan (C:\Users\Simon\IdeaProjects\crm-tool\crm-backend\node_modules\#prisma\client\runtime\index.js:25100:12)
at PrismaService._executeRequest (C:\Users\Simon\IdeaProjects\crm-tool\crm-backend\node_modules\#prisma\client\runtime\index.js:31883:31)
at consumer (C:\Users\Simon\IdeaProjects\crm-tool\crm-backend\node_modules\#prisma\client\runtime\index.js:31810:23)
at C:\Users\Simon\IdeaProjects\crm-tool\crm-backend\node_modules\#prisma\client\runtime\index.js:31815:51
at AsyncResource.runInAsyncScope (node:async_hooks:199:9)
at C:\Users\Simon\IdeaProjects\crm-tool\crm-backend\node_modules\#prisma\client\runtime\index.js:31815:29
at runInChildSpan (C:\Users\Simon\IdeaProjects\crm-tool\crm-backend\node_modules\#prisma\client\runtime\index.js:25100:12)
at PrismaService._request (C:\Users\Simon\IdeaProjects\crm-tool\crm-backend\node_modules\#prisma\client\runtime\index.js:31812:22)
The error says, you are not allowed to specify accountId when you are updating the address in this way. You can just remove it from your DTO and everything should be fine.
Related
I tried to create a database for a room management sytem and I'm confused about the relations and couldn't find helpful resources on the internet can you tell me if there is anything wrong with this prisma script? as I want to control it in expressJs and make an application based on it
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model Guest {
guestId String #id #default(uuid())
name String
phone String #unique()
address String?
nationality String
Reservation Reservation[] #relation("GuestReservation")
}
model Reservation {
reservationId Int #id #default(autoincrement())
checkIn DateTime
checkOut DateTime
Guest Guest #relation("GuestReservation", fields: [guestId], references: [guestId], onDelete: Cascade)
guestId String
visitors Int
Room Room #relation("RoomReservation", fields: [roomId], references: [roomId], onDelete: Cascade)
type ReservationType
roomId Int
Bill Bill? #relation("BillReservation")
}
enum ReservationType {
Booking
Contract
Booked
Canceled
}
model Room {
roomId Int #id #default(autoincrement())
price Float
type Type
Reservation Reservation[] #relation("RoomReservation")
}
enum Type {
Single
Double
Triple
}
model Bill {
invoiceNo String #id #default(uuid())
Reservation Reservation #relation("BillReservation", fields: [reservationId], references: [reservationId], onDelete: Cascade)
reservationId Int #unique()
roomService Float #default(0)
paymentMode Payment
Service Service[]
}
enum Payment {
Cash
Visa
}
model Service {
serviceId String #id #default(uuid())
type ServiceType
name String
price Float
Bill Bill #relation(fields: [billInvoiceNo], references: [invoiceNo], onDelete: Cascade)
billInvoiceNo String
}
enum ServiceType {
Bar
Laundry
}
I tried to make a crud for each entity but I end up with relational erros such as foregin key and stuff like that which means there is something wrong with my relations.
Your schema is valid, though I would recommend keeping consistency while defining id for your tables. Some of the tables have id of string type while some are of numeric type.
Here's an example of queries to create entites for your models.
import {
PrismaClient,
Type,
ServiceType,
Payment,
ReservationType,
} from '#prisma/client';
const prisma = new PrismaClient({
log: ['query'],
});
async function main() {
// Creating a room
await prisma.room.create({
data: {
price: 100,
type: Type.Single,
roomId: 1,
},
});
// Creating a guest
await prisma.guest.create({
data: {
name: 'Test',
nationality: 'Indian',
phone: '1234567890',
address: 'Test Address',
guestId: '1',
},
});
// Creating a service with a bill and a reservation
await prisma.service.create({
data: {
name: 'test',
price: 100,
type: ServiceType.Bar,
serviceId: '1',
Bill: {
create: {
paymentMode: Payment.Cash,
invoiceNo: '1',
Reservation: {
create: {
checkIn: new Date(),
checkOut: new Date(),
type: ReservationType.Booked,
visitors: 1,
roomId: 1,
guestId: '1',
},
},
},
},
},
});
}
main()
.catch((e) => {
throw e;
})
.finally(async () => {
await prisma.$disconnect();
});
Here's the query response:
> ts-node index.ts
prisma:query BEGIN
prisma:query INSERT INTO `white_egret`.`Room` (`roomId`,`price`,`type`) VALUES (?,?,?)
prisma:query SELECT `white_egret`.`Room`.`roomId`, `white_egret`.`Room`.`price`, `white_egret`.`Room`.`type` FROM `white_egret`.`Room` WHERE `white_egret`.`Room`.`roomId` = ? LIMIT ? OFFSET ?
prisma:query COMMIT
prisma:query BEGIN
prisma:query INSERT INTO `white_egret`.`Guest` (`guestId`,`name`,`phone`,`address`,`nationality`) VALUES (?,?,?,?,?)
prisma:query SELECT `white_egret`.`Guest`.`guestId`, `white_egret`.`Guest`.`name`, `white_egret`.`Guest`.`phone`, `white_egret`.`Guest`.`address`, `white_egret`.`Guest`.`nationality` FROM `white_egret`.`Guest` WHERE `white_egret`.`Guest`.`guestId` = ? LIMIT ? OFFSET ?
prisma:query COMMIT
prisma:query BEGIN
prisma:query INSERT INTO `white_egret`.`Reservation` (`reservationId`,`checkIn`,`checkOut`,`guestId`,`visitors`,`type`,`roomId`) VALUES (?,?,?,?,?,?,?)
prisma:query INSERT INTO `white_egret`.`Bill` (`invoiceNo`,`reservationId`,`roomService`,`paymentMode`) VALUES (?,?,?,?)
prisma:query INSERT INTO `white_egret`.`Service` (`serviceId`,`type`,`name`,`price`,`billInvoiceNo`) VALUES (?,?,?,?,?)
prisma:query SELECT `white_egret`.`Service`.`serviceId`, `white_egret`.`Service`.`type`, `white_egret`.`Service`.`name`, `white_egret`.`Service`.`price`, `white_egret`.`Service`.`billInvoiceNo` FROM `white_egret`.`Service` WHERE `white_egret`.`Service`.`serviceId` = ? LIMIT ? OFFSET ?
prisma:query COMMIT
Hi let's say that I have 3 Structs in the following format
type Employee struct {
Id int
Name string
CompanyId int `gorm:"column:companyId"`
Company Company `gorm:"foreignKey:CompanyId"`
}
type Company struct {
Id int
CompanyName string
OwnerId `gorm:"column:owner"`
Owner Owner `gorm:"foreignKey:OwnerId"`
}
type Owner struct {
Id int
Name string
Age int
Email string
}
func (E Employee) GetAllEmployees() ([]Employee, error) {
Employees := []Employee
db.Preload("Company").Find(&Employees)
}
// -- -- There response will be like
[
{
id: 1
name: "codernadir"
company: {
id: 5
company_name: "Company"
owner: {
id 0
Name ""
Age 0
Email ""
}
}
}
]
here I'm getting Owner values with the default values.
the given examples are for describing what I'm trying to reach.
I need a way how to load the Owner struct with its values when I load the Employees?
any suggestions will be appreciated and thanks in advance
You can use the gorm:"embedded" tag:
type Employee struct {
Id int
Name string
CompanyId int `gorm:"column:companyId"`
Company Company `gorm:"embedded"`
}
type Company struct {
Id int
CompanyName string
OwnerId `gorm:"column:owner"`
Owner Owner `gorm:"embedded"`
}
type Owner struct {
Id int
Name string
Age int
Email string
}
this is what I found as a solution to load the nested objects from embedded structs
db.Preload("Company").Preload("Company.Owner").Find(&Employees)
Trying to query in prisma and filter results from a related object but get the error:
Unknown arg 'where' in select.fruit.where for type UserFruit. Did you
mean 'select'? Available args fruit{}
async findShops(req) {
const userId = parseInt(req.params.id);
const shop = await prisma.shop.findMany({
select: {
id: true,
name: true,
logo: true,
fruit:{
select:{
id:true,
userId:true,
fruitNumber:true,
created: true,
updated: true,
},
where: {
userId: userId
}
}
}
})
return shop;
};
example payload expected:
[
{ id: 1001, name: 'test1', logo: 'log.png', fruit: null },
{ id: 1002, name: 'test2', logo: 'log2.jpg', fruit: null },
{ id: 1003, name: 'test3', logo: 'log3.jpg', fruit: null },
{
id: 1005,
name: 'test4',
logo: 'log4.png',
fruit: {
id: '62450ee5-e75d-4a67-8d79-120d11ddf508',
userId: 111,
fruitNumber: '123456',
created: 2022-07-01T06:39:52.924Z,
updated: 2022-07-01T06:39:52.936Z
}
},
{
id: 1004,
name: 'test5',
logo: 'log5.jpg',
fruit: {
id: '20e9af37-2e6f-4070-8475-c5a914f311dc',
userId: 111,
fruitNumber: '123878',
created: 2022-07-01T07:21:27.898Z,
updated: 2022-07-01T07:21:27.901Z
}
}
]
I can easily achieve the expected output by not having the "where" but I need it because the fruit object can contain more than 1 object so I need to filter by userId e.g.
fruit: {
id: '62450ee5-e75d-4a67-8d79-120d11ddf508',
userId: 111,
fruitNumber: '123456',
created: 2022-07-01T06:39:52.924Z,
updated: 2022-07-01T06:39:52.936Z
},
{
id: '62450ee5-e75d-4a67-8d79-120d11ddf508',
userId: 999,
fruitNumber: '123456',
created: 2022-07-01T06:39:52.924Z,
updated: 2022-07-01T06:39:52.936Z
}
For the fruit object I need nulls and anything that matches the userId and based on design it should only ever be 1 record for each shop for the specific user.
At somepoint my code seemed to work but after I did a prisma generate it stopped working. Is there another way I can achieve the same result or is there someway to fix this?
Note:version info below.
model UserFruit {
id String #id #default(uuid())
fruitNumber String #map("fruit_number")
shopId Int #unique #map("shop_id")
userId Int #map("user_id")
created DateTime #default(now())
updated DateTime #updatedAt
fruit Fruit #relation(fields: [fruitId], references: [id])
##unique([userId, fruitId], name: "userFruit")
##map("user_Fruit")
}
model Shop {
id Int #id #default(autoincrement())
name String #unique
logo String
created DateTime #default(now())
updated DateTime #updatedAt
fruit UserFruit?
##map("Shop")
}
model User {
id Int #id #default(autoincrement())
created DateTime #default(now())
updated DateTime #updatedAt
uid String #unique
email String #unique
phone String #unique
firstName String #map("first_name")
lastName String #map("last_name")
dob DateTime?
gender String?
roleId Int #default(1) #map("role_id")
role Role #relation(fields: [roleId], references: [id])
##map("user")
}
Why not do a nested where at the top level to only search for shops whose fruit has the userId you need, rather than doing a nested select? It should make your query simpler and also solve your problem.
const userId = parseInt(req.params.id);
const shop = await prisma.shop.findMany({
select: {
id: true,
name: true,
logo: true,
fruit: {
select: {
id: true,
userId: true,
fruitNumber: true,
created: true,
updated: true,
},
// Removed the nested "where" from here
},
},
where: {
// One of the following conditions must be true
OR: [
// Return shops who have a connected fruit AND
// the fruit's "userId" attribute equals the variable "userID"
{
fruit: {
is: {
userId: userId,
// Can also simplify this to the below line if you want
// userId
},
},
},
// Return shops who do not have a connected fruit
// this will be true if "fruitId" is null
// could also write this as {fruit: {is: {}}}
{
fruitId: {
equals: null,
},
},
],
},
});
This query should output an array of shops where the connected fruit model's userId property equals your userId variable.
I have prisma schema like below
model t1 {
id Int #id #default(autoincrement())
title String
previousNodeId Int? #unique
}
and I wanted to update title of rows who have null values in previousNodeId
I have written query
await prisma.t1.update({
where: { previousNodeId: null },
data: {
title:"update title"
}
});
but I am not able to update it.
Getting error Type 'null' is not assignable to type 'number | undefined'.
The expected type comes from property 'previousNodeId' which is declared here on type 'T1WhereUniqueInput'
I am able to get all rows using findMany.
await prisma.t1.findMany({
where: { previousNodeId: null },
});
Result of findMany
[
{
id: 3,
title: 'demo t1 1',
previousNodeId: null
}
]
I've been making an application for tracking user finances with NestJS, TypeORM and MySQL on the backend and all was going swell until I ran into a brick wall which was saving an entity called Financialchange which represents one unit of financial expense or gain. The problem is that in a table that represents a many to many relationship of user defined tags with the financial change, an empty row is inserted every time I save this entity along with the row that is correctly inserted.
The saving is done like this:
const financialChange = await this.financialChangeRepository.save({
amount: payload.amount,
description: payload.description,
expense: payload.expense,
paymentSourceId: payload.paymentSourceId,
appUserId: payload.appUserId,
createdAt: format(new Date(), "yyyy-MM-dd hh:mm:ss")
});
payload.tagIds.forEach(async (tagId) => {
await this.financialChangeTagRepository.save({
financialChangeId: financialChange.id,
tagId
});
});
An example of sent data:
mutation {
addFinancialChange(
financialChange: {
appUserId: 1
amount: 200
description: "Description"
expense: true
paymentSourceId: 1
tagIds: [1]
}
)
}
And when selecting data from the many to many table I get this:
The entity data is as follows, first the MySQL table creation:
CREATE TABLE financialchange (
id INT AUTO_INCREMENT PRIMARY KEY,
amount DOUBLE,
createdAt DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP(),
description VARCHAR(255),
expense BOOLEAN,
paymentSourceId INT,
appUserId INT,
FOREIGN KEY (appUserId) REFERENCES appuser(id),
FOREIGN KEY (paymentSourceId) REFERENCES paymentsource(id)
);
And then the TypeORM entity in Nest:
#Index("appUserId", ["appUserId"], {})
#Index("paymentSourceId", ["paymentSourceId"], {})
#Entity("financialchange", { schema: "finapp" })
export class Financialchange {
#PrimaryGeneratedColumn({ type: "int", name: "id" })
public id?: number;
#Column("double", { name: "amount", nullable: true, precision: 22 })
public amount?: number | null;
#Column("datetime", { name: "createdAt", default: () => "CURRENT_TIMESTAMP" })
public createdAt?: Date;
#Column("varchar", { name: "description", nullable: true, length: 255 })
public description?: string | null;
#Column("tinyint", { name: "expense", nullable: true, width: 1 })
public expense?: boolean | null;
#Column("int", { name: "paymentSourceId", nullable: true })
public paymentSourceId?: number | null;
#Column("int", { name: "appUserId", nullable: true })
public appUserId?: number | null;
#ManyToOne(() => Appuser, (appuser) => appuser.financialchanges, {
onDelete: "NO ACTION",
onUpdate: "NO ACTION"
})
#JoinColumn([{ name: "appUserId", referencedColumnName: "id" }])
public appUser?: Appuser;
#ManyToOne(
() => Paymentsource,
(paymentsource) => paymentsource.financialchanges,
{ onDelete: "NO ACTION", onUpdate: "NO ACTION" }
)
#JoinColumn([{ name: "paymentSourceId", referencedColumnName: "id" }])
public paymentSource?: Paymentsource;
#OneToMany(
() => Financialchangetag,
(financialchangetag) => financialchangetag.financialChange
)
public financialchangetags?: Financialchangetag[];
}
It is in concept defined as having N amounts of tags binded to it, which is why I have created a table that represents a many to many relation called financialchangetags:
CREATE TABLE financialchangetag (
id INT AUTO_INCREMENT PRIMARY KEY,
financialChangeId INT,
tagId INT,
FOREIGN KEY (financialChangeId) REFERENCES financialchange(id),
FOREIGN KEY (tagId) REFERENCES tag(id)
);
#Index("financialChangeId", ["financialChangeId"], {})
#Index("tagId", ["tagId"], {})
#Entity("financialchangetag", { schema: "finapp" })
export class Financialchangetag {
#PrimaryGeneratedColumn({ type: "int", name: "id" })
public id?: number;
#Column("int", { name: "financialChangeId", nullable: true })
public financialChangeId?: number | null;
#Column("int", { name: "tagId", nullable: true })
public tagId?: number | null;
#ManyToOne(
() => Financialchange,
(financialchange) => financialchange.financialchangetags,
{ onDelete: "NO ACTION", onUpdate: "NO ACTION" }
)
#JoinColumn([{ name: "financialChangeId", referencedColumnName: "id" }])
public financialChange?: Financialchange;
#ManyToOne(() => Tag, (tag) => tag.financialchangetags, {
onDelete: "NO ACTION",
onUpdate: "NO ACTION"
})
#JoinColumn([{ name: "tagId", referencedColumnName: "id" }])
public tag?: Tag;
}
And the tag table is defined in this manner:
CREATE TABLE tag (
id INT AUTO_INCREMENT PRIMARY KEY,
description VARCHAR(255)
);
#Entity("tag", { schema: "finapp" })
export class Tag {
#PrimaryGeneratedColumn({ type: "int", name: "id" })
public id?: number;
#Column("varchar", { name: "description", nullable: true, length: 255 })
public description?: string | null;
#OneToMany(
() => Financialchangetag,
(financialchangetag) => financialchangetag.tag
)
public financialchangetags?: Financialchangetag[];
}
I have no clue why this is, I have tried inserting a record into financialchange with a transaction manager and through other methods of saving data that TypeORM offers, but I still get an empty row in my M:N table.