149 lines
2.6 KiB
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
|
|
}
|