Closed divan closed 2 years ago
using the JSON approach looks something like this
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/edgedb/edgedb-go"
)
type Pet struct {
Name string `edgedb:"name"`
}
type Person struct {
Name string `edgedb:"name"`
Pets []Pet `edgedb:"pets"`
}
type Movie struct {
Title string `edgedb:"title"`
Actors []Person `edgedb:"actors"`
}
var movie = Movie{
Title: "The Matrix",
Actors: []Person{
{
Name: "Keanu Reeves",
Pets: []Pet{
{Name: "Neo"},
{Name: "Morpheus"},
},
},
{
Name: "Laurence Fishburne",
Pets: []Pet{
{Name: "Tank"},
{Name: "Cypher"},
},
},
},
}
func main() {
ctx := context.TODO()
client, err := edgedb.CreateClient(ctx, edgedb.Options{})
if err != nil {
log.Fatal(err)
}
defer client.Close()
var result struct {
id edgedb.UUID `edgedb:"id"`
}
data, err := json.Marshal(movie.Actors)
if err != nil {
log.Fatal(err)
}
fmt.Println(string(data))
err = client.QuerySingle(ctx, `
INSERT Movie {
title := <str>$0,
actors := (FOR actor IN json_array_unpack(to_json(<str>$1)) UNION (
INSERT Person {
name := <str>actor['Name'],
pets := (FOR pet in json_array_unpack(actor['Pets']) UNION (
INSERT Pet {
name := <str>pet['Name'],
}
))
}
))
}
`,
&result,
movie.Title,
string(data),
)
if err != nil {
log.Fatal(err)
}
fmt.Println(result)
}
Going through code I found something called "$inline" tag and PR that enabled it, but it's unclear if it's something that can be used for the nested inserts.
The $inline
tag is for promoting the fields of an embedded struct up to the embeder struct, but this is only relevant for decoding query results. There is currently no way to send objects or tuples as query arguments.
Thanks for the example @fmoor. JSON approach looks quite okay, suprisingly.
What about FOR ... json_array_unpack...
performance? I mean compared to sending equivalent pregenerated query? Is there any data or guesstimates available?
Also, are there any ideas or plans of query builder? https://github.com/edgedb/edgedb-go/issues/182
What about
FOR ... json_array_unpack...
performance? I mean compared to sending equivalent pregenerated query?
json_array_unpack
would be faster than a bunch of pregenerated text, because the query itself is smaller.
Thank you! Closing.
How would you suggest to insert nested structures from Go code that have multi links?
With single links it's relatively straighforward, albeit verbose.
But with multi links it's not clear how is it supposed to be handled.
Straightforward approach would be to iterate over children's slices, insert manually, keep IDs, then add ID's to the parent object. Super verbose and painful without codegeneration. Also, requires transaction.
Another approach I was drawing from the examples of bulk insert from EdgeQL docs – marshalling data into JSON and inserting from json array. But it feels super hackish and not clear how to use for more than one nesting level.
Going through code I found something called "$inline" tag and PR that enabled it, but it's unclear if it's something that can be used for the nested inserts.
Would appreaciate suggestions/advice here a lot.
Sample schema
Sample data (generated by Copilot, sorry)):
main.go
```go package main import ( "context" "fmt" "log" "github.com/edgedb/edgedb-go" ) type Pet struct { Name string `edgedb:"name"` } type Person struct { Name string `edgedb:"name"` Pets []Pet `edgedb:"pets"` } type Movie struct { Title string `edgedb:"title"` Actors []Person `edgedb:"actors"` } var movie = Movie{ Title: "The Matrix", Actors: []Person{ { Name: "Keanu Reeves", Pets: []Pet{ {Name: "Neo"}, {Name: "Morpheus"}, }, }, { Name: "Laurence Fishburne", Pets: []Pet{ {Name: "Tank"}, {Name: "Cypher"}, }, }, }, } func main() { ctx := context.TODO() client, err := edgedb.CreateClient(ctx, edgedb.Options{}) if err != nil { log.Fatal(err) } defer client.Close() var result struct { id edgedb.UUID `edgedb:"id"` } err = client.QuerySingle(ctx, `INSERT Movie { title :=