how to fetch mapped columns in prisma2 - prisma

I am new to prisma2 and I have created the below model schema with #map annotation
model User {
id Int #id #default(autoincrement())
name String #map("user_name")
}
Now when i see in my db I am having two columns in User table id and user_name but when i am fetching the data from user table like below:
const users = prisma.users.findMany()
So i am getting data like
[
{
id:1,
name: null
}
]
Because the schema points to name where as name is mapped to user_name, please help me how can i fetch the db column user_name in the result alias as name
output should be like below:
[
{
id:1,
user_name: "name value"
}
]

#map Maps a field name or enum value from the Prisma schema to a column or document field with a different name in the database.
So in your database the name of the column will be user_name but in the generated client the name of the field will be name.
#map does change the field names in the generated client.
If you want to use user_name in the response you will need to define it as user_name in your schema file.
model User {
id Int #id #default(autoincrement())
user_name String
}
#map reference

Related

Prisma, how to preserve foreign data?

It's been a few months since I started prisma and I'm still confused.
In a normal database, foreign key data also exists in table data. However, according to the prisma document, in prisma, the data does not exist at the database level.
So where is it stored? It seems that the things I do "connect:id:1" are stored in the Prisma client. If I delete the prisma dependency and install it again with npm install, will all these relational data be deleted too?? How can I make it as safe as possible????
And it seems too dangerous when I migrate later. what am I misunderstanding?
ADDED
const user = await prisma.user.create({
data: {
email: 'vlad#prisma.io',
posts: {
connect: [{ id: 8 }, { id: 9 }, { id: 10 }],
},
},
include: {
posts: true, // Include all posts in the returned object
},
})
in this case, id 8, id 9, id 10, Where are all these stored? Is there any way to check other than prisma studio or select query? I don't know where it is physically stored. It's not even in the planet scale database.
// In the workbench, the foriegn key is actually saved and can be exported. I don't know how it's not at the database level, but where it is referenced and stored.
Considering this Schema:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int #id #default(autoincrement())
name String
email String #unique
posts Post[]
}
model Post {
id Int #id #default(autoincrement())
title String
published Boolean #default(true)
author User #relation(fields: [authorId], references: [id])
authorId Int
}
There is a one-to-many relationship between User and Posts.
according to the prisma document, in prisma, the data does not exist
at the database level.
Only the relation fields do not exist at the database level, so in this case posts in User model and author in Post model would not exist at database level. But the foreign key exists at the database level, so in this case authorId is actually stored in the database.
Based on the create query you have shared:
in this case, id 8, id 9, id 10, Where are all these stored?
The connect statement in create query is essentially linking the records.
So to elaborate Posts with id 8,9,10 would have the authorId value of the new user record which is created.
So the data is stored in database, you can always check which posts are created by a specific author. You just need to query all the posts which has authorId set to the id which you are querying for.

Create a record and connect it to an existing record prisma client (1 to 1 relation)

I'm making a Next JS application with prisma and postgres.
I have 2 tables: User and Profile
Their prisma schema structure is as follows:
model User {
id String #id #default(cuid())
name String?
email String? #unique
emailVerified DateTime?
image String?
// foreign keys
sessions Session[]
profile Profile?
}
model Profile {
id Int #id #default(autoincrement())
isAdmin Boolean #default(false)
firstName String
lastName String
email String #unique
phone String
address String
gender String
image Bytes
guardianName1 String
guardianPhone1 String
guardianRelation1 String
guardianName2 String?
guardianPhone2 String?
guardianRelation2 String?
guardianName3 String?
guardianPhone3 String?
guardianRelation3 String?
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
// foreign keys
user User #relation(fields: [userId], references: [id], onDelete: Cascade)
userId String #default(cuid()) // relation scalar field (used in the `#relation` attribute above)
requests Request[]
}
I'm also using next-auth for the authentication part of this application. So when a user signs up then upon his email verification, next-auth itself adds the user's record to the User table.
Till here, there's no issue.
Then, when the user opens his dashboard for the first time, then he's shown a form to fill, upon submission of that form, a record needs to be inserted in the Profile table. As the Profile and User table's are linked, they also need to be connected.
So when the user submits profile details form, I do this:
try {
const newProfileData = {
// other fields data here...
user: {
connect: { id: '1' } // where User table already has a record with - 'id': 1
}
};
const profile = await prisma.profile.create({ data: newProfileData, include: { user: true } });
if(profile) {
console.log("Created: ", profile);
res.status(200).json({ msg: 'Successfully Created Profile!' });
}
}
catch(err)
{
console.log(err);
}
But upon running this code, I get the error:
The change you are trying to make would violate the required relation 'ProfileToUser' between the `Profile` and `User` models.
...
code: 'P2014',
clientVersion: '2.30.3',
meta: {
relation_name: 'ProfileToUser',
model_a_name: 'Profile',
model_b_name: 'User'
}
How can this be solved?
I even tried it the other way (i.e. updating the existing User and creating the Profile record connected to it):
const user = await prisma.user.update({
where: {
email: req.body.email,
},
data: {
profile: {
create: {
// data fields here... (without the user field)
},
},
},
});
But this also gives the same error...
I want to understand why the error comes. Is this not the correct way to create a record for a 1 to 1 relation using prisma-client?
The fix:
I think you need to remove #default(cuid()) from the Profile's userId field definition.
model Profile {
//...
// foreign keys
user User #relation(fields: [userId], references: [id], onDelete: Cascade)
userId String // relation scalar field (used in the `#relation` attribute above)
//...
}
And also get rid of include: { user: true }:
const profile = await prisma.profile.create({ data: newProfileData});
The explanation:
Profile's user and userId fields don't directly translate to actual columns on the db but are fields that let Prisma handle the link between the relations. It ends up translated to PostgreSQL's
create table profile(
--...
userId text references user (id),
--...
);
And later Prisma will populate that field with your User's id when you issue a user:{connect:{id:'1'}}. What could've happened is when you used #default(cuid()) in userId field definition, you interfered with that process. Now the column ends up as
userId text default gen_random_uuid() references user (id)
and whenever you create a Profile, a new row gets entered without specifying your own userId (which Prisma probably attempts to do before it'll try to link your User), a random id gets generated that doesn't correspond to any existing User, which violates the reference constraint.
It's that and/or your usage of include: { user: true } messes something up spawning a separate, new user, even though you tried to link your Profile to an existing one. But I would expect that to be just an unwanted side-effect making your code spawn a useless User object and row each time you create a Profile.
Once you get rid of the #default(cuid()) you can also just spawn a standalone, unlinked Profile and then link it to the appropriate User later with an update statement.
Merge the two tables into one, something like:
model User {
id String #id #default(cuid())
name String?
email String? #unique
emailVerified DateTime?
image String?
isAdmin Boolean #default(false)
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
// foreign keys
sessions Session[]
}
If you absolutely must have a Profile relation, create a database view:
create view Profile as
select
id,
isAdmin,
name,
email,
createdAt,
updatedAt,
userId
from user
and map it as a read only relation, but I can’t see the point.

After upgrading to Prisma2 should Psima1 still be able to create relation in nested create?

I'm attempting to upgrade Prisma from 1 to 2, opting to run prisma1 (1.34.12) along-side Prisma2 (3.4.1)
My problem is that after upgrading the MySQL DB and schema, my prisma1 queries are failing when trying to create nested creates in relation tables.
Example (paraphrased) Prisma2 schema:
model User {
id String #id #default(cuid()) #db.Char(30)
email String #db.MediumText
admin Admin?
}
model Admin {
id String #id #default(cuid()) #db.Char(30)
name String #db.MediumText
userId String #db.Char(30)
user User #relation(fields: [userId], references: [id], onUpdate: Restrict)
}
Example (paraphrased) Prisma1 query:
mutation ($data: UserCreateInput!) {
createuser(data: $data) {
id
email
}
}
variables
{
"data" {
"email": "diety#supremebeing.org"
"admin": {
"create": {
"name": "me"
}
}
}
}
The (paraphrased) error I get:
(conn=3216) Field 'userId' doesn't have a default value
This section of the schema-incompatibilities prisma-upgrade doc seems to indicate that, after updating the schema and MySQL DB via the directions in the work-around, prisma1 should stick the userId into that Admin table based on the foreign key constraint, shouldn't it?
https://www.prisma.io/docs/guides/upgrade-guides/upgrade-from-prisma-1/schema-incompatibilities-postgres#all-non-inline-relations-are-recognized-as-m-n
How might I get my prisma1 queries/mutations to play in the Prisma2-upgraded DB?
Thank you!

Updating many-to-many relations in Prisma

I have a group of checkboxes for skin concerns. Users can check/uncheck them before submitting, which means the set of skin concerns submitted can be different every time.
I modeled it in Prisma schema as an 'explicit' many-to-many relation.
model User {
id String #id #default(cuid())
name String?
nickname String? #unique
...
skinConcerns SkinConcernsForUsers[]
...
}
model SkinConcern {
id Int #id #default(autoincrement())
name String #unique
user SkinConcernsForUsers[]
}
model SkinConcernsForUsers {
user User #relation(fields: [userId], references: [id])
userId String
skinConcern SkinConcern #relation(fields: [skinConcernId], references: [id])
skinConcernId Int
##id([userId, skinConcernId])
}
Then, SkinConcerns table is seeded with the following values, using prisma.skinConcern.createMany:
"ACNE",
"DRYNESS",
"OILY_SKIN",
"PIGMENTATION",
"REDNESS",
"WRINKLES",
SkinConcerns in Update mutation input comes in the form of array of strings, e.g. ["PIGMENTATION", "REDNESS"].
I want to update the skin concerns for users (SkinConcernsForUsers) from the prisma.user.update query, but it's tricky, since I'm not merely creating SkinConcerns, but have to connect to existing set of skin concerns.
I've tried directly setting skinConcerns in user, like
await prisma.user.update({
where: { nickname },
data: {
// ... other user data
skinConcerns: {
set: [
{
skinConcern: {
connect: { name: "PIGMENTATION" },
},
},
{
skinConcern: {
connect: { name: "REDNESS" },
},
},
],
},
// ... other user data
}
});
among many other things, but of course this is not a correct argument and fails with error
Unknown arg `connect` in data.skinConcerns.update.0.where.connect for type SkinConcernsForUsersWhereUniqueInput. Did you mean `select`?
Argument data for data.skinConcerns.update.0.data is missing.
Unknown arg `connect` in data.skinConcerns.update.1.where.connect for type SkinConcernsForUsersWhereUniqueInput. Did you mean `select`?
Argument data for data.skinConcerns.update.1.data is missing.
Is there a way to do this? Is it even possible to update this in prisma.user.update?
I guess I could directly update SkinConcernsForUsers. In that case, should I just delete all rows associated to the user that are not in the user input ["PIGMENTATION", "REDNESS"], then create rows that don't already exist? What will it look like in prisma code?
First I would change your schema for SkinConcern. The id field is not necessary and will create complications in queries (you would needlessly need to map each name to id when trying to connect/disconnect records.
The name field is sufficient as the primary key, as it is always unique for a certain record.
The changed schema looks like this
model SkinConcern {
name String #id // name is the new #id.
user SkinConcernsForUsers[]
}
model SkinConcernsForUsers {
user User #relation(fields: [userId], references: [id])
userId String
skinConcern SkinConcern #relation(fields: [skinConcernName], references: [name])
skinConcernName String
##id([userId, skinConcernName])
}
The query you want to do can be executed in two steps with the SkinConcernsForUsers model.
Step 1: Remove existing SkinConcernsForUsers records a user is connected to. These are no longer relevant, as you want to overwrite the previous selection.
Step 2: Create new SkinConcernsForUsers records with the new choices.
Here is what the code looks like
// step 1
await prisma.skinConcernsForUsers.deleteMany({
where: {
userId: "1",
},
});
// step 2
await prisma.skinConcernsForUsers.createMany({
data: [
{
userId: "1",
skinConcernName: "REDNESS",
},
{
userId: "1",
skinConcernName: "PIGMENTATION",
},
],
});

How to scan into nested structs with sqlx?

Let's assume that I have two models,
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address Address `json:"adress"`
}
type Address struct {
Street string `json:"street" db:"street"`
City string `json:"city" db:"city"`
}
// ...
customer := models.Customer{}
err := db.Get(&customer , `select * from users where id=$1 and name=$2`, id, name)
But this scan throws an error as: missing destination name street in *models.Customer
Am I doing something wrong? As you can see I already updated the db corresponding of the value. I doubled check so case sensitivity shouldn't be a problem.
Or is it not possible using https://github.com/jmoiron/sqlx?
I can see it in the documentation but still couldn't figure out how to solve it.
http://jmoiron.github.io/sqlx/#advancedScanning
The users table is declared as:
CREATE TABLE `users` (
`id` varchar(256) NOT NULL,
`name` varchar(150) NOT NULL,
`street` varchar(150) NOT NULL,
`city` varchar(150) NOT NULL,
)
The very link you posted gives you an hint about how to do this:
StructScan is deceptively sophisticated. It supports embedded structs, and assigns to fields using the same precedence rules that Go uses for embedded attribute and method access
So given your DB schema, you can simply embed Address into Customer:
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address
}
In your original code, Address was a field with its own db tag. This is not correct, and by the way your schema has no address column at all. (it appears you edited it out of your code snippet)
By embedding the struct into Customer instead, Address fields including tags are promoted into Customer and sqlx will be able to populate them from your query result.
Warning: embedding the field will also flatten the output of any JSON marshalling. It will become:
{
"id": 1,
"name": "foo",
"street": "bar",
"city": "baz"
}
If you want to place street and city into a JSON address object as based on your original struct tags, the easiest way is probably to remap the DB struct to your original type.
You could also scan the query result into a map[string]interface{} but then you have to be careful about how Postgres data types are represented in Go.
I had the same problem and came up with a slightly more elegant solution than #blackgreen's.
He's right, the easiest way is to embed the objects, but I do it in a temporary object instead of making the original messier.
You then add a function to convert your temp (flat) object into your real (nested) one.
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address Address `json:"adress"`
}
type Address struct {
Street string `json:"street" db:"street"`
City string `json:"city" db:"city"`
}
type tempCustomer struct {
Customer
Address
}
func (c *tempCustomer) ToCustomer() Customer {
customer := c.Customer
customer.Address = c.Address
return customer
}
Now you can scan into tempCustomer and simply call tempCustomer.ToCustomer before you return. This keeps your JSON clean and doesn't require a custom scan function.