Skip to content

Commit bb06f9b

Browse files
feat: begin list type
1 parent ad39d11 commit bb06f9b

File tree

9 files changed

+595
-504
lines changed

9 files changed

+595
-504
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
namespace Ydb.Sdk.Ado.Internal;
2+
3+
using static YdbValueExtensions;
4+
5+
internal class YdbPrimitiveTypeInfo
6+
{
7+
internal static readonly YdbPrimitiveTypeInfo
8+
Bool = new(Type.Types.PrimitiveTypeId.Bool, TryPack<bool>(PackBool)),
9+
Int8 = new(Type.Types.PrimitiveTypeId.Int8, TryPack<sbyte>(PackInt8)),
10+
Int16 = new(Type.Types.PrimitiveTypeId.Int16, TryPackInt16),
11+
Int32 = new(Type.Types.PrimitiveTypeId.Int32, TryPackInt32),
12+
Int64 = new(Type.Types.PrimitiveTypeId.Int64, TryPackInt64),
13+
Uint8 = new(Type.Types.PrimitiveTypeId.Uint8, TryPack<byte>(PackUint8)),
14+
Uint16 = new(Type.Types.PrimitiveTypeId.Uint16, TryPackUint16),
15+
Uint32 = new(Type.Types.PrimitiveTypeId.Uint32, TryPackUint32),
16+
Uint64 = new(Type.Types.PrimitiveTypeId.Uint64, TryPackUint64),
17+
Float = new(Type.Types.PrimitiveTypeId.Float, TryPack<float>(PackFloat)),
18+
Double = new(Type.Types.PrimitiveTypeId.Double, TryPackDouble),
19+
Bytes = new(Type.Types.PrimitiveTypeId.String, TryPackBytes),
20+
Text = new(Type.Types.PrimitiveTypeId.Utf8, TryPack<string>(PackText)),
21+
Json = new(Type.Types.PrimitiveTypeId.Json, TryPack<string>(PackText)),
22+
JsonDocument = new(Type.Types.PrimitiveTypeId.JsonDocument, TryPack<string>(PackText)),
23+
Yson = new(Type.Types.PrimitiveTypeId.Yson, TryPackBytes),
24+
Uuid = new(Type.Types.PrimitiveTypeId.Uuid, TryPack<Guid>(PackUuid)),
25+
Date = new(Type.Types.PrimitiveTypeId.Date, TryPackDate),
26+
Date32 = new(Type.Types.PrimitiveTypeId.Date32, TryPackDate32),
27+
Datetime = new(Type.Types.PrimitiveTypeId.Datetime, TryPack<DateTime>(PackDatetime)),
28+
Datetime64 = new(Type.Types.PrimitiveTypeId.Datetime64, TryPack<DateTime>(PackDatetime64)),
29+
Timestamp = new(Type.Types.PrimitiveTypeId.Timestamp, TryPack<DateTime>(PackTimestamp)),
30+
Timestamp64 = new(Type.Types.PrimitiveTypeId.Timestamp64, TryPack<DateTime>(PackTimestamp64)),
31+
Interval = new(Type.Types.PrimitiveTypeId.Interval, TryPack<TimeSpan>(PackInterval)),
32+
Interval64 = new(Type.Types.PrimitiveTypeId.Interval64, TryPack<TimeSpan>(PackInterval64));
33+
34+
private YdbPrimitiveTypeInfo(Type.Types.PrimitiveTypeId primitiveTypeId, Func<object, Ydb.Value?> pack)
35+
{
36+
YdbType = new Type { TypeId = primitiveTypeId };
37+
NullValue = new TypedValue
38+
{ Type = new Type { OptionalType = new OptionalType { Item = YdbType } }, Value = YdbValueNull };
39+
Pack = pack;
40+
}
41+
42+
internal Type YdbType { get; }
43+
internal TypedValue NullValue { get; }
44+
internal Func<object, Ydb.Value?> Pack { get; }
45+
46+
internal static YdbPrimitiveTypeInfo? TryResolve(System.Type type)
47+
{
48+
if (type == typeof(bool)) return Bool;
49+
50+
if (type == typeof(sbyte)) return Int8;
51+
if (type == typeof(short)) return Int16;
52+
if (type == typeof(int)) return Int32;
53+
if (type == typeof(long)) return Int64;
54+
55+
if (type == typeof(byte)) return Uint8;
56+
if (type == typeof(ushort)) return Uint16;
57+
if (type == typeof(uint)) return Uint32;
58+
if (type == typeof(ulong)) return Uint64;
59+
60+
if (type == typeof(float)) return Float;
61+
if (type == typeof(double)) return Double;
62+
63+
if (type == typeof(byte[]) || type == typeof(MemoryStream)) return Bytes;
64+
if (type == typeof(string)) return Text;
65+
if (type == typeof(Guid)) return Uuid;
66+
67+
if (type == typeof(DateOnly)) return Date;
68+
if (type == typeof(DateTime)) return Timestamp;
69+
if (type == typeof(TimeSpan)) return Interval;
70+
71+
return null;
72+
}
73+
74+
private static Func<object, Ydb.Value?> TryPack<T>(Func<T, Ydb.Value> pack) =>
75+
value => value is T valueT ? pack(valueT) : null;
76+
77+
private static Ydb.Value? TryPackInt16(object value) => value switch
78+
{
79+
short shortValue => PackInt16(shortValue),
80+
sbyte sbyteValue => PackInt16(sbyteValue),
81+
byte byteValue => PackInt16(byteValue),
82+
_ => null
83+
};
84+
85+
private static Ydb.Value? TryPackInt32(object value) => value switch
86+
{
87+
int intValue => PackInt32(intValue),
88+
sbyte sbyteValue => PackInt32(sbyteValue),
89+
byte byteValue => PackInt32(byteValue),
90+
short shortValue => PackInt32(shortValue),
91+
ushort ushortValue => PackInt32(ushortValue),
92+
_ => null
93+
};
94+
95+
private static Ydb.Value? TryPackInt64(object value) => value switch
96+
{
97+
long longValue => PackInt64(longValue),
98+
sbyte sbyteValue => PackInt64(sbyteValue),
99+
byte byteValue => PackInt64(byteValue),
100+
short shortValue => PackInt64(shortValue),
101+
ushort ushortValue => PackInt64(ushortValue),
102+
int intValue => PackInt64(intValue),
103+
uint uintValue => PackInt64(uintValue),
104+
_ => null
105+
};
106+
107+
private static Ydb.Value? TryPackUint16(object value) => value switch
108+
{
109+
ushort shortValue => PackUint16(shortValue),
110+
byte byteValue => PackUint16(byteValue),
111+
_ => null
112+
};
113+
114+
private static Ydb.Value? TryPackUint32(object value) => value switch
115+
{
116+
uint intValue => PackUint32(intValue),
117+
byte byteValue => PackUint32(byteValue),
118+
ushort ushortValue => PackUint32(ushortValue),
119+
_ => null
120+
};
121+
122+
private static Ydb.Value? TryPackUint64(object value) => value switch
123+
{
124+
ulong longValue => PackUint64(longValue),
125+
byte byteValue => PackUint64(byteValue),
126+
ushort ushortValue => PackUint64(ushortValue),
127+
uint uintValue => PackUint64(uintValue),
128+
_ => null
129+
};
130+
131+
private static Ydb.Value? TryPackDouble(object value) => value switch
132+
{
133+
double doubleValue => PackDouble(doubleValue),
134+
float floatValue => PackDouble(floatValue),
135+
_ => null
136+
};
137+
138+
private static Ydb.Value? TryPackBytes(object value) => value switch
139+
{
140+
byte[] bytesValue => PackBytes(bytesValue),
141+
MemoryStream memoryStream => PackBytes(memoryStream.ToArray()),
142+
_ => null
143+
};
144+
145+
private static Ydb.Value? TryPackDate(object value) => value switch
146+
{
147+
DateTime dateTimeValue => PackDate(dateTimeValue),
148+
DateOnly dateOnlyValue => PackDate(dateOnlyValue.ToDateTime(TimeOnly.MinValue)),
149+
_ => null
150+
};
151+
152+
private static Ydb.Value? TryPackDate32(object value) => value switch
153+
{
154+
DateTime dateTimeValue => PackDate32(dateTimeValue),
155+
DateOnly dateOnlyValue => PackDate32(dateOnlyValue.ToDateTime(TimeOnly.MinValue)),
156+
_ => null
157+
};
158+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace Ydb.Sdk.Ado.Internal;
2+
3+
internal static class YdbTypeExtensions
4+
{
5+
internal const byte DefaultDecimalPrecision = 22;
6+
internal const byte DefaultDecimalScale = 9;
7+
8+
private static readonly Type DefaultDecimalType = DecimalType(DefaultDecimalPrecision, DefaultDecimalScale);
9+
10+
internal static Type DecimalType(byte precision, byte scale) => precision == 0 && scale == 0
11+
? DefaultDecimalType
12+
: new Type { DecimalType = new DecimalType { Precision = precision, Scale = scale } };
13+
14+
internal static Type ListType(Type type) => new() { ListType = new ListType { Item = type } };
15+
}
Lines changed: 21 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,11 @@
1-
using Google.Protobuf;
2-
using Google.Protobuf.WellKnownTypes;
1+
using static Ydb.Sdk.Ado.Internal.YdbTypeExtensions;
2+
using static Ydb.Sdk.Ado.Internal.YdbValueExtensions;
33

44
namespace Ydb.Sdk.Ado.Internal;
55

66
internal static class YdbTypedValueExtensions
77
{
8-
private const byte MaxPrecisionDecimal = 29;
9-
private static readonly decimal[] Pow10 = CreatePow10();
10-
11-
private static decimal[] CreatePow10()
12-
{
13-
var a = new decimal[29];
14-
a[0] = 1m;
15-
for (var i = 1; i < a.Length; i++) a[i] = a[i - 1] * 10m; // 1..1e28
16-
return a;
17-
}
18-
19-
internal static TypedValue Null(this Type.Types.PrimitiveTypeId primitiveTypeId) => new()
20-
{
21-
Type = new Type { OptionalType = new OptionalType { Item = new Type { TypeId = primitiveTypeId } } },
22-
Value = new Ydb.Value { NullFlagValue = NullValue.NullValue }
23-
};
8+
private static readonly TypedValue DecimalDefaultNull = DecimalNull(DefaultDecimalPrecision, DefaultDecimalScale);
249

2510
internal static string ToYql(this TypedValue typedValue) => ToYql(typedValue.Type);
2611

@@ -35,166 +20,35 @@ private static string ToYql(Type type) =>
3520
_ => "Unknown"
3621
};
3722

38-
internal static TypedValue NullDecimal(byte precision, byte scale) => new()
39-
{
40-
Type = new Type
41-
{
42-
OptionalType = new OptionalType
43-
{
44-
Item = new Type { DecimalType = new DecimalType { Precision = precision, Scale = scale } }
45-
}
46-
},
47-
Value = new Ydb.Value { NullFlagValue = NullValue.NullValue }
48-
};
49-
50-
internal static TypedValue Text(this string value) => MakeText(Type.Types.PrimitiveTypeId.Utf8, value);
51-
52-
internal static TypedValue Bool(this bool value) =>
53-
MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Bool, new Ydb.Value { BoolValue = value });
54-
55-
internal static TypedValue Int8(this sbyte value) =>
56-
MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Int8, new Ydb.Value { Int32Value = value });
57-
58-
internal static TypedValue Int16(this short value) =>
59-
MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Int16, new Ydb.Value { Int32Value = value });
60-
61-
internal static TypedValue Int32(this int value) =>
62-
MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Int32, new Ydb.Value { Int32Value = value });
63-
64-
internal static TypedValue Int64(this long value) =>
65-
MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Int64, new Ydb.Value { Int64Value = value });
66-
67-
internal static TypedValue Uint8(this byte value) =>
68-
MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Uint8, new Ydb.Value { Uint32Value = value });
69-
70-
internal static TypedValue Uint16(this ushort value) =>
71-
MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Uint16, new Ydb.Value { Uint32Value = value });
72-
73-
internal static TypedValue Uint32(this uint value) =>
74-
MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Uint32, new Ydb.Value { Uint32Value = value });
75-
76-
internal static TypedValue Uint64(this ulong value) =>
77-
MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Uint64, new Ydb.Value { Uint64Value = value });
78-
79-
internal static TypedValue Float(this float value) =>
80-
MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Float, new Ydb.Value { FloatValue = value });
81-
82-
internal static TypedValue Double(this double value) =>
83-
MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Double, new Ydb.Value { DoubleValue = value });
84-
85-
internal static TypedValue Decimal(this decimal value, byte precision, byte scale)
23+
internal static TypedValue List(this IEnumerable<TypedValue> values)
8624
{
87-
if (scale > precision)
88-
throw new ArgumentOutOfRangeException(nameof(scale), "Scale cannot exceed precision");
89-
90-
var origScale = (decimal.GetBits(value)[3] >> 16) & 0xFF;
91-
92-
if (origScale > scale || (precision < MaxPrecisionDecimal && Pow10[precision - scale] <= Math.Abs(value)))
93-
{
94-
throw new OverflowException($"Value {value} does not fit Decimal({precision}, {scale})");
95-
}
96-
97-
value *= 1.0000000000000000000000000000m; // 28 zeros, max supported by c# decimal
98-
value = Math.Round(value, scale);
99-
var bits = decimal.GetBits(value);
100-
var low = ((ulong)(uint)bits[1] << 32) | (uint)bits[0];
101-
var high = (ulong)(uint)bits[2];
102-
var isNegative = bits[3] < 0;
25+
TypedValue? first = null;
26+
var value = new Ydb.Value();
10327

104-
unchecked
28+
foreach (var v in values)
10529
{
106-
if (isNegative)
30+
first ??= v;
31+
if (first.Type.Equals(v.Type))
10732
{
108-
low = ~low + 1UL;
109-
high = ~high + (low == 0 ? 1UL : 0UL);
33+
throw new InvalidOperationException();
11034
}
111-
}
112-
113-
return new TypedValue
114-
{
115-
Type = new Type { DecimalType = new DecimalType { Precision = precision, Scale = scale } },
116-
Value = new Ydb.Value { Low128 = low, High128 = high }
117-
};
118-
}
119-
120-
internal static TypedValue Bytes(this byte[] value) => MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.String,
121-
new Ydb.Value { BytesValue = ByteString.CopyFrom(value) });
122-
123-
internal static TypedValue Yson(this byte[] value) => MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Yson,
124-
new Ydb.Value { BytesValue = ByteString.CopyFrom(value) });
125-
126-
internal static TypedValue Json(this string value) => MakeText(Type.Types.PrimitiveTypeId.Json, value);
127-
128-
internal static TypedValue JsonDocument(this string value) =>
129-
MakeText(Type.Types.PrimitiveTypeId.JsonDocument, value);
130-
131-
internal static TypedValue Uuid(this Guid value)
132-
{
133-
var bytes = value.ToByteArray();
134-
var low = BitConverter.ToUInt64(bytes, 0);
135-
var high = BitConverter.ToUInt64(bytes, 8);
136-
137-
return MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Uuid, new Ydb.Value { Low128 = low, High128 = high });
138-
}
139-
140-
internal static TypedValue Date(this DateTime value) => MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Date,
141-
new Ydb.Value { Uint32Value = (uint)(value.Subtract(DateTime.UnixEpoch).Ticks / TimeSpan.TicksPerDay) });
14235

143-
internal static TypedValue Date32(this DateTime value) => MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId.Date32,
144-
new Ydb.Value { Int32Value = (int)(value.Subtract(DateTime.UnixEpoch).Ticks / TimeSpan.TicksPerDay) });
145-
146-
internal static TypedValue Datetime(this DateTime dateTimeValue) => MakePrimitiveTypedValue(
147-
Type.Types.PrimitiveTypeId.Datetime, new Ydb.Value
148-
{ Uint32Value = (uint)(dateTimeValue.Subtract(DateTime.UnixEpoch).Ticks / TimeSpan.TicksPerSecond) }
149-
);
150-
151-
internal static TypedValue Datetime64(this DateTime dateTimeValue) => MakePrimitiveTypedValue(
152-
Type.Types.PrimitiveTypeId.Datetime64,
153-
new Ydb.Value { Int64Value = dateTimeValue.Subtract(DateTime.UnixEpoch).Ticks / TimeSpan.TicksPerSecond }
154-
);
155-
156-
internal static TypedValue Timestamp(this DateTime dateTimeValue) => MakePrimitiveTypedValue(
157-
Type.Types.PrimitiveTypeId.Timestamp, new Ydb.Value
158-
{
159-
Uint64Value = (ulong)(dateTimeValue.Ticks - DateTime.UnixEpoch.Ticks) / TimeSpanUtils.TicksPerMicrosecond
36+
value.Items.Add(v.Value);
16037
}
161-
);
162-
163-
internal static TypedValue Timestamp64(this DateTime dateTimeValue) => MakePrimitiveTypedValue(
164-
Type.Types.PrimitiveTypeId.Timestamp64, new Ydb.Value
165-
{ Int64Value = (dateTimeValue.Ticks - DateTime.UnixEpoch.Ticks) / TimeSpanUtils.TicksPerMicrosecond }
166-
);
167-
168-
internal static TypedValue Interval(this TimeSpan timeSpanValue) => MakePrimitiveTypedValue(
169-
Type.Types.PrimitiveTypeId.Interval,
170-
new Ydb.Value { Int64Value = timeSpanValue.Ticks / TimeSpanUtils.TicksPerMicrosecond }
171-
);
172-
173-
internal static TypedValue Interval64(this TimeSpan timeSpanValue) => MakePrimitiveTypedValue(
174-
Type.Types.PrimitiveTypeId.Interval64,
175-
new Ydb.Value { Int64Value = timeSpanValue.Ticks / TimeSpanUtils.TicksPerMicrosecond }
176-
);
17738

178-
internal static TypedValue List(this IReadOnlyList<TypedValue> values)
179-
{
180-
if (values.Count == 0)
181-
{
182-
throw new ArgumentOutOfRangeException(nameof(values));
183-
}
39+
if (first is null) throw new ArgumentOutOfRangeException(nameof(values));
18440

185-
var value = new Ydb.Value();
186-
value.Items.Add(values.Select(v => v.Value));
41+
return new TypedValue { Type = ListType(first.Type), Value = value };
42+
}
18743

188-
return new TypedValue
44+
internal static TypedValue DecimalNull(byte precision, byte scale) => precision == 0 && scale == 0
45+
? DecimalDefaultNull
46+
: new TypedValue
18947
{
190-
Type = new Type { ListType = new ListType { Item = values[0].Type } },
191-
Value = value
48+
Type = new Type { OptionalType = new OptionalType { Item = DecimalType(precision, scale) } },
49+
Value = YdbValueNull
19250
};
193-
}
194-
195-
private static TypedValue MakeText(Type.Types.PrimitiveTypeId primitiveTypeId, string textValue) =>
196-
MakePrimitiveTypedValue(primitiveTypeId, new Ydb.Value { TextValue = textValue });
19751

198-
private static TypedValue MakePrimitiveTypedValue(Type.Types.PrimitiveTypeId primitiveTypeId, Ydb.Value value) =>
199-
new() { Type = new Type { TypeId = primitiveTypeId }, Value = value };
52+
internal static TypedValue ListNull(Type type) => new()
53+
{ Type = new Type { OptionalType = { Item = ListType(type) } }, Value = YdbValueNull };
20054
}

0 commit comments

Comments
 (0)