Skip to content

Commit a70b800

Browse files
author
David Coe
committed
PR feedback
1 parent df1562d commit a70b800

File tree

6 files changed

+75
-68
lines changed

6 files changed

+75
-68
lines changed

csharp/src/Apache.Arrow.Adbc/Extensions/IArrowArrayExtensions.cs

Lines changed: 54 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
using System.Collections;
2020
using System.Collections.Generic;
2121
using System.Data.SqlTypes;
22-
using System.Dynamic;
2322
using System.IO;
2423
using System.Text.Json;
2524
using Apache.Arrow.Types;
@@ -35,19 +34,39 @@ public enum StructResultType
3534
public static class IArrowArrayExtensions
3635
{
3736
/// <summary>
38-
/// Helper extension to get a value from the <see cref="IArrowArray"/> at the specified index.
37+
/// Overloaded. Helper extension to get a value from the <see cref="IArrowArray"/> at the specified index.
3938
/// </summary>
4039
/// <param name="arrowArray">
4140
/// The Arrow array.
4241
/// </param>
4342
/// <param name="index">
4443
/// The index in the array to get the value from.
4544
/// </param>
45+
public static object? ValueAt(this IArrowArray arrowArray, int index)
46+
{
47+
return ValueAt(arrowArray, index, StructResultType.JsonString);
48+
}
49+
50+
/// <summary>
51+
/// Overloaded. Helper extension to get a value from the <see cref="IArrowArray"/> at the specified index.
52+
/// </summary>
53+
/// <param name="arrowArray">
54+
/// The Arrow array.
55+
/// </param>
56+
/// <param name="index">
57+
/// The index in the array to get the value from.
58+
/// </param>
59+
/// <param name="resultType">
60+
/// T
61+
/// </param>
4662
public static object? ValueAt(this IArrowArray arrowArray, int index, StructResultType resultType = StructResultType.JsonString)
4763
{
4864
if (arrowArray == null) throw new ArgumentNullException(nameof(arrowArray));
4965
if (index < 0) throw new ArgumentOutOfRangeException(nameof(index));
5066

67+
if (arrowArray.IsNull(index))
68+
return null;
69+
5170
switch (arrowArray.Data.DataType.TypeId)
5271
{
5372
case ArrowTypeId.Null:
@@ -136,14 +155,7 @@ public static class IArrowArrayExtensions
136155
throw new NotSupportedException($"Unsupported interval unit: {((IntervalType)arrowArray.Data.DataType).Unit}");
137156
}
138157
case ArrowTypeId.Binary:
139-
if (!arrowArray.IsNull(index))
140-
{
141-
return ((BinaryArray)arrowArray).GetBytes(index).ToArray();
142-
}
143-
else
144-
{
145-
return null;
146-
}
158+
return ((BinaryArray)arrowArray).GetBytes(index).ToArray();
147159
case ArrowTypeId.List:
148160
return ((ListArray)arrowArray).GetSlicedValues(index);
149161
case ArrowTypeId.Struct:
@@ -161,15 +173,29 @@ public static class IArrowArrayExtensions
161173
}
162174

163175
/// <summary>
164-
/// Helper extension to get a value from the <see cref="IArrowArray"/> at the specified index.
176+
/// Overloaded. Helper extension to get a value converter for the <see href="IArrowType"/>.
165177
/// </summary>
166-
/// <param name="arrowArray">
167-
/// The Arrow array.
178+
/// <param name="arrayType">
179+
/// The return type of an item in a StructArray.
168180
/// </param>
169-
/// <param name="index">
170-
/// The index in the array to get the value from.
181+
public static Func<IArrowArray, int, object?> GetValueConverter(this IArrowType arrayType)
182+
{
183+
return GetValueConverter(arrayType, StructResultType.JsonString);
184+
}
185+
186+
/// <summary>
187+
/// Overloaded. Helper extension to get a value from the <see cref="IArrowArray"/> at the specified index.
188+
/// </summary>
189+
/// <param name="arrayType">
190+
/// The Arrow array type.
191+
/// </param>
192+
/// <param name="sourceType">
193+
/// The incoming <see cref="SourceStringType"/>.
171194
/// </param>
172-
public static Func<IArrowArray, int, object?> GetValueConverter(this IArrowType arrayType, StructResultType resultType = StructResultType.JsonString)
195+
/// <param name="resultType">
196+
/// The return type of an item in a StructArray.
197+
/// </param>
198+
public static Func<IArrowArray, int, object?> GetValueConverter(this IArrowType arrayType, StructResultType resultType)
173199
{
174200
if (arrayType == null) throw new ArgumentNullException(nameof(arrayType));
175201

@@ -208,23 +234,9 @@ public static class IArrowArrayExtensions
208234
case ArrowTypeId.Int64:
209235
return (array, index) => ((Int64Array)array).GetValue(index);
210236
case ArrowTypeId.String:
211-
return (array, index) =>
212-
{
213-
StringArray? sArray = array as StringArray;
214-
215-
if (sArray != null)
216-
{
217-
return sArray.GetString(index);
218-
}
219-
else
220-
{
221-
// some callers treat the Decimal256Array values as a string
222-
Decimal256Array? array256 = array as Decimal256Array;
223-
return array256?.GetString(index);
224-
}
225-
226-
throw new AdbcException($"Cannot get the value at {index}. A String type was requested but neither a StringArray or Decimal256Array was found.", AdbcStatusCode.InvalidData);
227-
};
237+
return (array, index) => array.Data.DataType.TypeId == ArrowTypeId.Decimal256 ?
238+
((Decimal256Array)array).GetString(index) :
239+
((StringArray)array).GetString(index);
228240
#if NET6_0_OR_GREATER
229241
case ArrowTypeId.Time32:
230242
return (array, index) => ((Time32Array)array).GetTime(index);
@@ -282,7 +294,9 @@ public static class IArrowArrayExtensions
282294
case ArrowTypeId.List:
283295
return (array, index) => ((ListArray)array).GetSlicedValues(index);
284296
case ArrowTypeId.Struct:
285-
return (array, index) => resultType == StructResultType.JsonString ? SerializeToJson((StructArray)array, index) : ParseStructArray((StructArray)array, index) ;
297+
return resultType == StructResultType.JsonString ?
298+
(array, index) => SerializeToJson((StructArray)array, index) :
299+
(array, index) => ParseStructArray((StructArray)array, index);
286300

287301
// not covered:
288302
// -- map array
@@ -299,21 +313,20 @@ public static class IArrowArrayExtensions
299313
/// </summary>
300314
private static string SerializeToJson(StructArray structArray, int index)
301315
{
302-
ExpandoObject? obj = ParseStructArray(structArray, index);
316+
Dictionary<string, object?>? obj = ParseStructArray(structArray, index);
303317

304318
return JsonSerializer.Serialize(obj);
305319
}
306320

307321
/// <summary>
308-
/// Converts an item in the StructArray at the index position to an ExpandoObject.
322+
/// Converts an item in the StructArray at the index position to a Dictionary<string, object?>.
309323
/// </summary>
310-
private static ExpandoObject? ParseStructArray(StructArray structArray, int index)
324+
private static Dictionary<string, object?>? ParseStructArray(StructArray structArray, int index)
311325
{
312326
if (structArray.IsNull(index))
313327
return null;
314328

315-
var expando = new ExpandoObject();
316-
var jsonDictionary = (IDictionary<string, object?>)expando;
329+
Dictionary<string, object?> jsonDictionary = new Dictionary<string, object?>();
317330

318331
StructType structType = (StructType)structArray.Data.DataType;
319332
for (int i = 0; i < structArray.Data.Children.Length; i++)
@@ -323,7 +336,7 @@ private static string SerializeToJson(StructArray structArray, int index)
323336

324337
if (value is StructArray structArray1)
325338
{
326-
List<ExpandoObject?> children = new List<ExpandoObject?>();
339+
List<Dictionary<string, object?>?> children = new List<Dictionary<string, object?>?>();
327340

328341
for (int j = 0; j < structArray1.Length; j++)
329342
{
@@ -363,7 +376,7 @@ private static string SerializeToJson(StructArray structArray, int index)
363376
}
364377
}
365378

366-
return expando;
379+
return jsonDictionary;
367380
}
368381

369382
/// <summary>

csharp/src/Client/SchemaConverter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
*/
1717

1818
using System;
19+
using System.Collections.Generic;
1920
using System.Data;
2021
using System.Data.Common;
2122
using System.Data.SqlTypes;
22-
using System.Dynamic;
2323
using Apache.Arrow.Scalars;
2424
using Apache.Arrow.Types;
2525

@@ -194,7 +194,7 @@ public static Type GetArrowType(Field f, DecimalBehavior decimalBehavior, Struct
194194
return typeof(string);
195195

196196
case ArrowTypeId.Struct:
197-
return structBehavior == StructBehavior.JsonString ? typeof(string) : typeof(ExpandoObject);
197+
return structBehavior == StructBehavior.JsonString ? typeof(string) : typeof(Dictionary<string, object?>);
198198

199199
case ArrowTypeId.Timestamp:
200200
return typeof(DateTimeOffset);

csharp/src/Client/readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,5 @@ These properties are:
8080

8181
- __AdbcConnectionTimeout__ - This specifies the connection timeout value. The value needs to be in the form (driver.property.name, integer, unit) where the unit is one of `s` or `ms`, For example, `AdbcConnectionTimeout=(adbc.snowflake.sql.client_option.client_timeout,30,s)` would set the connection timeout to 30 seconds.
8282
- __AdbcCommandTimeout__ - This specifies the command timeout value. This follows the same pattern as `AdbcConnectionTimeout` and sets the `AdbcCommandTimeoutProperty` and `CommandTimeout` values on the `AdbcCommand` object.
83-
- __StructBehavior__ - This specifies the StructBehavior when working with Arrow Struct arrays. The valid values are `JsonString` (the default) or `Strict` (treat the struct as a native type). If using JsonString, the return ArrowType will be StringType and a string value. If using Strict, the return ArrowType will be StructType and an ExpandoObject.
83+
- __StructBehavior__ - This specifies the StructBehavior when working with Arrow Struct arrays. The valid values are `JsonString` (the default) or `Strict` (treat the struct as a native type). If using JsonString, the return ArrowType will be StringType and the result a string value. If using Strict, the return ArrowType will be StructType and the result a Dictionary<string, object?>.
8484
- __DecimalBehavior__ - This specifies the DecimalBehavior when parsing decimal values from Arrow libraries. The valid values are `UseSqlDecimal` or `OverflowDecimalAsString` where values like Decimal256 are treated as strings.

csharp/src/Drivers/BigQuery/BigQueryStatement.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,7 +374,7 @@ sealed class ReadRowsStream : Stream
374374
ReadOnlyMemory<byte> currentBuffer;
375375
bool first;
376376
int position;
377-
bool hasRows = true;
377+
bool hasRows;
378378

379379
public ReadRowsStream(IAsyncEnumerator<ReadRowsResponse> response)
380380
{
@@ -383,6 +383,7 @@ public ReadRowsStream(IAsyncEnumerator<ReadRowsResponse> response)
383383
if (response.Current != null)
384384
{
385385
this.currentBuffer = response.Current.ArrowSchema.SerializedSchema.Memory;
386+
this.hasRows = true;
386387
}
387388
else
388389
{
@@ -393,7 +394,7 @@ public ReadRowsStream(IAsyncEnumerator<ReadRowsResponse> response)
393394
this.first = true;
394395
}
395396

396-
public bool HasRows { get => this.hasRows; }
397+
public bool HasRows => this.hasRows;
397398

398399
public override bool CanRead => true;
399400

csharp/test/Apache.Arrow.Adbc.Tests/ClientTests.cs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
using System.Collections.ObjectModel;
2222
using System.Data;
2323
using System.Data.Common;
24-
using System.Dynamic;
2524
using System.Linq;
2625
using Apache.Arrow.Adbc.Client;
2726
using Apache.Arrow.Types;
@@ -279,15 +278,15 @@ static void AssertTypeAndValue(
279278
{
280279
bool areEqual = false;
281280

282-
if (value is ExpandoObject)
281+
if (value is Dictionary<string, object?>)
283282
{
284283
if (value == null && ctv.ExpectedValue == null)
285284
{
286285
areEqual = true;
287286
}
288287
else
289288
{
290-
areEqual = AreExpandoObjectsEqual(value as ExpandoObject, ctv.ExpectedValue as ExpandoObject);
289+
areEqual = AreDictionariesEqual(value as Dictionary<string, object?>, ctv.ExpectedValue as Dictionary<string, object?>);
291290
}
292291
}
293292
else
@@ -332,39 +331,34 @@ static void AssertTypeAndValue(
332331
}
333332
}
334333

335-
static bool AreExpandoObjectsEqual(ExpandoObject? obj1, ExpandoObject? obj2)
334+
static bool AreDictionariesEqual(Dictionary<string, object?>? dict1, Dictionary<string, object?>? dict2)
336335
{
337-
if (obj1 == null && obj2 == null)
336+
if (dict1 == null && dict2 == null)
338337
{
339338
return true;
340339
}
341-
else if (obj1 != null && obj2 == null)
340+
else if (dict1 != null && dict2 == null)
342341
{
343342
return false;
344343
}
345-
else if (obj1 == null && obj2 != null)
344+
else if (dict1 == null && dict2 != null)
346345
{
347346
return false;
348347
}
349348

350-
var dict1 = (IDictionary<string, object?>)obj1!;
351-
var dict2 = (IDictionary<string, object?>)obj2!;
352-
353-
if (dict1.Count != dict2.Count)
349+
if (dict1!.Count != dict2!.Count)
354350
return false;
355351

356352
foreach (var key in dict1.Keys)
357353
{
358-
if (!dict2.ContainsKey(key))
354+
if (!dict2.TryGetValue(key, out object? value2))
359355
return false;
360356

361357
object? value1 = dict1[key];
362-
object? value2 = dict2[key];
363358

364-
if (value1 is ExpandoObject expando1 && value2 is ExpandoObject expando2)
359+
if (value1 is Dictionary<string, object?> nextObj1 && value2 is Dictionary<string, object?> nextObj2)
365360
{
366-
// Recursively compare nested ExpandoObjects
367-
if (!AreExpandoObjectsEqual(expando1, expando2))
361+
if (!AreDictionariesEqual(nextObj1, nextObj2))
368362
return false;
369363
}
370364
else if (!object.Equals(value1, value2))

csharp/test/Drivers/BigQuery/BigQueryData.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,9 @@ public static SampleDataBuilder GetSampleData()
4444

4545
SampleDataBuilder sampleDataBuilder = new SampleDataBuilder();
4646

47-
ExpandoObject person = new ExpandoObject();
48-
IDictionary<string, object?> keyValues = (IDictionary<string, object?>)person;
49-
keyValues["name"] = "John Doe";
50-
keyValues["age"] = 30L;
47+
Dictionary<string, object?> person = new Dictionary<string, object?>();
48+
person["name"] = "John Doe";
49+
person["age"] = 30L;
5150

5251
// StructBehavior = "Strict"
5352
sampleDataBuilder.Samples.Add(
@@ -58,7 +57,7 @@ public static SampleDataBuilder GetSampleData()
5857
StructBehavior = "Strict",
5958
ExpectedValues = new List<ColumnNetTypeArrowTypeValue>()
6059
{
61-
new ColumnNetTypeArrowTypeValue("person", typeof(ExpandoObject), typeof(StructType), person),
60+
new ColumnNetTypeArrowTypeValue("person", typeof(Dictionary<string, object?>), typeof(StructType), person),
6261
}
6362
});
6463

@@ -116,7 +115,7 @@ public static SampleDataBuilder GetSampleData()
116115
new ColumnNetTypeArrowTypeValue("point", typeof(string), typeof(StringType), "POINT(1 2)"),
117116
new ColumnNetTypeArrowTypeValue("numbers", typeof(Int64Array), typeof(ListType), numbersArray),
118117

119-
new ColumnNetTypeArrowTypeValue("person", typeof(ExpandoObject), typeof(StructType), person),
118+
new ColumnNetTypeArrowTypeValue("person", typeof(Dictionary<string, object?>), typeof(StructType), person),
120119
new ColumnNetTypeArrowTypeValue("json", typeof(string), typeof(StringType), "{\"age\":29,\"name\":\"Jane Doe\"}")
121120
}
122121
});

0 commit comments

Comments
 (0)