Open krakowski opened 2 months ago
Hey, @krakowski 👋
This is the expected behavior. Edge schemas are primarily meant for use in JOIN tables because extra edge fields can be attached to the type itself.
The Usage Of Edge Schema In Other Edge Types example uses a unique index to enforce the cardinality. We can consider extending this and supporting the setting of Unique
edges for edge-schemas, although I'm not sure how common this is.
Hi @a8m,
thanks for taking a look at this so fast :slightly_smiling_face:
We can consider extending this and supporting the setting of Unique edges for edge-schemas, although I'm not sure how common this is.
This would solve my problem. I convert my entities to JSON, where the mentioned fields are represented as arrays, although they can only have a single reference. In Typescript I then need to check if the array is present, has a length > 0 and extract the first value.
Generally speaking, this problem will always occur if several entities can optionally hold at most one reference to another entity.
The Address
entity is a good example of this, as it can be linked to different entities (e.g Company
, Warehouse
, Employee
, Customer
, ...).
A solution to this would be a foreign key on Address
within each individual entity, which can be set to NULL
. However, I would like to avoid this solution as I want to avoid NULL
values.
@a8m Is there any reason why setting Unique
on edges for edge-schemas is not supported / allowed? I created a code generation hook, which sets them Unique
by inspecting if the conditions I mentioned in my issue are met. This way entc
does not throw an error and generates the following struct (*Address
instead of []*Address
).
type CompanyEdges struct {
// Address holds the value of the address edge.
Address *Address `json:"address,omitempty"`
// CompanyAddresses holds the value of the company_addresses edge.
CompanyAddresses []*CompanyAddress `json:"company_addresses,omitempty"`
// loadedTypes holds the information for reporting if a
// type was loaded (or requested) in eager-loading or not.
loadedTypes [2]bool
}
Here's my code generation hook.
func FixEdgeSchemaFields() gen.Hook {
return func(next gen.Generator) gen.Generator {
return gen.GenerateFunc(func(graph *gen.Graph) error {
// Iterate over all nodes and edges
for _, node := range graph.Nodes {
for _, edge := range node.Edges {
// Check if the current edge is connected to a edge schema
edgeSchema := edge.Through
if edgeSchema == nil {
continue
}
// Iterate over all edges of the edge schema
for _, edgeSchemaEdge := range edgeSchema.Edges {
// Check if the edge schema's edge references our original node
if edgeSchemaEdge.Type.Name == node.Name {
// Iterate over all indexes within the edge schema
for _, edgeSchemaIndex := range edgeSchema.Indexes {
// Check if index contains exactly one field
if len(edgeSchemaIndex.Columns) != 1 {
continue
}
// Compare index column name to edge schema edge's column name
// and set the original node's edge to unique if they match
if edgeSchemaIndex.Columns[0] == edgeSchemaEdge.Field().Name {
edge.Unique = true
}
}
}
}
}
}
return next.Generate(graph)
})
}
}
I tried running the generated code and it seems to work. Calling WithAddress
fills the address
field and the serialized json object doesn't contain an array field anymore. :slightly_smiling_face:
I followed the Usage Of Edge Schema In Other Edge Types documentation for a usecase where one entity
Address
can have two optional edges (O2M) to entitesCompany
andEmployee
. BothCompany
andEmployee
can reference 0 or 1Address
entites (constrained using an index). After running the code generator, I noticed that the fields referencing entityAddress
within theCompanyEdges
andEmployeeEdges
struct is of typeslice
.I tried calling
Unique
on the edge builder within theCompany
entity, but this does not seem to be allowed when usingThrough
.Schema:
Current Behavior 😯
The struct field is of type
[]*Address
Expected Behavior 🤔
The struct field should be of type
*Address
Steps to Reproduce 🕹
go test
Your Environment 🌎