Given Prisma schema:
model companiesOnUsers {
company company #relation(fields: [companyId], references: [id])
companyId Int
user user #relation(fields: [userId], references: [id])
userId Int
role companyRoles #relation(fields: [roleId], references: [id])
roleId Int
createdAt DateTime #default(now())
updatedAt DateTime #updatedAt
##id([companyId, userId])
}
The question is, how do you generate GraphQL out of it? Writing this twice is not an option.
I think I found an answer: TypeGraphQL Prisma package
Works with Prisma 4.8.0
Related
This is more a design question than a coding question. Suppose the following schema:
// schema.prisma
// Solution 1
model Entity {
id Int #id #default(autoincrement())
attrs EntityAttr[]
}
model EntityAttr {
id Int #id #default(autoincrement())
value Json // or String, doesnt matter much here
// the point is I need to attach info on the
// join table of this relation
attr Attr #relation(fields: [attrId], references: [id])
entity Entity #relation(fields: [entityId], references: [id])
entityId Int
attrId Int
##unique([entityId, attrId])
}
model Attr {
id Int #id #default(autoincrement())
entities EntityAttr[]
}
// Solution 2
model Entity {
id Int #id #default(autoincrement())
dateAttrs DateAttr[]
recordAttrs RecordAttr[]
// ... this pattern could continue for more Attr-like models
}
model DateAttr {
id Int #id #default(autoincrement())
name String
entity Entity #relation(fields: [entityId], references: [id])
value DateTime // Stronger typing in generated code
}
model RecordAttr {
// ... define another Entity #relation(...)
name String
value String
// ...
}
// ... and so on
Please note that the schema might not be 100% complete or accurate. It is mainly to get the point across.
Solution 1 has its merits where redundancy and the number of tables in the database is reduced significantly (depending on the number of Attrs). Its downfall comes as confusing queries*, possible case-specific type casting and no code-completion for the value field for each Attr-like model.
* by confusing, I mean that the option for simplified m-n queries in prisma is functionally disabled when using a custom join table (e.g. EntityAttr)
Solution 2 has its merits where the generated code results in more strongly typed code generation for the value field, however it falls in the number of generated tables (I don't actually know if more tables is a good thing or a bad thing, all I think is that if you have similar values, they ought to be in the same table).
What would you do in my shoes?
I was looking pretty long for an appropriate answer and found it here.
I'm not sure if it could be applied to your question, but this is question about prisma and polymorphism, so I think this code snippet might be useful for developers:
model Photo {
id Int #id #default(autoincrement())
likes Like[] #relation("PhotoLike")
}
model Video {
id Int #id #default(autoincrement())
likes Like[] #relation("VideoLike")
}
enum LikableType {
Photo
Video
}
model Like {
id Int #id #default(autoincrement())
Photo Photo? #relation("PhotoLike", fields: [likableId], references: [id], map: "photo_likableId")
Video Video? #relation("VideoLike", fields: [likableId], references: [id], map: "video_likableId")
likableId Int
likableType LikableType
}
Resuling relations in dbdocs:
Sometimes the use case can't be generalized to abstract and have a typing's.
if you control them and has a limited attribute sure you can create each attribute as a separate table each has it is own schema.
Some Times more freedom is needed or the blocks are dynamic.
Use Case: Build A Block Document Editor Like 'notion.so' and you want to let the user create custom blocks or configure them.
you can do it like :
model Document {
id String #id
blocks Block[]
}
model Block {
id String #id
value Json
index Int
customConfig Json?
document Document? #relation(fields: [documentID], references: [id])
documentID String?
blockType BlockType #relation(fields: [blockTypeID], references: [id])
blockTypeID String
}
model BlockType {
id String #id
name String
config Json
blocks Block[]
}
where config and custom config can contains html,custom css classes, link attribute color or anything.
using type script you can create block.types.ts and add different let say templates for the config's .
I hope that I was useful to you, To sum it, it depends on the requirements :>)
I am using GORM with GO.
I have an entity User
type User struct {
Id int `json:"id" gorm:"primaryKey;autoIncrement"`
Name string `json:"name"`
gorm.Model
}
My Create record code is
user := User{}
user.Name = "Afzal"
DB.Create(&user)
Now as per Doc user.ID should return inserted data's primary key
But it's returning 0 which is the default value when struct User was initialized.
User.Id will have the correct value, because you've added that field and tagged it as being the primary key. user.ID actually accesses user.Model.ID. This, too, has the primaryKey tag, but it's superseded by the Id field on your User type.
You've embedded the gorm.Model type (as per the docs, I imagine), but that means your User type actually looks like this:
User{
Id int
Name string
gorm.Model{
ID uint `gorm:"primarykey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt DeletedAt `gorm:"index"`
}
}
So when you look at user.ID, you're accessing the embedded ID field. Either check the Id field (lower-case d), or remove the Id field you've added, and rely on the ID from the embedded Model.
If you do want to keep your own Id field, I think the gorm.Model is right to make it a uint. If you're needing to faff around with negative ID elements in your data, you're probably doing something wrong... I've seen negative ID's being used, but every time I saw it happen, it was some absolutely horrible hack.
There are two model use gorm in my project as following:
type User struct {
gorm.Model
Name string `gorm:"type:varchar(128)" json:"name"`
}
type Service struct {
gorm.Model
Name string `gorm:"type:varchar(128)" json:"name"`
Members []*User `gorm:"many2many:user_to_service;" json:"members"`
}
Now, I need to add a field role in the user_to_service, represent the user role in the service such as admin, member, guest and so on.
How do I add the role field in user_to_service? And How to update or query with this field use gorm?
For example, I have the following models
type Company struct {
ID uint `gorm:"PRIMARY_KEY"`
Name string
Departments []*Department `gorm:"FOREIGNKEY:CompanyID"`
Managers []*Manager
}
type Department struct {
ID uint `gorm:"PRIMARY_KEY"`
Name string
Managers []*Manager `gorm:"FOREIGNKEY:DepartmentID"`
CompanyID uint
}
type Manager struct {
ID uint `gorm:"PRIMARY_KEY"`
Name string
DepartmentID uint
}
That is, company has many departments, and department has many managers. How can I create an association between company and manager such that I can say company has many managers through departments?
Is this feature even possible in Go GORM? I am used to seeing this in Rails ActiveRecord
class Company < ApplicationRecord
has_many :departments
has_many :managers, through: :departments
end
Thanks
I'm trying to create self-reference field using gorm:
type Post struct {
ID uint `gorm:"primary_key" json:"id"`
Post *Post `json:"post" xml:"post" sql:"default:null"`
}
db.AutoMigrate(&Post{})
Column post_id is not created in DB. Tried several struct field names, no luck.
Which is the correct way to handle self-refrenced associations?
Thank you.
The Gorm magic isn't in the association (foreign key) part but in the data part.
Gorm will do the sql joins to retrieve the related Post row based on PostID It will then store that data in the nested Post field in Post.
If you only provide Post without PostID Gorm will do nothing as there is no foreign key for it to work with.
type Post struct {
ID uint `gorm:"primary_key" json:"id"`
Post *Post `json:"post" xml:"post" sql:"default:null"`
PostID uint `json:"post_id" xml:"post_id"`
}
db.AutoMigrate(&Post{})