One-to-many relation with additional field - sql

I am creating a schema in prisma with the model User and Guild.
User can have one guild or none
Guild can have multiple User
Now I want to add an additional field of the role a user have in the guild.
What would be the best to achieve this?
I could add them to the user but then I have to manage it in the code that all are null or not null.
enum GuildRole {
MEMBER
CO_LEADER
LEADER
}
model Guild {
id Int #id #default(autoincrement())
name String
users User[]
}
model User {
id Int #id #default(autoincrement())
username String? #unique
guild Guild? #relation(fields: [guildId], references: [id])
guildId Int?
guildRole GuildRole?
}

You can do it as following when adding an existing user to a guild.
import { PrismaClient, GuildRole } from '#prisma/client'
const prisma = new PrismaClient()
// add user to guild
const addAnExistingUserToAGuild = async (userId: number, guildId: number, guildRole: GuildRole) => {
return await prisma.user?.create({
data: {
guildId: guildId,
userId: userId,
guildRole: guildRole,
},
})
}
The modelling will completely depend on your personal/company preference/style, I've modelled your schema like this :
enum GuildRole {
MEMBER
CO_LEADER
LEADER
}
model User {
userId Int #id #default(autoincrement())
username String? #unique
guild Guild? #relation(fields: [guildId], references: [guildId])
guildId Int?
guildRole GuildRole?
}
model Guild {
guildId Int #id #default(autoincrement())
name String
users User[]
}
More examples in our docs here for how you can create a one-to-many relationship :
https://www.prisma.io/docs/concepts/components/prisma-schema/relations/one-to-many-relations

Related

data available but not show composite key prisma

here is my all model example i trying to find from many to many relationship. the code exucuted but no data found.
model UsersHavePermission{
user User #relation(fields: [userId],references: [id])
userId Int
permission Permission #relation(fields: [permissionId],references: [id])
permissionId Int
create Boolean
update Boolean
delete Boolean
##id([userId,permissionId])
model Permission{
id Int #id #default(autoincrement())
name String #unique
isActive Boolean
user UsersHavePermission[]
}
model User{
id Int #id #default(autoincrement())
email String #unique
password String
is_active Boolean
roll Roll #relation(fields: [rollId],references: [id])
rollId Int
profile Profile?
permissions UsersHavePermission[]
degees DegreeBasedJobForUser[]
categories CategoriesBasedJobForUser[]
}
const checkCreate = await prisma.usersHavePermission.findFirst({
where: {
userId_permissionId: {
userId: parseInt(req.body.userId),
permissionId: parseInt(req.body.permissionId),
},
},
});
res.send(checkCreate);
enter image description here
i want userId and permisssionId base data

How to filter by relationships using each Prisma orm

I have a one to many relationship, and I need to filter the relationship values, I need to bring all the records that contain all the values ​​of the array/
example: const attributes = ["Car", "Bike", "Truck"]
prisma.car.findMany({
where: {
attribute: {
typeCar: {
every: {
value: { hasSome: attributes },
},
},
},
},
});
This search works only if all attributes exist, if any attribute does not exist, nothing is returned
I need it to return the record, even if typeCar does not contain all records.
How could I do that with the prisma?
My model
model Car {
id String #id
name String
status String
description String
thumbnailUrl String?
groupId String?
categoryName String
attribute Attribute[]
images CarImage[]
createdAt DateTime #default(now())
updatedAt DateTime? #updatedAt
##map("car")
}
model Attribute {
id String #id
typeCar String[]
car Car? #relation(fields: [carId], references: [id])
carId String?
createdAt DateTime #default(now())
updatedAt DateTime? #updatedAt
##map("attributeProductValue")
}
One solution I found was to add a new field in the car table. Saving the values ​​of the typeCar
model Car {
id String #id
name String
status String
description String
thumbnailUrl String?
groupId String?
categoryName String
attribute Attribute[]
images CarImage[]
typeCarValues String[]
createdAt DateTime #default(now())
updatedAt DateTime? #updatedAt
##map("car")
}
So I can filter without going through the relationship, and the hasEvery option works.
example: const attributes = ["Car", "Bike", "Truck"]
prisma.car.findMany({
where: {
typeCarValues: {
hasEvery: attributes,
},
},
})
The problem was in filtering the relationship in attributes using every and then hasEvery, to return the value all attributes of typeCar need to be informed and exist, if any of them is not informed, it does not return.

Prisma: Type '{ where: { variable: "value"; }; }' is not assignable to type 'boolean'

So I am using prisma and I am trying to get the count of votes on thread where the vote value is VoteStatus.down. I am following the docs here.
I am getting Type '{ where: { vote: "down"; }; }' is not assignable to type 'boolean'. when I do this:
await this.prisma.thread.findMany({
select: {
_count: {
select: {
votes: { where: { vote: VoteStatus.down } }
}
}
}
});
Here are my models in schema.prisma (note: I have modified for simplicity of the question):
model Thread {
id Int #id #default(autoincrement())
votes ThreadVote[]
}
model ThreadVote {
id Int #id #default(autoincrement())
thread Thread #relation(fields: [threadId], references: [id])
threadId Int
vote VoteStatus
}
enum VoteStatus {
up
down
}
I'm wondering if there is a bug in prisma? It seems to line up with the docs perfectly. Note that I am on Prisma 4.3.1.
Edit: I am now thinking it is because I have to add the filter relation count:
generator client {
provider = "prisma-client-js"
previewFeatures = ["filteredRelationCount"]
}

Having a hard time with Prisma/Graphql One to One and One to many

I have a lot of trouble figuring out the 1 to 1 and 1 to many relation i made this schema then I have my graphql derived from that
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model Games {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
short_hand String #unique #db.VarChar(255)
name String #unique #db.VarChar(255)
in_boxes Box[]
set Sets[]
}
model User {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
username String #unique #db.VarChar(255)
password String #db.VarChar(255)
role Role #default(USER)
first_name String? #db.VarChar(255)
last_name String? #db.VarChar(255)
store String? #db.VarChar(255)
boxes Box[]
}
model Store {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
name String #unique #db.VarChar(255)
}
model Box {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
box_number String #db.VarChar(100)
box_second_number String? #db.VarChar(100)
set String #db.VarChar(255)
set_list Sets #relation(fields: [set], references: [name])
gameid Int? #default(1)
game Games? #relation(fields: [gameid], references: [id])
User User? #relation(fields: [userId], references: [id])
userId Int?
}
model Sets {
id Int #id #default(autoincrement())
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
name String #unique #db.VarChar(255)
code String #unique #db.VarChar(255)
children String[]
in_boxes Box[]
game String? #db.VarChar(255)
gamerel Games? #relation(fields: [game], references: [short_hand])
edition String?
}
enum Role {
USER
ADMIN
CHRIS
}
Basically a user will have boxes that they own (
The boxes has a Game Type and contains a parent Set which
Has it own set code and contain set children (array)
The game type it self has only name and shortcode
My main issue is that when I try to create a set with the resolver code
the graphql
mutation {
createBox (input:{box_number:"001", secondary_number:"A", game:{name:"yu"}, set:"Crucibile of War Unlimit"}) {
box_number
set
game
id
}
}
the resolver
createBox: async (_: any, { input }: any, context: Context) => {
const find = await context.prisma.games.findFirst({
where: {name: {contains:input.game[0].name,
mode:"insensitive"}}
}
);
console.log(find);
console.log(input.set);
return await context.prisma.box.create({
data: {
box_number: input.box_number,
box_second_number: input.secondary_number,
gameid: find?.id,
set: {connect: {
name: input.set
},
},
},
});
},
I get
" Foreign key constraint failed on the field: `Box_set_fkey (index)`",
" at cb
I'm really confused on how to make it work
In this case, set directly expects the relation so you don't need connect here. This should work:
const find = await prisma.games.findFirst({
where: { name: { contains: input.game[0].name } },
})
await prisma.box.create({
data: {
box_number: input.box_number,
box_second_number: input.secondary_number,
gameid: find?.id,
set: input.set,
},
})

How to get Role Claims?

I've created a user and attached to him a role that has a number of claims. The problem is I don't see a direct way to access retrieve them using Entity Framework Core and Identity integration. Here's what I'd like to do ideally:
return _context.Users
.Include(u => u.Roles)
.ThenInclude(r => r.Role)
.ThenInclude(r => r.Claims)
But there's not Role property, just RoleId. So I can not Include role claims. Of course I get make a separate query to get claims or even use RoleManager:
var user = _context.Users.Single(x => x.Id == ...);
var role = _roleManager.Roles.Single(x => x.Id == user.Roles.ElementAt(0).RoleId);
var claims = _roleManager.GetClaimsAsync(role).Result;
but it looks inefficient and even ugly. There should be a way to make a single query.
My last hope was Controller.User property (ClaimsIdentity). I hoped it somehow smartly aggregates claims from all the roles. But seems like it doesn't...
You can use SQL-like query expressions and get all claims from all roles of a user like this:
var claims = from ur in _context.UserRoles
where ur.UserId == "user_id"
join r in _context.Roles on ur.RoleId equals r.Id
join rc in _context.RoleClaims on r.Id equals rc.RoleId
select rc;
You can add navigation properties.
public class Role : IdentityRole
{
public virtual ICollection<RoleClaim> RoleClaims { get; set; }
}
public class RoleClaim : IdentityRoleClaim<string>
{
public virtual Role Role { get; set; }
}
Then you have to configure your identity db context:
public class MyIdentityDbContext : IdentityDbContext<User, Role, string, IdentityUserClaim<string>, IdentityUserRole<string>, IdentityUserLogin<string>, RoleClaim, IdentityUserToken<string>>
Usage:
await _context.Roles.Include(r => r.RoleClaims).ToListAsync();
At the end it generates the following query:
SELECT `r`.`Id`, `r`.`ConcurrencyStamp`, `r`.`Name`, `r`.`NormalizedName`, `r0`.`Id`, `r0`.`ClaimType`, `r0`.`ClaimValue`, `r0`.`RoleId`
FROM `roles` AS `r`
LEFT JOIN `role_claims` AS `r0` ON `r`.`Id` = `r0`.`RoleId`
ORDER BY `r`.`Id`, `r0`.`Id`
Source: Identity model customization in ASP.NET Core
Make sure you are adding the roles and claims correctly. Below is an example of how I create a user and add claims and roles.
private async Task<IdentityResult> CreateNewUser(ApplicationUser user, string password = null){
//_roleManger is of type RoleManager<IdentityRole>
// _userManger is of type UserManager<ApplicationUser>
//and both are injected in to the controller.
if (!await _roleManger.RoleExistsAsync("SomeRole")){
await _roleManger.CreateAsync(new IdentityRole("SomeRole"));
}
var result = password != null ? await _userManager.CreateAsync(user, password) : await _userManager.CreateAsync(user);
if(result.Succeeded) {
await _userManager.AddToRoleAsync(user, "SomeRole");
await _userManager.AddClaimAsync(user, new Claim(ClaimTypes.Name, user.Email));
}
return result;
}
Then you can use the _userManager to get the claims. This is how I get the current user using _userManager. Then you can just call something like this:
var claims = await _userManager.GetClaimsAsync(user);