You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ke...@apache.org on 2023/09/15 18:40:27 UTC
[arrow] branch main updated: GH-37654: [MATLAB] Add `Fields` property to `arrow.type.Type` MATLAB class (#37725)
This is an automated email from the ASF dual-hosted git repository.
kevingurney pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new e32e87529e GH-37654: [MATLAB] Add `Fields` property to `arrow.type.Type` MATLAB class (#37725)
e32e87529e is described below
commit e32e87529e0810572821b0e11afbe1562f1e7edd
Author: sgilmore10 <74...@users.noreply.github.com>
AuthorDate: Fri Sep 15 14:40:20 2023 -0400
GH-37654: [MATLAB] Add `Fields` property to `arrow.type.Type` MATLAB class (#37725)
### Rationale for this change
In order to implement `arrow.array.StructType`, we need to add a property called `Fields` to `arrow.type.Type`. This property will be a N-by-1 `arrow.type.Field` array. Adding `Fields` will let users inspect the `Type`s contained by a `StructType` object.
### What changes are included in this PR?
1. Added `Fields` as a property to `arrow.type.Type`. `Fields` is a 1xN `arrow.type.Field` array, where `N` is the number of fields.
2. Added method `field(idx)` to `arrow.type.Type`. This method accepts a numeric index and returns the `arrow.type.Field` stored at the specified index.
### Are these changes tested?
1. Yes, updated `hFixedWidthType.m` and `tStringType.m` to verify the behavior of the new property and method.
2. Currently, all of the concrete `arrow.type.Type`s do not have any fields. This means the `Fields` property is always a 0x0 `arrow.type.Field` array. Once we implement `StructType`, we will be able to test having a nonempty `Fields` property.
### Are there any user-facing changes?
Yes, users can now extract fields from an `arrow.type.Type` object.
### Future Directions
1. #37724
2. #37653
* Closes: #37654
Authored-by: Sarah Gilmore <sg...@mathworks.com>
Signed-off-by: Kevin Gurney <kg...@mathworks.com>
---
matlab/src/cpp/arrow/matlab/error/error.h | 8 +--
matlab/src/cpp/arrow/matlab/index/validate.cc | 56 ++++++++++++++++++
.../matlab/{type/proxy/type.h => index/validate.h} | 29 ++-------
.../src/cpp/arrow/matlab/tabular/proxy/schema.cc | 68 ++++++----------------
matlab/src/cpp/arrow/matlab/type/proxy/type.cc | 35 +++++++++++
matlab/src/cpp/arrow/matlab/type/proxy/type.h | 2 +
matlab/src/matlab/+arrow/+type/Type.m | 24 ++++++++
matlab/test/arrow/tabular/tSchema.m | 10 ++--
matlab/test/arrow/type/hFixedWidthType.m | 25 ++++++++
matlab/test/arrow/type/tStringType.m | 25 ++++++++
matlab/tools/cmake/BuildMatlabArrowInterface.cmake | 4 +-
11 files changed, 202 insertions(+), 84 deletions(-)
diff --git a/matlab/src/cpp/arrow/matlab/error/error.h b/matlab/src/cpp/arrow/matlab/error/error.h
index 2b3009d51e..4ff77da8d8 100644
--- a/matlab/src/cpp/arrow/matlab/error/error.h
+++ b/matlab/src/cpp/arrow/matlab/error/error.h
@@ -174,10 +174,7 @@ namespace arrow::matlab::error {
static const char* INVALID_TIME_UNIT = "arrow:type:InvalidTimeUnit";
static const char* FIELD_FAILED_TO_CREATE_TYPE_PROXY = "arrow:field:FailedToCreateTypeProxy";
static const char* ARRAY_FAILED_TO_CREATE_TYPE_PROXY = "arrow:array:FailedToCreateTypeProxy";
- static const char* ARROW_TABULAR_SCHEMA_INVALID_NUMERIC_FIELD_INDEX = "arrow:tabular:schema:InvalidNumericFieldIndex";
- static const char* ARROW_TABULAR_SCHEMA_UNKNOWN_FIELD_NAME = "arrow:tabular:schema:UnknownFieldName";
static const char* ARROW_TABULAR_SCHEMA_AMBIGUOUS_FIELD_NAME = "arrow:tabular:schema:AmbiguousFieldName";
- static const char* ARROW_TABULAR_SCHEMA_NUMERIC_FIELD_INDEX_WITH_EMPTY_SCHEMA = "arrow:tabular:schema:NumericFieldIndexWithEmptySchema";
static const char* UNKNOWN_PROXY_FOR_ARRAY_TYPE = "arrow:array:UnknownProxyForArrayType";
static const char* RECORD_BATCH_NUMERIC_INDEX_WITH_EMPTY_RECORD_BATCH = "arrow:tabular:recordbatch:NumericIndexWithEmptyRecordBatch";
static const char* RECORD_BATCH_INVALID_NUMERIC_COLUMN_INDEX = "arrow:tabular:recordbatch:InvalidNumericColumnIndex";
@@ -195,6 +192,7 @@ namespace arrow::matlab::error {
static const char* CHUNKED_ARRAY_MAKE_FAILED = "arrow:chunkedarray:MakeFailed";
static const char* CHUNKED_ARRAY_NUMERIC_INDEX_WITH_EMPTY_CHUNKED_ARRAY = "arrow:chunkedarray:NumericIndexWithEmptyChunkedArray";
static const char* CHUNKED_ARRAY_INVALID_NUMERIC_CHUNK_INDEX = "arrow:chunkedarray:InvalidNumericChunkIndex";
-
-
+
+ static const char* INDEX_EMPTY_CONTAINER = "arrow:index:EmptyContainer";
+ static const char* INDEX_OUT_OF_RANGE = "arrow:index:OutOfRange";
}
diff --git a/matlab/src/cpp/arrow/matlab/index/validate.cc b/matlab/src/cpp/arrow/matlab/index/validate.cc
new file mode 100644
index 0000000000..b24653f1b8
--- /dev/null
+++ b/matlab/src/cpp/arrow/matlab/index/validate.cc
@@ -0,0 +1,56 @@
+// 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/index/validate.h"
+
+#include <sstream>
+
+namespace arrow::matlab::index {
+
+ namespace {
+ std::string makeEmptyContainerErrorMessage() {
+ return "Numeric indexing using the field method is not supported for objects with zero fields.";
+ }
+
+ std::string makeIndexOutOfRangeErrorMessage(const int32_t matlab_index, const int32_t num_fields) {
+ std::stringstream error_message_stream;
+ error_message_stream << "Invalid field index: ";
+ // matlab uses 1-based indexing
+ error_message_stream << matlab_index;
+ error_message_stream << ". Field index must be between 1 and the number of fields (";
+ error_message_stream << num_fields;
+ error_message_stream << ").";
+ return error_message_stream.str();
+ }
+ } // anonymous namespace
+
+ arrow::Status validateNonEmptyContainer(const int32_t num_fields) {
+ if (num_fields == 0) {
+ const auto msg = makeEmptyContainerErrorMessage();
+ return arrow::Status::Invalid(std::move(msg));
+ }
+ return arrow::Status::OK();
+ }
+
+ arrow::Status validateInRange(const int32_t matlab_index, const int32_t num_fields) {
+ if (matlab_index < 1 || matlab_index > num_fields) {
+ const auto msg = makeIndexOutOfRangeErrorMessage(matlab_index, num_fields);
+ return arrow::Status::Invalid(std::move(msg));
+ }
+ return arrow::Status::OK();
+ }
+}
\ No newline at end of file
diff --git a/matlab/src/cpp/arrow/matlab/type/proxy/type.h b/matlab/src/cpp/arrow/matlab/index/validate.h
similarity index 58%
copy from matlab/src/cpp/arrow/matlab/type/proxy/type.h
copy to matlab/src/cpp/arrow/matlab/index/validate.h
index efd2b8255a..40e109c19e 100644
--- a/matlab/src/cpp/arrow/matlab/type/proxy/type.h
+++ b/matlab/src/cpp/arrow/matlab/index/validate.h
@@ -17,29 +17,10 @@
#pragma once
-#include "arrow/type.h"
+#include "arrow/status.h"
-#include "libmexclass/proxy/Proxy.h"
+namespace arrow::matlab::index {
-namespace arrow::matlab::type::proxy {
-
-class Type : public libmexclass::proxy::Proxy {
- public:
- Type(std::shared_ptr<arrow::DataType> type);
-
- virtual ~Type() {}
-
- std::shared_ptr<arrow::DataType> unwrap();
-
- protected:
-
- void getTypeID(libmexclass::proxy::method::Context& context);
-
- void getNumFields(libmexclass::proxy::method::Context& context);
-
- void isEqual(libmexclass::proxy::method::Context& context);
-
- std::shared_ptr<arrow::DataType> data_type;
-};
-
-}
+ arrow::Status validateNonEmptyContainer(const int32_t num_fields);
+ arrow::Status validateInRange(const int32_t matlab_index, const int32_t num_fields);
+}
\ No newline at end of file
diff --git a/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.cc b/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.cc
index 62fe863ca8..ec1ac1eecb 100644
--- a/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.cc
+++ b/matlab/src/cpp/arrow/matlab/tabular/proxy/schema.cc
@@ -18,6 +18,7 @@
#include "arrow/matlab/error/error.h"
#include "arrow/matlab/tabular/proxy/schema.h"
#include "arrow/matlab/type/proxy/field.h"
+#include "arrow/matlab/index/validate.h"
#include "libmexclass/proxy/ProxyManager.h"
#include "libmexclass/error/Error.h"
@@ -28,25 +29,6 @@
namespace arrow::matlab::tabular::proxy {
- namespace {
-
- libmexclass::error::Error makeUnknownFieldNameError(const std::string& name) {
- using namespace libmexclass::error;
- std::stringstream error_message_stream;
- error_message_stream << "Unknown field name: '";
- error_message_stream << name;
- error_message_stream << "'.";
- return Error{error::ARROW_TABULAR_SCHEMA_UNKNOWN_FIELD_NAME, error_message_stream.str()};
- }
-
- libmexclass::error::Error makeEmptySchemaError() {
- using namespace libmexclass::error;
- return Error{error::ARROW_TABULAR_SCHEMA_NUMERIC_FIELD_INDEX_WITH_EMPTY_SCHEMA,
- "Numeric indexing using the field method is not supported for schemas with no fields."};
- }
-
- }
-
Schema::Schema(std::shared_ptr<arrow::Schema> schema) : schema{std::move(schema)} {
REGISTER_METHOD(Schema, getFieldByIndex);
REGISTER_METHOD(Schema, getFieldByName);
@@ -86,37 +68,27 @@ namespace arrow::matlab::tabular::proxy {
mda::StructArray args = context.inputs[0];
const mda::TypedArray<int32_t> index_mda = args[0]["Index"];
const auto matlab_index = int32_t(index_mda[0]);
- // Note: MATLAB uses 1-based indexing, so subtract 1.
- // arrow::Schema::field does not do any bounds checking.
- const int32_t index = matlab_index - 1;
- const auto num_fields = schema->num_fields();
- if (num_fields == 0) {
- const auto& error = makeEmptySchemaError();
- context.error = error;
- return;
- }
+ // Validate there is at least 1 field
+ MATLAB_ERROR_IF_NOT_OK_WITH_CONTEXT(
+ index::validateNonEmptyContainer(schema->num_fields()),
+ context,
+ error::INDEX_EMPTY_CONTAINER);
- if (matlab_index < 1 || matlab_index > num_fields) {
- using namespace libmexclass::error;
- const std::string& error_message_id = std::string{error::ARROW_TABULAR_SCHEMA_INVALID_NUMERIC_FIELD_INDEX};
- std::stringstream error_message_stream;
- error_message_stream << "Invalid field index: ";
- error_message_stream << matlab_index;
- error_message_stream << ". Field index must be between 1 and the number of fields (";
- error_message_stream << num_fields;
- error_message_stream << ").";
- const std::string& error_message = error_message_stream.str();
- context.error = Error{error_message_id, error_message};
- return;
- }
+ // Validate the matlab index provided is within the range [1, num_fields]
+ MATLAB_ERROR_IF_NOT_OK_WITH_CONTEXT(
+ index::validateInRange(matlab_index, schema->num_fields()),
+ context,
+ error::INDEX_OUT_OF_RANGE);
- const auto& field = schema->field(index);
- auto field_proxy = std::make_shared<FieldProxy>(field);
- const auto field_proxy_id = ProxyManager::manageProxy(field_proxy);
- const auto field_proxy_id_mda = factory.createScalar(field_proxy_id);
+ // Note: MATLAB uses 1-based indexing, so subtract 1.
+ // arrow::Schema::field does not do any bounds checking.
+ const int32_t index = matlab_index - 1;
- context.outputs[0] = field_proxy_id_mda;
+ auto field = schema->field(index);
+ auto field_proxy = std::make_shared<FieldProxy>(std::move(field));
+ auto field_proxy_id = ProxyManager::manageProxy(field_proxy);
+ context.outputs[0] = factory.createScalar(field_proxy_id);
}
void Schema::getFieldByName(libmexclass::proxy::method::Context& context) {
@@ -135,9 +107,7 @@ namespace arrow::matlab::tabular::proxy {
const auto field = schema->GetFieldByName(name);
auto field_proxy = std::make_shared<FieldProxy>(field);
const auto field_proxy_id = ProxyManager::manageProxy(field_proxy);
- const auto field_proxy_id_mda = factory.createScalar(field_proxy_id);
-
- context.outputs[0] = field_proxy_id_mda;
+ context.outputs[0] = factory.createScalar(field_proxy_id);
}
void Schema::getNumFields(libmexclass::proxy::method::Context& context) {
diff --git a/matlab/src/cpp/arrow/matlab/type/proxy/type.cc b/matlab/src/cpp/arrow/matlab/type/proxy/type.cc
index 1eed4e6141..1cbaaf328e 100644
--- a/matlab/src/cpp/arrow/matlab/type/proxy/type.cc
+++ b/matlab/src/cpp/arrow/matlab/type/proxy/type.cc
@@ -15,7 +15,11 @@
// specific language governing permissions and limitations
// under the License.
+
+#include "arrow/matlab/error/error.h"
+#include "arrow/matlab/index/validate.h"
#include "arrow/matlab/type/proxy/type.h"
+#include "arrow/matlab/type/proxy/field.h"
#include "libmexclass/proxy/ProxyManager.h"
@@ -24,6 +28,7 @@ namespace arrow::matlab::type::proxy {
Type::Type(std::shared_ptr<arrow::DataType> type) : data_type{std::move(type)} {
REGISTER_METHOD(Type, getTypeID);
REGISTER_METHOD(Type, getNumFields);
+ REGISTER_METHOD(Type, getFieldByIndex);
REGISTER_METHOD(Type, isEqual);
}
@@ -47,6 +52,36 @@ namespace arrow::matlab::type::proxy {
context.outputs[0] = num_fields_mda;
}
+ void Type::getFieldByIndex(libmexclass::proxy::method::Context& context) {
+ namespace mda = ::matlab::data;
+ mda::ArrayFactory factory;
+
+ mda::StructArray args = context.inputs[0];
+ const mda::TypedArray<int32_t> index_mda = args[0]["Index"];
+ const auto matlab_index = int32_t(index_mda[0]);
+
+ // Validate there is at least 1 field
+ MATLAB_ERROR_IF_NOT_OK_WITH_CONTEXT(
+ index::validateNonEmptyContainer(data_type->num_fields()),
+ context,
+ error::INDEX_EMPTY_CONTAINER);
+
+ // Validate the matlab index provided is within the range [1, num_fields]
+ MATLAB_ERROR_IF_NOT_OK_WITH_CONTEXT(
+ index::validateInRange(matlab_index, data_type->num_fields()),
+ context,
+ error::INDEX_OUT_OF_RANGE);
+
+ // Note: MATLAB uses 1-based indexing, so subtract 1.
+ // arrow::DataType::field does not do any bounds checking.
+ const int32_t index = matlab_index - 1;
+
+ auto field = data_type->field(index);
+ auto field_proxy = std::make_shared<proxy::Field>(std::move(field));
+ auto field_proxy_id = libmexclass::proxy::ProxyManager::manageProxy(field_proxy);
+ context.outputs[0] = factory.createScalar(field_proxy_id);
+ }
+
void Type::isEqual(libmexclass::proxy::method::Context& context) {
namespace mda = ::matlab::data;
diff --git a/matlab/src/cpp/arrow/matlab/type/proxy/type.h b/matlab/src/cpp/arrow/matlab/type/proxy/type.h
index efd2b8255a..3a6b287a92 100644
--- a/matlab/src/cpp/arrow/matlab/type/proxy/type.h
+++ b/matlab/src/cpp/arrow/matlab/type/proxy/type.h
@@ -37,6 +37,8 @@ class Type : public libmexclass::proxy::Proxy {
void getNumFields(libmexclass::proxy::method::Context& context);
+ void getFieldByIndex(libmexclass::proxy::method::Context& context);
+
void isEqual(libmexclass::proxy::method::Context& context);
std::shared_ptr<arrow::DataType> data_type;
diff --git a/matlab/src/matlab/+arrow/+type/Type.m b/matlab/src/matlab/+arrow/+type/Type.m
index 24f83e0267..0fd0139b18 100644
--- a/matlab/src/matlab/+arrow/+type/Type.m
+++ b/matlab/src/matlab/+arrow/+type/Type.m
@@ -19,6 +19,7 @@ classdef (Abstract) Type < matlab.mixin.CustomDisplay & ...
properties (Dependent, GetAccess=public, SetAccess=private)
ID
+ Fields
NumFields
end
@@ -41,6 +42,29 @@ classdef (Abstract) Type < matlab.mixin.CustomDisplay & ...
function typeID = get.ID(obj)
typeID = arrow.type.ID(obj.Proxy.getTypeID());
end
+
+ function F = field(obj, idx)
+ import arrow.internal.validate.*
+
+ idx = index.numeric(idx, "int32", AllowNonScalar=false);
+ args = struct(Index=idx);
+ proxyID = obj.Proxy.getFieldByIndex(args);
+ proxy = libmexclass.proxy.Proxy(Name="arrow.type.proxy.Field", ID=proxyID);
+ F = arrow.type.Field(proxy);
+ end
+
+ function fields = get.Fields(obj)
+ numFields = obj.NumFields;
+ if numFields == 0
+ fields = arrow.type.Field.empty(0, 0);
+ else
+ fields = cell(1, numFields);
+ for ii = 1:numFields
+ fields{ii} = obj.field(ii);
+ end
+ fields = horzcat(fields);
+ end
+ end
end
methods(Access = protected)
diff --git a/matlab/test/arrow/tabular/tSchema.m b/matlab/test/arrow/tabular/tSchema.m
index 3220236d4a..e4c706d9a3 100644
--- a/matlab/test/arrow/tabular/tSchema.m
+++ b/matlab/test/arrow/tabular/tSchema.m
@@ -239,7 +239,7 @@ classdef tSchema < matlab.unittest.TestCase
testCase.verifyEqual(field.Type.ID, arrow.type.ID.UInt32);
end
- function ErrorIfInvalidNumericFieldIndex(testCase)
+ function ErrorIfIndexIsOutOfRange(testCase)
% Verify that an error is thrown when trying to access a field
% with an invalid numeric index (e.g. greater than NumFields).
schema = arrow.schema([...
@@ -250,7 +250,7 @@ classdef tSchema < matlab.unittest.TestCase
% Index is greater than NumFields.
index = 100;
- testCase.verifyError(@() schema.field(index), "arrow:tabular:schema:InvalidNumericFieldIndex");
+ testCase.verifyError(@() schema.field(index), "arrow:index:OutOfRange");
end
function ErrorIfFieldNameDoesNotExist(testCase)
@@ -376,7 +376,7 @@ classdef tSchema < matlab.unittest.TestCase
testCase.verifyEqual(schema.FieldNames, string.empty(1, 0));
testCase.verifyEqual(schema.Fields, arrow.type.Field.empty(0, 0));
testCase.verifyError(@() schema.field(0), "arrow:badsubscript:NonPositive");
- testCase.verifyError(@() schema.field(1), "arrow:tabular:schema:NumericFieldIndexWithEmptySchema");
+ testCase.verifyError(@() schema.field(1), "arrow:index:EmptyContainer");
% 0x1 empty Field array.
fields = arrow.type.Field.empty(0, 1);
@@ -385,7 +385,7 @@ classdef tSchema < matlab.unittest.TestCase
testCase.verifyEqual(schema.FieldNames, string.empty(1, 0));
testCase.verifyEqual(schema.Fields, arrow.type.Field.empty(0, 0));
testCase.verifyError(@() schema.field(0), "arrow:badsubscript:NonPositive");
- testCase.verifyError(@() schema.field(1), "arrow:tabular:schema:NumericFieldIndexWithEmptySchema");
+ testCase.verifyError(@() schema.field(1), "arrow:index:EmptyContainer");
% 1x0 empty Field array.
fields = arrow.type.Field.empty(1, 0);
@@ -394,7 +394,7 @@ classdef tSchema < matlab.unittest.TestCase
testCase.verifyEqual(schema.FieldNames, string.empty(1, 0));
testCase.verifyEqual(schema.Fields, arrow.type.Field.empty(0, 0));
testCase.verifyError(@() schema.field(0), "arrow:badsubscript:NonPositive");
- testCase.verifyError(@() schema.field(1), "arrow:tabular:schema:NumericFieldIndexWithEmptySchema");
+ testCase.verifyError(@() schema.field(1), "arrow:index:EmptyContainer");
end
function GetFieldByNameWithChar(testCase)
diff --git a/matlab/test/arrow/type/hFixedWidthType.m b/matlab/test/arrow/type/hFixedWidthType.m
index adb234bbd3..b23c21a6b4 100644
--- a/matlab/test/arrow/type/hFixedWidthType.m
+++ b/matlab/test/arrow/type/hFixedWidthType.m
@@ -49,6 +49,31 @@ classdef hFixedWidthType < matlab.unittest.TestCase
testCase.verifyEqual(arrowType.NumFields, int32(0));
end
+ function TestFieldsProperty(testCase)
+ % Verify Fields is a 0x0 arrow.type.Field array.
+ type = testCase.ArrowType;
+ fields = type.Fields;
+ testCase.verifyEqual(fields, arrow.type.Field.empty(0, 0));
+ end
+
+ function FieldsNoSetter(testCase)
+ % Verify the Fields property is not settable.
+ type = testCase.ArrowType;
+ testCase.verifyError(@() setfield(type, "Fields", "1"), "MATLAB:class:SetProhibited");
+ end
+
+ function InvalidFieldIndex(testCase)
+ % Verify the field() method throws the expected error message
+ % when given an invalid index.
+ type = testCase.ArrowType;
+
+ testCase.verifyError(@() type.field(0), "arrow:badsubscript:NonPositive");
+ testCase.verifyError(@() type.field("A"), "arrow:badsubscript:NonNumeric");
+
+ % NOTE: For FixedWidthTypes, Fields is always empty.
+ testCase.verifyError(@() type.field(1), "arrow:index:EmptyContainer");
+ end
+
function TestBitWidthNoSetter(testCase)
% Verify that an error is thrown when trying to set the value
% of the BitWidth property.
diff --git a/matlab/test/arrow/type/tStringType.m b/matlab/test/arrow/type/tStringType.m
index e2a16ab133..3d518b3da3 100644
--- a/matlab/test/arrow/type/tStringType.m
+++ b/matlab/test/arrow/type/tStringType.m
@@ -64,6 +64,31 @@ classdef tStringType < matlab.unittest.TestCase
testCase.verifyFalse(isequal(typeArray1, typeArray2));
end
+ function TestFieldsProperty(testCase)
+ % Verify Fields is a 0x0 arrow.type.Field array.
+ type = arrow.string();
+ fields = type.Fields;
+ testCase.verifyEqual(fields, arrow.type.Field.empty(0, 0));
+ end
+
+ function FieldsNoSetter(testCase)
+ % Verify the Fields property is not settable.
+ type = arrow.string();
+ testCase.verifyError(@() setfield(type, "Fields", "1"), "MATLAB:class:SetProhibited");
+ end
+
+ function InvalidFieldIndex(testCase)
+ % Verify the field() method throws the expected error message
+ % when given an invalid index.
+ type = arrow.string();
+
+ testCase.verifyError(@() type.field(0), "arrow:badsubscript:NonPositive");
+ testCase.verifyError(@() type.field("A"), "arrow:badsubscript:NonNumeric");
+
+ % NOTE: For StringType, Fields is always empty.
+ testCase.verifyError(@() type.field(1), "arrow:index:EmptyContainer");
+ end
+
end
end
diff --git a/matlab/tools/cmake/BuildMatlabArrowInterface.cmake b/matlab/tools/cmake/BuildMatlabArrowInterface.cmake
index a5c0b079b3..b5c480d6a6 100644
--- a/matlab/tools/cmake/BuildMatlabArrowInterface.cmake
+++ b/matlab/tools/cmake/BuildMatlabArrowInterface.cmake
@@ -68,7 +68,9 @@ set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_SOURCES "${CMAKE_SOURCE_DIR}/src/cpp/a
"${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"
- "${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/io/feather/proxy/reader.cc")
+ "${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/io/feather/proxy/reader.cc"
+ "${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/index/validate.cc")
+
set(MATLAB_ARROW_LIBMEXCLASS_CLIENT_PROXY_FACTORY_INCLUDE_DIR "${CMAKE_SOURCE_DIR}/src/cpp/arrow/matlab/proxy")