github.com/datastax/go-cassandra-native-protocol@v0.0.0-20220706104457-5e8aad05cf90/datacodec/codec.go (about)

     1  // Copyright 2020 DataStax
     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  //      http://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 datacodec
    16  
    17  import (
    18  	"reflect"
    19  
    20  	"github.com/datastax/go-cassandra-native-protocol/datatype"
    21  	"github.com/datastax/go-cassandra-native-protocol/primitive"
    22  )
    23  
    24  type Encoder interface {
    25  
    26  	// Encode encodes the given source into dest. The parameter source must be a value of a supported Go type for the
    27  	// CQL type being encoded, or a pointer thereto; a nil value is encoded as a CQL NULL.
    28  	Encode(source interface{}, version primitive.ProtocolVersion) (dest []byte, err error)
    29  }
    30  
    31  type Decoder interface {
    32  
    33  	// Decode decodes the given source into dest. The parameter dest must be a pointer to a supported Go type for
    34  	// the CQL type being decoded; it cannot be nil. If return parameter wasNull is true, then the decoded value was a
    35  	// NULL, in which case the actual value stored in dest will be set to its zero value.
    36  	Decode(source []byte, dest interface{}, version primitive.ProtocolVersion) (wasNull bool, err error)
    37  }
    38  
    39  // Codec is a codec for a specific CQL type.
    40  type Codec interface {
    41  	Encoder
    42  	Decoder
    43  
    44  	DataType() datatype.DataType
    45  }
    46  
    47  // NewCodec creates a new codec for the given data type. For simple CQL types, this function actually returns one of
    48  // the existing singletons. For complex CQL types, it delegates to one of the constructor functions available:
    49  // NewList, NewSet, NewMap, NewTuple, NewUserDefined and NewCustom.
    50  func NewCodec(dt datatype.DataType) (Codec, error) {
    51  	switch dt.Code() {
    52  	case primitive.DataTypeCodeAscii:
    53  		return Ascii, nil
    54  	case primitive.DataTypeCodeBigint:
    55  		return Bigint, nil
    56  	case primitive.DataTypeCodeBlob:
    57  		return Blob, nil
    58  	case primitive.DataTypeCodeBoolean:
    59  		return Boolean, nil
    60  	case primitive.DataTypeCodeCounter:
    61  		return Counter, nil
    62  	case primitive.DataTypeCodeDate:
    63  		return Date, nil
    64  	case primitive.DataTypeCodeDecimal:
    65  		return Decimal, nil
    66  	case primitive.DataTypeCodeDouble:
    67  		return Double, nil
    68  	case primitive.DataTypeCodeDuration:
    69  		return Duration, nil
    70  	case primitive.DataTypeCodeFloat:
    71  		return Float, nil
    72  	case primitive.DataTypeCodeInet:
    73  		return Inet, nil
    74  	case primitive.DataTypeCodeInt:
    75  		return Int, nil
    76  	case primitive.DataTypeCodeSmallint:
    77  		return Smallint, nil
    78  	case primitive.DataTypeCodeTime:
    79  		return Time, nil
    80  	case primitive.DataTypeCodeTimestamp:
    81  		return Timestamp, nil
    82  	case primitive.DataTypeCodeTimeuuid:
    83  		return Timeuuid, nil
    84  	case primitive.DataTypeCodeTinyint:
    85  		return Tinyint, nil
    86  	case primitive.DataTypeCodeUuid:
    87  		return Uuid, nil
    88  	case primitive.DataTypeCodeVarchar:
    89  		return Varchar, nil
    90  	case primitive.DataTypeCodeVarint:
    91  		return Varint, nil
    92  	case primitive.DataTypeCodeCustom:
    93  		return NewCustom(dt.(*datatype.Custom)), nil
    94  	case primitive.DataTypeCodeList:
    95  		return NewList(dt.(*datatype.List))
    96  	case primitive.DataTypeCodeSet:
    97  		return NewSet(dt.(*datatype.Set))
    98  	case primitive.DataTypeCodeMap:
    99  		return NewMap(dt.(*datatype.Map))
   100  	case primitive.DataTypeCodeTuple:
   101  		return NewTuple(dt.(*datatype.Tuple))
   102  	case primitive.DataTypeCodeUdt:
   103  		return NewUserDefined(dt.(*datatype.UserDefined))
   104  	}
   105  	return nil, errCannotCreateCodec(dt)
   106  }
   107  
   108  // PreferredGoType returns the best matching Go type for the given data type; e.g. for the CQL type varchar it returns
   109  // string, and for the CQL type timestamp it returns time.Time. Note that this function avoids pointer types unless
   110  // they are absolutely required, e.g. for the CQL type varint this function returns *big.Int since the usage of the
   111  // value type big.Int is not recommended.
   112  func PreferredGoType(dt datatype.DataType) (reflect.Type, error) {
   113  	switch dt.Code() {
   114  	case primitive.DataTypeCodeAscii:
   115  		return typeOfString, nil
   116  	case primitive.DataTypeCodeBigint:
   117  		return typeOfInt64, nil
   118  	case primitive.DataTypeCodeBlob:
   119  		return typeOfByteSlice, nil
   120  	case primitive.DataTypeCodeBoolean:
   121  		return typeOfBoolean, nil
   122  	case primitive.DataTypeCodeCounter:
   123  		return typeOfInt64, nil
   124  	case primitive.DataTypeCodeCustom:
   125  		return typeOfByteSlice, nil
   126  	case primitive.DataTypeCodeDate:
   127  		return typeOfTime, nil
   128  	case primitive.DataTypeCodeDecimal:
   129  		return typeOfCqlDecimal, nil
   130  	case primitive.DataTypeCodeDouble:
   131  		return typeOfFloat64, nil
   132  	case primitive.DataTypeCodeDuration:
   133  		return typeOfCqlDuration, nil
   134  	case primitive.DataTypeCodeFloat:
   135  		return typeOfFloat32, nil
   136  	case primitive.DataTypeCodeInet:
   137  		return typeOfNetIP, nil
   138  	case primitive.DataTypeCodeInt:
   139  		return typeOfInt32, nil
   140  	case primitive.DataTypeCodeSmallint:
   141  		return typeOfInt16, nil
   142  	case primitive.DataTypeCodeTime:
   143  		return typeOfDuration, nil
   144  	case primitive.DataTypeCodeTimestamp:
   145  		return typeOfTime, nil
   146  	case primitive.DataTypeCodeTimeuuid:
   147  		return typeOfUUID, nil
   148  	case primitive.DataTypeCodeTinyint:
   149  		return typeOfInt8, nil
   150  	case primitive.DataTypeCodeTuple:
   151  		return typeOfInterfaceSlice, nil
   152  	case primitive.DataTypeCodeUdt:
   153  		return typeOfStringToInterfaceMap, nil
   154  	case primitive.DataTypeCodeUuid:
   155  		return typeOfUUID, nil
   156  	case primitive.DataTypeCodeVarchar:
   157  		return typeOfString, nil
   158  	case primitive.DataTypeCodeVarint:
   159  		return typeOfBigIntPointer, nil
   160  	case primitive.DataTypeCodeList:
   161  		listType := dt.(*datatype.List)
   162  		elemType, err := PreferredGoType(listType.ElementType)
   163  		if err != nil {
   164  			return nil, err
   165  		}
   166  		return reflect.SliceOf(ensureNillable(elemType)), nil
   167  	case primitive.DataTypeCodeSet:
   168  		setType := dt.(*datatype.Set)
   169  		elemType, err := PreferredGoType(setType.ElementType)
   170  		if err != nil {
   171  			return nil, err
   172  		}
   173  		return reflect.SliceOf(ensureNillable(elemType)), nil
   174  	case primitive.DataTypeCodeMap:
   175  		mapType := dt.(*datatype.Map)
   176  		keyType, err := PreferredGoType(mapType.KeyType)
   177  		if err != nil {
   178  			return nil, err
   179  		}
   180  		valueType, err := PreferredGoType(mapType.ValueType)
   181  		if err != nil {
   182  			return nil, err
   183  		}
   184  		return reflect.MapOf(ensureNillable(keyType), ensureNillable(valueType)), nil
   185  	}
   186  	return nil, errCannotFindGoType(dt)
   187  }