Skip to content

Commit b42be62

Browse files
committed
Updated
1 parent 66fe75f commit b42be62

File tree

1 file changed

+201
-0
lines changed

1 file changed

+201
-0
lines changed

sys/sqlite3/marshall.go_old

Lines changed: 201 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
package sqlite
2+
3+
import (
4+
sql "database/sql/driver"
5+
"errors"
6+
"math"
7+
"reflect"
8+
"time"
9+
10+
// Modules
11+
multierror "github.com/hashicorp/go-multierror"
12+
13+
// Import namespaces
14+
. "github.com/djthorpe/go-errors"
15+
)
16+
17+
///////////////////////////////////////////////////////////////////////////////
18+
// GLOBALS
19+
20+
const (
21+
funcMarshalName = "MarshalSQ"
22+
funcUnmarshalName = "UnmarshalSQ"
23+
)
24+
25+
var (
26+
timeType = reflect.TypeOf(time.Time{})
27+
blobType = reflect.TypeOf([]byte{})
28+
intType = reflect.TypeOf(int64(0))
29+
)
30+
31+
///////////////////////////////////////////////////////////////////////////////
32+
// PUBLIC METHODS
33+
34+
// BoundValue returns a bound value from an arbitary value,
35+
// which needs to be a scalar (not a map or slice) or a
36+
// time.Time, []byte
37+
func BoundValue(v reflect.Value) (interface{}, error) {
38+
// Where value is not valid, return NULL
39+
if v.IsValid() == false {
40+
return nil, nil
41+
}
42+
// Try Ptr, Bool, Int, Unit, Float, String, time.Time and []byte
43+
if v_, err := boundScalarValue(v); errors.Is(err, ErrBadParameter) {
44+
// Bad parameter means we should try Marshal function
45+
return boundCustomValue(v, err)
46+
} else if err != nil {
47+
return nil, err
48+
} else {
49+
return v_, nil
50+
}
51+
}
52+
53+
// Unbound value returns a value of type t from an arbitary value
54+
// which needs to be uint, int, float, string, bool, []byte, or time.Time
55+
// if v is nil then zero value is assigned
56+
func UnboundValue(v interface{}, t reflect.Type) (reflect.Value, error) {
57+
if v == nil {
58+
return reflect.Zero(t), nil
59+
}
60+
// Do simple cases first
61+
rv := reflect.ValueOf(v)
62+
if rv.CanConvert(t) {
63+
return rv.Convert(t), nil
64+
}
65+
// More complex cases
66+
switch t.Kind() {
67+
case reflect.Bool:
68+
if rv.CanConvert(intType) {
69+
if rv.Convert(intType).Int() == 0 {
70+
return reflect.ValueOf(false), nil
71+
} else {
72+
return reflect.ValueOf(true), nil
73+
}
74+
}
75+
}
76+
// Check for UnmarshalSQ method on pointer type
77+
if proto, err := unboundCustomValue(rv, t); errors.Is(err, ErrBadParameter) {
78+
// No custom unmarshaller found
79+
return reflect.Zero(t), ErrBadParameter.Withf("Unable to convert %q to %q", rv.Kind(), t.Kind())
80+
} else if err != nil {
81+
return reflect.Zero(t), err
82+
} else {
83+
return proto, nil
84+
}
85+
}
86+
87+
// BoundValues decodes a set of values into a form which can be accepted by
88+
// Exec or Query, which supports int64, float64, string, bool, []byte, and time.Time
89+
// returns any errors
90+
func BoundValues(v []interface{}) ([]sql.Value, error) {
91+
var errs error
92+
result := make([]sql.Value, len(v))
93+
for i, v := range v {
94+
if v_, err := BoundValue(reflect.ValueOf(v)); err != nil {
95+
errs = multierror.Append(errs, err)
96+
} else {
97+
result[i] = v_
98+
}
99+
}
100+
return result, errs
101+
}
102+
103+
///////////////////////////////////////////////////////////////////////////////
104+
// PRIVATE METHODS
105+
106+
// boundScalarValue translates from a scalar value to a bound value
107+
// and returns ErrBadParameter if not a supported type
108+
func boundScalarValue(v reflect.Value) (interface{}, error) {
109+
switch v.Kind() {
110+
case reflect.Ptr:
111+
if v.IsNil() {
112+
return nil, nil
113+
} else {
114+
return BoundValue(v.Elem())
115+
}
116+
case reflect.Bool:
117+
return v.Bool(), nil
118+
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
119+
return v.Int(), nil
120+
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
121+
if v.Uint() > math.MaxInt64 {
122+
return nil, ErrBadParameter.With("uint value overflow")
123+
} else {
124+
return int64(v.Uint()), nil
125+
}
126+
case reflect.Float32, reflect.Float64:
127+
return v.Float(), nil
128+
case reflect.String:
129+
return v.String(), nil
130+
case reflect.Slice:
131+
if v.IsNil() {
132+
return nil, nil
133+
}
134+
if v.Type() == blobType {
135+
return v.Interface().([]byte), nil
136+
}
137+
case reflect.Struct:
138+
if v.Type() == timeType {
139+
value := v.Interface().(time.Time)
140+
if value.IsZero() {
141+
return nil, nil
142+
} else {
143+
return v.Interface().(time.Time), nil
144+
}
145+
}
146+
}
147+
// Return unsupported type
148+
return nil, ErrBadParameter.With("Unsupported bind type: ", v.Type())
149+
}
150+
151+
// boundCustomValue attempts to call func (t Type) MarshalSQ() (interface{}, error)
152+
// on type to translate value into a bound scalar value
153+
func boundCustomValue(v reflect.Value, err error) (interface{}, error) {
154+
// Check for MarshalSQ function
155+
fn := v.MethodByName(funcMarshalName)
156+
if !fn.IsValid() {
157+
// Return existing error
158+
return nil, err
159+
}
160+
// Call and expect two result arguments
161+
if result := fn.Call(nil); len(result) == 2 {
162+
if err, ok := result[1].Interface().(error); ok && err != nil {
163+
return nil, err
164+
} else {
165+
return boundScalarValue(reflect.ValueOf(result[0].Interface()))
166+
}
167+
}
168+
// Return internal app error
169+
return nil, ErrInternalAppError.With("Invalid number of arguments")
170+
}
171+
172+
// unboundedCustomValue attempts to call func (t Type) UnmarshalSQ() (interface{}, error)
173+
func unboundCustomValue(v reflect.Value, t reflect.Type) (reflect.Value, error) {
174+
var elem bool
175+
if t.Kind() != reflect.Ptr {
176+
t = reflect.New(t).Type()
177+
elem = true
178+
}
179+
// Lookup custom function, return ErrBadParameter if not found
180+
fn, exists := t.MethodByName(funcUnmarshalName)
181+
if !exists {
182+
return reflect.Zero(t), ErrBadParameter
183+
}
184+
// Create prototype object and fill it
185+
proto := reflect.New(t.Elem())
186+
result := fn.Func.Call([]reflect.Value{proto, v})
187+
if len(result) != 1 {
188+
return reflect.Zero(t), ErrInternalAppError.With("Invalid number of return arguments")
189+
}
190+
// Check for errors
191+
err, ok := result[0].Interface().(error)
192+
if ok && err != nil {
193+
return reflect.Zero(t), err
194+
}
195+
// Convert back into an element if needed
196+
if elem {
197+
proto = proto.Elem()
198+
}
199+
// Return object
200+
return proto, nil
201+
}

0 commit comments

Comments
 (0)