func (p *SampleSearchTimePropertyInfo) GreaterThanOrEqual(value time.Time) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.GtEq, Value: value.UTC()})
	return p.b
}
query spec for time.Time.
https://cloud.google.com/appengine/docs/go/search/query_strings#Go_Queries_on_date_fields
It using date, not datetime.
GreaterThanOrEqual add query operand.
package f
import (
	"bytes"
	"context"
	"encoding/json"
	"errors"
	"github.com/favclip/smg/smgutils"
	"google.golang.org/appengine/log"
	"google.golang.org/appengine/search"
	"time"
)
type SampleSearch struct {
	src *Sample
	A string
}
func (src *Sample) Searchfy() (*SampleSearch, error) {
	if src == nil {
		return nil, nil
	}
	dest := &SampleSearch{}
	dest.src = src
	var err error
	var b []byte
	b, err = json.Marshal(src.A)
	if err != nil {
		return nil, err
	}
	if str := string(b); str != "" && str != "\"\"" {
		dest.A = str
	}
	return dest, nil
}
func NewSampleSearch() *SampleSearchBuilder {
	op := &smgutils.Op{}
	b := &SampleSearchBuilder{
		rootOp:    op,
		currentOp: op,
		opts: &search.SearchOptions{
			Sort: &search.SortOptions{},
		},
	}
	b.A = &SampleSearchStringPropertyInfo{"A", b}
	return b
}
func NewSampleSearchWithIndexName(name string) *SampleSearchBuilder {
	b := NewSampleSearch()
	b.indexName = name
	return b
}
var _ smgutils.SearchBuilder = &SampleSearchBuilder{}
type SampleSearchBuilder struct {
	rootOp    *smgutils.Op
	currentOp *smgutils.Op  
	opts      *search.SearchOptions
	query     string
	indexName string
	index     *search.Index
	A         *SampleSearchStringPropertyInfo
}
func (b *SampleSearchBuilder) IndexName() string {
	if b.indexName != "" {
		return b.indexName
	}
	return "Sample"
}
func (b *SampleSearchBuilder) QueryString() (string, error) {
	buffer := &bytes.Buffer{}
	err := b.rootOp.Query(buffer)
	if err != nil {
		return "", err
	}
	return buffer.String(), nil
}
func (b *SampleSearchBuilder) SearchOptions() *search.SearchOptions {
	return b.opts
}
func (b *SampleSearchBuilder) And() *SampleSearchBuilder {
	b.currentOp.Children = append(b.currentOp.Children, &smgutils.Op{Type: smgutils.And})
	return b
}
func (b *SampleSearchBuilder) Or() *SampleSearchBuilder {
	b.currentOp.Children = append(b.currentOp.Children, &smgutils.Op{Type: smgutils.Or})
	return b
}
func (b *SampleSearchBuilder) Group(p func()) *SampleSearchBuilder {
	b.StartGroup()
	p()
	b.EndGroup()
	return b
}
func (b *SampleSearchBuilder) StartGroup() *SampleSearchBuilder {
	op := &smgutils.Op{Type: smgutils.Group, Parent: b.currentOp}
	b.currentOp.Children = append(b.currentOp.Children, op)
	b.currentOp = op
	return b
}
func (b *SampleSearchBuilder) EndGroup() *SampleSearchBuilder {
	b.currentOp = b.currentOp.Parent
	return b
}
func (b *SampleSearchBuilder) Put(c context.Context, src *Sample) (string, error) {
	doc, err := src.Searchfy()
	if err != nil {
		return "", err
	}
	return b.PutDocument(c, doc)
}
func (b *SampleSearchBuilder) PutMulti(c context.Context, srcs []*Sample) ([]string, error) {
	docs := make([]*SampleSearch, 0, len(srcs))
	for _, src := range srcs {
		doc, err := src.Searchfy()
		if err != nil {
			return nil, err
		}
		docs = append(docs, doc)
	}
	return b.PutDocumentMulti(c, docs)
}
func (b *SampleSearchBuilder) PutDocument(c context.Context, src *SampleSearch) (string, error) {
	docIDs, err := b.PutDocumentMulti(c, []*SampleSearch{src})
	if err != nil {
		return "", err
	}
	return docIDs[0], nil
}
func (b *SampleSearchBuilder) PutDocumentMulti(c context.Context, srcs []*SampleSearch) ([]string, error) {
	index, err := search.Open(b.IndexName())
	if err != nil {
		return nil, err
	}
	docIDs := make([]string, 0, len(srcs))
	putSrcs := make([]interface{}, 0, len(srcs))
	for _, src := range srcs {
		docID := ""
		if v, ok := interface{}(src).(smgutils.DocIDer); ok {
			docID, err = v.DocID(c)
			if err != nil {
				return nil, err
			}
		}
		docIDs = append(docIDs, docID)
		putSrcs = append(putSrcs, src)
		log.Debugf(c, "id: %#v, payload: %#v", docID, src)
	}
	docIDs, err = index.PutMulti(c, docIDs, putSrcs)
	if err != nil {
		return nil, err
	}
	return docIDs, nil
}
func (b *SampleSearchBuilder) Delete(c context.Context, src *Sample) error {
	doc, err := src.Searchfy()
	if err != nil {
		return err
	}
	return b.DeleteDocument(c, doc)
}
func (b *SampleSearchBuilder) DeleteMulti(c context.Context, srcs []*Sample) error {
	docs := make([]*SampleSearch, 0, len(srcs))
	for _, src := range srcs {
		doc, err := src.Searchfy()
		if err != nil {
			return err
		}
		docs = append(docs, doc)
	}
	return b.DeleteDocumentMulti(c, docs)
}
func (b *SampleSearchBuilder) DeleteDocument(c context.Context, src *SampleSearch) error {
	return b.DeleteDocumentMulti(c, []*SampleSearch{src})
}
func (b *SampleSearchBuilder) DeleteDocumentMulti(c context.Context, srcs []*SampleSearch) error {
	docIDs := make([]string, 0, len(srcs))
	for _, src := range srcs {
		if v, ok := interface{}(src).(smgutils.DocIDer); ok {
			docID, err := v.DocID(c)
			if err != nil {
				return err
			}
			docIDs = append(docIDs, docID)
			continue
		}
		return errors.New("src is not implemented DocIDer interface")
	}
	return b.DeleteMultiByDocIDs(c, docIDs)
}
func (b *SampleSearchBuilder) DeleteByDocID(c context.Context, docID string) error {
	return b.DeleteMultiByDocIDs(c, []string{docID})
}
func (b *SampleSearchBuilder) DeleteMultiByDocIDs(c context.Context, docIDs []string) error {
	index, err := search.Open(b.IndexName())
	if err != nil {
		return err
	}
	return index.DeleteMulti(c, docIDs)
}
func (b *SampleSearchBuilder) Opts() *SampleSearchOptions {
	return &SampleSearchOptions{b: b}
}
func (b *SampleSearchBuilder) Search(c context.Context) (*SampleSearchIterator, error) {
	index, err := search.Open(b.IndexName())
	if err != nil {
		return nil, err
	}
	b.index = index
	query, err := b.QueryString()
	if err != nil {
		return nil, err
	}
	b.query = query
	log.Debugf(c, "query: '%s', opts: %#v", b.query, b.opts)
	iter := b.index.Search(c, b.query, b.opts)
	return &SampleSearchIterator{b, iter}, nil
}
type SampleSearchOptions struct {
	b *SampleSearchBuilder
}
func (b *SampleSearchOptions) Limit(value int) *SampleSearchOptions {
	b.b.opts.Limit = value
	return b
}
func (b *SampleSearchOptions) IDsOnly() *SampleSearchOptions {
	b.b.opts.IDsOnly = true
	return b
}
func (b *SampleSearchOptions) Cursor(cursor search.Cursor) *SampleSearchOptions {
	b.b.opts.Cursor = cursor
	return b
}
func (b *SampleSearchOptions) Offset(value int) *SampleSearchOptions {
	b.b.opts.Offset = value
	return b
}
type SampleSearchIterator struct {
	b    *SampleSearchBuilder
	iter *search.Iterator
}
func (b *SampleSearchIterator) Next(c context.Context) (string, *SampleSearch, error) {
	var s *SampleSearch
	if b.b.opts == nil || b.b.opts.IDsOnly != true {
		s = &SampleSearch{}
	}
	docID, err := b.iter.Next(s)
	if err != nil {
		return "", nil, err
	}
	return docID, s, err
}
func (b *SampleSearchIterator) Cursor() search.Cursor {
	return b.iter.Cursor()
}
type SampleSearchStringPropertyInfo struct {
	Name string
	b    *SampleSearchBuilder
}
func (p *SampleSearchStringPropertyInfo) Match(value string) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.Match, Value: value})
	return p.b
}
func (p *SampleSearchStringPropertyInfo) Asc() *SampleSearchBuilder {
	if p.b.opts == nil {
		p.b.opts = &search.SearchOptions{}
	}
	if p.b.opts.Sort == nil {
		p.b.opts.Sort = &search.SortOptions{}
	}
	p.b.opts.Sort.Expressions = append(p.b.opts.Sort.Expressions, search.SortExpression{
		Expr:    p.Name,
		Reverse: true,
	})
	return p.b
}
func (p *SampleSearchStringPropertyInfo) Desc() *SampleSearchBuilder {
	if p.b.opts == nil {
		p.b.opts = &search.SearchOptions{}
	}
	if p.b.opts.Sort == nil {
		p.b.opts.Sort = &search.SortOptions{}
	}
	p.b.opts.Sort.Expressions = append(p.b.opts.Sort.Expressions, search.SortExpression{
		Expr:    p.Name,
		Reverse: false,
	})
	return p.b
}
type SampleSearchNgramStringPropertyInfo struct {
	SampleSearchStringPropertyInfo
}
func (p *SampleSearchNgramStringPropertyInfo) NgramMatch(value string) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.NgramMatch, Value: value})
	return p.b
}
type SampleSearchNumberPropertyInfo struct {
	Name string
	b    *SampleSearchBuilder
}
func (p *SampleSearchNumberPropertyInfo) IntGreaterThanOrEqual(value int) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.GtEq, Value: value})
	return p.b
}
func (p *SampleSearchNumberPropertyInfo) IntGreaterThan(value int) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.Gt, Value: value})
	return p.b
}
func (p *SampleSearchNumberPropertyInfo) IntLessThanOrEqual(value int) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.LtEq, Value: value})
	return p.b
}
func (p *SampleSearchNumberPropertyInfo) IntLessThan(value int) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.Lt, Value: value})
	return p.b
}
func (p *SampleSearchNumberPropertyInfo) IntEqual(value int) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.Eq, Value: value})
	return p.b
}
func (p *SampleSearchNumberPropertyInfo) Int64GreaterThanOrEqual(value int64) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.GtEq, Value: value})
	return p.b
}
func (p *SampleSearchNumberPropertyInfo) Int64GreaterThan(value int64) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.Gt, Value: value})
	return p.b
}
func (p *SampleSearchNumberPropertyInfo) Int64LessThanOrEqual(value int64) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.LtEq, Value: value})
	return p.b
}
func (p *SampleSearchNumberPropertyInfo) Int64LessThan(value int64) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.Lt, Value: value})
	return p.b
}
func (p *SampleSearchNumberPropertyInfo) Int64Equal(value int64) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.Eq, Value: value})
	return p.b
}
func (p *SampleSearchNumberPropertyInfo) Asc() *SampleSearchBuilder {
	if p.b.opts == nil {
		p.b.opts = &search.SearchOptions{}
	}
	if p.b.opts.Sort == nil {
		p.b.opts.Sort = &search.SortOptions{}
	}
	p.b.opts.Sort.Expressions = append(p.b.opts.Sort.Expressions, search.SortExpression{
		Expr:    p.Name,
		Reverse: true,
	})
	return p.b
}
func (p *SampleSearchNumberPropertyInfo) Desc() *SampleSearchBuilder {
	if p.b.opts == nil {
		p.b.opts = &search.SearchOptions{}
	}
	if p.b.opts.Sort == nil {
		p.b.opts.Sort = &search.SortOptions{}
	}
	p.b.opts.Sort.Expressions = append(p.b.opts.Sort.Expressions, search.SortExpression{
		Expr:    p.Name,
		Reverse: false,
	})
	return p.b
}
type SampleSearchBoolPropertyInfo struct {
	Name string
	b    *SampleSearchBuilder
}
func (p *SampleSearchNumberPropertyInfo) Equal(value bool) *SampleSearchBuilder {
	p.b.currentOp.Children = append(p.b.currentOp.Children, &smgutils.Op{FieldName: p.Name, Type: smgutils.Eq, Value: value})
	return p.b
}
type SampleSearchTimePropertyInfo struct {
	Name string
	b    *SampleSearchBuilder
}