Kinetica   C#   API  Version 7.2.3.1
RecordValue.cs
Go to the documentation of this file.
1 using System;
2 using System.Runtime.CompilerServices;
3 
4 namespace kinetica.Records;
5 
10  public enum RecordValueType
11  {
13  Null,
15  Int,
17  Long,
19  Float,
21  Double,
23  String,
25  Bytes
26  }
27 
34  public readonly struct RecordValue : IEquatable<RecordValue>
35  {
36  private readonly RecordValueType _type;
37  private readonly long _intValue;
38  private readonly double _floatValue;
39  private readonly object? _objectValue; // string or byte[]
40 
41  private RecordValue(RecordValueType type, long intValue = 0, double floatValue = 0, object? objectValue = null)
42  {
43  _type = type;
44  _intValue = intValue;
45  _floatValue = floatValue;
46  _objectValue = objectValue;
47  }
48 
50  public RecordValueType Type => _type;
51 
53  public bool IsNull => _type == RecordValueType.Null;
54 
55  #region Factory Methods
56 
58  public static RecordValue Null() => new(RecordValueType.Null);
59 
61  public static RecordValue Int(int value) => new(RecordValueType.Int, value);
62 
64  public static RecordValue Long(long value) => new(RecordValueType.Long, value);
65 
67  public static RecordValue Float(float value) => new(RecordValueType.Float, floatValue: value);
68 
70  public static RecordValue Double(double value) => new(RecordValueType.Double, floatValue: value);
71 
73  public static RecordValue String(string value) => new(RecordValueType.String, objectValue: value);
74 
76  public static RecordValue Bytes(byte[] value) => new(RecordValueType.Bytes, objectValue: value);
77 
79  public static RecordValue Boolean(bool value) => new(RecordValueType.Int, value ? 1 : 0);
80 
81  #endregion
82 
83  #region Implicit Conversions
84 
85  public static implicit operator RecordValue(int value) => Int(value);
86  public static implicit operator RecordValue(long value) => Long(value);
87  public static implicit operator RecordValue(float value) => Float(value);
88  public static implicit operator RecordValue(double value) => Double(value);
89  public static implicit operator RecordValue(string value) => value == null ? Null() : String(value);
90  public static implicit operator RecordValue(byte[] value) => value == null ? Null() : Bytes(value);
91  public static implicit operator RecordValue(bool value) => Boolean(value);
92 
93  // Nullable conversions
94  public static implicit operator RecordValue(int? value) => value.HasValue ? Int(value.Value) : Null();
95  public static implicit operator RecordValue(long? value) => value.HasValue ? Long(value.Value) : Null();
96  public static implicit operator RecordValue(float? value) => value.HasValue ? Float(value.Value) : Null();
97  public static implicit operator RecordValue(double? value) => value.HasValue ? Double(value.Value) : Null();
98  public static implicit operator RecordValue(bool? value) => value.HasValue ? Boolean(value.Value) : Null();
99 
100  #endregion
101 
102  #region Value Accessors
103 
105  [MethodImpl(MethodImplOptions.AggressiveInlining)]
106  public int? AsInt()
107  {
108  return _type switch
109  {
110  RecordValueType.Int => (int)_intValue,
111  RecordValueType.Null => null,
112  _ => throw new InvalidOperationException($"Cannot convert {_type} to Int")
113  };
114  }
115 
117  [MethodImpl(MethodImplOptions.AggressiveInlining)]
118  public long? AsLong()
119  {
120  return _type switch
121  {
122  RecordValueType.Long => _intValue,
123  RecordValueType.Int => _intValue,
124  RecordValueType.Null => null,
125  _ => throw new InvalidOperationException($"Cannot convert {_type} to Long")
126  };
127  }
128 
130  [MethodImpl(MethodImplOptions.AggressiveInlining)]
131  public float? AsFloat()
132  {
133  return _type switch
134  {
135  RecordValueType.Float => (float)_floatValue,
136  RecordValueType.Null => null,
137  _ => throw new InvalidOperationException($"Cannot convert {_type} to Float")
138  };
139  }
140 
142  [MethodImpl(MethodImplOptions.AggressiveInlining)]
143  public double? AsDouble()
144  {
145  return _type switch
146  {
147  RecordValueType.Double => _floatValue,
148  RecordValueType.Float => _floatValue,
149  RecordValueType.Null => null,
150  _ => throw new InvalidOperationException($"Cannot convert {_type} to Double")
151  };
152  }
153 
155  [MethodImpl(MethodImplOptions.AggressiveInlining)]
156  public string? AsString()
157  {
158  return _type switch
159  {
160  RecordValueType.String => (string?)_objectValue,
161  RecordValueType.Null => null,
162  _ => throw new InvalidOperationException($"Cannot convert {_type} to String")
163  };
164  }
165 
167  [MethodImpl(MethodImplOptions.AggressiveInlining)]
168  public byte[]? AsBytes()
169  {
170  return _type switch
171  {
172  RecordValueType.Bytes => (byte[]?)_objectValue,
173  RecordValueType.Null => null,
174  _ => throw new InvalidOperationException($"Cannot convert {_type} to Bytes")
175  };
176  }
177 
179  [MethodImpl(MethodImplOptions.AggressiveInlining)]
180  public bool? AsBool()
181  {
182  return _type switch
183  {
184  RecordValueType.Int => _intValue != 0,
185  RecordValueType.Null => null,
186  _ => throw new InvalidOperationException($"Cannot convert {_type} to Boolean")
187  };
188  }
189 
190  #endregion
191 
192  #region TryGet Methods
193 
195  public bool TryGetInt(out int value)
196  {
197  if (_type == RecordValueType.Int)
198  {
199  value = (int)_intValue;
200  return true;
201  }
202  value = default;
203  return false;
204  }
205 
207  public bool TryGetLong(out long value)
208  {
209  if (_type is RecordValueType.Long or RecordValueType.Int)
210  {
211  value = _intValue;
212  return true;
213  }
214  value = default;
215  return false;
216  }
217 
219  public bool TryGetFloat(out float value)
220  {
221  if (_type == RecordValueType.Float)
222  {
223  value = (float)_floatValue;
224  return true;
225  }
226  value = default;
227  return false;
228  }
229 
231  public bool TryGetDouble(out double value)
232  {
233  if (_type is RecordValueType.Double or RecordValueType.Float)
234  {
235  value = _floatValue;
236  return true;
237  }
238  value = default;
239  return false;
240  }
241 
243  public bool TryGetString(out string? value)
244  {
245  if (_type == RecordValueType.String)
246  {
247  value = (string?)_objectValue;
248  return true;
249  }
250  if (_type == RecordValueType.Null)
251  {
252  value = null;
253  return true;
254  }
255  value = default;
256  return false;
257  }
258 
260  public bool TryGetBytes(out byte[]? value)
261  {
262  if (_type == RecordValueType.Bytes)
263  {
264  value = (byte[]?)_objectValue;
265  return true;
266  }
267  if (_type == RecordValueType.Null)
268  {
269  value = null;
270  return true;
271  }
272  value = default;
273  return false;
274  }
275 
277  public bool TryGetBool(out bool value)
278  {
279  if (_type == RecordValueType.Int)
280  {
281  value = _intValue != 0;
282  return true;
283  }
284  value = default;
285  return false;
286  }
287 
288  #endregion
289 
290  #region Equality and Hashing
291 
292  public bool Equals(RecordValue other)
293  {
294  if (_type != other._type) return false;
295 
296  return _type switch
297  {
298  RecordValueType.Null => true,
299  RecordValueType.Int or RecordValueType.Long => _intValue == other._intValue,
300  RecordValueType.Float or RecordValueType.Double => _floatValue == other._floatValue,
301  RecordValueType.String => string.Equals((string?)_objectValue, (string?)other._objectValue, StringComparison.Ordinal),
302  RecordValueType.Bytes => ByteArrayEquals((byte[]?)_objectValue, (byte[]?)other._objectValue),
303  _ => false
304  };
305  }
306 
307  private static bool ByteArrayEquals(byte[]? a, byte[]? b)
308  {
309  if (ReferenceEquals(a, b)) return true;
310  if (a == null || b == null) return false;
311  if (a.Length != b.Length) return false;
312  for (int i = 0; i < a.Length; i++)
313  {
314  if (a[i] != b[i]) return false;
315  }
316  return true;
317  }
318 
319  public override bool Equals(object? obj) => obj is RecordValue other && Equals(other);
320 
321  public override int GetHashCode()
322  {
323  return _type switch
324  {
325  RecordValueType.Null => 0,
326  RecordValueType.Int or RecordValueType.Long => HashCode.Combine(_type, _intValue),
327  RecordValueType.Float or RecordValueType.Double => HashCode.Combine(_type, _floatValue),
328  RecordValueType.String => HashCode.Combine(_type, _objectValue),
329  RecordValueType.Bytes => HashCode.Combine(_type, ((byte[]?)_objectValue)?.Length ?? 0),
330  _ => 0
331  };
332  }
333 
334  public static bool operator ==(RecordValue left, RecordValue right) => left.Equals(right);
335  public static bool operator !=(RecordValue left, RecordValue right) => !left.Equals(right);
336 
337  #endregion
338 
339  public override string ToString()
340  {
341  return _type switch
342  {
343  RecordValueType.Null => "null",
344  RecordValueType.Int or RecordValueType.Long => _intValue.ToString(),
345  RecordValueType.Float or RecordValueType.Double => _floatValue.ToString(),
346  RecordValueType.String => $"\"{_objectValue}\"",
347  RecordValueType.Bytes => $"bytes[{((byte[]?)_objectValue)?.Length ?? 0}]",
348  _ => "unknown"
349  };
350  }
351  }
string? AsString()
Gets the value as a string.
Definition: RecordValue.cs:156
static RecordValue Null()
Creates a null record value.
64-bit signed integer
static RecordValue Long(long value)
Creates a 64-bit integer record value.
bool TryGetFloat(out float value)
Tries to get the value as a float.
Definition: RecordValue.cs:219
long? AsLong()
Gets the value as a 64-bit integer.
Definition: RecordValue.cs:118
bool TryGetInt(out int value)
Tries to get the value as an integer.
Definition: RecordValue.cs:195
static RecordValue Boolean(bool value)
Creates a boolean record value (stored as int).
bool IsNull
Returns true if this value is null.
Definition: RecordValue.cs:53
override string ToString()
Definition: RecordValue.cs:339
32-bit IEEE 754 float
byte? [] AsBytes()
Gets the value as a byte array.
Definition: RecordValue.cs:168
bool? AsBool()
Gets the value as a boolean (from int).
Definition: RecordValue.cs:180
int? AsInt()
Gets the value as a 32-bit integer.
Definition: RecordValue.cs:106
override int GetHashCode()
Definition: RecordValue.cs:321
bool TryGetBool(out bool value)
Tries to get the value as a boolean.
Definition: RecordValue.cs:277
static RecordValue Float(float value)
Creates a 32-bit float record value.
bool TryGetBytes(out byte[]? value)
Tries to get the value as bytes.
Definition: RecordValue.cs:260
static RecordValue String(string value)
Creates a string record value.
static bool operator !=(RecordValue left, RecordValue right)
64-bit IEEE 754 double
static RecordValue Bytes(byte[] value)
Creates a bytes record value.
double? AsDouble()
Gets the value as a 64-bit double.
Definition: RecordValue.cs:143
Immutable collection of metadata about a Kinetica type.
Definition: Type.cs:36
static RecordValue Int(int value)
Creates a 32-bit integer record value.
bool TryGetString(out string? value)
Tries to get the value as a string.
Definition: RecordValue.cs:243
RecordValueType
Represents the type of a record value.
Definition: RecordValue.cs:10
32-bit signed integer (also used for boolean, int8, int16)
bool TryGetDouble(out double value)
Tries to get the value as a double.
Definition: RecordValue.cs:231
float? AsFloat()
Gets the value as a 32-bit float.
Definition: RecordValue.cs:131
static RecordValue Double(double value)
Creates a 64-bit double record value.
A typed value that can be stored in a GenericRecord.
Definition: RecordValue.cs:34
bool TryGetLong(out long value)
Tries to get the value as a long.
Definition: RecordValue.cs:207
bool Equals(RecordValue other)
Definition: RecordValue.cs:292
static bool operator==(RecordValue left, RecordValue right)