diamond-orm/indexes.go

149 lines
2.6 KiB
Go

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
}