Skip to content

Commit

Permalink
apacheGH-37232: [MATLAB] Add arrow.type.Time64Type class and `arrow…
Browse files Browse the repository at this point in the history
….time64` construction function (apache#37287)

### Rationale for this change

To add support for `arrow.array.Time64Array`, we will need to add support for a `arrow.type.Time64Type` class and associated `arrow.time64` construction function to the MATLAB interface.

### What changes are included in this PR?

1. New `arrow.type.Time64Type` class.
2. New `arrow.time64` construction function that returns an `arrow.type.Time64Type` instance.

**Example**

```matlab
>> type = arrow.time64(TimeUnit="Nanosecond")

type = 

  Time64Type with properties:

          ID: Time64
    TimeUnit: Nanosecond

>> class(type)

ans =

    'arrow.type.Time64Type'
```

### Are these changes tested?

Yes.

1. Added a new test class `tTime64Type`.
2. Added new tests for `Time64` type ID enumeration to `tID`.

### Are there any user-facing changes?

Yes.

1. `arrow.time64` construction function
3. `arrow.type.Time64Type` class

### Future Directions

1. apache#37229
2. apache#37230 
3. Add `arrow.array.Time64Array` class  

* Closes: apache#37232

Authored-by: Sarah Gilmore <sgilmore@mathworks.com>
Signed-off-by: Kevin Gurney <kgurney@mathworks.com>
  • Loading branch information
sgilmore10 authored and loicalleyne committed Nov 13, 2023
1 parent f01f1bf commit 1a03dae
Show file tree
Hide file tree
Showing 9 changed files with 292 additions and 2 deletions.
2 changes: 2 additions & 0 deletions matlab/src/cpp/arrow/matlab/proxy/factory.cc
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "arrow/matlab/type/proxy/string_type.h"
#include "arrow/matlab/type/proxy/timestamp_type.h"
#include "arrow/matlab/type/proxy/time32_type.h"
#include "arrow/matlab/type/proxy/time64_type.h"
#include "arrow/matlab/type/proxy/field.h"
#include "arrow/matlab/io/feather/proxy/writer.h"
#include "arrow/matlab/io/feather/proxy/reader.h"
Expand Down Expand Up @@ -64,6 +65,7 @@ libmexclass::proxy::MakeResult Factory::make_proxy(const ClassName& class_name,
REGISTER_PROXY(arrow.type.proxy.BooleanType , arrow::matlab::type::proxy::PrimitiveCType<bool>);
REGISTER_PROXY(arrow.type.proxy.StringType , arrow::matlab::type::proxy::StringType);
REGISTER_PROXY(arrow.type.proxy.TimestampType , arrow::matlab::type::proxy::TimestampType);
REGISTER_PROXY(arrow.type.proxy.Time64Type , arrow::matlab::type::proxy::Time64Type);
REGISTER_PROXY(arrow.type.proxy.Time32Type , arrow::matlab::type::proxy::Time32Type);
REGISTER_PROXY(arrow.io.feather.proxy.Writer , arrow::matlab::io::feather::proxy::Writer);
REGISTER_PROXY(arrow.io.feather.proxy.Reader , arrow::matlab::io::feather::proxy::Reader);
Expand Down
46 changes: 46 additions & 0 deletions matlab/src/cpp/arrow/matlab/type/proxy/time64_type.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// 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.

#include "arrow/matlab/type/proxy/time64_type.h"
#include "arrow/matlab/type/time_unit.h"
#include "arrow/matlab/error/error.h"
#include "arrow/util/utf8.h"

namespace arrow::matlab::type::proxy {

Time64Type::Time64Type(std::shared_ptr<arrow::Time64Type> time64_type) : TimeType(std::move(time64_type)) {}

libmexclass::proxy::MakeResult Time64Type::make(const libmexclass::proxy::FunctionArguments& constructor_arguments) {
namespace mda = ::matlab::data;

using Time64TypeProxy = arrow::matlab::type::proxy::Time64Type;

mda::StructArray opts = constructor_arguments[0];

const mda::StringArray timeunit_mda = opts[0]["TimeUnit"];

// extract the time unit
const std::u16string& utf16_timeunit = timeunit_mda[0];
MATLAB_ASSIGN_OR_ERROR(const auto timeunit,
arrow::matlab::type::timeUnitFromString(utf16_timeunit),
error::UKNOWN_TIME_UNIT_ERROR_ID);

auto type = arrow::time64(timeunit);
auto time_type = std::static_pointer_cast<arrow::Time64Type>(type);
return std::make_shared<Time64TypeProxy>(std::move(time_type));
}
}
36 changes: 36 additions & 0 deletions matlab/src/cpp/arrow/matlab/type/proxy/time64_type.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// 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.

#pragma once

#include "arrow/matlab/type/proxy/time_type.h"

namespace arrow::matlab::type::proxy {

class Time64Type : public arrow::matlab::type::proxy::TimeType {

public:
Time64Type(std::shared_ptr<arrow::Time64Type> time64_type);

~Time64Type() {}

static libmexclass::proxy::MakeResult make(const libmexclass::proxy::FunctionArguments& constructor_arguments);

};

}

4 changes: 3 additions & 1 deletion matlab/src/matlab/+arrow/+type/ID.m
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
%ID Data type enumeration

% 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.
Expand All @@ -14,7 +16,6 @@
% permissions and limitations under the License.

classdef ID < uint64
%ID Data type enumeration
enumeration
Boolean (1)
UInt8 (2)
Expand All @@ -35,5 +36,6 @@
% Date64 (17)
Timestamp (18)
Time32 (19)
Time64 (20)
end
end
30 changes: 30 additions & 0 deletions matlab/src/matlab/+arrow/+type/Time64Type.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
%TIME64TYPE Type class for time64 data.

% 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.

classdef Time64Type < arrow.type.TimeType

methods
function obj = Time64Type(proxy)
arguments
proxy(1, 1) libmexclass.proxy.Proxy {validate(proxy, "arrow.type.proxy.Time64Type")}
end
import arrow.internal.proxy.validate
obj@arrow.type.TimeType(proxy);
end
end

end
26 changes: 26 additions & 0 deletions matlab/src/matlab/+arrow/time64.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
%TIME64 Creates an arrow.type.Time64Type object

% 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.

function type = time64(opts)
arguments
opts.TimeUnit(1, 1) arrow.type.TimeUnit {timeUnit("Time64", opts.TimeUnit)} = arrow.type.TimeUnit.Microsecond
end
import arrow.internal.validate.temporal.timeUnit
args = struct(TimeUnit=string(opts.TimeUnit));
proxy = arrow.internal.proxy.create("arrow.type.proxy.Time64Type", args);
type = arrow.type.Time64Type(proxy);
end
3 changes: 2 additions & 1 deletion matlab/test/arrow/type/tID.m
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ function CastToUInt64(testCase)
ID.Float64, 12, ...
ID.String, 13, ...
ID.Timestamp, 18, ...
ID.Time32, 19 ...
ID.Time32, 19, ...
ID.Time64, 20 ...
);

enumValues = typeIDs.keys();
Expand Down
146 changes: 146 additions & 0 deletions matlab/test/arrow/type/tTime64Type.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
%TTIME64TYPE Test class for arrow.type.Time64Type and arrow.time64

% 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.

classdef tTime64Type < hFixedWidthType

properties
ConstructionFcn = @arrow.time64
ArrowType = arrow.time64
TypeID = arrow.type.ID.Time64
BitWidth = int32(64)
ClassName = "arrow.type.Time64Type"
end

methods(Test)
function TestClass(testCase)
% Verify ArrowType is an object of the expected class type.
name = string(class(testCase.ArrowType));
testCase.verifyEqual(name, testCase.ClassName);
end

function DefaultTimeUnit(testCase)
% Verify the default TimeUnit is Microsecond.
type = testCase.ArrowType;
actualUnit = type.TimeUnit;
expectedUnit = arrow.type.TimeUnit.Microsecond;
testCase.verifyEqual(actualUnit, expectedUnit);
end

function SupplyTimeUnitEnum(testCase)
% Verify that TimeUnit can be specified as an enum value.
import arrow.type.*
expectedUnit = [TimeUnit.Microsecond, TimeUnit.Nanosecond];

for unit = expectedUnit
type = testCase.ConstructionFcn(TimeUnit=unit);
testCase.verifyEqual(type.TimeUnit, unit);
end
end

function SupplyTimeUnitString(testCase)
% Supply TimeUnit as a string value. Verify TimeUnit is set to
% the appropriate TimeUnit enum value.
import arrow.type.*
unitString = ["Microsecond", "Nanosecond"];
expectedUnit = [TimeUnit.Microsecond, TimeUnit.Nanosecond];

for ii = 1:numel(unitString)
type = testCase.ConstructionFcn(TimeUnit=unitString(ii));
testCase.verifyEqual(type.TimeUnit, expectedUnit(ii));
end
end

function ErrorIfAmbiguousTimeUnit(testCase)
% Verify that an error is thrown if an ambiguous value is
% provided for the TimeUnit name-value pair.
fcn = @() testCase.ConstructionFcn(TimeUnit="mi");
testCase.verifyError(fcn, "MATLAB:validation:UnableToConvert");
end

function ErrorIfTimeUnitIsNonScalar(testCase)
% Verify that an error is thrown if a nonscalar value is
% provided for the TimeUnit name-value pair.
units = [arrow.type.TimeUnit.Microsecond; arrow.type.TimeUnit.Nanosecond];
fcn = @() testCase.ConstructionFcn(TimeUnit=units);
testCase.verifyError(fcn, "MATLAB:validation:IncompatibleSize");

units = ["Microsecond" "Nanosecond"];
fcn = @() testCase.ConstructionFcn(TimeUnit=units);
testCase.verifyError(fcn, "MATLAB:validation:IncompatibleSize");
end

function Display(testCase)
% Verify the display of Time64Type objects.
%
% Example:
%
% Time64Type with properties:
%
% ID: Time64
% TimeUnit: Microsecond
%
type = testCase.ConstructionFcn(TimeUnit="Microsecond"); %#ok<NASGU>
classnameLink = "<a href=""matlab:helpPopup arrow.type.Time64Type"" style=""font-weight:bold"">Time64Type</a>";
header = " " + classnameLink + " with properties:" + newline;
body = strjust(pad(["ID:"; "TimeUnit:"]));
body = body + " " + ["Time64"; "Microsecond"];
body = " " + body;
footer = string(newline);
expectedDisplay = char(strjoin([header body' footer], newline));
actualDisplay = evalc('disp(type)');
testCase.verifyEqual(actualDisplay, expectedDisplay);
end

function TimeUnitNoSetter(testCase)
% Verify that an error is thrown when trying to set the value
% of the TimeUnit property.
schema = arrow.time64(TimeUnit="Nanosecond");
testCase.verifyError(@() setfield(schema, "TimeUnit", "Microsecond"), "MATLAB:class:SetProhibited");
end

function BitWidthNoSetter(testCase)
% Verify that an error is thrown when trying to set the value
% of the BitWidth property.
schema = arrow.time64(TimeUnit="Nanosecond");
testCase.verifyError(@() setfield(schema, "BitWidth", 32), "MATLAB:class:SetProhibited");
end

function IDNoSetter(testCase)
% Verify that an error is thrown when trying to set the value
% of the ID property.
schema = arrow.time64(TimeUnit="Nanosecond");
testCase.verifyError(@() setfield(schema, "ID", 15), "MATLAB:class:SetProhibited");
end

function NumFieldsNoSetter(testCase)
% Verify that an error is thrown when trying to set the value
% of the NumFields property.
schema = arrow.time64(TimeUnit="Nanosecond");
testCase.verifyError(@() setfield(schema, "NumFields", 2), "MATLAB:class:SetProhibited");
end

function InvalidProxy(testCase)
% Verify that an error is thrown when a Proxy of an unexpected
% type is passed to the arrow.type.Time64Type constructor.
array = arrow.array([1, 2, 3]);
proxy = array.Proxy;
testCase.verifyError(@() arrow.type.Time64Type(proxy), "arrow:proxy:ProxyNameMismatch");
end

end

end
1 change: 1 addition & 0 deletions matlab/tools/cmake/BuildMatlabArrowInterface.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_SOURCES "${CMAKE_SOURCE_DIR}/src/cpp/a
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/type/proxy/timestamp_type.cc"
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/type/proxy/time_type.cc"
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/type/proxy/time32_type.cc"
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/type/proxy/time64_type.cc"
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/type/proxy/field.cc"
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/type/proxy/wrap.cc"
"${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/io/feather/proxy/writer.cc"
Expand Down

0 comments on commit 1a03dae

Please sign in to comment.