modelInfo and indexInfo

This commit is contained in:
Asdine El Hrychy
2016-03-07 23:31:34 +01:00
parent 2ea0226646
commit c03487dcfc
7 changed files with 268 additions and 48 deletions

View File

@@ -11,15 +11,6 @@ import (
"github.com/stretchr/testify/assert"
)
type ToEmbed struct {
ID string
}
type NestedID struct {
ToEmbed `storm:"inline"`
Name string
}
func TestAllByIndex(t *testing.T) {
dir, _ := ioutil.TempDir(os.TempDir(), "storm")
defer os.RemoveAll(dir)

8
errors.go Normal file
View File

@@ -0,0 +1,8 @@
package storm
import "errors"
// Errors
var (
ErrNoID = errors.New("missing struct tag id or ID field")
)

97
extract.go Normal file
View File

@@ -0,0 +1,97 @@
package storm
import (
"fmt"
"github.com/fatih/structs"
)
type indexInfo struct {
Type string
Field *structs.Field
}
// modelInfo is a structure gathering all the relevant informations about a model
type modelInfo struct {
Name string
ID *structs.Field
Indexes map[string]indexInfo
}
func (m *modelInfo) AddIndex(f *structs.Field, indexType string, override bool) {
fieldName := f.Name()
if _, ok := m.Indexes[fieldName]; !ok || override {
m.Indexes[fieldName] = indexInfo{
Type: indexType,
Field: f,
}
}
}
func (m *modelInfo) AllByType(indexType string) []indexInfo {
var idx []indexInfo
for k := range m.Indexes {
if m.Indexes[k].Type == indexType {
idx = append(idx, m.Indexes[k])
}
}
return idx
}
func extract(data interface{}, mi ...*modelInfo) (*modelInfo, error) {
s := structs.New(data)
fields := s.Fields()
var child bool
var m *modelInfo
if len(mi) > 0 {
m = mi[0]
child = true
} else {
m = &modelInfo{}
m.Indexes = make(map[string]indexInfo)
}
if m.Name == "" {
m.Name = s.Name()
}
for _, f := range fields {
if !f.IsExported() {
continue
}
tag := f.Tag("storm")
if tag != "" {
switch tag {
case "id":
m.ID = f
case "unique", "index":
m.AddIndex(f, tag, !child)
case "inline":
if structs.IsStruct(f.Value()) {
_, err := extract(f.Value(), m)
if err != nil {
return nil, err
}
}
default:
return nil, fmt.Errorf("unknown tag %s", tag)
}
}
// the field is named ID and no ID field has been detected before
if f.Name() == "ID" && m.ID == nil {
m.ID = f
}
}
// ID field or tag detected, add to the unique index
if m.ID != nil {
m.AddIndex(m.ID, "unique", !child)
}
return m, nil
}

58
extract_test.go Normal file
View File

@@ -0,0 +1,58 @@
package storm
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestExtractNoTags(t *testing.T) {
s := ClassicNoTags{}
infos, err := extract(&s)
assert.NoError(t, err)
assert.NotNil(t, infos)
assert.Nil(t, infos.ID)
assert.Equal(t, "ClassicNoTags", infos.Name)
assert.Len(t, infos.AllByType("index"), 0)
}
func TestExtractBadTags(t *testing.T) {
s := ClassicBadTags{}
infos, err := extract(&s)
assert.Error(t, err)
assert.EqualError(t, err, "unknown tag mrots")
assert.Nil(t, infos)
}
func TestExtractUniqueTags(t *testing.T) {
s := ClassicUnique{}
infos, err := extract(&s)
assert.NoError(t, err)
assert.NotNil(t, infos)
assert.Nil(t, infos.ID)
assert.Equal(t, "ClassicUnique", infos.Name)
assert.Len(t, infos.AllByType("index"), 0)
assert.Len(t, infos.AllByType("unique"), 4)
}
func TestExtractIndexTags(t *testing.T) {
s := ClassicIndex{}
infos, err := extract(&s)
assert.NoError(t, err)
assert.NotNil(t, infos)
assert.Nil(t, infos.ID)
assert.Equal(t, "ClassicIndex", infos.Name)
assert.Len(t, infos.AllByType("index"), 5)
assert.Len(t, infos.AllByType("unique"), 0)
}
func TestExtractInlineWithIndex(t *testing.T) {
s := ClassicInline{ToEmbed: &ToEmbed{ID: "50"}}
infos, err := extract(&s)
assert.NoError(t, err)
assert.NotNil(t, infos)
assert.NotNil(t, infos.ID)
assert.Equal(t, "ClassicInline", infos.Name)
assert.Len(t, infos.AllByType("index"), 3)
assert.Len(t, infos.AllByType("unique"), 3)
}

View File

@@ -6,20 +6,10 @@ import (
"os"
"path/filepath"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
type User struct {
ID int `storm:"id"`
Name string `storm:"index"`
age int
DateOfBirth time.Time `storm:"index"`
Group string
Slug string `storm:"unique"`
}
func TestFind(t *testing.T) {
dir, _ := ioutil.TempDir(os.TempDir(), "storm")
defer os.RemoveAll(dir)

View File

@@ -6,32 +6,11 @@ import (
"os"
"path/filepath"
"testing"
"time"
"github.com/boltdb/bolt"
"github.com/stretchr/testify/assert"
)
type SimpleUser struct {
ID int `storm:"id"`
Name string
age int
}
type UserWithNoID struct {
Name string
}
type UserWithIDField struct {
ID int
Name string
}
type UserWithEmbeddedIDField struct {
UserWithIDField `storm:"inline"`
Age int
}
func TestSave(t *testing.T) {
dir, _ := ioutil.TempDir(os.TempDir(), "storm")
defer os.RemoveAll(dir)
@@ -121,14 +100,6 @@ func TestSaveUnique(t *testing.T) {
})
}
type IndexedNameUser struct {
ID int `storm:"id"`
Name string `storm:"index"`
age int
DateOfBirth time.Time `storm:"index"`
Group string
}
func TestSaveIndex(t *testing.T) {
dir, _ := ioutil.TempDir(os.TempDir(), "storm")
defer os.RemoveAll(dir)

105
structs_test.go Normal file
View File

@@ -0,0 +1,105 @@
package storm
import (
"io"
"time"
)
type ClassicNoTags struct {
PublicField int
privateField string
Date time.Time
InlineStruct struct {
a float32
B float64
}
Interf io.Writer
}
type ClassicBadTags struct {
PublicField int `storm:"mrots"`
privateField string
Date time.Time
InlineStruct struct {
a float32
B float64
}
Interf io.Writer
}
type ClassicUnique struct {
PublicField int `storm:"unique"`
privateField string `storm:"unique"`
privateField2 string `storm:"id"`
Date time.Time `storm:"unique"`
InlineStruct struct {
a float32
B float64
} `storm:"unique"`
Interf io.Writer `storm:"unique"`
}
type ClassicIndex struct {
PublicField int `storm:"index"`
privateField string `storm:"index"`
Date time.Time `storm:"index"`
InlineStruct struct {
a float32
B float64
} `storm:"index"`
InlineStructPtr *UserWithNoID `storm:"index"`
Interf io.Writer `storm:"index"`
}
type ClassicInline struct {
PublicField int `storm:"unique"`
ClassicIndex `storm:"inline"`
*ToEmbed `storm:"inline"`
Date time.Time `storm:"unique"`
}
type User struct {
ID int `storm:"id"`
Name string `storm:"index"`
age int
DateOfBirth time.Time `storm:"index"`
Group string
Slug string `storm:"unique"`
}
type ToEmbed struct {
ID string
}
type NestedID struct {
ToEmbed `storm:"inline"`
Name string
}
type SimpleUser struct {
ID int `storm:"id"`
Name string
age int
}
type UserWithNoID struct {
Name string
}
type UserWithIDField struct {
ID int
Name string
}
type UserWithEmbeddedIDField struct {
UserWithIDField `storm:"inline"`
Age int
}
type IndexedNameUser struct {
ID int `storm:"id"`
Name string `storm:"index"`
age int
DateOfBirth time.Time `storm:"index"`
Group string
}