diff --git a/matlab/src/matlab/+arrow/+type/Field.m b/matlab/src/matlab/+arrow/+type/Field.m index fb0b579e20bb9..f67ba69fe9826 100644 --- a/matlab/src/matlab/+arrow/+type/Field.m +++ b/matlab/src/matlab/+arrow/+type/Field.m @@ -1,3 +1,7 @@ +%FIELD A class representing a name and a type. +% Fields are often used in tabular schemas for describing a column's +% name and 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. @@ -14,9 +18,6 @@ % permissions and limitations under the License. classdef Field < matlab.mixin.CustomDisplay -%FIELD A class representing a name and a type. -% Fields are often used in tabular schemas for describing a column's -% name and type. properties (GetAccess=public, SetAccess=private, Hidden) Proxy @@ -50,6 +51,44 @@ name = obj.Proxy.getName(); end + function tf = isequal(obj, varargin) + narginchk(2, inf); + tf = false; + + namesToCompare = strings(numel(obj), numel(varargin)); + typesToCompare = cell([1 numel(varargin)]); + + for ii = 1:numel(varargin) + field = varargin{ii}; + if ~isa(field, "arrow.type.Field") || ~isequal(size(obj), size(field)) + % Return early if field is not an arrow.type.Field + % or if the dimensions of obj and field do not match. + return; + end + + namesToCompare(:, ii) = [field(:).Name]; + typesToCompare{1, ii} = [field(:).Type]; + end + + if isempty(obj) + % At this point, since we have already confirmed all the + % Fields have the same dimensions, if one of the Fields are + % empty, then they must all be empty. This means they must + % all be equal. + tf = true; + else + names = [obj(:).Name]'; + if any(names ~= namesToCompare, "all") + % Return false early if the field names are not equal. + return; + end + + % Field names were equal. Check if their corresponding types + % are equal and return the result. + types = [obj(:).Type]; + tf = isequal(types, typesToCompare{:}); + end + end end methods (Access = private) diff --git a/matlab/test/arrow/type/tField.m b/matlab/test/arrow/type/tField.m index 77a05bbe39513..dba7190b49ce2 100644 --- a/matlab/test/arrow/type/tField.m +++ b/matlab/test/arrow/type/tField.m @@ -127,5 +127,108 @@ function TestImmutableProperties(testCase) testCase.verifyError(@() setfield(field, "Type", arrow.boolean), "MATLAB:class:noSetMethod") end + function TestIsEqualScalarTrue(testCase) + % Two scalar arrow.type.Field objects are equal if: + % + % 1. Their Name properties are equal + % 2. Their Type properties are equal + + f1 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second")); + f2 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second")); + testCase.verifyTrue(isequal(f1, f2)); + end + + function TestIsEqualScalarFalse(testCase) + % Verifies isequal returns false when expected. + f1 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second")); + f2 = arrow.field("B", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second")); + f3 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Millisecond")); + f4 = arrow.field("A", arrow.time32()); + + % Name properties are not equal + testCase.verifyFalse(isequal(f1, f2)); + + % Type properties are not equal + testCase.verifyFalse(isequal(f1, f3)); + + % Type properties have different class types + testCase.verifyFalse(isequal(f1, f4)); + + % Compare arrow.type.Field and a string + testCase.verifyFalse(isequal(f1, "A")); + end + + function TestIsEqualNonScalarTrue(testCase) + % Two nonscalar arrow.type.Field arrays are equal if: + % 1. They have the same shape + % 2. Their corresponding Field elements are equal + + f1 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second")); + f2 = arrow.field("B", arrow.string()); + fieldArray1 = [f1 f2 f1; f2 f1 f1]; + fieldArray2 = [f1 f2 f1; f2 f1 f1]; + + testCase.verifyTrue(isequal(fieldArray1, fieldArray2)); + testCase.verifyTrue(isequal(fieldArray1, fieldArray2, fieldArray1)); + end + + function TestIsEqualEmptyFields(testCase) + % Verify isequal returns the expected value when at least one + % of the inputs is empty. + + f1 = arrow.type.Field.empty(1, 0); + f2 = arrow.type.Field.empty(0, 1); + f3 = arrow.type.Field.empty(0, 0); + f4 = arrow.field("B", arrow.string()); + + % Compare two 1x0 Field arrays + testCase.verifyTrue(isequal(f1, f1)); + + % Compare two 0x1 Field arrays + testCase.verifyTrue(isequal(f2, f2)); + + % Compare two 0x0 Field arrays + testCase.verifyTrue(isequal(f3, f3)); + + % Compare 1x0 and 0x1 Field arrays + testCase.verifyFalse(isequal(f1, f2)); + + % Compare 1x0 and 0x0 Field arrays + testCase.verifyFalse(isequal(f1, f3)); + + % Compare 0x1 and 0x0 Field arrays + testCase.verifyFalse(isequal(f2, f3)); + + % Compare 1x0 and 1x1 Field arrays + testCase.verifyFalse(isequal(f1, f4)); + end + + function TestIsEqualNonScalarFalse(testCase) + % Verifies isequal returns false when expected for non-scalar + % Field arrays. + + f1 = arrow.field("A", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second")); + f2 = arrow.field("B", arrow.string()); + f3 = arrow.field("B", arrow.date32()); + f4 = arrow.field("C", arrow.timestamp(TimeZone="America/New_York", TimeUnit="Second")); + + fieldArray1 = [f1 f2 f3; f4 f1 f2]; + fieldArray2 = reshape(fieldArray1, [3 2]); + fieldArray3 = [f1 f3 f3; f4 f1 f2]; + fieldArray4 = [f4 f2 f3; f4 f1 f2]; + + % They have different shapes + testCase.verifyFalse(isequal(fieldArray1, fieldArray2)); + testCase.verifyFalse(isequal(fieldArray1, fieldArray2, fieldArray1)); + + % Their corresponding elements are not equal - type mismatch + testCase.verifyFalse(isequal(fieldArray1, fieldArray3)); + + % Their corresponding elements are not equal - name mismatch + testCase.verifyFalse(isequal(fieldArray1, fieldArray4)); + + % Compare arrow.type.Field array and a string array + testCase.verifyFalse(isequal(f1, strings(size(f1)))); + end end end