Skip to content

Commit

Permalink
Small changes plus tests
Browse files Browse the repository at this point in the history
  • Loading branch information
CurtHagenlocher committed Oct 5, 2023
1 parent cc85740 commit e70a59e
Show file tree
Hide file tree
Showing 8 changed files with 205 additions and 3 deletions.
11 changes: 11 additions & 0 deletions csharp/src/Apache.Arrow/Arrays/DurationArray.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,17 @@ public DurationArray(ArrayData data)
data.EnsureDataType(ArrowTypeId.Duration);
}

public DurationType DataType => (DurationType)this.Data.DataType;

public TimeSpan? GetTimeSpan(int index)
{
if (index < 0 || index >= Length)
{
throw new ArgumentOutOfRangeException(nameof(index));
}
return IsValid(index) ? new TimeSpan(DataType.Unit.ConvertToTicks(Values[index])) : null;
}

public override void Accept(IArrowArrayVisitor visitor) => Accept(this, visitor);
}
}
2 changes: 1 addition & 1 deletion csharp/src/Apache.Arrow/Types/DurationType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

namespace Apache.Arrow.Types
{
public sealed class DurationType: TimeBasedType
public sealed class DurationType : TimeBasedType
{
public static readonly DurationType Second = new DurationType(TimeUnit.Second);
public static readonly DurationType Millisecond = new DurationType(TimeUnit.Millisecond);
Expand Down
2 changes: 2 additions & 0 deletions csharp/test/Apache.Arrow.IntegrationTest/JsonFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ private class ArrayCreator :
IArrowTypeVisitor<Date64Type>,
IArrowTypeVisitor<Time32Type>,
IArrowTypeVisitor<Time64Type>,
IArrowTypeVisitor<DurationType>,
IArrowTypeVisitor<TimestampType>,
IArrowTypeVisitor<StringType>,
IArrowTypeVisitor<BinaryType>,
Expand Down Expand Up @@ -396,6 +397,7 @@ public void Visit(BooleanType type)
public void Visit(DoubleType type) => GenerateArray<double, DoubleArray>((v, n, c, nc, o) => new DoubleArray(v, n, c, nc, o));
public void Visit(Time32Type type) => GenerateArray<int, Time32Array>((v, n, c, nc, o) => new Time32Array(type, v, n, c, nc, o));
public void Visit(Time64Type type) => GenerateLongArray<long, Time64Array>((v, n, c, nc, o) => new Time64Array(type, v, n, c, nc, o), s => long.Parse(s));
public void Visit(DurationType type) => GenerateLongArray<long, DurationArray>((v, n, c, nc, o) => new DurationArray(type, v, n, c, nc, o), s => long.Parse(s));

public void Visit(Decimal128Type type)
{
Expand Down
28 changes: 28 additions & 0 deletions csharp/test/Apache.Arrow.Tests/ArrowArrayConcatenatorTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ private class TestDataGenerator :
IArrowTypeVisitor<Decimal256Type>,
IArrowTypeVisitor<Date32Type>,
IArrowTypeVisitor<Date64Type>,
IArrowTypeVisitor<DurationType>,
IArrowTypeVisitor<TimestampType>,
IArrowTypeVisitor<ListType>,
IArrowTypeVisitor<FixedSizeListType>,
Expand Down Expand Up @@ -263,6 +264,33 @@ public void Visit(TimestampType type)
ExpectedArray = resultBuilder.Build();
}

public void Visit(DurationType type)
{
DurationArray.Builder resultBuilder = new DurationArray.Builder(type).Reserve(_baseDataTotalElementCount);
DateTimeOffset basis = DateTimeOffset.UtcNow;

for (int i = 0; i < _baseDataListCount; i++)
{
List<int?> dataList = _baseData[i];
DurationArray.Builder builder = new DurationArray.Builder(type).Reserve(dataList.Count);
foreach (int? value in dataList)
{
if (value.HasValue)
{
builder.Append(value.Value);
resultBuilder.Append(value.Value);
}
else
{
builder.AppendNull();
resultBuilder.AppendNull();
}
}
TestTargetArrayList.Add(builder.Build());
}

ExpectedArray = resultBuilder.Build();
}

public void Visit(BinaryType type)
{
Expand Down
16 changes: 15 additions & 1 deletion csharp/test/Apache.Arrow.Tests/CDataInterfacePythonTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ private static Schema GetTestSchema()

.Field(f => f.Name("map").DataType(new MapType(StringType.Default, Int32Type.Default)).Nullable(false))

.Field(f => f.Name("duration_s").DataType(DurationType.Second).Nullable(false))
.Field(f => f.Name("duration_ms").DataType(DurationType.Millisecond).Nullable(true))
.Field(f => f.Name("duration_us").DataType(DurationType.Microsecond).Nullable(false))
.Field(f => f.Name("duration_ns").DataType(DurationType.Nanosecond).Nullable(true))

// Checking wider characters.
.Field(f => f.Name("hello 你好 😄").DataType(BooleanType.Default).Nullable(true))

Expand Down Expand Up @@ -182,6 +187,11 @@ private static IEnumerable<dynamic> GetPythonFields()

yield return pa.field("map", pa.map_(pa.@string(), pa.int32()), false);

yield return pa.field("duration_s", pa.duration("s"), false);
yield return pa.field("duration_ms", pa.duration("ms"), true);
yield return pa.field("duration_us", pa.duration("us"), false);
yield return pa.field("duration_ns", pa.duration("ns"), true);

yield return pa.field("hello 你好 😄", pa.bool_(), true);
}
}
Expand Down Expand Up @@ -520,8 +530,9 @@ public unsafe void ImportRecordBatch()
List(0, 0, 1, 2, 4, 10),
pa.array(List("one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten")),
pa.array(List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10))),
pa.array(List(1234, 2345, 3456, null, 6789), pa.duration("ms")),
}),
new[] { "col1", "col2", "col3", "col4", "col5", "col6", "col7", "col8", "col9", "col10" });
new[] { "col1", "col2", "col3", "col4", "col5", "col6", "col7", "col8", "col9", "col10", "col11" });

dynamic batch = table.to_batches()[0];

Expand Down Expand Up @@ -598,6 +609,9 @@ public unsafe void ImportRecordBatch()
Assert.Equal(5, col10.Length);
Assert.Equal(new int[] { 0, 0, 1, 2, 4, 10}, col10.ValueOffsets.ToArray());
Assert.Equal(new long?[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, ((Int64Array)col10.Values).ToList().ToArray());

DurationArray col11 = (DurationArray)recordBatch.Column("col11");
Assert.Equal(5, col11.Length);
}

[SkippableFact]
Expand Down
134 changes: 134 additions & 0 deletions csharp/test/Apache.Arrow.Tests/DurationArrayTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

using System;
using System.Collections.Generic;
using System.Linq;
using Apache.Arrow.Types;
using Xunit;

namespace Apache.Arrow.Tests
{
public class DurationArrayTests
{
private const long TicksPerMicrosecond = 10;

private static readonly TimeSpan?[] _exampleTimeSpans =
{
null,
TimeSpan.FromDays(10.5),
TimeSpan.FromHours(10.5),
TimeSpan.FromMinutes(10.5),
TimeSpan.FromSeconds(10.5),
TimeSpan.FromMilliseconds(10.5),
TimeSpan.FromTicks(11),
};

private static readonly long?[] _exampleDurations =
{
null,
1,
1000,
1000000,
1000000000,
1000000000000,
};

private static readonly DurationType[] _durationTypes =
{
DurationType.Second,
DurationType.Millisecond,
DurationType.Microsecond,
DurationType.Nanosecond,
};

public static IEnumerable<object[]> GetTimeSpansData() =>
from timeSpan in _exampleTimeSpans
from type in _durationTypes
where type.Unit >= RequiredPrecision(timeSpan)
select new object[] { timeSpan, type };

public static IEnumerable<object[]> GetDurationsData() =>
from duration in _exampleDurations
from type in _durationTypes
select new object[] { duration, type };

static TimeUnit RequiredPrecision(TimeSpan? timeSpan)
{
if (timeSpan == null) { return TimeUnit.Second; }
if ((timeSpan.Value.Ticks % TicksPerMicrosecond) > 0) { return TimeUnit.Nanosecond; }
if (timeSpan.Value.Microseconds > 0) { return TimeUnit.Microsecond; }
if (timeSpan.Value.Milliseconds > 0) { return TimeUnit.Millisecond; }
return TimeUnit.Second;
}

public class AppendNull
{
[Fact]
public void AppendThenGetGivesNull()
{
// Arrange
var builder = new DurationArray.Builder(DurationType.Millisecond);

// Act
builder = builder.AppendNull();

// Assert
var array = builder.Build();
Assert.Equal(1, array.Length);
Assert.Null(array.GetValue(0));
Assert.Null(array.GetTimeSpan(0));
}
}

public class AppendTimeSpan
{
[Theory]
[MemberData(nameof(GetTimeSpansData), MemberType = typeof(DurationArrayTests))]
public void AppendTimeSpanGivesSameTimeSpan(TimeSpan? timeSpan, DurationType type)
{
// Arrange
var builder = new DurationArray.Builder(type);

// Act
builder = builder.Append(timeSpan);

// Assert
var array = builder.Build();
Assert.Equal(1, array.Length);
Assert.Equal(timeSpan, array.GetTimeSpan(0));
}
}

public class AppendDuration
{
[Theory]
[MemberData(nameof(GetDurationsData), MemberType = typeof(DurationArrayTests))]
public void AppendDurationGivesSameDuration(long? duration, DurationType type)
{
// Arrange
var builder = new DurationArray.Builder(type);

// Act
builder = builder.Append(duration);

// Assert
var array = builder.Build();
Assert.Equal(1, array.Length);
Assert.Equal(duration, array.GetValue(0));
}
}
}
}
13 changes: 13 additions & 0 deletions csharp/test/Apache.Arrow.Tests/TestData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ private class ArrayCreator :
IArrowTypeVisitor<Date64Type>,
IArrowTypeVisitor<Time32Type>,
IArrowTypeVisitor<Time64Type>,
IArrowTypeVisitor<DurationType>,
IArrowTypeVisitor<Int8Type>,
IArrowTypeVisitor<Int16Type>,
IArrowTypeVisitor<Int32Type>,
Expand Down Expand Up @@ -233,6 +234,18 @@ public void Visit(Time64Type type)
Array = builder.Build();
}

public void Visit(DurationType type)
{
var builder = new DurationArray.Builder(type).Reserve(Length);

for (var i = 0; i < Length; i++)
{
builder.Append(i);
}

Array = builder.Build();
}

public void Visit(TimestampType type)
{
var builder = new TimestampArray.Builder().Reserve(Length);
Expand Down
2 changes: 1 addition & 1 deletion docs/source/status.rst
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Data Types
+-------------------+-------+-------+-------+------------+-------+-------+-------+-------+
| Timestamp |||||||| |
+-------------------+-------+-------+-------+------------+-------+-------+-------+-------+
| Duration ||||| ||| |
| Duration ||||| ||| |
+-------------------+-------+-------+-------+------------+-------+-------+-------+-------+
| Interval |||| | ||| |
+-------------------+-------+-------+-------+------------+-------+-------+-------+-------+
Expand Down

0 comments on commit e70a59e

Please sign in to comment.