github.com/thiagoyeds/go-cloud@v0.26.0/docstore/awsdynamodb/codec.go (about)

     1  // Copyright 2019 The Go Cloud Development Kit Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     https://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package awsdynamodb
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"reflect"
    21  	"strconv"
    22  	"time"
    23  
    24  	dyn "github.com/aws/aws-sdk-go/service/dynamodb"
    25  	"gocloud.dev/docstore/driver"
    26  )
    27  
    28  var nullValue = new(dyn.AttributeValue).SetNULL(true)
    29  
    30  type encoder struct {
    31  	av *dyn.AttributeValue
    32  }
    33  
    34  func (e *encoder) EncodeNil()        { e.av = nullValue }
    35  func (e *encoder) EncodeBool(x bool) { e.av = new(dyn.AttributeValue).SetBOOL(x) }
    36  func (e *encoder) EncodeInt(x int64) { e.av = new(dyn.AttributeValue).SetN(strconv.FormatInt(x, 10)) }
    37  func (e *encoder) EncodeUint(x uint64) {
    38  	e.av = new(dyn.AttributeValue).SetN(strconv.FormatUint(x, 10))
    39  }
    40  func (e *encoder) EncodeBytes(x []byte)  { e.av = new(dyn.AttributeValue).SetB(x) }
    41  func (e *encoder) EncodeFloat(x float64) { e.av = encodeFloat(x) }
    42  
    43  func (e *encoder) ListIndex(int) { panic("impossible") }
    44  func (e *encoder) MapKey(string) { panic("impossible") }
    45  
    46  func (e *encoder) EncodeString(x string) {
    47  	if len(x) == 0 {
    48  		e.av = nullValue
    49  	} else {
    50  		e.av = new(dyn.AttributeValue).SetS(x)
    51  	}
    52  }
    53  
    54  func (e *encoder) EncodeComplex(x complex128) {
    55  	e.av = new(dyn.AttributeValue).SetL([]*dyn.AttributeValue{encodeFloat(real(x)), encodeFloat(imag(x))})
    56  }
    57  
    58  func (e *encoder) EncodeList(n int) driver.Encoder {
    59  	s := make([]*dyn.AttributeValue, n)
    60  	e.av = new(dyn.AttributeValue).SetL(s)
    61  	return &listEncoder{s: s}
    62  }
    63  
    64  func (e *encoder) EncodeMap(n int) driver.Encoder {
    65  	m := make(map[string]*dyn.AttributeValue, n)
    66  	e.av = new(dyn.AttributeValue).SetM(m)
    67  	return &mapEncoder{m: m}
    68  }
    69  
    70  var typeOfGoTime = reflect.TypeOf(time.Time{})
    71  
    72  // EncodeSpecial encodes time.Time specially.
    73  func (e *encoder) EncodeSpecial(v reflect.Value) (bool, error) {
    74  	switch v.Type() {
    75  	case typeOfGoTime:
    76  		ts := v.Interface().(time.Time).Format(time.RFC3339Nano)
    77  		e.EncodeString(ts)
    78  	default:
    79  		return false, nil
    80  	}
    81  	return true, nil
    82  }
    83  
    84  type listEncoder struct {
    85  	s []*dyn.AttributeValue
    86  	encoder
    87  }
    88  
    89  func (e *listEncoder) ListIndex(i int) { e.s[i] = e.av }
    90  
    91  type mapEncoder struct {
    92  	m map[string]*dyn.AttributeValue
    93  	encoder
    94  }
    95  
    96  func (e *mapEncoder) MapKey(k string) { e.m[k] = e.av }
    97  
    98  func encodeDoc(doc driver.Document) (*dyn.AttributeValue, error) {
    99  	var e encoder
   100  	if err := doc.Encode(&e); err != nil {
   101  		return nil, err
   102  	}
   103  	return e.av, nil
   104  }
   105  
   106  // Encode the key fields of the given document into a map AttributeValue.
   107  // pkey and skey are the names of the partition key field and the sort key field.
   108  // pkey must always be non-empty, but skey may be empty if the collection has no sort key.
   109  func encodeDocKeyFields(doc driver.Document, pkey, skey string) (*dyn.AttributeValue, error) {
   110  	m := map[string]*dyn.AttributeValue{}
   111  
   112  	set := func(fieldName string) error {
   113  		fieldVal, err := doc.GetField(fieldName)
   114  		if err != nil {
   115  			return err
   116  		}
   117  		attrVal, err := encodeValue(fieldVal)
   118  		if err != nil {
   119  			return err
   120  		}
   121  		m[fieldName] = attrVal
   122  		return nil
   123  	}
   124  
   125  	if err := set(pkey); err != nil {
   126  		return nil, err
   127  	}
   128  	if skey != "" {
   129  		if err := set(skey); err != nil {
   130  			return nil, err
   131  		}
   132  	}
   133  	return new(dyn.AttributeValue).SetM(m), nil
   134  }
   135  
   136  func encodeValue(v interface{}) (*dyn.AttributeValue, error) {
   137  	var e encoder
   138  	if err := driver.Encode(reflect.ValueOf(v), &e); err != nil {
   139  		return nil, err
   140  	}
   141  	return e.av, nil
   142  }
   143  
   144  func encodeFloat(f float64) *dyn.AttributeValue {
   145  	return new(dyn.AttributeValue).SetN(strconv.FormatFloat(f, 'f', -1, 64))
   146  }
   147  
   148  ////////////////////////////////////////////////////////////////
   149  
   150  func decodeDoc(item *dyn.AttributeValue, doc driver.Document) error {
   151  	return doc.Decode(decoder{av: item})
   152  }
   153  
   154  type decoder struct {
   155  	av *dyn.AttributeValue
   156  }
   157  
   158  func (d decoder) String() string {
   159  	return d.av.String()
   160  }
   161  
   162  func (d decoder) AsBool() (bool, bool) {
   163  	if d.av.BOOL == nil {
   164  		return false, false
   165  	}
   166  	return *d.av.BOOL, true
   167  }
   168  
   169  func (d decoder) AsNull() bool {
   170  	return d.av.NULL != nil
   171  }
   172  
   173  func (d decoder) AsString() (string, bool) {
   174  	// Empty string is represented by NULL.
   175  	if d.av.NULL != nil {
   176  		return "", true
   177  	}
   178  	if d.av.S == nil {
   179  		return "", false
   180  	}
   181  	return *d.av.S, true
   182  }
   183  
   184  func (d decoder) AsInt() (int64, bool) {
   185  	if d.av.N == nil {
   186  		return 0, false
   187  	}
   188  	i, err := strconv.ParseInt(*d.av.N, 10, 64)
   189  	if err != nil {
   190  		return 0, false
   191  	}
   192  	return i, true
   193  }
   194  
   195  func (d decoder) AsUint() (uint64, bool) {
   196  	if d.av.N == nil {
   197  		return 0, false
   198  	}
   199  	u, err := strconv.ParseUint(*d.av.N, 10, 64)
   200  	if err != nil {
   201  		return 0, false
   202  	}
   203  	return u, true
   204  }
   205  
   206  func (d decoder) AsFloat() (float64, bool) {
   207  	if d.av.N == nil {
   208  		return 0, false
   209  	}
   210  	f, err := strconv.ParseFloat(*d.av.N, 64)
   211  	if err != nil {
   212  		return 0, false
   213  	}
   214  	return f, true
   215  
   216  }
   217  
   218  func (d decoder) AsComplex() (complex128, bool) {
   219  	if d.av.L == nil {
   220  		return 0, false
   221  	}
   222  	if len(d.av.L) != 2 {
   223  		return 0, false
   224  	}
   225  	r, ok := decoder{d.av.L[0]}.AsFloat()
   226  	if !ok {
   227  		return 0, false
   228  	}
   229  	i, ok := decoder{d.av.L[1]}.AsFloat()
   230  	if !ok {
   231  		return 0, false
   232  	}
   233  	return complex(r, i), true
   234  }
   235  
   236  func (d decoder) AsBytes() ([]byte, bool) {
   237  	if d.av.B == nil {
   238  		return nil, false
   239  	}
   240  	return d.av.B, true
   241  }
   242  
   243  func (d decoder) ListLen() (int, bool) {
   244  	if d.av.L == nil {
   245  		return 0, false
   246  	}
   247  	return len(d.av.L), true
   248  }
   249  
   250  func (d decoder) DecodeList(f func(i int, vd driver.Decoder) bool) {
   251  	for i, el := range d.av.L {
   252  		if !f(i, decoder{el}) {
   253  			break
   254  		}
   255  	}
   256  }
   257  
   258  func (d decoder) MapLen() (int, bool) {
   259  	if d.av.M == nil {
   260  		return 0, false
   261  	}
   262  	return len(d.av.M), true
   263  }
   264  
   265  func (d decoder) DecodeMap(f func(key string, vd driver.Decoder, exactMatch bool) bool) {
   266  	for k, av := range d.av.M {
   267  		if !f(k, decoder{av}, true) {
   268  			break
   269  		}
   270  	}
   271  }
   272  
   273  func (d decoder) AsInterface() (interface{}, error) {
   274  	return toGoValue(d.av)
   275  }
   276  
   277  func toGoValue(av *dyn.AttributeValue) (interface{}, error) {
   278  	switch {
   279  	case av.NULL != nil:
   280  		return nil, nil
   281  	case av.BOOL != nil:
   282  		return *av.BOOL, nil
   283  	case av.N != nil:
   284  		f, err := strconv.ParseFloat(*av.N, 64)
   285  		if err != nil {
   286  			return nil, err
   287  		}
   288  		i := int64(f)
   289  		if float64(i) == f {
   290  			return i, nil
   291  		}
   292  		u := uint64(f)
   293  		if float64(u) == f {
   294  			return u, nil
   295  		}
   296  		return f, nil
   297  
   298  	case av.B != nil:
   299  		return av.B, nil
   300  	case av.S != nil:
   301  		return *av.S, nil
   302  
   303  	case av.L != nil:
   304  		s := make([]interface{}, len(av.L))
   305  		for i, v := range av.L {
   306  			x, err := toGoValue(v)
   307  			if err != nil {
   308  				return nil, err
   309  			}
   310  			s[i] = x
   311  		}
   312  		return s, nil
   313  
   314  	case av.M != nil:
   315  		m := make(map[string]interface{}, len(av.M))
   316  		for k, v := range av.M {
   317  			x, err := toGoValue(v)
   318  			if err != nil {
   319  				return nil, err
   320  			}
   321  			m[k] = x
   322  		}
   323  		return m, nil
   324  
   325  	default:
   326  		return nil, fmt.Errorf("awsdynamodb: AttributeValue %s not supported", av)
   327  	}
   328  }
   329  
   330  func (d decoder) AsSpecial(v reflect.Value) (bool, interface{}, error) {
   331  	unsupportedTypes := `unsupported type, the docstore driver for DynamoDB does
   332  	not decode DynamoDB set types, such as string set, number set and binary set`
   333  	if d.av.SS != nil || d.av.NS != nil || d.av.BS != nil {
   334  		return true, nil, errors.New(unsupportedTypes)
   335  	}
   336  	switch v.Type() {
   337  	case typeOfGoTime:
   338  		if d.av.S == nil {
   339  			return false, nil, errors.New("expected string field for time.Time")
   340  		}
   341  		t, err := time.Parse(time.RFC3339Nano, *d.av.S)
   342  		return true, t, err
   343  	}
   344  	return false, nil, nil
   345  }