package core // import ( // "bytes" // "errors" // "fmt" // "net/http" // "sync" // "github.com/cespare/xxhash/v2" // "github.com/dosco/super-graph/jsn" // "github.com/dosco/super-graph/core/internal/qcode" // ) // func execRemoteJoin(st *stmt, data []byte, hdr http.Header) ([]byte, error) { // var err error // if len(data) == 0 || st.skipped == 0 { // return data, nil // } // sel := st.qc.Selects // h := xxhash.New() // // fetch the field name used within the db response json // // that are used to mark insertion points and the mapping between // // those field names and their select objects // fids, sfmap := parentFieldIds(h, sel, st.skipped) // // fetch the field values of the marked insertion points // // these values contain the id to be used with fetching remote data // from := jsn.Get(data, fids) // var to []jsn.Field // switch { // case len(from) == 1: // to, err = resolveRemote(hdr, h, from[0], sel, sfmap) // case len(from) > 1: // to, err = resolveRemotes(hdr, h, from, sel, sfmap) // default: // return nil, errors.New("something wrong no remote ids found in db response") // } // if err != nil { // return nil, err // } // var ob bytes.Buffer // err = jsn.Replace(&ob, data, from, to) // if err != nil { // return nil, err // } // return ob.Bytes(), nil // } // func resolveRemote( // hdr http.Header, // h *xxhash.Digest, // field jsn.Field, // sel []qcode.Select, // sfmap map[uint64]*qcode.Select) ([]jsn.Field, error) { // // replacement data for the marked insertion points // // key and value will be replaced by whats below // toA := [1]jsn.Field{} // to := toA[:1] // // use the json key to find the related Select object // k1 := xxhash.Sum64(field.Key) // s, ok := sfmap[k1] // if !ok { // return nil, nil // } // p := sel[s.ParentID] // // then use the Table nme in the Select and it's parent // // to find the resolver to use for this relationship // k2 := mkkey(h, s.Name, p.Name) // r, ok := rmap[k2] // if !ok { // return nil, nil // } // id := jsn.Value(field.Value) // if len(id) == 0 { // return nil, nil // } // //st := time.Now() // b, err := r.Fn(hdr, id) // if err != nil { // return nil, err // } // if len(r.Path) != 0 { // b = jsn.Strip(b, r.Path) // } // var ob bytes.Buffer // if len(s.Cols) != 0 { // err = jsn.Filter(&ob, b, colsToList(s.Cols)) // if err != nil { // return nil, err // } // } else { // ob.WriteString("null") // } // to[0] = jsn.Field{Key: []byte(s.FieldName), Value: ob.Bytes()} // return to, nil // } // func resolveRemotes( // hdr http.Header, // h *xxhash.Digest, // from []jsn.Field, // sel []qcode.Select, // sfmap map[uint64]*qcode.Select) ([]jsn.Field, error) { // // replacement data for the marked insertion points // // key and value will be replaced by whats below // to := make([]jsn.Field, len(from)) // var wg sync.WaitGroup // wg.Add(len(from)) // var cerr error // for i, id := range from { // // use the json key to find the related Select object // k1 := xxhash.Sum64(id.Key) // s, ok := sfmap[k1] // if !ok { // return nil, nil // } // p := sel[s.ParentID] // // then use the Table nme in the Select and it's parent // // to find the resolver to use for this relationship // k2 := mkkey(h, s.Name, p.Name) // r, ok := rmap[k2] // if !ok { // return nil, nil // } // id := jsn.Value(id.Value) // if len(id) == 0 { // return nil, nil // } // go func(n int, id []byte, s *qcode.Select) { // defer wg.Done() // //st := time.Now() // b, err := r.Fn(hdr, id) // if err != nil { // cerr = fmt.Errorf("%s: %s", s.Name, err) // return // } // if len(r.Path) != 0 { // b = jsn.Strip(b, r.Path) // } // var ob bytes.Buffer // if len(s.Cols) != 0 { // err = jsn.Filter(&ob, b, colsToList(s.Cols)) // if err != nil { // cerr = fmt.Errorf("%s: %s", s.Name, err) // return // } // } else { // ob.WriteString("null") // } // to[n] = jsn.Field{Key: []byte(s.FieldName), Value: ob.Bytes()} // }(i, id, s) // } // wg.Wait() // return to, cerr // } // func parentFieldIds(h *xxhash.Digest, sel []qcode.Select, skipped uint32) ( // [][]byte, // map[uint64]*qcode.Select) { // c := 0 // for i := range sel { // s := &sel[i] // if isSkipped(skipped, uint32(s.ID)) { // c++ // } // } // // list of keys (and it's related value) to extract from // // the db json response // fm := make([][]byte, c) // // mapping between the above extracted key and a Select // // object // sm := make(map[uint64]*qcode.Select, c) // n := 0 // for i := range sel { // s := &sel[i] // if !isSkipped(skipped, uint32(s.ID)) { // continue // } // p := sel[s.ParentID] // k := mkkey(h, s.Name, p.Name) // if r, ok := rmap[k]; ok { // fm[n] = r.IDField // n++ // k := xxhash.Sum64(r.IDField) // sm[k] = s // } // } // return fm, sm // } // func isSkipped(n uint32, pos uint32) bool { // return ((n & (1 << pos)) != 0) // } // func colsToList(cols []qcode.Column) []string { // var f []string // for i := range cols { // f = append(f, cols[i].Name) // } // return f // }