Skip to content

Commit

Permalink
GH-37231: [MATLAB] Add arrow.type.Time32Type class and `arrow.time3…
Browse files Browse the repository at this point in the history
…2` construction function (#37250)

### Rationale for this change

To support the addition of `arrow.array.Time32Array`, this pull request adds a new `arrow.type.Time32Type` class and associated `arrow.time32` construction function to the MATLAB interface.

### What changes are included in this PR?

1. New `arrow.type.Time32Type` class.
2. New `arrow.time32` construction function that returns an `arrow.type.Time32Type` instance.

**Example**

```matlab
>> type = arrow.time32(TimeUnit="Millisecond")

type = 

  Time32Type with properties:

          ID: Time32
    TimeUnit: Millisecond

>> class(type)

ans =

    'arrow.type.Time32Type'
```

### Are these changes tested?

Yes.

1. Added new tests for `Time32` type ID enumeration to `tID`.
2. Added a test class `tTimeUnit` for the new validation function `arrow.internal.validate.temporal.timeUnit`.
4. Added a new test class `tTime32Type`.

### Are there any user-facing changes?

Yes.

There are two new user-facing APIs:

1. `arrow.time32` construction function
2. `arrow.type.Time32Type` class

### Future Directions:

1. #37232
2. #37229
3.  #37230
4. #37251

### Notes

1. Thank you @ sgilmore10 for your help with this pull request!
* Closes: #37231

Lead-authored-by: Kevin Gurney <kgurney@mathworks.com>
Co-authored-by: Sarah Gilmore <sgilmore@mathworks.com>
Signed-off-by: Kevin Gurney <kgurney@mathworks.com>
  • Loading branch information
kevingurney and sgilmore10 committed Aug 18, 2023
1 parent 61bff28 commit ec1602c
Show file tree
Hide file tree
Showing 12 changed files with 507 additions and 9 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 @@ -25,6 +25,7 @@
#include "arrow/matlab/type/proxy/primitive_ctype.h"
#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/field.h"
#include "arrow/matlab/io/feather/proxy/writer.h"
#include "arrow/matlab/io/feather/proxy/reader.h"
Expand Down Expand Up @@ -63,6 +64,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.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
60 changes: 60 additions & 0 deletions matlab/src/cpp/arrow/matlab/type/proxy/time32_type.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// 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/time32_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 {

Time32Type::Time32Type(std::shared_ptr<arrow::Time32Type> time32_type) : FixedWidthType(std::move(time32_type)) {
REGISTER_METHOD(Time32Type, getTimeUnit);
}

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

using Time32TypeProxy = arrow::matlab::type::proxy::Time32Type;

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::time32(timeunit);
auto time_type = std::static_pointer_cast<arrow::Time32Type>(type);
return std::make_shared<Time32TypeProxy>(std::move(time_type));
}

void Time32Type::getTimeUnit(libmexclass::proxy::method::Context& context) {
namespace mda = ::matlab::data;
mda::ArrayFactory factory;

auto time32_type = std::static_pointer_cast<arrow::Time32Type>(data_type);
const auto timeunit = time32_type->unit();
// Cast to uint8_t since there are only four supported TimeUnit enumeration values:
// Nanosecond, Microsecond, Millisecond, Second
auto timeunit_mda = factory.createScalar(static_cast<uint8_t>(timeunit));
context.outputs[0] = timeunit_mda;
}
}
39 changes: 39 additions & 0 deletions matlab/src/cpp/arrow/matlab/type/proxy/time32_type.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// 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/fixed_width_type.h"
#include "arrow/type_traits.h"

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

class Time32Type : public arrow::matlab::type::proxy::FixedWidthType {

public:
Time32Type(std::shared_ptr<arrow::Time32Type> time32_type);

~Time32Type() {}

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

protected:
void getTimeUnit(libmexclass::proxy::method::Context& context);
};

}

39 changes: 39 additions & 0 deletions matlab/src/matlab/+arrow/+internal/+validate/+temporal/timeUnit.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
%TIMEUNIT Validates whether the given arrow.type.TimeUnit enumeration
% value is supported for the specified temporal type.

% 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 timeUnit(temporalType, timeUnit)
arguments
temporalType (1,1) string {mustBeMember(temporalType, ["Time32", "Time64"])}
timeUnit (1,1) arrow.type.TimeUnit
end
import arrow.type.TimeUnit

switch temporalType
case "Time32"
if ~(timeUnit == TimeUnit.Second || timeUnit == TimeUnit.Millisecond)
errid = "arrow:validate:temporal:UnsupportedTime32TimeUnit";
msg = "Supported TimeUnit values for Time32Type are ""Second"" and ""Millisecond"".";
error(errid, msg);
end
case "Time64"
if ~(timeUnit == TimeUnit.Microsecond || timeUnit == TimeUnit.Nanosecond)
errid = "arrow:validate:temporal:UnsupportedTime64TimeUnit";
msg = "Supported TimeUnit values for Time64Type are ""Microsecond"" and ""Nanosecond"".";
error(errid, msg);
end
end
end
1 change: 1 addition & 0 deletions matlab/src/matlab/+arrow/+type/ID.m
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,6 @@
% Date32 (16)
% Date64 (17)
Timestamp (18)
Time32 (19)
end
end
38 changes: 38 additions & 0 deletions matlab/src/matlab/+arrow/+type/Time32Type.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
%TIME32TYPE Type class for time32 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 Time32Type < arrow.type.TemporalType

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

obj@arrow.type.TemporalType(proxy);
end
end

methods (Access=protected)
function group = getPropertyGroups(~)
targets = ["ID" "TimeUnit"];
group = matlab.mixin.util.PropertyGroup(targets);
end
end

end
25 changes: 25 additions & 0 deletions matlab/src/matlab/+arrow/time32.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
% 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 = time32(opts)
%TIME32 Creates an arrow.type.Time32Type object
arguments
opts.TimeUnit(1, 1) arrow.type.TimeUnit {timeUnit("Time32", opts.TimeUnit)} = arrow.type.TimeUnit.Second
end
import arrow.internal.validate.temporal.timeUnit
args = struct(TimeUnit=string(opts.TimeUnit));
proxy = arrow.internal.proxy.create("arrow.type.proxy.Time32Type", args);
type = arrow.type.Time32Type(proxy);
end
133 changes: 133 additions & 0 deletions matlab/test/arrow/internal/validate/temporal/tTimeUnit.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
%TTIMEUNIT Unit tests for arrow.internal.validate.temporal.timeUnit.

% 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 tTimeUnit < matlab.unittest.TestCase

methods(Test)

function ErrorIfUnsupportedTemporalType(testCase)
import arrow.internal.validate.temporal.timeUnit
import arrow.type.TimeUnit

temporalType = "abc";
unit = TimeUnit.Second;
fcn = @() timeUnit(temporalType, unit);
errid = "MATLAB:validators:mustBeMember";
testCase.verifyError(fcn, errid);

temporalType = 123;
unit = TimeUnit.Second;
fcn = @() timeUnit(temporalType, unit);
errid = "MATLAB:validators:mustBeMember";
testCase.verifyError(fcn, errid);

temporalType = [1, 2, 3];
unit = TimeUnit.Second;
fcn = @() timeUnit(temporalType, unit);
errid = "MATLAB:validation:IncompatibleSize";
testCase.verifyError(fcn, errid);
end

function ErrorIfUnsupportedTimeUnitType(testCase)
import arrow.internal.validate.temporal.timeUnit
import arrow.type.TimeUnit

temporalType = "Time32";
unit = "abc";
fcn = @() timeUnit(temporalType, unit);
errid = "MATLAB:validation:UnableToConvert";
testCase.verifyError(fcn, errid);

temporalType = "Time32";
unit = 123;
fcn = @() timeUnit(temporalType, unit);
errid = "MATLAB:validation:UnableToConvert";
testCase.verifyError(fcn, errid);

temporalType = "Time32";
unit = [1, 2, 3];
fcn = @() timeUnit(temporalType, unit);
errid = "MATLAB:validation:IncompatibleSize";
testCase.verifyError(fcn, errid);
end

function SupportedTime32TimeUnit(testCase)
import arrow.internal.validate.temporal.timeUnit
import arrow.type.TimeUnit

temporalType = "Time32";

unit = TimeUnit.Second;
fcn = @() timeUnit(temporalType, unit);
testCase.verifyWarningFree(fcn);

unit = TimeUnit.Millisecond;
fcn = @() timeUnit(temporalType, unit);
testCase.verifyWarningFree(fcn);
end

function SupportedTime64TimeUnit(testCase)
import arrow.internal.validate.temporal.timeUnit
import arrow.type.TimeUnit

temporalType = "Time64";

unit = TimeUnit.Microsecond;
fcn = @() timeUnit(temporalType, unit);
testCase.verifyWarningFree(fcn);

unit = TimeUnit.Nanosecond;
fcn = @() timeUnit(temporalType, unit);
testCase.verifyWarningFree(fcn);
end

function UnsupportedTime32TimeUnit(testCase)
import arrow.internal.validate.temporal.timeUnit
import arrow.type.TimeUnit

temporalType = "Time32";

unit = TimeUnit.Microsecond;
fcn = @() timeUnit(temporalType, unit);
errorID = "arrow:validate:temporal:UnsupportedTime32TimeUnit";
testCase.verifyError(fcn, errorID);

unit = TimeUnit.Nanosecond;
fcn = @() timeUnit(temporalType, unit);
errorID = "arrow:validate:temporal:UnsupportedTime32TimeUnit";
testCase.verifyError(fcn, errorID);
end

function UnsupportedTime64TimeUnit(testCase)
import arrow.internal.validate.temporal.timeUnit
import arrow.type.TimeUnit

temporalType = "Time64";

unit = TimeUnit.Second;
fcn = @() timeUnit(temporalType, unit);
errorID = "arrow:validate:temporal:UnsupportedTime64TimeUnit";
testCase.verifyError(fcn, errorID);

unit = TimeUnit.Millisecond;
fcn = @() timeUnit(temporalType, unit);
errorID = "arrow:validate:temporal:UnsupportedTime64TimeUnit";
testCase.verifyError(fcn, errorID);
end

end
end
29 changes: 22 additions & 7 deletions matlab/test/arrow/type/tID.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,29 @@ function verifyOnMatlabPath(tc)
function CastToUInt64(testCase)
import arrow.type.ID

typeIDs = [ID.Boolean, ID.UInt8, ID.Int8, ID.UInt16, ...
ID.Int16, ID.UInt32, ID.Int32, ID.UInt64, ...
ID.Int64, ID.Float32, ID.Float64];
typeIDs = dictionary( ...
ID.Boolean, 1, ...
ID.UInt8, 2, ...
ID.Int8, 3, ...
ID.UInt16, 4, ...
ID.Int16, 5, ...
ID.UInt32, 6, ...
ID.Int32, 7, ...
ID.UInt64, 8, ...
ID.Int64, 9, ...
ID.Float32, 11, ...
ID.Float64, 12, ...
ID.String, 13, ...
ID.Timestamp, 18, ...
ID.Time32, 19 ...
);

expectedValues = uint64([1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12]);
for ii = 1:numel(typeIDs)
actualValue = uint64(typeIDs(ii));
expectedValue = expectedValues(ii);
enumValues = typeIDs.keys();
uint64Values = uint64(typeIDs.values());

for ii = 1:numel(enumValues)
actualValue = uint64(enumValues(ii));
expectedValue = uint64Values(ii);
testCase.verifyEqual(actualValue, expectedValue);
end
end
Expand Down

0 comments on commit ec1602c

Please sign in to comment.