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 }