package orm import ( "go/scanner" "go/token" "strings" "unicode" "go.mongodb.org/mongo-driver/mongo" ) var optionKeywords = [...]string{"unique", "sparse", "background", "dropdups"} // prolly won't need to use indexes, but just in case... type InternalIndex struct { Fields []string Options []string lastFieldIdx int sticky bool } func (in *InternalIndex) appendOption(o string) { o = strings.ToLower(o) o = strings.Trim(o, " ") for i := range optionKeywords { if optionKeywords[i] == o { in.Options = append(in.Options, o) } } } func (in *InternalIndex) appendField(f string) { in.Fields = append(in.Fields, f) } func (in *InternalIndex) appendDotField(f string) { in.Fields[in.lastFieldIdx] = in.Fields[in.lastFieldIdx] + "." + f } func (in *InternalIndex) updateLastField() { if len(in.Fields) > 0 { in.lastFieldIdx = len(in.Fields) - 1 return } in.lastFieldIdx = 0 } func (in *InternalIndex) setSticky(s bool) { in.sticky = s } func (in *InternalIndex) getSticky() bool { return in.sticky } func scanIndex(src string) []InternalIndex { var s scanner.Scanner var parsed []InternalIndex src = func(ss string) string { return strings.Map(func(r rune) rune { if unicode.IsSpace(r) { return -1 } return r }, ss) }(src) fset := token.NewFileSet() file := fset.AddFile("", fset.Base(), len(src)) s.Init(file, []byte(src), nil, scanner.ScanComments) lb := false p := &InternalIndex{} for { _, tok, lit := s.Scan() switch tok { case token.LBRACE: if lb { goto panik } lb = true case token.RBRACE: if !lb || len(p.Fields) == 0 { goto panik } lb = false case token.IDENT: if lb { if p.getSticky() { p.appendDotField(lit) p.setSticky(false) break } p.appendField(lit) break } p.appendOption(lit) case token.PERIOD: if p.getSticky() { goto panik } p.setSticky(true) p.updateLastField() case token.COMMA: case token.COLON: if lb { goto panik } case token.SEMICOLON: if lb { goto panik } parsed = append(parsed, *p) p = &InternalIndex{} case token.EOF: if lb { goto panik } return parsed default: goto panik } } panik: panic("parsing error in index expression!") } func BuildIndex(i InternalIndex) *mongo.IndexModel { idx := &mongo.IndexModel{ Keys: i.Fields, } for _, o := range i.Options { switch o { case "unique": idx.Options.SetUnique(true) case "background": idx.Options.SetBackground(true) case "sparse": idx.Options.SetSparse(true) } } return idx }