diff --git a/matlab/src/cpp/arrow/matlab/array/proxy/list_array.cc b/matlab/src/cpp/arrow/matlab/array/proxy/list_array.cc index fc75e55dd6012..941e658c25127 100644 --- a/matlab/src/cpp/arrow/matlab/array/proxy/list_array.cc +++ b/matlab/src/cpp/arrow/matlab/array/proxy/list_array.cc @@ -15,6 +15,7 @@ // specific language governing permissions and limitations // under the License. +#include "arrow/matlab/array/validation_mode.h" #include "arrow/matlab/array/proxy/list_array.h" #include "arrow/matlab/array/proxy/numeric_array.h" #include "arrow/matlab/array/proxy/wrap.h" @@ -26,6 +27,7 @@ namespace arrow::matlab::array::proxy { ListArray::ListArray(std::shared_ptr list_array) : proxy::Array{std::move(list_array)} { REGISTER_METHOD(ListArray, getValues); REGISTER_METHOD(ListArray, getOffsets); + REGISTER_METHOD(ListArray, validate); } libmexclass::proxy::MakeResult ListArray::make(const libmexclass::proxy::FunctionArguments& constructor_arguments) { @@ -100,4 +102,38 @@ namespace arrow::matlab::array::proxy { mda::ArrayFactory factory; context.outputs[0] = factory.createScalar(offsets_int32_array_proxy_id); } + + void ListArray::validate(libmexclass::proxy::method::Context& context) { + namespace mda = ::matlab::data; + mda::StructArray args = context.inputs[0]; + const mda::TypedArray validation_mode_mda = args[0]["ValidationMode"]; + const auto validation_mode_integer = uint8_t(validation_mode_mda[0]); + // Convert integer representation to ValidationMode enum. + const auto validation_mode = static_cast(validation_mode_integer); + switch (validation_mode) { + case ValidationMode::None: { + // Do nothing. + break; + } + case ValidationMode::Minimal: { + MATLAB_ERROR_IF_NOT_OK_WITH_CONTEXT(array->Validate(), + context, + error::ARRAY_VALIDATE_MINIMAL_FAILED); + break; + } + case ValidationMode::Full: { + MATLAB_ERROR_IF_NOT_OK_WITH_CONTEXT(array->ValidateFull(), + context, + error::ARRAY_VALIDATE_FULL_FAILED); + break; + } + default: { + // Throw an error if an unsupported enumeration value is provided. + const auto msg = "Unsupported ValidationMode enumeration value: " + std::to_string(validation_mode_integer); + context.error = libmexclass::error::Error{error::ARRAY_VALIDATE_UNSUPPORTED_ENUM, msg}; + return; + } + } + } + } diff --git a/matlab/src/cpp/arrow/matlab/array/proxy/list_array.h b/matlab/src/cpp/arrow/matlab/array/proxy/list_array.h index 8db6b6bf1d632..1f34b11406594 100644 --- a/matlab/src/cpp/arrow/matlab/array/proxy/list_array.h +++ b/matlab/src/cpp/arrow/matlab/array/proxy/list_array.h @@ -32,6 +32,7 @@ class ListArray : public arrow::matlab::array::proxy::Array { protected: void getValues(libmexclass::proxy::method::Context& context); void getOffsets(libmexclass::proxy::method::Context& context); + void validate(libmexclass::proxy::method::Context& context); }; diff --git a/matlab/src/cpp/arrow/matlab/array/validation_mode.h b/matlab/src/cpp/arrow/matlab/array/validation_mode.h new file mode 100644 index 0000000000000..92e10f47aa4e7 --- /dev/null +++ b/matlab/src/cpp/arrow/matlab/array/validation_mode.h @@ -0,0 +1,30 @@ +// 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 + +namespace arrow::matlab::array { + + enum class ValidationMode : uint8_t { + None = 0, + Minimal = 1, + Full = 2 + }; + +} diff --git a/matlab/src/cpp/arrow/matlab/error/error.h b/matlab/src/cpp/arrow/matlab/error/error.h index 33e80bca8cc5a..5aa8f05c8c315 100644 --- a/matlab/src/cpp/arrow/matlab/error/error.h +++ b/matlab/src/cpp/arrow/matlab/error/error.h @@ -203,4 +203,7 @@ namespace arrow::matlab::error { static const char* BUFFER_VIEW_OR_COPY_FAILED = "arrow:buffer:ViewOrCopyFailed"; static const char* ARRAY_PRETTY_PRINT_FAILED = "arrow:array:PrettyPrintFailed"; static const char* TABULAR_GET_ROW_AS_STRING_FAILED = "arrow:tabular:GetRowAsStringFailed"; + static const char* ARRAY_VALIDATE_MINIMAL_FAILED = "arrow:array:ValidateMinimalFailed"; + static const char* ARRAY_VALIDATE_FULL_FAILED = "arrow:array:ValidateFullFailed"; + static const char* ARRAY_VALIDATE_UNSUPPORTED_ENUM = "arrow:array:ValidateUnsupportedEnum"; } diff --git a/matlab/src/matlab/+arrow/+array/ListArray.m b/matlab/src/matlab/+arrow/+array/ListArray.m index f8fd934b7c448..9a93c39ec6193 100644 --- a/matlab/src/matlab/+arrow/+array/ListArray.m +++ b/matlab/src/matlab/+arrow/+array/ListArray.m @@ -79,8 +79,9 @@ offsets (1, 1) arrow.array.Int32Array values (1, 1) arrow.array.Array opts.Valid + opts.ValidationMode (1, 1) arrow.array.ValidationMode = arrow.array.ValidationMode.Minimal end - + import arrow.internal.validate.parseValid if nargin < 2 @@ -100,9 +101,11 @@ ValuesProxyID=valuesProxyID, ... Valid=validElements ... ); - + proxyName = "arrow.array.proxy.ListArray"; proxy = arrow.internal.proxy.create(proxyName, args); + % Validate the provided offsets and values. + proxy.validate(struct(ValidationMode=uint8(opts.ValidationMode))); array = arrow.array.ListArray(proxy); end diff --git a/matlab/src/matlab/+arrow/+array/ValidationMode.m b/matlab/src/matlab/+arrow/+array/ValidationMode.m new file mode 100644 index 0000000000000..3442bcccf725b --- /dev/null +++ b/matlab/src/matlab/+arrow/+array/ValidationMode.m @@ -0,0 +1,24 @@ +% Mode to use for Array validation. + +% 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 ValidationMode < uint8 + enumeration + None (0) + Minimal (1) + Full (2) + end +end \ No newline at end of file diff --git a/matlab/test/arrow/array/tListArray.m b/matlab/test/arrow/array/tListArray.m index 1ebf66e2f0999..07304eb384299 100644 --- a/matlab/test/arrow/array/tListArray.m +++ b/matlab/test/arrow/array/tListArray.m @@ -23,6 +23,7 @@ properties (TestParameter) TestArrowArray + TestValidationModeArray end methods (TestParameterDefinition, Static) @@ -113,6 +114,29 @@ ); end + function TestValidationModeArray = initializeTestValidationModeArray() + %% Valid ListArray + Offsets = arrow.array(int32([0, 1, 2, 3])); + Values = arrow.array([1, 2, 3]); + + TestValidationModeArray.ValidList = struct( ... + Offsets=Offsets, ... + Values=Values, ... + Valid=true ... + ); + + %% Invalid ListArray + % Incorrect number of offsets (length should be 1 more than the number of Values). + Offsets = arrow.array(int32([0, 1, 2, 3, 4, 5])); + Values = arrow.array([1, 2, 3]); + + TestValidationModeArray.InvalidList = struct( ... + Offsets=Offsets, ... + Values=Values, ... + Valid=false ... + ); + end + end methods (Test) @@ -160,6 +184,87 @@ function TestErrorIfEmptyOffsets(testCase) testCase.verifyError(fcn, "arrow:array:ListArrayFromArraysFailed"); end + function TestValidationModeDefault(testCase, TestValidationModeArray) + % Verify that the default ValidationMode value for the + % arrow.array.ListArray.fromArrays method is + % arrow.array.ValidationMode.Minimal. + offsets = TestValidationModeArray.Offsets; + values = TestValidationModeArray.Values; + valid = TestValidationModeArray.Valid; + fcn = @() arrow.array.ListArray.fromArrays(offsets, values); + if valid + testCase.verifyWarningFree(fcn); + else + testCase.verifyError(fcn, "arrow:array:ValidateMinimalFailed"); + end + end + + function TestValidationModeNone(testCase, TestValidationModeArray) + % Verify that no error is thrown when supplying the + % ValidatationMode name-value pair, with a value of + % arrow.array.ValidationMode.None, to the + % arrow.array.ListArray.fromArrays method. + offsets = TestValidationModeArray.Offsets; + values = TestValidationModeArray.Values; + validationMode = arrow.array.ValidationMode.None; + fcn = @() arrow.array.ListArray.fromArrays(offsets, values, ValidationMode=validationMode); + testCase.verifyWarningFree(fcn); + end + + function TestValidationModeMinimal(testCase, TestValidationModeArray) + % Verify that an error of type arrow:array:ValidateMinimalFailed + % is thrown when supplying the ValidatationMode name-value pair, + % with a value of arrow.array.ValidationMode.Minimal, to the + % arrow.array.ListArray.fromArrays method, if the provided offsets + % and values arrays are invalid. + offsets = TestValidationModeArray.Offsets; + values = TestValidationModeArray.Values; + valid = TestValidationModeArray.Valid; + validationMode = arrow.array.ValidationMode.Minimal; + fcn = @() arrow.array.ListArray.fromArrays(offsets, values, ValidationMode=validationMode); + if valid + testCase.verifyWarningFree(fcn); + else + testCase.verifyError(fcn, "arrow:array:ValidateMinimalFailed"); + end + end + + function TestValidationModeFull(testCase, TestValidationModeArray) + % Verify that an error of type arrow:array:ValidateFullFailed + % is thrown when supplying the ValidatationMode name-value pair, + % with a value of arrow.array.ValidationMode.Full, to the + % arrow.array.ListArray.fromArrays method, if the provided offsets + % and values arrays are invalid. + offsets = TestValidationModeArray.Offsets; + values = TestValidationModeArray.Values; + validationMode = arrow.array.ValidationMode.Full; + valid = TestValidationModeArray.Valid; + fcn = @() arrow.array.ListArray.fromArrays(offsets, values, ValidationMode=validationMode); + if valid + testCase.verifyWarningFree(fcn); + else + testCase.verifyError(fcn, "arrow:array:ValidateFullFailed"); + end + end + + function TestValidationModeUnsupportedEnum(testCase) + % Verify that an error of type arrow:array:ValidateUnsupportedEnum + % is thrown when an unsupported integer enumeration value is + % supplied for the ValidatationMode parameter to the internal + % C++ ListArray Proxy validate method. + offsets = arrow.array.Int32Array.fromMATLAB(int32([0, 1, 2])); + values = arrow.array.Float64Array.fromMATLAB([1, 2, 3]); + array = arrow.array.ListArray.fromArrays(offsets, values); + % Get the underlying Proxy instance from the ListArray. + proxy = array.Proxy; + % Call the internal Proxy method "validate" with an unsupported + % integer ValidationMode value. + validationMode = uint8(3); + args = struct(ValidationMode=validationMode); + fcn = @() proxy.validate(args); + testCase.verifyError(fcn, "arrow:array:ValidateUnsupportedEnum"); + end + end end