func (q *Query) After(uid string) *Query {
	q.after = uid
	return q
}
After uses default UID ordering to skip directly past a node specified by UID
package dgman
import (
	"context"
	stdjson "encoding/json"
	"reflect"
	"fmt"
	"strconv"
	"strings"
	"github.com/dgraph-io/dgo/v210/protos/api"
	"github.com/pkg/errors"
	"github.com/dgraph-io/dgo/v210"
)
var (
	ErrNodeNotFound = errors.New("node not found")
)
type ParamFormatter interface {
	FormatParams() []byte
}
type QueryBlock struct {
	ctx         context.Context
	tx          *dgo.Txn
	paramString string
	vars        map[string]string
	blocks      []*Query
}
func (q *QueryBlock) Vars(funcDef string, vars map[string]string) *QueryBlock {
	q.paramString = funcDef
	q.vars = vars
	return q
}
func (q *QueryBlock) Add(query ...*Query) *QueryBlock {
	q.blocks = append(q.blocks, query...)
	return q
}
func (q *QueryBlock) Blocks(query ...*Query) *QueryBlock {
	q.blocks = query
	return q
}
func (q *QueryBlock) scan(result []byte, dst ...interface{}) error {
	if len(dst) == 0 {
		err := q.scanModel(result)
		if err != nil {
			return errors.Wrap(err, "scanModel failed")
		}
		return nil
	}
	if err := json.Unmarshal(result, dst[0]); err != nil {
		return errors.Wrap(err, "unmarshal query result failed")
	}
	return nil
}
func (q *QueryBlock) scanModel(result []byte) error {
	var queryMap map[string]stdjson.RawMessage
	if err := json.Unmarshal(result, &queryMap); err != nil {
		return errors.Wrap(err, "queryMap unmarshal failed")
	}
	for _, block := range q.blocks {
		blockResult := queryMap[block.name]
		if len(blockResult) == 0 {
			continue
		}
		if block.model == nil {
			continue
		}
		modelType := reflect.TypeOf(block.model)
		if modelType.Kind() != reflect.Ptr {
			continue
		}
		modelType = modelType.Elem()
		switch modelType.Kind() {
		case reflect.Struct:
			modelSliceRef := reflect.MakeSlice(reflect.SliceOf(reflect.PtrTo(modelType)), 1, 1)
			modelSlice := reflect.New(modelSliceRef.Type())
			modelSlice.Elem().Set(modelSliceRef)
			if err := json.Unmarshal(blockResult, modelSlice.Interface()); err != nil {
				return errors.Wrapf(err, "queryMap %s unmarshal failed", block.name)
			}
			if modelSlice.Elem().Len() > 0 {
				reflect.ValueOf(block.model).Elem().Set(modelSlice.Elem().Index(0).Elem())
			}
		case reflect.Slice:
			if err := json.Unmarshal(blockResult, block.model); err != nil {
				return errors.Wrapf(err, "queryMap %s unmarshal failed", block.name)
			}
		}
	}
	return nil
}
func (q *QueryBlock) Scan(dst ...interface{}) error {
	result, err := q.executeQuery()
	if err != nil {
		return err
	}
	if err = q.scan(result, dst...); err != nil {
		return errors.Wrap(err, "scan failed")
	}
	return nil
}
func (q *QueryBlock) String() string {
	var queryBuf strings.Builder
	if q.vars != nil {
		queryBuf.WriteString("query ")
		queryBuf.WriteString(q.paramString)
	}
	queryBuf.WriteString("{\n")
	for _, block := range q.blocks {
		block.generateQuery(&queryBuf)
	}
	queryBuf.WriteString("}")
	return queryBuf.String()
}
func (q *QueryBlock) executeQuery() (result []byte, err error) {
	queryString := q.String()
	var resp *api.Response
	if q.vars != nil {
		resp, err = q.tx.QueryWithVars(q.ctx, queryString, q.vars)
	} else {
		resp, err = q.tx.Query(q.ctx, queryString)
	}
	if err != nil {
		return nil, err
	}
	return resp.Json, nil
}
type order struct {
	descending bool
	clause     string
}
type Query struct {
	ctx         context.Context
	tx          *dgo.Txn
	model       interface{}
	name        string
	as          string
	isVar       bool
	paramString string
	vars        map[string]string
	rootFunc    string
	first       int
	offset      int
	after       string
	order       []order
	groupBy     string
	cascade     []string
	uid         string
	filter      string
	query       string
}
type PagedResults struct {
	Result   stdjson.RawMessage
	PageInfo []*PageInfo
}
type PageInfo struct {
	Count int
}
func (q *Query) Model(model interface{}) *Query {
	q.model = model
	return q
}
func (q *Query) Name(queryName string) *Query {
	q.name = queryName
	return q
}
func (q *Query) As(varName string) *Query {
	q.as = varName
	return q
}
func (q *Query) Var() *Query {
	q.isVar = true
	return q
}
func (q *Query) Query(query string, params ...interface{}) *Query {
	q.query = parseQueryWithParams(query, params)
	return q
}
func (q *Query) Filter(filter string, params ...interface{}) *Query {
	q.filter = parseQueryWithParams(filter, params)
	return q
}
func (q *Query) UID(uid string) *Query {
	q.uid = uid
	return q
}
func expandPredicate(buffer *strings.Builder, depth int) {
	for i := 0; i < depth; i++ {
		tabs := strings.Repeat("\t", i+1)
		buffer.WriteString(" {\n\t\t")
		buffer.WriteString(tabs)
		buffer.WriteString("uid\n\t\t")
		buffer.WriteString(tabs)
		buffer.WriteString("dgraph.type\n\t\t")
		buffer.WriteString(tabs)
		buffer.WriteString("expand(_all_)")
	}
	for i := depth - 1; i >= 0; i-- {
		tabs := strings.Repeat("\t", i)
		buffer.WriteString("\n\t\t")
		buffer.WriteString(tabs)
		buffer.WriteString("}")
	}
}
func expandAll(depth int) string {
	var buffer strings.Builder
	buffer.WriteString("{\n\t\tuid\n\t\tdgraph.type\n\t\texpand(_all_)")
	expandPredicate(&buffer, depth)
	buffer.WriteString("\n\t}")
	return buffer.String()
}
func (q *Query) All(depthParam ...int) *Query {
	depth := 0
	if len(depthParam) > 0 {
		depth = depthParam[0]
	}
	q.query = expandAll(depth)
	return q
}
func (q *Query) Vars(funcDef string, vars map[string]string) *Query {
	q.paramString = funcDef
	q.vars = vars
	return q
}
func (q *Query) RootFunc(rootFunc string) *Query {
	q.rootFunc = rootFunc
	return q
}
func (q *Query) First(n int) *Query {
	q.first = n
	return q
}
func (q *Query) Offset(n int) *Query {
	q.offset = n
	return q
}