Skip to content

Commit 06365eb

Browse files
committed
Abstract class for TypeSerializer
1 parent 1534d7c commit 06365eb

29 files changed

+1614
-0
lines changed

src/Cassandra.Tests/TypeCodecTests.cs

+48
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
using System.Collections.Generic;
2121
using System.Linq;
2222
using System.Net;
23+
using Cassandra.Serialization;
2324

2425
namespace Cassandra.Tests
2526
{
@@ -689,6 +690,53 @@ public void Encode_Decode_With_Binary_Representation()
689690
}
690691
}
691692

693+
[Test]
694+
public void GetClrType_Should_Get_Clr_Type_For_Primitive_Cql_Types()
695+
{
696+
var notPrimitive = new[] { ColumnTypeCode.List, ColumnTypeCode.Set, ColumnTypeCode.Map, ColumnTypeCode.Udt, ColumnTypeCode.Tuple, ColumnTypeCode.Custom };
697+
var serializer = NewInstance();
698+
foreach (ColumnTypeCode typeCode in Enum.GetValues(typeof(ColumnTypeCode)))
699+
{
700+
if (notPrimitive.Contains(typeCode))
701+
{
702+
continue;
703+
}
704+
var type = serializer.GetClrType(typeCode, null);
705+
Assert.NotNull(type);
706+
if (type.IsValueType)
707+
{
708+
Assert.NotNull(serializer.Serialize(Activator.CreateInstance(type)));
709+
}
710+
}
711+
}
712+
713+
[Test]
714+
public void GetClrType_Should_Get_Clr_Type_For_Non_Primitive_Cql_Types()
715+
{
716+
var notPrimitive = new []
717+
{
718+
Tuple.Create<Type, ColumnTypeCode, IColumnInfo>(typeof(IEnumerable<string>), ColumnTypeCode.List, new ListColumnInfo { ValueTypeCode = ColumnTypeCode.Text}),
719+
Tuple.Create<Type, ColumnTypeCode, IColumnInfo>(typeof(IEnumerable<int>), ColumnTypeCode.Set, new SetColumnInfo { KeyTypeCode = ColumnTypeCode.Int}),
720+
Tuple.Create<Type, ColumnTypeCode, IColumnInfo>(typeof(IEnumerable<IEnumerable<DateTimeOffset>>), ColumnTypeCode.List,
721+
new ListColumnInfo { ValueTypeCode = ColumnTypeCode.Set, ValueTypeInfo = new SetColumnInfo { KeyTypeCode = ColumnTypeCode.Timestamp}}),
722+
Tuple.Create<Type, ColumnTypeCode, IColumnInfo>(typeof(IDictionary<string, int>), ColumnTypeCode.Map,
723+
new MapColumnInfo { KeyTypeCode = ColumnTypeCode.Text, ValueTypeCode = ColumnTypeCode.Int }),
724+
Tuple.Create<Type, ColumnTypeCode, IColumnInfo>(typeof(Tuple<string, int, LocalDate>), ColumnTypeCode.Tuple,
725+
new TupleColumnInfo(new [] { ColumnTypeCode.Text, ColumnTypeCode.Int, ColumnTypeCode.Date}.Select(c => new ColumnDesc {TypeCode = c})))
726+
};
727+
var serializer = NewInstance();
728+
foreach (var item in notPrimitive)
729+
{
730+
var type = serializer.GetClrType(item.Item2, item.Item3);
731+
Assert.AreEqual(item.Item1, type);
732+
}
733+
}
734+
735+
private static Serializer NewInstance()
736+
{
737+
return new Serializer(4);
738+
}
739+
692740
/// <summary>
693741
/// Helper method to generate a list column info of nested lists
694742
/// </summary>

src/Cassandra/Cassandra.csproj

+25
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,31 @@
346346
<Compile Include="ProtocolOptions.cs" />
347347
<Compile Include="Requests\RequestExecution.cs" />
348348
<Compile Include="SchemaParser.cs" />
349+
<Compile Include="Serialization\CollectionSerializer.cs" />
350+
<Compile Include="Serialization\CustomTypeSerializer.cs" />
351+
<Compile Include="Serialization\ITypeSerializer.cs" />
352+
<Compile Include="Serialization\LegacyTypeSerializer.cs" />
353+
<Compile Include="Serialization\Primitive\BigIntegerSerializer.cs" />
354+
<Compile Include="Serialization\Primitive\BooleanSerializer.cs" />
355+
<Compile Include="Serialization\Primitive\ByteArraySerializer.cs" />
356+
<Compile Include="Serialization\Primitive\DateTimeOffsetSerializer.cs" />
357+
<Compile Include="Serialization\Primitive\DateTimeSerializer.cs" />
358+
<Compile Include="Serialization\Primitive\DecimalSerializer.cs" />
359+
<Compile Include="Serialization\Primitive\DoubleSerializer.cs" />
360+
<Compile Include="Serialization\Primitive\FloatSerializer.cs" />
361+
<Compile Include="Serialization\Primitive\LongSerializer.cs" />
362+
<Compile Include="Serialization\Primitive\TimeUuidSerializer.cs" />
363+
<Compile Include="Serialization\Primitive\GuidSerializer.cs" />
364+
<Compile Include="Serialization\Primitive\IntSerializer.cs" />
365+
<Compile Include="Serialization\Primitive\IpAddressSerializer.cs" />
366+
<Compile Include="Serialization\Primitive\LocalDateSerializer.cs" />
367+
<Compile Include="Serialization\Primitive\LocalTimeSerializer.cs" />
368+
<Compile Include="Serialization\Primitive\SbyteSerializer.cs" />
369+
<Compile Include="Serialization\Primitive\ShortSerializer.cs" />
370+
<Compile Include="Serialization\Primitive\StringSerializer.cs" />
371+
<Compile Include="Serialization\UdtSerializer.cs" />
372+
<Compile Include="Serialization\Serializer.cs" />
373+
<Compile Include="Serialization\TypeSerializer.cs" />
349374
<Compile Include="Statement.cs" />
350375
<Compile Include="QueryOptions.cs" />
351376
<Compile Include="QueryProtocolOptions.cs" />

src/Cassandra/RowPopulators/RowSetMetadata.cs

+62
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,31 @@ public interface IColumnInfo
7777
public class CustomColumnInfo : IColumnInfo
7878
{
7979
public string CustomTypeName { get; set; }
80+
81+
public CustomColumnInfo()
82+
{
83+
84+
}
85+
86+
public CustomColumnInfo(string name)
87+
{
88+
CustomTypeName = name;
89+
}
90+
91+
public override int GetHashCode()
92+
{
93+
return (CustomTypeName ?? "").GetHashCode();
94+
}
95+
96+
public override bool Equals(object obj)
97+
{
98+
var other = obj as CustomColumnInfo;
99+
if (other == null)
100+
{
101+
return false;
102+
}
103+
return CustomTypeName == other.CustomTypeName;
104+
}
80105
}
81106

82107
public class ListColumnInfo : IColumnInfo
@@ -119,6 +144,20 @@ public UdtColumnInfo(string name)
119144
Name = name;
120145
Fields = new List<ColumnDesc>();
121146
}
147+
148+
public override int GetHashCode()
149+
{
150+
return ("UDT>" + Name).GetHashCode();
151+
}
152+
153+
public override bool Equals(object obj)
154+
{
155+
if (!(obj is UdtColumnInfo))
156+
{
157+
return false;
158+
}
159+
return GetHashCode() == obj.GetHashCode();
160+
}
122161
}
123162

124163
/// <summary>
@@ -140,6 +179,29 @@ internal TupleColumnInfo(IEnumerable<ColumnDesc> elements)
140179
{
141180
Elements = new List<ColumnDesc>(elements);
142181
}
182+
183+
public override int GetHashCode()
184+
{
185+
unchecked
186+
{
187+
var hash = 19;
188+
foreach (var elem in Elements)
189+
{
190+
hash = hash * 31 +
191+
(elem.TypeCode.GetHashCode() ^ (elem.TypeInfo != null ? elem.TypeInfo.GetHashCode() : 0));
192+
}
193+
return hash;
194+
}
195+
}
196+
197+
public override bool Equals(object obj)
198+
{
199+
if (!(obj is TupleColumnInfo))
200+
{
201+
return false;
202+
}
203+
return GetHashCode() == obj.GetHashCode();
204+
}
143205
}
144206

145207
/// <summary>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
using System;
2+
using System.Collections;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Text;
6+
7+
namespace Cassandra.Serialization
8+
{
9+
internal class CollectionSerializer : TypeSerializer<IEnumerable>
10+
{
11+
private Serializer _serializer;
12+
13+
public override ColumnTypeCode CqlType
14+
{
15+
get { throw new NotSupportedException("CollectionSerializer does not map to a single cql type"); }
16+
}
17+
18+
internal void SetChildSerializer(Serializer serializer)
19+
{
20+
_serializer = serializer;
21+
}
22+
23+
private byte[] SerializeChild(object obj)
24+
{
25+
if (_serializer == null)
26+
{
27+
throw new NullReferenceException("Child serializer can not be null");
28+
}
29+
return _serializer.Serialize(obj);
30+
}
31+
32+
private object DeserializeChild(byte[] buffer, ColumnTypeCode typeCode, IColumnInfo typeInfo)
33+
{
34+
if (_serializer == null)
35+
{
36+
throw new NullReferenceException("Child serializer can not be null");
37+
}
38+
return _serializer.Deserialize(buffer, typeCode, typeInfo);
39+
}
40+
41+
public override IEnumerable Deserialize(ushort protocolVersion, byte[] buffer, IColumnInfo typeInfo)
42+
{
43+
throw new NotImplementedException();
44+
}
45+
46+
public override byte[] Serialize(ushort protocolVersion, IEnumerable value)
47+
{
48+
throw new NotImplementedException();
49+
}
50+
51+
private IEnumerable DeserializeCollection(int protocolVersion, Type childType, ColumnTypeCode childTypeCode, IColumnInfo childTypeInfo, byte[] buffer)
52+
{
53+
var index = 0;
54+
var count = DecodeCollectionLength(protocolVersion, buffer, ref index);
55+
var result = Array.CreateInstance(childType, count);
56+
for (var i = 0; i < count; i++)
57+
{
58+
var valueBufferLength = DecodeCollectionLength(protocolVersion, buffer, ref index);
59+
var itemBuffer = new byte[valueBufferLength];
60+
Buffer.BlockCopy(buffer, index, itemBuffer, 0, valueBufferLength);
61+
index += valueBufferLength;
62+
result.SetValue(DeserializeChild(itemBuffer, childTypeCode, childTypeInfo), i);
63+
}
64+
return result;
65+
}
66+
67+
/// <summary>
68+
/// Decodes length for collection types depending on the protocol version
69+
/// </summary>
70+
private static int DecodeCollectionLength(int protocolVersion, byte[] buffer, ref int index)
71+
{
72+
int result;
73+
if (protocolVersion < 3)
74+
{
75+
//length is a short
76+
result = BeConverter.ToInt16(buffer, index);
77+
index += 2;
78+
}
79+
else
80+
{
81+
//length is expressed in int
82+
result = BeConverter.ToInt32(buffer, index);
83+
index += 4;
84+
}
85+
return result;
86+
}
87+
88+
}
89+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//
2+
// Copyright (C) 2012-2016 DataStax Inc.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
//
16+
17+
namespace Cassandra.Serialization
18+
{
19+
/// <summary>
20+
/// Base serializer for custom types.
21+
/// </summary>
22+
public abstract class CustomTypeSerializer<T> : TypeSerializer<T>
23+
{
24+
private readonly IColumnInfo _typeInfo;
25+
26+
public override ColumnTypeCode CqlType
27+
{
28+
get { return ColumnTypeCode.Custom; }
29+
}
30+
31+
public override IColumnInfo TypeInfo
32+
{
33+
get { return _typeInfo; }
34+
}
35+
36+
/// <summary>
37+
/// Creates a new instance of the serializer for custom types.
38+
/// </summary>
39+
/// <param name="name">Fully qualified name of the custom type</param>
40+
protected CustomTypeSerializer(string name)
41+
{
42+
_typeInfo = new CustomColumnInfo(name);
43+
}
44+
}
45+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Text;
6+
7+
namespace Cassandra.Serialization
8+
{
9+
internal interface ITypeSerializer
10+
{
11+
Type Type { get; }
12+
13+
ColumnTypeCode CqlType { get; }
14+
15+
object Deserialize(ushort protocolVersion, byte[] buffer, IColumnInfo typeInfo);
16+
17+
byte[] Serialize(ushort protocolVersion, object obj);
18+
}
19+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace Cassandra.Serialization
7+
{
8+
/// <summary>
9+
/// Legacy <see cref="ITypeSerializer"/> to support <see cref="ITypeAdapter"/>.
10+
/// </summary>
11+
internal class LegacyTypeSerializer : ITypeSerializer
12+
{
13+
private readonly ColumnTypeCode _typeCode;
14+
private readonly ITypeAdapter _adapter;
15+
16+
public Type Type
17+
{
18+
get { return _adapter.GetDataType(); }
19+
}
20+
public ColumnTypeCode CqlType {
21+
get { return _typeCode; }
22+
}
23+
24+
internal LegacyTypeSerializer(ColumnTypeCode typeCode, ITypeAdapter adapter)
25+
{
26+
_typeCode = typeCode;
27+
_adapter = adapter;
28+
}
29+
30+
public object Deserialize(ushort protocolVersion, byte[] buffer, IColumnInfo typeInfo)
31+
{
32+
return _adapter.ConvertFrom(buffer);
33+
}
34+
35+
public byte[] Serialize(ushort protocolVersion, object obj)
36+
{
37+
return _adapter.ConvertTo(obj);
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)