forked from kubernetes/kubernetes
-
Notifications
You must be signed in to change notification settings - Fork 1
/
field.go
144 lines (129 loc) · 3.78 KB
/
field.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package search
import (
"fmt"
"reflect"
)
// Field is a name/value pair. A search index's document can be loaded and
// saved as a sequence of Fields.
type Field struct {
// Name is the field name.
Name string
// Value is the field value. The valid types are:
// - string,
// - search.Atom,
// - search.HTML,
// - time.Time (stored with millisecond precision),
// - float64,
// - GeoPoint.
Value interface{}
// Language is a two-letter ISO 693-1 code for the field's language,
// defaulting to "en" if nothing is specified. It may only be specified for
// fields of type string and search.HTML.
Language string
// Derived marks fields that were calculated as a result of a
// FieldExpression provided to Search. This field is ignored when saving a
// document.
Derived bool
}
// DocumentMetadata is a struct containing information describing a given document.
type DocumentMetadata struct {
// Rank is an integer specifying the order the document will be returned in
// search results. If zero, the rank will be set to the number of seconds since
// 2011-01-01 00:00:00 UTC when being Put into an index.
Rank int
}
// FieldLoadSaver can be converted from and to a slice of Fields
// with additional document metadata.
type FieldLoadSaver interface {
Load([]Field, *DocumentMetadata) error
Save() ([]Field, *DocumentMetadata, error)
}
// FieldList converts a []Field to implement FieldLoadSaver.
type FieldList []Field
// Load loads all of the provided fields into l.
// It does not first reset *l to an empty slice.
func (l *FieldList) Load(f []Field, _ *DocumentMetadata) error {
*l = append(*l, f...)
return nil
}
// Save returns all of l's fields as a slice of Fields.
func (l *FieldList) Save() ([]Field, *DocumentMetadata, error) {
return *l, nil, nil
}
var _ FieldLoadSaver = (*FieldList)(nil)
// structFLS adapts a struct to be a FieldLoadSaver.
type structFLS struct {
reflect.Value
}
func (s structFLS) Load(fields []Field, _ *DocumentMetadata) (err error) {
for _, field := range fields {
f := s.FieldByName(field.Name)
if !f.IsValid() {
err = &ErrFieldMismatch{
FieldName: field.Name,
Reason: "no such struct field",
}
continue
}
if !f.CanSet() {
err = &ErrFieldMismatch{
FieldName: field.Name,
Reason: "cannot set struct field",
}
continue
}
v := reflect.ValueOf(field.Value)
if ft, vt := f.Type(), v.Type(); ft != vt {
err = &ErrFieldMismatch{
FieldName: field.Name,
Reason: fmt.Sprintf("type mismatch: %v for %v data", ft, vt),
}
continue
}
f.Set(v)
}
return err
}
func (s structFLS) Save() ([]Field, *DocumentMetadata, error) {
fields := make([]Field, 0, s.NumField())
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
if !f.CanSet() {
continue
}
fields = append(fields, Field{
Name: s.Type().Field(i).Name,
Value: f.Interface(),
})
}
return fields, nil, nil
}
// newStructFLS returns a FieldLoadSaver for the struct pointer p.
func newStructFLS(p interface{}) (FieldLoadSaver, error) {
v := reflect.ValueOf(p)
if v.Kind() != reflect.Ptr || v.IsNil() || v.Elem().Kind() != reflect.Struct {
return nil, ErrInvalidDocumentType
}
return structFLS{v.Elem()}, nil
}
// LoadStruct loads the fields from f to dst. dst must be a struct pointer.
func LoadStruct(dst interface{}, f []Field) error {
x, err := newStructFLS(dst)
if err != nil {
return err
}
return x.Load(f, nil)
}
// SaveStruct returns the fields from src as a slice of Field.
// src must be a struct pointer.
func SaveStruct(src interface{}) ([]Field, error) {
x, err := newStructFLS(src)
if err != nil {
return nil, err
}
fs, _, err := x.Save()
return fs, err
}