Recursive type detection on mutate
Closed this issue · 5 comments
Hello,
First of all, thank you for this very helpful lib.
I've a question (maybe an issue) on mutation when the object to mutate enclose other object with different types, for exemple :
type T1 struct {
UID string `json:"uid,omitempty"`
Name string `json:"name,omitempty"`
T2s []T2 `json:"t2s,omitempty"`
}
type T2 struct {
UID string `json:"uid,omitempty"`
Age int `json:"age,omitempty"`
T3s []T3 `json:"t3s,omitempty"`
}
type T3 struct {
UID string `json:"uid,omitempty"`
Color string `json:"color,omitempty"`
}
The schema generation work well, but...
Lets say I would like to persist this kind of value :
test := T1{
Name: "testName",
T2s: []T2{
{
Age: 30,
T3s: []T3{
{
Color: "blue",
},
{
Color: "Red",
},
},
},
},
}
It seems dgman will generate a JSON GraphQL+ representation with only one "dgraph.type"
predicate, in this case `"dgraph.type": "T1", omitting the type for T2 and T3 values.
This is problematics on last versions of dgraph (> v1.1.0) because :
expand(_all_)
work now only on typed nodes- dgman
Get
useexpand(_all_)
to discover node values and fill target structure
Then, when I try to get an T1 node type in a T1 struct I will get only the first level of data despite the depthParam
.
I've I missed something ? or is it a real issue ?
Yes this is a real issue that I have come across while developing the lib. I might or might not have a fix for this.
Currently, for each depth of the node structure, you will need to create a separate mutation. For example:
// Currently, you must use a slice of pointer structs, so UIDs can be injected
// might need to fix this too allowing slice of structs
t3s := []*T3{
{
Color: "blue",
},
{
Color: "Red",
},
}
if err := dgman.NewTxn(c).Mutate(&t3s, true); err != nil {
log.Println(err)
}
t2s := []*T2{
Age: 30,
T3s: t3s, // uid should be injected on t3s, connecting the nodes
}
if err := dgman.NewTxn(c).Mutate(&t2s, true); err != nil {
log.Println(err)
}
t1 := T1{
Name: "testName",
T2s: t2s,
}
if err := dgman.NewTxn(c).Mutate(&t1, true); err != nil {
log.Println(err)
}
log.Println(t1) // uids should be populated on every depth
// try to query the data
var t1 T1
err := dgman.NewReadOnlyTxn(c).Get(&t1).
Filter("eq(name, $1)", "testName").
All(3).
Node()
log.Println(t1) // should resolve nodes tree until T3
Thank you pointing out this issue, I will evaluate my priorities on the development of this lib, if this an urgent issue.
Thank you for your response.
Another solution is to overwrite MarshalSHON
method for each sub-structure.
Then T1 (with sub-structures) can be mutated directly.
I'll try to generify that in marshalAndInjectType
method.
func (p *T2) MarshalJSON() ([]byte, error) {
type Copy T2
v := *p
return json.Marshal(&struct {
DgraphType string `json:"dgraph.type"`
*Copy
}{
DgraphType: reflect.TypeOf(v).Name(),
Copy: (*Copy)(p),
})
}
Cool.. That would be great, contributions are highly welcome.
Though we can't make assumptions on the underlying type, without doing reflection, but we might go down that route.
Hi @protheusfr, this is fixed in #36 .
It allows recursive type detection, though it requires dgraph.type
field to be present on the struct.
Great! thank you @wildan2711 .