From a7f5ee01b5949687bbc3b3918454860c6db6934c Mon Sep 17 00:00:00 2001 From: sgilmore10 <74676073+sgilmore10@users.noreply.github.com> Date: Mon, 18 Sep 2023 11:26:34 -0400 Subject: [PATCH] GH-37724: [MATLAB] Add `arrow.type.StructType` MATLAB class (#37749) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ### Rationale for this change In order to add a `arrow.array.StructArray` MATLAB class (https://github.com/apache/arrow/issues/37653), we first need to implement the `arrow.type.StructType` MATLAB class. ### What changes are included in this PR? 1. Added a new MATLAB class `arrow.type.StructType` 2. Added convenience constructor function `arrow.struct()` 3. Added `Struct` as a enumeration value to `arrow.type.ID` 4. Added `arrow.type.traits.StructTraits` MATLAB class. Some of its properties, such as `ArrayConstructor` and `ArrayProxyClassName`, are set to `missing` because they require `arrow.array.StructArray` (#37653). When that class is added, we can initialize these properties to correct values. **Example Usage** ```matlab >> fieldA = arrow.field("A", arrow.int32()); >> fieldB = arrow.field("B", arrow.timestamp(TimeZone="America/New_York")); >> fieldC = arrow.field("C", arrow.string()); >> structType = arrow.struct(fieldA, fieldB, fieldC) structType = StructType with properties: ID: Struct Fields: [1×3 arrow.type.Field] >> fieldBFromStruct = structType.field(2) fieldBFromStruct = B: timestamp[us, tz=America/New_York] ``` ### Are these changes tested? Yes. 1. Added a new test class called `tStructType.m` 2. Added a new test case to `tTypeDisplay.m` 3. Updated test case in `tID.m` ### Are there any user-facing changes? Yes. Users can now create an `arrow.type.StructType` object using the new `arrow.struct()` funciton. ### Future Directions 1. #37653 * Closes: #37724 Authored-by: Sarah Gilmore Signed-off-by: Kevin Gurney --- matlab/src/cpp/arrow/matlab/proxy/factory.cc | 2 + .../arrow/matlab/type/proxy/struct_type.cc | 45 +++++ .../cpp/arrow/matlab/type/proxy/struct_type.h | 34 ++++ .../src/cpp/arrow/matlab/type/proxy/wrap.cc | 3 + .../+arrow/+type/+traits/StructTraits.m | 36 ++++ .../src/matlab/+arrow/+type/+traits/traits.m | 2 + matlab/src/matlab/+arrow/+type/ID.m | 6 + matlab/src/matlab/+arrow/+type/StructType.m | 46 +++++ matlab/src/matlab/+arrow/+type/Type.m | 2 +- matlab/src/matlab/+arrow/struct.m | 43 ++++ matlab/test/arrow/type/tField.m | 1 + matlab/test/arrow/type/tID.m | 3 +- matlab/test/arrow/type/tStructType.m | 190 ++++++++++++++++++ matlab/test/arrow/type/tTypeDisplay.m | 28 ++- matlab/test/arrow/type/traits/tStructTraits.m | 31 +++ matlab/test/arrow/type/traits/ttraits.m | 12 ++ .../cmake/BuildMatlabArrowInterface.cmake | 1 + 17 files changed, 482 insertions(+), 3 deletions(-) create mode 100644 matlab/src/cpp/arrow/matlab/type/proxy/struct_type.cc create mode 100644 matlab/src/cpp/arrow/matlab/type/proxy/struct_type.h create mode 100644 matlab/src/matlab/+arrow/+type/+traits/StructTraits.m create mode 100644 matlab/src/matlab/+arrow/+type/StructType.m create mode 100644 matlab/src/matlab/+arrow/struct.m create mode 100644 matlab/test/arrow/type/tStructType.m create mode 100644 matlab/test/arrow/type/traits/tStructTraits.m diff --git a/matlab/src/cpp/arrow/matlab/proxy/factory.cc b/matlab/src/cpp/arrow/matlab/proxy/factory.cc index 4035725f2b382..ebeb020a9e7c7 100644 --- a/matlab/src/cpp/arrow/matlab/proxy/factory.cc +++ b/matlab/src/cpp/arrow/matlab/proxy/factory.cc @@ -33,6 +33,7 @@ #include "arrow/matlab/type/proxy/date64_type.h" #include "arrow/matlab/type/proxy/time32_type.h" #include "arrow/matlab/type/proxy/time64_type.h" +#include "arrow/matlab/type/proxy/struct_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" @@ -81,6 +82,7 @@ libmexclass::proxy::MakeResult Factory::make_proxy(const ClassName& class_name, REGISTER_PROXY(arrow.type.proxy.Time64Type , arrow::matlab::type::proxy::Time64Type); REGISTER_PROXY(arrow.type.proxy.Date32Type , arrow::matlab::type::proxy::Date32Type); REGISTER_PROXY(arrow.type.proxy.Date64Type , arrow::matlab::type::proxy::Date64Type); + REGISTER_PROXY(arrow.type.proxy.StructType , arrow::matlab::type::proxy::StructType); 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); diff --git a/matlab/src/cpp/arrow/matlab/type/proxy/struct_type.cc b/matlab/src/cpp/arrow/matlab/type/proxy/struct_type.cc new file mode 100644 index 0000000000000..fbb8dc3f6edbe --- /dev/null +++ b/matlab/src/cpp/arrow/matlab/type/proxy/struct_type.cc @@ -0,0 +1,45 @@ +// 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/struct_type.h" +#include "arrow/matlab/type/proxy/field.h" +#include "libmexclass/proxy/ProxyManager.h" + +namespace arrow::matlab::type::proxy { + + StructType::StructType(std::shared_ptr struct_type) : Type(std::move(struct_type)) {} + + libmexclass::proxy::MakeResult StructType::make(const libmexclass::proxy::FunctionArguments& constructor_arguments) { + namespace mda = ::matlab::data; + using StructTypeProxy = arrow::matlab::type::proxy::StructType; + + mda::StructArray args = constructor_arguments[0]; + const mda::TypedArray field_proxy_ids_mda = args[0]["FieldProxyIDs"]; + + std::vector> fields; + fields.reserve(field_proxy_ids_mda.getNumberOfElements()); + for (const auto proxy_id : field_proxy_ids_mda) { + using namespace libmexclass::proxy; + auto proxy = std::static_pointer_cast(ProxyManager::getProxy(proxy_id)); + auto field = proxy->unwrap(); + fields.push_back(field); + } + + auto struct_type = std::static_pointer_cast(arrow::struct_(fields)); + return std::make_shared(std::move(struct_type)); + } +} \ No newline at end of file diff --git a/matlab/src/cpp/arrow/matlab/type/proxy/struct_type.h b/matlab/src/cpp/arrow/matlab/type/proxy/struct_type.h new file mode 100644 index 0000000000000..8ec6217b34278 --- /dev/null +++ b/matlab/src/cpp/arrow/matlab/type/proxy/struct_type.h @@ -0,0 +1,34 @@ +// 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/type.h" + +namespace arrow::matlab::type::proxy { + + class StructType : public arrow::matlab::type::proxy::Type { + + public: + StructType(std::shared_ptr struct_type); + + ~StructType() {} + + static libmexclass::proxy::MakeResult make(const libmexclass::proxy::FunctionArguments& constructor_arguments); +}; + +} \ No newline at end of file diff --git a/matlab/src/cpp/arrow/matlab/type/proxy/wrap.cc b/matlab/src/cpp/arrow/matlab/type/proxy/wrap.cc index 91a1e353496c7..3dd86e91409fa 100644 --- a/matlab/src/cpp/arrow/matlab/type/proxy/wrap.cc +++ b/matlab/src/cpp/arrow/matlab/type/proxy/wrap.cc @@ -24,6 +24,7 @@ #include "arrow/matlab/type/proxy/date32_type.h" #include "arrow/matlab/type/proxy/date64_type.h" #include "arrow/matlab/type/proxy/string_type.h" +#include "arrow/matlab/type/proxy/struct_type.h" namespace arrow::matlab::type::proxy { @@ -64,6 +65,8 @@ namespace arrow::matlab::type::proxy { return std::make_shared(std::static_pointer_cast(type)); case ID::STRING: return std::make_shared(std::static_pointer_cast(type)); + case ID::STRUCT: + return std::make_shared(std::static_pointer_cast(type)); default: return arrow::Status::NotImplemented("Unsupported DataType: " + type->ToString()); } diff --git a/matlab/src/matlab/+arrow/+type/+traits/StructTraits.m b/matlab/src/matlab/+arrow/+type/+traits/StructTraits.m new file mode 100644 index 0000000000000..a8ed98f8ae468 --- /dev/null +++ b/matlab/src/matlab/+arrow/+type/+traits/StructTraits.m @@ -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. + +classdef StructTraits < arrow.type.traits.TypeTraits + + properties (Constant) + % TODO: When arrow.array.StructArray is implemented, set these + % properties appropriately + ArrayConstructor = missing + ArrayClassName = missing + ArrayProxyClassName = missing + ArrayStaticConstructor = missing + + TypeConstructor = @arrow.type.StructType + TypeClassName = "arrow.type.StructType" + TypeProxyClassName = "arrow.type.proxy.StructType" + + % TODO: When arrow.array.StructArray is implemented, set these + % properties appropriately + MatlabConstructor = missing + MatlabClassName = missing + end + +end \ No newline at end of file diff --git a/matlab/src/matlab/+arrow/+type/+traits/traits.m b/matlab/src/matlab/+arrow/+type/+traits/traits.m index 78804fdccb3f0..f737108ce5f76 100644 --- a/matlab/src/matlab/+arrow/+type/+traits/traits.m +++ b/matlab/src/matlab/+arrow/+type/+traits/traits.m @@ -56,6 +56,8 @@ typeTraits = Date32Traits(); case ID.Date64 typeTraits = Date64Traits(); + case ID.Struct + typeTraits = StructTraits(); otherwise error("arrow:type:traits:UnsupportedArrowTypeID", "Unsupported Arrow type ID: " + type); end diff --git a/matlab/src/matlab/+arrow/+type/ID.m b/matlab/src/matlab/+arrow/+type/ID.m index 646edb85c6632..b2c4facbe4065 100644 --- a/matlab/src/matlab/+arrow/+type/ID.m +++ b/matlab/src/matlab/+arrow/+type/ID.m @@ -37,5 +37,11 @@ Timestamp (18) Time32 (19) Time64 (20) + % IntervalMonths (21) + % IntervalDayTime (22) + % Decimal128 (23) + % Decimal256 (24) + % List (25) + Struct (26) end end diff --git a/matlab/src/matlab/+arrow/+type/StructType.m b/matlab/src/matlab/+arrow/+type/StructType.m new file mode 100644 index 0000000000000..6c1318f6376f3 --- /dev/null +++ b/matlab/src/matlab/+arrow/+type/StructType.m @@ -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. + +classdef StructType < arrow.type.Type + + methods + function obj = StructType(proxy) + arguments + proxy(1, 1) libmexclass.proxy.Proxy {validate(proxy, "arrow.type.proxy.StructType")} + end + import arrow.internal.proxy.validate + obj@arrow.type.Type(proxy); + end + end + + methods(Access = protected) + function groups = getDisplayPropertyGroups(obj) + targets = ["ID", "Fields"]; + groups = matlab.mixin.util.PropertyGroup(targets); + end + end + + methods (Hidden) + % TODO: Consider using a mixin approach to add this behavior. For + % example, ChunkedArray's toMATLAB method could check if its + % Type inherits from a mixin called "Preallocateable" (or something + % more descriptive). If so, we can call preallocateMATLABArray + % in the toMATLAB method. + function preallocateMATLABArray(~) + error("arrow:type:UnsupportedFunction", ... + "preallocateMATLABArray is not supported for StructType"); + end + end +end \ No newline at end of file diff --git a/matlab/src/matlab/+arrow/+type/Type.m b/matlab/src/matlab/+arrow/+type/Type.m index 0fd0139b18b7a..6dc4fbc438f34 100644 --- a/matlab/src/matlab/+arrow/+type/Type.m +++ b/matlab/src/matlab/+arrow/+type/Type.m @@ -62,7 +62,7 @@ for ii = 1:numFields fields{ii} = obj.field(ii); end - fields = horzcat(fields); + fields = horzcat(fields{:}); end end end diff --git a/matlab/src/matlab/+arrow/struct.m b/matlab/src/matlab/+arrow/struct.m new file mode 100644 index 0000000000000..2fdbd6a9864fd --- /dev/null +++ b/matlab/src/matlab/+arrow/struct.m @@ -0,0 +1,43 @@ +%STRUCT Constructs an arrow.type.StructType 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 = struct(fields) + arguments(Repeating) + fields(1, :) arrow.type.Field {mustBeNonempty} + end + + % Must have at least one Field in a Struct + if isempty(fields) + error("arrow:struct:TooFewInputs", ... + "Must supply at least one arrow.type.Field"); + end + + fields = horzcat(fields{:}); + + % Extract the corresponding Proxy IDs from each of the + % supplied arrow.type.Field objects. + numFields = numel(fields); + fieldProxyIDs = zeros(1, numFields, "uint64"); + for ii = 1:numFields + fieldProxyIDs(ii) = fields(ii).Proxy.ID; + end + + % Construct an Arrow Field Proxy in C++ from the supplied Field Proxy IDs. + args = struct(FieldProxyIDs=fieldProxyIDs); + proxy = arrow.internal.proxy.create("arrow.type.proxy.StructType", args); + type = arrow.type.StructType(proxy); +end \ No newline at end of file diff --git a/matlab/test/arrow/type/tField.m b/matlab/test/arrow/type/tField.m index dba7190b49ce2..1a89c0077b5ae 100644 --- a/matlab/test/arrow/type/tField.m +++ b/matlab/test/arrow/type/tField.m @@ -42,6 +42,7 @@ function TestSupportedTypes(testCase) arrow.float64, ... arrow.string, ... arrow.timestamp, ... + arrow.struct(arrow.field("A", arrow.float32())) }; for ii = 1:numel(supportedTypes) supportedType = supportedTypes{ii}; diff --git a/matlab/test/arrow/type/tID.m b/matlab/test/arrow/type/tID.m index b69cd89842d73..e97d77e81c124 100644 --- a/matlab/test/arrow/type/tID.m +++ b/matlab/test/arrow/type/tID.m @@ -46,7 +46,8 @@ function CastToUInt64(testCase) ID.Date64, 17, ... ID.Timestamp, 18, ... ID.Time32, 19, ... - ID.Time64, 20 ... + ID.Time64, 20, ... + ID.Struct, 26 ... ); enumValues = typeIDs.keys(); diff --git a/matlab/test/arrow/type/tStructType.m b/matlab/test/arrow/type/tStructType.m new file mode 100644 index 0000000000000..f0585823f8dcf --- /dev/null +++ b/matlab/test/arrow/type/tStructType.m @@ -0,0 +1,190 @@ +% TSTRUCTTYPE Unit tests for arrow.type.StructType + +% 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 tStructType < matlab.unittest.TestCase + + properties (Constant) + Field1 = arrow.field("A", arrow.float64()) + Field2 = arrow.field("C", arrow.boolean()) + Field3 = arrow.field("B", arrow.timestamp(TimeUnit="Microsecond", TimeZone="America/New_York")); + end + + methods (Test) + function Basic(tc) + % Verify arrow.struct() returns an arrow.type.StructType + % object. + type = arrow.struct(tc.Field1); + className = string(class(type)); + tc.verifyEqual(className, "arrow.type.StructType"); + tc.verifyEqual(type.ID, arrow.type.ID.Struct); + end + + function TooFewInputsError(tc) + % Verify arrow.struct() errors if given zero input arguments. + fcn = @() arrow.struct(); + tc.verifyError(fcn, "arrow:struct:TooFewInputs"); + end + + function InvalidInputTypeError(tc) + % Verify arrow.struct() errors if any one of the input + % arguments is not an arrow.type.Field object. + fcn = @() arrow.struct(1); + tc.verifyError(fcn, "MATLAB:validation:UnableToConvert"); + end + + function EmptyFieldError(tc) + % Verify arrow.struct() errors if given an empty + % arrow.type.Field array as one of its inputs. + fcn = @() arrow.struct(tc.Field1, arrow.type.Field.empty(0, 0)); + tc.verifyError(fcn, "MATLAB:validators:mustBeNonempty"); + end + + function NumFieldsGetter(tc) + % Verify the NumFields getter returns the expected value. + type = arrow.struct(tc.Field1); + tc.verifyEqual(type.NumFields, int32(1)); + + type = arrow.struct(tc.Field1, tc.Field2); + tc.verifyEqual(type.NumFields, int32(2)); + + type = arrow.struct(tc.Field1, tc.Field2, tc.Field3); + tc.verifyEqual(type.NumFields, int32(3)); + end + + function NumFieldsNoSetter(tc) + % Verify the NumFields property is not settable. + type = arrow.struct(tc.Field1); + fcn = @() setfield(type, "NumFields", 20); + tc.verifyError(fcn, "MATLAB:class:SetProhibited"); + end + + function FieldsGetter(tc) + % Verify the Fields getter returns the expected + % arrow.type.Field array. + type = arrow.struct(tc.Field1, tc.Field2, tc.Field3); + actual = type.Fields; + expected = [tc.Field1, tc.Field2, tc.Field3]; + tc.verifyEqual(actual, expected); + end + + function FieldsNoSetter(tc) + % Verify the Fields property is not settable. + type = arrow.struct(tc.Field1, tc.Field2, tc.Field3); + fcn = @() setfield(type, "Fields", tc.Field3); + tc.verifyError(fcn, "MATLAB:class:SetProhibited"); + end + + function IDGetter(tc) + % Verify the ID getter returns the expected enum value. + type = arrow.struct(tc.Field1); + actual = type.ID; + expected = arrow.type.ID.Struct; + tc.verifyEqual(actual, expected); + end + + function IDNoSetter(tc) + % Verify the ID property is not settable. + type = arrow.struct(tc.Field1); + fcn = @() setfield(type, "ID", arrow.type.ID.Boolean); + tc.verifyError(fcn, "MATLAB:class:SetProhibited"); + end + + function FieldMethod(tc) + % Verify the field method returns the expected arrow.type.Field + % with respect to the index provided. + type = arrow.struct(tc.Field1, tc.Field2, tc.Field3); + + % Extract the 1st field + actual1 = type.field(1); + expected1 = tc.Field1; + tc.verifyEqual(actual1, expected1); + + % Extract the 2nd field + actual2 = type.field(2); + expected2 = tc.Field2; + tc.verifyEqual(actual2, expected2); + + % Extract the 3rd field + actual3 = type.field(3); + expected3 = tc.Field3; + tc.verifyEqual(actual3, expected3); + end + + function FieldIndexOutOfRangeError(tc) + % Verify field() throws an error if provided an index that + % exceeds NumFields. + type = arrow.struct(tc.Field1, tc.Field2, tc.Field3); + fcn = @() type.field(100); + tc.verifyError(fcn, "arrow:index:OutOfRange"); + end + + function FieldIndexNonScalarError(tc) + % Verify field() throws an error if provided a nonscalar array + % of indices. + type = arrow.struct(tc.Field1, tc.Field2, tc.Field3); + fcn = @() type.field([1 2]); + tc.verifyError(fcn, "arrow:badsubscript:NonScalar"); + end + + function FieldIndexNonNumberError(tc) + % Verify field() throws an error if not provided a number as + % the index. + + type = arrow.struct(tc.Field1, tc.Field2, tc.Field3); + fcn = @() type.field("A"); + tc.verifyError(fcn, "arrow:badsubscript:NonNumeric"); + end + + function IsEqualTrue(tc) + % Verify two StructTypes are considered equal if their Fields + % properties are equal. + + type1 = arrow.struct(tc.Field1, tc.Field2, tc.Field3); + type2 = arrow.struct(tc.Field1, tc.Field2, tc.Field3); + + tc.verifyTrue(isequal(type1, type2)); + tc.verifyTrue(isequal(type1, type2, type2, type1)); + + % Non-scalar arrow.type.StructType arrays + type3 = [type1 type2]; + type4 = [type1 type2]; + tc.verifyTrue(isequal(type3, type4)); + end + + function IsEqualFalse(tc) + % Verify isequal returns false when expected. + type1 = arrow.struct(tc.Field1, tc.Field2, tc.Field3); + type2 = arrow.struct(tc.Field1, tc.Field2); + type3 = arrow.struct(tc.Field1, tc.Field3, tc.Field2); + + % Fields properties have different lengths + tc.verifyFalse(isequal(type1, type2)); + + % The corresponding elements in the Fields arrays are not equal + tc.verifyFalse(isequal(type1, type3)); + + % Non-scalar arrow.type.StructType arrays + type4 = [type1 type2]; + type5 = [type1; type2]; + type6 = [type1 type2]; + type7 = [type1 type3]; + tc.verifyFalse(isequal(type4, type5)); + tc.verifyFalse(isequal(type6, type7)); + + end + end +end \ No newline at end of file diff --git a/matlab/test/arrow/type/tTypeDisplay.m b/matlab/test/arrow/type/tTypeDisplay.m index 4d3c023da71ab..f84c5ab56e270 100644 --- a/matlab/test/arrow/type/tTypeDisplay.m +++ b/matlab/test/arrow/type/tTypeDisplay.m @@ -189,7 +189,7 @@ function TestDateType(testCase, DateType) testCase.verifyEqual(actualDisplay, expectedDisplay); end - function Display(testCase) + function TimestampTypeDisplay(testCase) % Verify the display of TimestampType objects. % % Example: @@ -211,6 +211,32 @@ function Display(testCase) actualDisplay = evalc('disp(type)'); testCase.verifyEqual(actualDisplay, expectedDisplay); end + + function StructTypeDisplay(testCase) + % Verify the display of StructType objects. + % + % Example: + % + % StructType with properties: + % + % ID: Struct + % Fields: [1x2 arrow.type.Field] + + fieldA = arrow.field("A", arrow.int32()); + fieldB = arrow.field("B", arrow.timestamp(TimeZone="America/Anchorage")); + type = arrow.struct(fieldA, fieldB); %#ok + classnameLink = makeLinkString(FullClassName="arrow.type.StructType", ClassName="StructType", BoldFont=true); + header = " " + classnameLink + " with properties:" + newline; + body = strjust(pad(["ID:"; "Fields:"])); + dimensionString = makeDimensionString([1 2]); + fieldString = compose("[%s %s]", dimensionString, "arrow.type.Field"); + body = body + " " + ["Struct"; fieldString]; + body = " " + body; + footer = string(newline); + expectedDisplay = char(strjoin([header body' footer], newline)); + actualDisplay = evalc('disp(type)'); + testCase.verifyDisplay(actualDisplay, expectedDisplay); + end end methods diff --git a/matlab/test/arrow/type/traits/tStructTraits.m b/matlab/test/arrow/type/traits/tStructTraits.m new file mode 100644 index 0000000000000..6a97b1e1852d6 --- /dev/null +++ b/matlab/test/arrow/type/traits/tStructTraits.m @@ -0,0 +1,31 @@ +% 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 tStructTraits < hTypeTraits + + properties + TraitsConstructor = @arrow.type.traits.StructTraits + ArrayConstructor = missing + ArrayClassName = missing + ArrayProxyClassName = missing + ArrayStaticConstructor = missing + TypeConstructor = @arrow.type.StructType + TypeClassName = "arrow.type.StructType" + TypeProxyClassName = "arrow.type.proxy.StructType" + MatlabConstructor = missing + MatlabClassName = missing + end + +end \ No newline at end of file diff --git a/matlab/test/arrow/type/traits/ttraits.m b/matlab/test/arrow/type/traits/ttraits.m index cdc5990ed03ba..2880645f2957c 100644 --- a/matlab/test/arrow/type/traits/ttraits.m +++ b/matlab/test/arrow/type/traits/ttraits.m @@ -199,6 +199,18 @@ function TestDate64(testCase) testCase.verifyEqual(actualTraits, expectedTraits); end + function TestStruct(testCase) + import arrow.type.traits.* + import arrow.type.* + + type = ID.Struct; + expectedTraits = StructTraits(); + + actualTraits = traits(type); + + testCase.verifyEqual(actualTraits, expectedTraits); + end + function TestMatlabUInt8(testCase) import arrow.type.traits.* diff --git a/matlab/tools/cmake/BuildMatlabArrowInterface.cmake b/matlab/tools/cmake/BuildMatlabArrowInterface.cmake index b5c480d6a68e7..40c6b5a51d4fe 100644 --- a/matlab/tools/cmake/BuildMatlabArrowInterface.cmake +++ b/matlab/tools/cmake/BuildMatlabArrowInterface.cmake @@ -65,6 +65,7 @@ set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_SOURCES "${CMAKE_SOURCE_DIR}/src/cpp/a "${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/struct_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"