mirror of
https://github.com/asdine/storm.git
synced 2025-11-03 00:54:00 +08:00
modelInfo and indexInfo
This commit is contained in:
@@ -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
8
errors.go
Normal 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
97
extract.go
Normal 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
58
extract_test.go
Normal 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)
|
||||
}
|
||||
10
find_test.go
10
find_test.go
@@ -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)
|
||||
|
||||
29
save_test.go
29
save_test.go
@@ -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
105
structs_test.go
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user