This is an automated email from the ASF dual-hosted git repository.

kou 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 d14b42ac6b GH-35788: [Swift] bug fixes and change reader/writer to 
user Result type (#35774)
d14b42ac6b is described below

commit d14b42ac6b25823042b9da83ee16615579a81fa1
Author: abandy <[email protected]>
AuthorDate: Sun May 28 03:09:19 2023 -0400

    GH-35788: [Swift] bug fixes and change reader/writer to user Result type 
(#35774)
    
    Changes:
    - Changed Reader and Writer to use Result<T, Error> instead of throwing.  
Since the Error is an enum the handling of the error is enforced.
    - Update RecordBatch to accept only a single array per column instead of 
chunked arrays (which could cause problems when writing out)
    - Added ability for Table to be created from RecordBatches
    - Fixed a bug with indexing in Chunked array with many arrays
    - Added tests for the above changes.
    - Switched ValidationErrors to ArrowError and added additional ArrowError 
values.
    
    * Closes: #35788
    
    Authored-by: Alva Bandy <[email protected]>
    Signed-off-by: Sutou Kouhei <[email protected]>
---
 swift/Arrow/Sources/Arrow/ArrowArray.swift         |  65 +++++++-
 swift/Arrow/Sources/Arrow/ArrowArrayBuilder.swift  |   2 +-
 swift/Arrow/Sources/Arrow/ArrowBufferBuilder.swift |  10 +-
 swift/Arrow/Sources/Arrow/ArrowData.swift          |   4 +-
 swift/Arrow/Sources/Arrow/ArrowReader.swift        | 144 ++++++++++-------
 swift/Arrow/Sources/Arrow/ArrowReaderHelper.swift  | 121 ++++++++++-----
 swift/Arrow/Sources/Arrow/ArrowSchema.swift        |   2 +
 swift/Arrow/Sources/Arrow/ArrowTable.swift         | 149 ++++++++----------
 swift/Arrow/Sources/Arrow/ArrowType.swift          |  12 +-
 swift/Arrow/Sources/Arrow/ArrowWriter.swift        | 172 ++++++++++++++-------
 swift/Arrow/Sources/Arrow/ArrowWriterHelper.swift  |  40 ++---
 swift/Arrow/Sources/Arrow/ChunkedArray.swift       |  71 ++++++++-
 swift/Arrow/Tests/ArrowTests/IPCTests.swift        | 138 +++++++++++------
 .../Arrow/Tests/ArrowTests/RecordBatchTests.swift  |  42 ++---
 swift/Arrow/Tests/ArrowTests/TableTests.swift      |  91 +++++++++--
 15 files changed, 714 insertions(+), 349 deletions(-)

diff --git a/swift/Arrow/Sources/Arrow/ArrowArray.swift 
b/swift/Arrow/Sources/Arrow/ArrowArray.swift
index 47c733502c..07a66dafe0 100644
--- a/swift/Arrow/Sources/Arrow/ArrowArray.swift
+++ b/swift/Arrow/Sources/Arrow/ArrowArray.swift
@@ -17,7 +17,60 @@
 
 import Foundation
 
-public class ArrowArray<T> {
+public class ArrowArrayHolder {
+    public let type: ArrowType.Info
+    public let length: UInt
+    public let nullCount: UInt
+    public let array: Any
+    public let getBufferData: () -> [Data]
+    public let getBufferDataSizes: () -> [Int]
+    private let getArrowColumn: (ArrowField, [ArrowArrayHolder]) throws -> 
ArrowColumn
+    public init<T>(_ arrowArray: ArrowArray<T>) {
+        self.array = arrowArray
+        self.length = arrowArray.length
+        self.type = arrowArray.arrowData.type
+        self.nullCount = arrowArray.nullCount
+        self.getBufferData = {() -> [Data] in
+            var bufferData = [Data]()
+            for buffer in arrowArray.arrowData.buffers {
+                bufferData.append(Data())
+                buffer.append(to: &bufferData[bufferData.count - 1])
+            }
+
+            return bufferData;
+        }
+        
+        self.getBufferDataSizes = {() -> [Int] in
+            var bufferDataSizes = [Int]()
+            for buffer in arrowArray.arrowData.buffers {
+                bufferDataSizes.append(Int(buffer.capacity))
+            }
+
+            return bufferDataSizes
+        }
+        
+        self.getArrowColumn = {(field: ArrowField, arrayHolders: 
[ArrowArrayHolder]) throws -> ArrowColumn in
+            var arrays = [ArrowArray<T>]()
+            for arrayHolder in arrayHolders {
+                if let array = arrayHolder.array as? ArrowArray<T> {
+                    arrays.append(array)
+                }
+            }
+            
+            return ArrowColumn(field, chunked: ChunkedArrayHolder(try 
ChunkedArray<T>(arrays)))
+        }
+    }
+    
+    public static func makeArrowColumn(_ field: ArrowField, holders: 
[ArrowArrayHolder]) -> Result<ArrowColumn, ArrowError> {
+        do {
+            return .success(try holders[0].getArrowColumn(field, holders))
+        } catch {
+            return .failure(.runtimeError("\(error)"))
+        }
+    }
+}
+
+public class ArrowArray<T>: AsString {
     public typealias ItemType = T
     public let arrowData: ArrowData
     public var nullCount : UInt {get{return self.arrowData.nullCount}}
@@ -29,7 +82,7 @@ public class ArrowArray<T> {
 
     public func isNull(_ at: UInt) throws -> Bool {
         if at >= self.length {
-            throw ValidationError.outOfBounds(index: at)
+            throw ArrowError.outOfBounds(index: Int64(at))
         }
         
         return self.arrowData.isNull(at)
@@ -40,6 +93,14 @@ public class ArrowArray<T> {
             fatalError("subscript() has not been implemented")
         }
     }
+    
+    public func asString(_ index: UInt) -> String {
+        if self[index] == nil {
+            return ""
+        }
+        
+        return "\(self[index]!)"
+    }
 }
 
 public class FixedArray<T>: ArrowArray<T> {
diff --git a/swift/Arrow/Sources/Arrow/ArrowArrayBuilder.swift 
b/swift/Arrow/Sources/Arrow/ArrowArrayBuilder.swift
index 8672186061..c456f5a00b 100644
--- a/swift/Arrow/Sources/Arrow/ArrowArrayBuilder.swift
+++ b/swift/Arrow/Sources/Arrow/ArrowArrayBuilder.swift
@@ -107,7 +107,7 @@ public class ArrowArrayBuilders {
         } else if t == Double.self {
             return try NumberArrayBuilder<T>()
         } else {
-            throw ValidationError.unknownType
+            throw ArrowError.unknownType
         }
     }
 
diff --git a/swift/Arrow/Sources/Arrow/ArrowBufferBuilder.swift 
b/swift/Arrow/Sources/Arrow/ArrowBufferBuilder.swift
index 6dc50208ed..587c55dab5 100644
--- a/swift/Arrow/Sources/Arrow/ArrowBufferBuilder.swift
+++ b/swift/Arrow/Sources/Arrow/ArrowBufferBuilder.swift
@@ -39,7 +39,7 @@ public class BaseBufferBuilder<T> {
     public var length: UInt = 0
     public var nullCount : UInt  = 0
 
-    init(values: ArrowBuffer, nulls: ArrowBuffer, stride: Int = 
MemoryLayout<T>.stride) throws {
+    init(values: ArrowBuffer, nulls: ArrowBuffer, stride: Int = 
MemoryLayout<T>.stride) {
         self.stride = stride
         self.values = values
         self.nulls = nulls
@@ -68,7 +68,7 @@ public class FixedBufferBuilder<T>: BaseBufferBuilder<T>, 
ArrowBufferBuilder {
         self.defaultVal = try FixedBufferBuilder<T>.defaultValueForType()
         let values = ArrowBuffer.createBuffer(0, size: 
UInt(MemoryLayout<T>.stride))
         let nulls = ArrowBuffer.createBuffer(0, size: 
UInt(MemoryLayout<UInt8>.stride))
-        try super.init(values: values, nulls: nulls)
+        super.init(values: values, nulls: nulls)
     }
 
     public func append(_ newValue: ItemType?) {
@@ -134,7 +134,7 @@ public class FixedBufferBuilder<T>: BaseBufferBuilder<T>, 
ArrowBufferBuilder {
             return Double(0) as! T
         }
         
-        throw ValidationError.unknownType
+        throw ArrowError.unknownType
     }
 }
 
@@ -143,7 +143,7 @@ public class BoolBufferBuilder: BaseBufferBuilder<Bool>, 
ArrowBufferBuilder {
     public required init() throws {
         let values = ArrowBuffer.createBuffer(0, size: 
UInt(MemoryLayout<UInt8>.stride))
         let nulls = ArrowBuffer.createBuffer(0, size: 
UInt(MemoryLayout<UInt8>.stride))
-        try super.init(values: values, nulls: nulls)
+        super.init(values: values, nulls: nulls)
     }
 
     public func append(_ newValue: ItemType?) {
@@ -198,7 +198,7 @@ public class VariableBufferBuilder<T>: 
BaseBufferBuilder<T>, ArrowBufferBuilder
         let values = ArrowBuffer.createBuffer(0, size: UInt(binaryStride))
         let nulls = ArrowBuffer.createBuffer(0, size: UInt(binaryStride))
         self.offsets = ArrowBuffer.createBuffer(0, size: 
UInt(MemoryLayout<Int32>.stride))
-        try super.init(values: values, nulls: nulls, stride: binaryStride)
+        super.init(values: values, nulls: nulls, stride: binaryStride)
     }
 
     public func append(_ newValue: ItemType?) {
diff --git a/swift/Arrow/Sources/Arrow/ArrowData.swift 
b/swift/Arrow/Sources/Arrow/ArrowData.swift
index f70e5b551e..ead76b1c87 100644
--- a/swift/Arrow/Sources/Arrow/ArrowData.swift
+++ b/swift/Arrow/Sources/Arrow/ArrowData.swift
@@ -28,11 +28,11 @@ public class ArrowData {
         switch(type) {
             case let .PrimitiveInfo(typeId):
                 if typeId == ArrowTypeId.Unknown {
-                    throw ValidationError.unknownType
+                    throw ArrowError.unknownType
                 }
             case let .VariableInfo(typeId):
                 if typeId == ArrowTypeId.Unknown {
-                    throw ValidationError.unknownType
+                    throw ArrowError.unknownType
                 }
         }
 
diff --git a/swift/Arrow/Sources/Arrow/ArrowReader.swift 
b/swift/Arrow/Sources/Arrow/ArrowReader.swift
index 68647ca93a..151e0d1fd2 100644
--- a/swift/Arrow/Sources/Arrow/ArrowReader.swift
+++ b/swift/Arrow/Sources/Arrow/ArrowReader.swift
@@ -18,10 +18,6 @@
 import FlatBuffers
 import Foundation
 
-public enum ArrowError: Error {
-    case runtimeError(String)
-}
-
 let FILEMARKER = "ARROW1"
 let CONTINUATIONMARKER = -1
 
@@ -35,77 +31,101 @@ public class ArrowReader {
         let messageOffset: Int64
     }
 
-    private func loadSchema(_ schema: org_apache_arrow_flatbuf_Schema) throws 
-> ArrowSchema {
+    private func loadSchema(_ schema: org_apache_arrow_flatbuf_Schema) -> 
Result<ArrowSchema, ArrowError> {
         let builder = ArrowSchema.Builder()
         for index in 0 ..< schema.fieldsCount {
             let field = schema.fields(at: index)!
             let arrowField = ArrowField(field.name!, type: 
findArrowType(field), isNullable: field.nullable)
-            let _ = builder.addField(arrowField)
+            builder.addField(arrowField)
             if field.typeType == .struct_ {
-                throw ValidationError.unknownType
+                return .failure(.unknownType)
             }
         }
 
-        return builder.finish()
+        return .success(builder.finish())
     }
 
-    private func loadPrimitiveData(_ loadInfo: DataLoadInfo) throws -> 
ChunkedArrayHolder {
-        let node = loadInfo.recordBatch.nodes(at: loadInfo.nodeIndex)!
-        try validateBufferIndex(loadInfo.recordBatch, index: 
loadInfo.bufferIndex)
-        let nullBuffer = loadInfo.recordBatch.buffers(at: 
loadInfo.bufferIndex)!
-        let arrowNullBuffer = makeBuffer(nullBuffer, fileData: 
loadInfo.fileData,
-                                         length: UInt(node.nullCount), 
messageOffset: loadInfo.messageOffset)
-        try validateBufferIndex(loadInfo.recordBatch, index: 
loadInfo.bufferIndex + 1)
-        let valueBuffer = loadInfo.recordBatch.buffers(at: 
loadInfo.bufferIndex + 1)!
-        let arrowValueBuffer = makeBuffer(valueBuffer, fileData: 
loadInfo.fileData,
-                                          length: UInt(node.length), 
messageOffset: loadInfo.messageOffset)
-        return try makeArrayHolder(loadInfo.field, buffers: [arrowNullBuffer, 
arrowValueBuffer])
+    private func loadPrimitiveData(_ loadInfo: DataLoadInfo) -> 
Result<ArrowArrayHolder, ArrowError> {
+        do {
+            let node = loadInfo.recordBatch.nodes(at: loadInfo.nodeIndex)!
+            try validateBufferIndex(loadInfo.recordBatch, index: 
loadInfo.bufferIndex)
+            let nullBuffer = loadInfo.recordBatch.buffers(at: 
loadInfo.bufferIndex)!
+            let arrowNullBuffer = makeBuffer(nullBuffer, fileData: 
loadInfo.fileData,
+                                             length: UInt(node.nullCount), 
messageOffset: loadInfo.messageOffset)
+            try validateBufferIndex(loadInfo.recordBatch, index: 
loadInfo.bufferIndex + 1)
+            let valueBuffer = loadInfo.recordBatch.buffers(at: 
loadInfo.bufferIndex + 1)!
+            let arrowValueBuffer = makeBuffer(valueBuffer, fileData: 
loadInfo.fileData,
+                                              length: UInt(node.length), 
messageOffset: loadInfo.messageOffset)
+            return makeArrayHolder(loadInfo.field, buffers: [arrowNullBuffer, 
arrowValueBuffer])
+        } catch let error as ArrowError {
+            return .failure(error)
+        } catch {
+            return .failure(.unknownError("\(error)"))
+        }
     }
 
-    private func loadVariableData(_ loadInfo: DataLoadInfo) throws -> 
ChunkedArrayHolder {
+    private func loadVariableData(_ loadInfo: DataLoadInfo) -> 
Result<ArrowArrayHolder, ArrowError> {
         let node = loadInfo.recordBatch.nodes(at: loadInfo.nodeIndex)!
-        try validateBufferIndex(loadInfo.recordBatch, index: 
loadInfo.bufferIndex)
-        let nullBuffer = loadInfo.recordBatch.buffers(at: 
loadInfo.bufferIndex)!
-        let arrowNullBuffer = makeBuffer(nullBuffer, fileData: 
loadInfo.fileData,
-                                         length: UInt(node.nullCount), 
messageOffset: loadInfo.messageOffset)
-        try validateBufferIndex(loadInfo.recordBatch, index: 
loadInfo.bufferIndex + 1)
-        let offsetBuffer = loadInfo.recordBatch.buffers(at: 
loadInfo.bufferIndex + 1)!
-        let arrowOffsetBuffer = makeBuffer(offsetBuffer, fileData: 
loadInfo.fileData,
-                                           length: UInt(node.length), 
messageOffset: loadInfo.messageOffset)
-        try validateBufferIndex(loadInfo.recordBatch, index: 
loadInfo.bufferIndex + 2)
-        let valueBuffer = loadInfo.recordBatch.buffers(at: 
loadInfo.bufferIndex + 2)!
-        let arrowValueBuffer = makeBuffer(valueBuffer, fileData: 
loadInfo.fileData,
-                                          length: UInt(node.length), 
messageOffset: loadInfo.messageOffset)
-        return try makeArrayHolder(loadInfo.field, buffers: [arrowNullBuffer, 
arrowOffsetBuffer, arrowValueBuffer])
+        do {
+            try validateBufferIndex(loadInfo.recordBatch, index: 
loadInfo.bufferIndex)
+            let nullBuffer = loadInfo.recordBatch.buffers(at: 
loadInfo.bufferIndex)!
+            let arrowNullBuffer = makeBuffer(nullBuffer, fileData: 
loadInfo.fileData,
+                                             length: UInt(node.nullCount), 
messageOffset: loadInfo.messageOffset)
+            try validateBufferIndex(loadInfo.recordBatch, index: 
loadInfo.bufferIndex + 1)
+            let offsetBuffer = loadInfo.recordBatch.buffers(at: 
loadInfo.bufferIndex + 1)!
+            let arrowOffsetBuffer = makeBuffer(offsetBuffer, fileData: 
loadInfo.fileData,
+                                               length: UInt(node.length), 
messageOffset: loadInfo.messageOffset)
+            try validateBufferIndex(loadInfo.recordBatch, index: 
loadInfo.bufferIndex + 2)
+            let valueBuffer = loadInfo.recordBatch.buffers(at: 
loadInfo.bufferIndex + 2)!
+            let arrowValueBuffer = makeBuffer(valueBuffer, fileData: 
loadInfo.fileData,
+                                              length: UInt(node.length), 
messageOffset: loadInfo.messageOffset)
+            return makeArrayHolder(loadInfo.field, buffers: [arrowNullBuffer, 
arrowOffsetBuffer, arrowValueBuffer])
+        } catch let error as ArrowError {
+            return .failure(error)
+        } catch {
+            return .failure(.unknownError("\(error)"))
+        }
     }
 
     private func loadRecordBatch(_ message: org_apache_arrow_flatbuf_Message, 
schema: org_apache_arrow_flatbuf_Schema,
-                                 data: Data, messageEndOffset: Int64) throws 
-> RecordBatch {
+                                 data: Data, messageEndOffset: Int64) -> 
Result<RecordBatch, ArrowError> {
         let recordBatch = message.header(type: 
org_apache_arrow_flatbuf_RecordBatch.self)
         let nodesCount = recordBatch?.nodesCount ?? 0
         var bufferIndex: Int32 = 0
-        var columns: [ChunkedArrayHolder] = []
-        let arrowSchema = try loadSchema(schema)
+        var columns: [ArrowArrayHolder] = []
         for nodeIndex in 0 ..< nodesCount {
             let field = schema.fields(at: nodeIndex)!
             let loadInfo = DataLoadInfo(recordBatch: recordBatch!, field: 
field,
                                         nodeIndex: nodeIndex, bufferIndex: 
bufferIndex,
                                         fileData: data, messageOffset: 
messageEndOffset)
+            var result: Result<ArrowArrayHolder, ArrowError>
             if isFixedPrimitive(field.typeType) {
-                let holder = try loadPrimitiveData(loadInfo)
-                columns.append(holder)
+                result = loadPrimitiveData(loadInfo)
                 bufferIndex += 2
             } else {
-                let holder = try loadVariableData(loadInfo)
-                columns.append(holder)
+                result = loadVariableData(loadInfo)
                 bufferIndex += 3
             }
+            
+            switch result {
+            case .success(let holder):
+                columns.append(holder)
+            case .failure(let error):
+                return .failure(error)
+            }
+            
+        }
+        
+        let schemaResult = loadSchema(schema)
+        switch schemaResult {
+        case .success(let arrowSchema):
+            return .success(RecordBatch(arrowSchema, columns: columns))
+        case .failure(let error):
+            return .failure(error)
         }
-
-        return RecordBatch(arrowSchema, columns: columns)
     }
 
-    public func fromStream(_ fileData: Data) throws -> [RecordBatch] {
+    public func fromStream(_ fileData: Data) -> Result<[RecordBatch], 
ArrowError> {
         let footerLength = fileData.withUnsafeBytes { rawBuffer in
             rawBuffer.loadUnaligned(fromByteOffset: fileData.count - 4, as: 
Int32.self)
         }
@@ -138,26 +158,36 @@ public class ArrowReader {
             let message = 
org_apache_arrow_flatbuf_Message.getRootAsMessage(bb: mbb)
             switch message.headerType {
             case .recordbatch:
-                let recordBatch = try loadRecordBatch(message, schema: 
footer.schema!,
-                                                      data: fileData, 
messageEndOffset: messageEndOffset)
-                recordBatchs.append(recordBatch)
+                do {
+                    let recordBatch = try loadRecordBatch(message, schema: 
footer.schema!,
+                                                          data: fileData, 
messageEndOffset: messageEndOffset).get()
+                    recordBatchs.append(recordBatch)
+                } catch let error as ArrowError {
+                    return .failure(error)
+                } catch {
+                    return .failure(.unknownError("Unexpected error: 
\(error)"))
+                }
             default:
-                print("Unhandled header type: \(message.headerType)")
+                return .failure(.unknownError("Unhandled header type: 
\(message.headerType)"))
             }
         }
 
-        return recordBatchs
+        return .success(recordBatchs)
     }
 
-    public func fromFile(_ fileURL: URL) throws -> [RecordBatch] {
-        let fileData = try Data(contentsOf: fileURL)
-        if !validateFileData(fileData) {
-            throw ArrowError.runtimeError("Not a valid arrow file.")
-        }
+    public func fromFile(_ fileURL: URL) -> Result<[RecordBatch], ArrowError> {
+        do {
+            let fileData = try Data(contentsOf: fileURL)
+            if !validateFileData(fileData) {
+                return .failure(.ioError("Not a valid arrow file."))
+            }
 
-        let markerLength = FILEMARKER.utf8.count
-        let footerLengthEnd = Int(fileData.count - markerLength)
-        let data = fileData[..<(footerLengthEnd)]
-        return try fromStream(data)
+            let markerLength = FILEMARKER.utf8.count
+            let footerLengthEnd = Int(fileData.count - markerLength)
+            let data = fileData[..<(footerLengthEnd)]
+            return fromStream(data)
+        } catch {
+            return .failure(.unknownError("Error loading file: \(error)"))
+        }
     }
 }
diff --git a/swift/Arrow/Sources/Arrow/ArrowReaderHelper.swift 
b/swift/Arrow/Sources/Arrow/ArrowReaderHelper.swift
index c4e7b55b01..604b93f766 100644
--- a/swift/Arrow/Sources/Arrow/ArrowReaderHelper.swift
+++ b/swift/Arrow/Sources/Arrow/ArrowReaderHelper.swift
@@ -18,15 +18,72 @@
 import FlatBuffers
 import Foundation
 
-fileprivate func makeFixedHolder<T>(_: T.Type, buffers: [ArrowBuffer]) throws 
-> ChunkedArrayHolder {
-    let nullCount = buffers[0].length
-    let arrowData = try ArrowData(ArrowType.ArrowInt32, buffers: buffers,
-                                  nullCount: nullCount, stride: 
MemoryLayout<T>.stride)
-    let chuckedArray = try ChunkedArray<T>([FixedArray<T>(arrowData)])
-    return ChunkedArrayHolder(chuckedArray)
+fileprivate func makeStringHolder(_ buffers: [ArrowBuffer]) -> 
Result<ArrowArrayHolder, ArrowError> {
+    do {
+        let arrowData = try ArrowData(ArrowType.ArrowString, buffers: buffers,
+                                      nullCount: buffers[0].length, stride: 
MemoryLayout<Int8>.stride)
+        return .success(ArrowArrayHolder(StringArray(arrowData)))
+    } catch let error as ArrowError {
+        return .failure(error)
+    } catch {
+        return .failure(.unknownError("\(error)"))
+    }
+}
+
+fileprivate func makeFloatHolder(_ floatType: 
org_apache_arrow_flatbuf_FloatingPoint, buffers: [ArrowBuffer]) -> 
Result<ArrowArrayHolder, ArrowError> {
+    switch floatType.precision {
+    case .single:
+        return makeFixedHolder(Float.self, buffers: buffers)
+    case .double:
+        return makeFixedHolder(Double.self, buffers: buffers)
+    default:
+        return .failure(.unknownType)
+    }
+}
+
+fileprivate func makeDateHolder(_ dateType: org_apache_arrow_flatbuf_Date, 
buffers: [ArrowBuffer]) -> Result<ArrowArrayHolder, ArrowError> {
+    do  {
+        if dateType.unit == .day {
+            let arrowData = try ArrowData(ArrowType.ArrowString, buffers: 
buffers,
+                                          nullCount: buffers[0].length, 
stride: MemoryLayout<Date>.stride)
+            return .success(ArrowArrayHolder(Date32Array(arrowData)))
+        }
+        
+        let arrowData = try ArrowData(ArrowType.ArrowString, buffers: buffers,
+                                      nullCount: buffers[0].length, stride: 
MemoryLayout<Date>.stride)
+        return .success(ArrowArrayHolder(Date64Array(arrowData)))
+    } catch let error as ArrowError {
+        return .failure(error)
+    } catch {
+        return .failure(.unknownError("\(error)"))
+    }
+}
+
+fileprivate func makeBoolHolder(_ buffers: [ArrowBuffer]) -> 
Result<ArrowArrayHolder, ArrowError> {
+    do {
+        let arrowData = try ArrowData(ArrowType.ArrowInt32, buffers: buffers,
+                                      nullCount: buffers[0].length, stride: 
MemoryLayout<UInt8>.stride)
+        return .success(ArrowArrayHolder(BoolArray(arrowData)))
+    } catch let error as ArrowError {
+        return .failure(error)
+    } catch {
+        return .failure(.unknownError("\(error)"))
+    }
+}
+
+fileprivate func makeFixedHolder<T>(_: T.Type, buffers: [ArrowBuffer]) -> 
Result<ArrowArrayHolder, ArrowError> {
+    do {
+        let arrowData = try ArrowData(ArrowType.ArrowInt32, buffers: buffers,
+                                      nullCount: buffers[0].length, stride: 
MemoryLayout<T>.stride)
+        return .success(ArrowArrayHolder(FixedArray<T>(arrowData)))
+    } catch let error as ArrowError {
+        return .failure(error)
+    } catch {
+        return .failure(.unknownError("\(error)"))
+    }
 }
 
-func makeArrayHolder(_ field: org_apache_arrow_flatbuf_Field, buffers: 
[ArrowBuffer]) throws -> ChunkedArrayHolder {
+func makeArrayHolder(_ field: org_apache_arrow_flatbuf_Field, buffers: 
[ArrowBuffer]) -> Result<ArrowArrayHolder, ArrowError> {
     let type = field.typeType
     switch type {
     case .int:
@@ -34,62 +91,42 @@ func makeArrayHolder(_ field: 
org_apache_arrow_flatbuf_Field, buffers: [ArrowBuf
         let bitWidth = intType.bitWidth
         if bitWidth == 8 {
             if intType.isSigned {
-                return try makeFixedHolder(Int8.self, buffers: buffers)
+                return makeFixedHolder(Int8.self, buffers: buffers)
             } else {
-                return try makeFixedHolder(UInt8.self, buffers: buffers)
+                return makeFixedHolder(UInt8.self, buffers: buffers)
             }
         } else if bitWidth == 16 {
             if intType.isSigned {
-                return try makeFixedHolder(Int16.self, buffers: buffers)
+                return makeFixedHolder(Int16.self, buffers: buffers)
             } else {
-                return try makeFixedHolder(UInt16.self, buffers: buffers)
+                return makeFixedHolder(UInt16.self, buffers: buffers)
             }
         } else if bitWidth == 32 {
             if intType.isSigned {
-                return try makeFixedHolder(Int32.self, buffers: buffers)
+                return makeFixedHolder(Int32.self, buffers: buffers)
             } else {
-                return try makeFixedHolder(UInt32.self, buffers: buffers)
+                return makeFixedHolder(UInt32.self, buffers: buffers)
             }
         } else if bitWidth == 64 {
             if intType.isSigned {
-                return try makeFixedHolder(Int64.self, buffers: buffers)
+                return makeFixedHolder(Int64.self, buffers: buffers)
             } else {
-                return try makeFixedHolder(UInt64.self, buffers: buffers)
+                return makeFixedHolder(UInt64.self, buffers: buffers)
             }
         }
-        throw ValidationError.unknownType
+        return .failure(.unknownType)
     case .bool:
-        let arrowData = try ArrowData(ArrowType.ArrowInt32, buffers: buffers,
-                                      nullCount: buffers[0].length, stride: 
MemoryLayout<UInt8>.stride)
-        let chuckedArray = try ChunkedArray<Bool>([BoolArray(arrowData)])
-        return ChunkedArrayHolder(chuckedArray)
+        return makeBoolHolder(buffers)
     case .floatingpoint:
         let floatType = field.type(type: 
org_apache_arrow_flatbuf_FloatingPoint.self)!
-        switch floatType.precision {
-        case .single:
-            return try makeFixedHolder(Float.self, buffers: buffers)
-        case .double:
-            return try makeFixedHolder(Double.self, buffers: buffers)
-        default:
-            throw ValidationError.unknownType
-        }
+        return makeFloatHolder(floatType, buffers: buffers)
     case .utf8:
-        let arrowData = try ArrowData(ArrowType.ArrowString, buffers: buffers,
-                                      nullCount: buffers[0].length, stride: 
MemoryLayout<Int8>.stride)
-        return ChunkedArrayHolder(try 
ChunkedArray<String>([StringArray(arrowData)]))
+        return makeStringHolder(buffers)
     case .date:
         let dateType = field.type(type: org_apache_arrow_flatbuf_Date.self)!
-        if dateType.unit == .day {
-            let arrowData = try ArrowData(ArrowType.ArrowString, buffers: 
buffers,
-                                          nullCount: buffers[0].length, 
stride: MemoryLayout<Date>.stride)
-            return ChunkedArrayHolder(try 
ChunkedArray<Date>([Date32Array(arrowData)]))
-        }
-        
-        let arrowData = try ArrowData(ArrowType.ArrowString, buffers: buffers,
-                                      nullCount: buffers[0].length, stride: 
MemoryLayout<Date>.stride)
-        return ChunkedArrayHolder(try 
ChunkedArray<Date>([Date64Array(arrowData)]))
+        return makeDateHolder(dateType, buffers: buffers)
     default:
-        throw ValidationError.unknownType
+        return .failure(.unknownType)
     }
 }
 
@@ -149,7 +186,7 @@ func findArrowType(_ field: org_apache_arrow_flatbuf_Field) 
-> ArrowType.Info {
 
 func validateBufferIndex(_ recordBatch: org_apache_arrow_flatbuf_RecordBatch, 
index: Int32) throws {
     if index >= recordBatch.buffersCount {
-        throw ArrowError.runtimeError("Buffer index is out of bounds: 
\(index)")
+        throw ArrowError.outOfBounds(index: Int64(index))
     }
 }
 
diff --git a/swift/Arrow/Sources/Arrow/ArrowSchema.swift 
b/swift/Arrow/Sources/Arrow/ArrowSchema.swift
index 4214403824..fc47ee7307 100644
--- a/swift/Arrow/Sources/Arrow/ArrowSchema.swift
+++ b/swift/Arrow/Sources/Arrow/ArrowSchema.swift
@@ -52,11 +52,13 @@ public class ArrowSchema {
     public class Builder {
         private var fields: [ArrowField] = []
         
+        @discardableResult
         public func addField(_ field: ArrowField) -> Builder {
             fields.append(field)
             return self
         }
 
+        @discardableResult
         public func addField(_ name: String, type: ArrowType.Info, isNullable: 
Bool) -> Builder {
             fields.append(ArrowField(name, type: type, isNullable: isNullable))
             return self
diff --git a/swift/Arrow/Sources/Arrow/ArrowTable.swift 
b/swift/Arrow/Sources/Arrow/ArrowTable.swift
index b8b87079f6..70cabfaa7b 100644
--- a/swift/Arrow/Sources/Arrow/ArrowTable.swift
+++ b/swift/Arrow/Sources/Arrow/ArrowTable.swift
@@ -17,60 +17,6 @@
 
 import Foundation
 
-public class ChunkedArrayHolder {
-    public let type: ArrowType.Info
-    public let length: UInt
-    public let nullCount: UInt
-    public let holder: Any
-    public let getBufferData: () throws -> [Data]
-    public let getBufferDataSizes: () throws -> [Int]
-    public init<T>(_ chunked: ChunkedArray<T>) {
-        self.holder = chunked
-        self.length = chunked.length
-        self.type = chunked.type
-        self.nullCount = chunked.nullCount
-        self.getBufferData = {() throws -> [Data] in 
-            var bufferData = [Data]()
-            var numBuffers = 2;
-            if !isFixedPrimitive(try toFBTypeEnum(chunked.type)) {
-                numBuffers = 3
-            }
-
-            for _ in 0 ..< numBuffers {
-                bufferData.append(Data())
-            }
-
-            for arrow_data in chunked.arrays {
-                for index in 0 ..< numBuffers {
-                    arrow_data.arrowData.buffers[index].append(to: 
&bufferData[index])
-                }
-            }
-
-            return bufferData;
-        }
-        
-        self.getBufferDataSizes = {() throws -> [Int] in
-            var bufferDataSizes = [Int]()
-            var numBuffers = 2;
-            if !isFixedPrimitive(try toFBTypeEnum(chunked.type)) {
-                numBuffers = 3
-            }
-            for _ in 0 ..< numBuffers {
-                bufferDataSizes.append(Int(0))
-            }
-            
-            for arrow_data in chunked.arrays {
-                for index in 0 ..< numBuffers {
-                    bufferDataSizes[index] += 
Int(arrow_data.arrowData.buffers[index].capacity);
-                }
-            }
-
-            return bufferDataSizes;
-        }
-
-    }
-}
-
 public class ArrowColumn {
     public let field: ArrowField
     fileprivate let dataHolder: ChunkedArrayHolder
@@ -83,9 +29,9 @@ public class ArrowColumn {
     }
 
     public var name: String {get{return field.name}}
-    public init<T>(_ field: ArrowField, chunked: ChunkedArray<T>) {
+    public init(_ field: ArrowField, chunked: ChunkedArrayHolder) {
         self.field = field
-        self.dataHolder = ChunkedArrayHolder(chunked)
+        self.dataHolder = chunked
     }
 }
 
@@ -100,43 +46,70 @@ public class ArrowTable {
         self.rowCount = columns[0].length
     }
     
-    public func toRecordBatch() -> RecordBatch {
-        var rbColumns = [ChunkedArrayHolder]()
-        for column in self.columns {
-            rbColumns.append(column.dataHolder)
+    public static func from(recordBatches: [RecordBatch]) -> 
Result<ArrowTable, ArrowError> {
+        if(recordBatches.isEmpty) {
+            return .failure(.arrayHasNoElements)
+        }
+        
+        var holders = [[ArrowArrayHolder]]()
+        let schema = recordBatches[0].schema;
+        for recordBatch in recordBatches {
+            for index in 0..<schema.fields.count {
+                if holders.count <= index {
+                    holders.append([ArrowArrayHolder]())
+                }
+                holders[index].append(recordBatch.columns[index])
+            }
+        }
+        
+        let builder = ArrowTable.Builder()
+        for index in 0..<schema.fields.count {
+            switch ArrowArrayHolder.makeArrowColumn(schema.fields[index], 
holders: holders[index]) {
+            case .success(let column):
+                builder.addColumn(column)
+            case .failure(let error):
+                return .failure(error)
+            }
         }
         
-        return RecordBatch(schema, columns: rbColumns)
+        return .success(builder.finish())
     }
     
     public class Builder {
         let schemaBuilder = ArrowSchema.Builder()
         var columns = [ArrowColumn]()
         
+        @discardableResult
         public func addColumn<T>(_ fieldName: String, arrowArray: 
ArrowArray<T>) throws -> Builder {
             return self.addColumn(fieldName, chunked: try 
ChunkedArray([arrowArray]))
         }
 
+        @discardableResult
         public func addColumn<T>(_ fieldName: String, chunked: 
ChunkedArray<T>) -> Builder {
             let field = ArrowField(fieldName, type: chunked.type, isNullable: 
chunked.nullCount != 0)
-            let _ = self.schemaBuilder.addField(field)
-            self.columns.append(ArrowColumn(field, chunked: chunked))
+            self.schemaBuilder.addField(field)
+            self.columns.append(ArrowColumn(field, chunked: 
ChunkedArrayHolder(chunked)))
             return self
         }
 
+        @discardableResult
         public func addColumn<T>(_ field: ArrowField, arrowArray: 
ArrowArray<T>) throws -> Builder {
-            let _ = self.schemaBuilder.addField(field)
-            self.columns.append(ArrowColumn(field, chunked: try 
ChunkedArray([arrowArray])))
+            self.schemaBuilder.addField(field)
+            let holder = ChunkedArrayHolder(try ChunkedArray([arrowArray]))
+            self.columns.append(ArrowColumn(field, chunked: holder))
             return self
         }
 
+        @discardableResult
         public func addColumn<T>(_ field: ArrowField, chunked: 
ChunkedArray<T>) -> Builder {
-            let _ = self.schemaBuilder.addField(field)
-            self.columns.append(ArrowColumn(field, chunked: chunked))
+            self.schemaBuilder.addField(field)
+            self.columns.append(ArrowColumn(field, chunked: 
ChunkedArrayHolder(chunked)))
             return self
         }
 
+        @discardableResult
         public func addColumn(_ column: ArrowColumn) -> Builder {
+            self.schemaBuilder.addField(column.field)
             self.columns.append(column)
             return self
         }
@@ -150,9 +123,9 @@ public class ArrowTable {
 public class RecordBatch {
     let schema: ArrowSchema
     var columnCount: UInt {get{return UInt(self.columns.count)}}
-    let columns: [ChunkedArrayHolder]
+    let columns: [ArrowArrayHolder]
     let length: UInt
-    public init(_ schema: ArrowSchema, columns: [ChunkedArrayHolder]) {
+    public init(_ schema: ArrowSchema, columns: [ArrowArrayHolder]) {
         self.schema = schema
         self.columns = columns
         self.length = columns[0].length
@@ -160,36 +133,46 @@ public class RecordBatch {
     
     public class Builder {
         let schemaBuilder = ArrowSchema.Builder()
-        var columns = [ChunkedArrayHolder]()
+        var columns = [ArrowArrayHolder]()
         
-        public func addColumn(_ fieldName: String, chunked: 
ChunkedArrayHolder) -> Builder {
-            let field = ArrowField(fieldName, type: chunked.type, isNullable: 
chunked.nullCount != 0)
-            let _ = self.schemaBuilder.addField(field)
-            self.columns.append(chunked)
+        @discardableResult
+        public func addColumn(_ fieldName: String, arrowArray: 
ArrowArrayHolder) -> Builder {
+            let field = ArrowField(fieldName, type: arrowArray.type, 
isNullable: arrowArray.nullCount != 0)
+            self.schemaBuilder.addField(field)
+            self.columns.append(arrowArray)
             return self
         }
 
-        public func addColumn(_ field: ArrowField, chunked: 
ChunkedArrayHolder) -> Builder {
-            let _ = self.schemaBuilder.addField(field)
-            self.columns.append(chunked)
+        @discardableResult
+        public func addColumn(_ field: ArrowField, arrowArray: 
ArrowArrayHolder) -> Builder {
+            self.schemaBuilder.addField(field)
+            self.columns.append(arrowArray)
             return self
         }
 
-        public func finish() -> RecordBatch {
-            return RecordBatch(self.schemaBuilder.finish(), columns: 
self.columns)
+        public func finish() -> Result<RecordBatch, ArrowError> {
+            if columns.count > 0 {
+                let columnLength = columns[0].length
+                for column in columns {
+                    if column.length != columnLength {
+                        return .failure(.runtimeError("Columns have different 
sizes"))
+                    }
+                }
+            }
+            return .success(RecordBatch(self.schemaBuilder.finish(), columns: 
self.columns))
         }
     }
     
-    public func data<T>(for columnIndex: Int) -> ChunkedArray<T> {
+    public func data<T>(for columnIndex: Int) -> ArrowArray<T> {
         let arrayHolder = column(columnIndex)
-        return (arrayHolder.holder as! ChunkedArray<T>)
+        return (arrayHolder.array as! ArrowArray<T>)
     }
     
-    public func column(_ index: Int) -> ChunkedArrayHolder {
+    public func column(_ index: Int) -> ArrowArrayHolder {
         return self.columns[index]
     }
 
-    public func column(_ name: String) -> ChunkedArrayHolder? {
+    public func column(_ name: String) -> ArrowArrayHolder? {
         if let index = self.schema.fieldIndex(name) {
             return self.columns[index]
         }
diff --git a/swift/Arrow/Sources/Arrow/ArrowType.swift 
b/swift/Arrow/Sources/Arrow/ArrowType.swift
index 0dc998287e..4064191918 100644
--- a/swift/Arrow/Sources/Arrow/ArrowType.swift
+++ b/swift/Arrow/Sources/Arrow/ArrowType.swift
@@ -19,11 +19,17 @@ import Foundation
 
 func FlatBuffersVersion_23_1_4() {
 }
-
-public enum ValidationError: Error {
+                                                                               
                                 
+public enum ArrowError: Error {
+    case none
     case unknownType
-    case outOfBounds(index: UInt)
+    case runtimeError(String)
+    case outOfBounds(index: Int64)
     case arrayHasNoElements
+    case unknownError(String)
+    case notImplemented
+    case ioError(String)
+    case invalid(String)
 }
 
 public enum ArrowTypeId {
diff --git a/swift/Arrow/Sources/Arrow/ArrowWriter.swift 
b/swift/Arrow/Sources/Arrow/ArrowWriter.swift
index 70b4d0ed18..c76dd94c13 100644
--- a/swift/Arrow/Sources/Arrow/ArrowWriter.swift
+++ b/swift/Arrow/Sources/Arrow/ArrowWriter.swift
@@ -53,45 +53,70 @@ public class ArrowWriter {
         }
     }
 
-    private func writeField(_ fbb: inout FlatBufferBuilder, field: ArrowField) 
throws -> Offset {
+    private func writeField(_ fbb: inout FlatBufferBuilder, field: ArrowField) 
-> Result<Offset, ArrowError> {
         let nameOffset = fbb.create(string: field.name)
-        let fieldTypeOfffset = try toFBType(&fbb, infoType: field.type)
+        let fieldTypeOffsetResult = toFBType(&fbb, infoType: field.type)
         let startOffset = org_apache_arrow_flatbuf_Field.startField(&fbb)
         org_apache_arrow_flatbuf_Field.add(name: nameOffset, &fbb)
         org_apache_arrow_flatbuf_Field.add(nullable: field.isNullable, &fbb)
-        org_apache_arrow_flatbuf_Field.add(typeType: try 
toFBTypeEnum(field.type), &fbb)
-        org_apache_arrow_flatbuf_Field.add(type: fieldTypeOfffset, &fbb)
-        return org_apache_arrow_flatbuf_Field.endField(&fbb, start: 
startOffset)
+        switch toFBTypeEnum(field.type) {
+        case .success(let type):
+            org_apache_arrow_flatbuf_Field.add(typeType: type, &fbb)
+        case .failure(let error):
+            return .failure(error)
+        }
+        
+        switch fieldTypeOffsetResult {
+        case .success(let offset):
+            org_apache_arrow_flatbuf_Field.add(type: offset, &fbb)
+            return .success(org_apache_arrow_flatbuf_Field.endField(&fbb, 
start: startOffset))
+        case .failure(let error):
+            return .failure(error)
+        }
     }
 
-    private func writeSchema(_ fbb: inout FlatBufferBuilder, schema: 
ArrowSchema) throws -> Offset {
+    private func writeSchema(_ fbb: inout FlatBufferBuilder, schema: 
ArrowSchema) -> Result<Offset, ArrowError> {
         var fieldOffsets = [Offset]()
         for field in schema.fields {
-            fieldOffsets.append(try writeField(&fbb, field: field))
+            switch writeField(&fbb, field: field) {
+            case .success(let offset):
+                fieldOffsets.append(offset)
+            case .failure(let error):
+                return .failure(error)
+            }
+            
         }
 
         let fieldsOffset: Offset = fbb.createVector(ofOffsets: fieldOffsets)
         let schemaOffset = org_apache_arrow_flatbuf_Schema.createSchema(&fbb, 
endianness: .little, fieldsVectorOffset: fieldsOffset)
-        return schemaOffset
+        return .success(schemaOffset)
 
     }
     
-    private func writeRecordBatches(_ writer: inout DataWriter, batches: 
[RecordBatch]) throws -> [org_apache_arrow_flatbuf_Block] {
+    private func writeRecordBatches(_ writer: inout DataWriter, batches: 
[RecordBatch]) -> Result<[org_apache_arrow_flatbuf_Block], ArrowError> {
         var rbBlocks = [org_apache_arrow_flatbuf_Block]()
 
         for batch in batches {
             let startIndex = writer.count
-            let rbResult = try writeRecordBatch(batch: batch)
-            withUnsafeBytes(of: rbResult.1.o.littleEndian) 
{writer.append(Data($0))}
-            writer.append(rbResult.0)
-            try writeRecordBatchData(&writer, batch: batch)
-            rbBlocks.append(org_apache_arrow_flatbuf_Block(offset: 
Int64(startIndex), metaDataLength: Int32(0), bodyLength: Int64(rbResult.1.o)))
+            switch writeRecordBatch(batch: batch) {
+            case .success(let rbResult):
+                withUnsafeBytes(of: rbResult.1.o.littleEndian) 
{writer.append(Data($0))}
+                writer.append(rbResult.0)
+                switch writeRecordBatchData(&writer, batch: batch) {
+                case .success(_):
+                    rbBlocks.append(org_apache_arrow_flatbuf_Block(offset: 
Int64(startIndex), metaDataLength: Int32(0), bodyLength: Int64(rbResult.1.o)))
+                case .failure(let error):
+                    return .failure(error)
+                }
+            case .failure(let error):
+                return .failure(error)
+            }
         }
                 
-        return rbBlocks
+        return .success(rbBlocks)
     }
         
-    private func writeRecordBatch(batch: RecordBatch) throws -> (Data, Offset) 
{
+    private func writeRecordBatch(batch: RecordBatch) -> Result<(Data, 
Offset), ArrowError> {
         let schema = batch.schema
         var output = Data()
         var fbb = FlatBufferBuilder()
@@ -112,7 +137,7 @@ public class ArrowWriter {
         var bufferOffset = Int(0)
         for index in 0 ..< batch.schema.fields.count {
             let column = batch.column(index)
-            let colBufferDataSizes = try column.getBufferDataSizes()
+            let colBufferDataSizes = column.getBufferDataSizes()
             for var bufferDataSize in colBufferDataSizes {
                 bufferDataSize = getPadForAlignment(bufferDataSize)
                 let buffer = org_apache_arrow_flatbuf_Buffer(offset: 
Int64(bufferOffset), length: Int64(bufferDataSize))
@@ -140,66 +165,95 @@ public class ArrowWriter {
         let messageOffset = org_apache_arrow_flatbuf_Message.endMessage(&fbb, 
start: startMessage)
         fbb.finish(offset: messageOffset)
         output.append(fbb.data)
-        return (output, Offset(offset: UInt32(output.count)))
+        return .success((output, Offset(offset: UInt32(output.count))))
     }
     
-    private func writeRecordBatchData(_ writer: inout DataWriter, batch: 
RecordBatch) throws {
+    private func writeRecordBatchData(_ writer: inout DataWriter, batch: 
RecordBatch) -> Result<Bool, ArrowError> {
         for index in 0 ..< batch.schema.fields.count {
             let column = batch.column(index)
-            let colBufferData = try column.getBufferData()
+            let colBufferData = column.getBufferData();
             for var bufferData in colBufferData {
                 addPadForAlignment(&bufferData)
                 writer.append(bufferData)
             }
         }
+
+        return .success(true)
     }
     
-    private func writeFooter(schema: ArrowSchema, rbBlocks: 
[org_apache_arrow_flatbuf_Block])  throws -> Data {
+    private func writeFooter(schema: ArrowSchema, rbBlocks: 
[org_apache_arrow_flatbuf_Block])  -> Result<Data, ArrowError> {
         var fbb: FlatBufferBuilder = FlatBufferBuilder()
-        let schemaOffset = try writeSchema(&fbb, schema: schema)
-        
-        let _ = fbb.startVector(rbBlocks.count, elementSize: 
MemoryLayout<org_apache_arrow_flatbuf_Block>.size)
-        for blkInfo in rbBlocks.reversed() {
-            fbb.create(struct: blkInfo)
+        switch writeSchema(&fbb, schema: schema) {
+        case .success(let schemaOffset):
+            fbb.startVector(rbBlocks.count, elementSize: 
MemoryLayout<org_apache_arrow_flatbuf_Block>.size)
+            for blkInfo in rbBlocks.reversed() {
+                fbb.create(struct: blkInfo)
+            }
+            
+            let rbBlkEnd = fbb.endVector(len: rbBlocks.count)
+            
+            
+            let footerStartOffset = 
org_apache_arrow_flatbuf_Footer.startFooter(&fbb)
+            org_apache_arrow_flatbuf_Footer.add(schema: schemaOffset, &fbb)
+            org_apache_arrow_flatbuf_Footer.addVectorOf(recordBatches: 
rbBlkEnd, &fbb)
+            let footerOffset = org_apache_arrow_flatbuf_Footer.endFooter(&fbb, 
start: footerStartOffset)
+            fbb.finish(offset: footerOffset)
+        case .failure(let error):
+            return .failure(error)
         }
-        
-        let rbBlkEnd = fbb.endVector(len: rbBlocks.count)
-        
 
-        let footerStartOffset = 
org_apache_arrow_flatbuf_Footer.startFooter(&fbb)
-        org_apache_arrow_flatbuf_Footer.add(schema: schemaOffset, &fbb)
-        org_apache_arrow_flatbuf_Footer.addVectorOf(recordBatches: rbBlkEnd, 
&fbb)
-        let footerOffset = org_apache_arrow_flatbuf_Footer.endFooter(&fbb, 
start: footerStartOffset)
-        fbb.finish(offset: footerOffset)
-        return fbb.data
+        return .success(fbb.data)
     }
 
-    private func writeStream(_ writer: inout DataWriter, schema: ArrowSchema, 
batches: [RecordBatch]) throws {
+    private func writeStream(_ writer: inout DataWriter, schema: ArrowSchema, 
batches: [RecordBatch]) -> Result<Bool, ArrowError> {
         var fbb: FlatBufferBuilder = FlatBufferBuilder()
-        let schemaOffset = try writeSchema(&fbb, schema: schema)
-        fbb.finish(offset: schemaOffset)
-        writer.append(fbb.data)
-        
-        let rbBlocks = try writeRecordBatches(&writer, batches: batches)
-        let footerData = try writeFooter(schema: schema, rbBlocks: rbBlocks)
-        fbb.finish(offset: Offset(offset: fbb.buffer.size))
-        let footerOffset = writer.count
-        writer.append(footerData)
-        addPadForAlignment(&writer)
+        switch writeSchema(&fbb, schema: schema) {
+        case .success(let schemaOffset):
+            fbb.finish(offset: schemaOffset)
+            writer.append(fbb.data)
+        case .failure(let error):
+            return .failure(error)
+        }
         
-        withUnsafeBytes(of: Int32(0).littleEndian) { writer.append(Data($0)) }
-        let footerDiff = (UInt32(writer.count) - UInt32(footerOffset));
-        withUnsafeBytes(of: footerDiff.littleEndian) { writer.append(Data($0)) 
}
+        switch writeRecordBatches(&writer, batches: batches) {
+        case .success(let rbBlocks):
+            switch writeFooter(schema: schema, rbBlocks: rbBlocks) {
+            case .success(let footerData):
+                fbb.finish(offset: Offset(offset: fbb.buffer.size))
+                let footerOffset = writer.count
+                writer.append(footerData)
+                addPadForAlignment(&writer)
+                
+                withUnsafeBytes(of: Int32(0).littleEndian) { 
writer.append(Data($0)) }
+                let footerDiff = (UInt32(writer.count) - UInt32(footerOffset));
+                withUnsafeBytes(of: footerDiff.littleEndian) { 
writer.append(Data($0)) }
+            case .failure(let error):
+                return .failure(error)
+            }
+        case .failure(let error):
+            return .failure(error)
+        }
+
+        return .success(true)
     }
 
-    public func toStream(_ schema: ArrowSchema, batches: [RecordBatch]) throws 
-> Data {
+    public func toStream(_ schema: ArrowSchema, batches: [RecordBatch]) -> 
Result<Data, ArrowError> {
         var writer: any DataWriter = InMemDataWriter()
-        try writeStream(&writer, schema: schema, batches: batches)
-        return (writer as! InMemDataWriter).data
+        switch writeStream(&writer, schema: schema, batches: batches) {
+        case .success(_):
+            return .success((writer as! InMemDataWriter).data)
+        case .failure(let error):
+            return .failure(error)
+        }
     }
 
-    public func toFile(_ fileName: URL, schema: ArrowSchema, batches: 
[RecordBatch]) throws {
-        try Data().write(to: fileName)
+    public func toFile(_ fileName: URL, schema: ArrowSchema, batches: 
[RecordBatch]) -> Result<Bool, ArrowError> {
+        do {
+            try Data().write(to: fileName)
+        } catch {
+            return .failure(.ioError("\(error)"))
+        }
+        
         let fileHandle = FileHandle(forUpdatingAtPath: fileName.path)!
         defer { fileHandle.closeFile() }
         
@@ -208,7 +262,13 @@ public class ArrowWriter {
 
         var writer: any DataWriter = FileDataWriter(fileHandle)
         writer.append(FILEMARKER.data(using: .utf8)!)
-        try writeStream(&writer, schema: schema, batches: batches)
-        writer.append(FILEMARKER.data(using: .utf8)!)
+        switch writeStream(&writer, schema: schema, batches: batches) {
+        case .success(_):
+            writer.append(FILEMARKER.data(using: .utf8)!)
+        case .failure(let error):
+            return .failure(error)
+        }
+        
+        return .success(true)
     }
 }
diff --git a/swift/Arrow/Sources/Arrow/ArrowWriterHelper.swift 
b/swift/Arrow/Sources/Arrow/ArrowWriterHelper.swift
index 520d4f0614..75f76be1e2 100644
--- a/swift/Arrow/Sources/Arrow/ArrowWriterHelper.swift
+++ b/swift/Arrow/Sources/Arrow/ArrowWriterHelper.swift
@@ -24,53 +24,53 @@ extension Data {
     }
 }
 
-func toFBTypeEnum(_ infoType: ArrowType.Info) throws -> 
org_apache_arrow_flatbuf_Type_ {
+func toFBTypeEnum(_ infoType: ArrowType.Info) -> 
Result<org_apache_arrow_flatbuf_Type_, ArrowError> {
     if infoType == ArrowType.ArrowInt8 || infoType == ArrowType.ArrowInt16 ||
         infoType == ArrowType.ArrowInt64 || infoType == ArrowType.ArrowUInt8 ||
         infoType == ArrowType.ArrowUInt16 || infoType == ArrowType.ArrowUInt32 
||
         infoType == ArrowType.ArrowUInt64 || infoType == ArrowType.ArrowInt32 {
-        return org_apache_arrow_flatbuf_Type_.int
+        return .success(org_apache_arrow_flatbuf_Type_.int)
     } else if infoType == ArrowType.ArrowFloat || infoType == 
ArrowType.ArrowDouble {
-        return org_apache_arrow_flatbuf_Type_.floatingpoint
+        return .success(org_apache_arrow_flatbuf_Type_.floatingpoint)
     } else if infoType == ArrowType.ArrowString {
-        return org_apache_arrow_flatbuf_Type_.utf8
+        return .success(org_apache_arrow_flatbuf_Type_.utf8)
     } else if infoType == ArrowType.ArrowBool {
-        return org_apache_arrow_flatbuf_Type_.bool
+        return .success(org_apache_arrow_flatbuf_Type_.bool)
     } else if infoType == ArrowType.ArrowDate32 || infoType == 
ArrowType.ArrowDate64 {
-        return org_apache_arrow_flatbuf_Type_.date
+        return .success(org_apache_arrow_flatbuf_Type_.date)
     }
 
-    throw ValidationError.unknownType
+    return .failure(.unknownType)
 }
 
-func toFBType(_ fbb: inout FlatBufferBuilder, infoType: ArrowType.Info) throws 
-> Offset {
+func toFBType(_ fbb: inout FlatBufferBuilder, infoType: ArrowType.Info) -> 
Result<Offset, ArrowError> {
     if infoType == ArrowType.ArrowInt8 || infoType == ArrowType.ArrowUInt8 {
-        return org_apache_arrow_flatbuf_Int.createInt(&fbb, bitWidth: 8, 
isSigned: infoType == ArrowType.ArrowInt8);
+        return .success(org_apache_arrow_flatbuf_Int.createInt(&fbb, bitWidth: 
8, isSigned: infoType == ArrowType.ArrowInt8))
     } else if infoType == ArrowType.ArrowInt16 || infoType == 
ArrowType.ArrowUInt16 {
-        return org_apache_arrow_flatbuf_Int.createInt(&fbb, bitWidth: 16, 
isSigned: infoType == ArrowType.ArrowInt16);
+        return .success(org_apache_arrow_flatbuf_Int.createInt(&fbb, bitWidth: 
16, isSigned: infoType == ArrowType.ArrowInt16))
     } else if infoType == ArrowType.ArrowInt32 || infoType == 
ArrowType.ArrowUInt32 {
-        return org_apache_arrow_flatbuf_Int.createInt(&fbb, bitWidth: 32, 
isSigned: infoType == ArrowType.ArrowInt32);
+        return .success(org_apache_arrow_flatbuf_Int.createInt(&fbb, bitWidth: 
32, isSigned: infoType == ArrowType.ArrowInt32))
     } else if infoType == ArrowType.ArrowInt64 || infoType == 
ArrowType.ArrowUInt64 {
-        return org_apache_arrow_flatbuf_Int.createInt(&fbb, bitWidth: 64, 
isSigned: infoType == ArrowType.ArrowInt64);
+        return .success(org_apache_arrow_flatbuf_Int.createInt(&fbb, bitWidth: 
64, isSigned: infoType == ArrowType.ArrowInt64))
     } else if infoType == ArrowType.ArrowFloat {
-        return 
org_apache_arrow_flatbuf_FloatingPoint.createFloatingPoint(&fbb, precision: 
.single)
+        return 
.success(org_apache_arrow_flatbuf_FloatingPoint.createFloatingPoint(&fbb, 
precision: .single))
     } else if infoType == ArrowType.ArrowDouble {
-        return 
org_apache_arrow_flatbuf_FloatingPoint.createFloatingPoint(&fbb, precision: 
.double)
+        return 
.success(org_apache_arrow_flatbuf_FloatingPoint.createFloatingPoint(&fbb, 
precision: .double))
     } else if infoType == ArrowType.ArrowString {
-        return org_apache_arrow_flatbuf_Utf8.endUtf8(&fbb, start: 
org_apache_arrow_flatbuf_Utf8.startUtf8(&fbb))
+        return .success(org_apache_arrow_flatbuf_Utf8.endUtf8(&fbb, start: 
org_apache_arrow_flatbuf_Utf8.startUtf8(&fbb)))
     } else if infoType == ArrowType.ArrowBool {
-        return org_apache_arrow_flatbuf_Bool.endBool(&fbb, start: 
org_apache_arrow_flatbuf_Bool.startBool(&fbb))
+        return .success(org_apache_arrow_flatbuf_Bool.endBool(&fbb, start: 
org_apache_arrow_flatbuf_Bool.startBool(&fbb)))
     } else if infoType == ArrowType.ArrowDate32 {
         let startOffset = org_apache_arrow_flatbuf_Date.startDate(&fbb)
         org_apache_arrow_flatbuf_Date.add(unit: .day, &fbb)
-        return org_apache_arrow_flatbuf_Date.endDate(&fbb, start: startOffset)
+        return .success(org_apache_arrow_flatbuf_Date.endDate(&fbb, start: 
startOffset))
     } else if infoType == ArrowType.ArrowDate64 {
         let startOffset = org_apache_arrow_flatbuf_Date.startDate(&fbb)
         org_apache_arrow_flatbuf_Date.add(unit: .millisecond, &fbb)
-        return org_apache_arrow_flatbuf_Date.endDate(&fbb, start: startOffset)
+        return .success(org_apache_arrow_flatbuf_Date.endDate(&fbb, start: 
startOffset))
     }
-
-    throw ValidationError.unknownType
+    
+    return .failure(.unknownType)
 }
 
 func addPadForAlignment(_ data: inout Data, alignment: Int = 8) {
diff --git a/swift/Arrow/Sources/Arrow/ChunkedArray.swift 
b/swift/Arrow/Sources/Arrow/ChunkedArray.swift
index 2e060b3b66..c23c953290 100644
--- a/swift/Arrow/Sources/Arrow/ChunkedArray.swift
+++ b/swift/Arrow/Sources/Arrow/ChunkedArray.swift
@@ -20,6 +20,73 @@ import Foundation
 public protocol AsString {
     func asString(_ index: UInt) -> String
 }
+
+public class ChunkedArrayHolder {
+    public let type: ArrowType.Info
+    public let length: UInt
+    public let nullCount: UInt
+    public let holder: Any
+    public let getBufferData: () -> Result<[Data], ArrowError>
+    public let getBufferDataSizes: () -> Result<[Int], ArrowError>
+    public init<T>(_ chunked: ChunkedArray<T>) {
+        self.holder = chunked
+        self.length = chunked.length
+        self.type = chunked.type
+        self.nullCount = chunked.nullCount
+        self.getBufferData = {() -> Result<[Data], ArrowError> in
+            var bufferData = [Data]()
+            var numBuffers = 2;
+            switch toFBTypeEnum(chunked.type) {
+            case .success(let fbType):
+                if !isFixedPrimitive(fbType) {
+                    numBuffers = 3
+                }
+            case .failure(let error):
+                return .failure(error)
+            }
+
+            for _ in 0 ..< numBuffers {
+                bufferData.append(Data())
+            }
+
+            for arrow_data in chunked.arrays {
+                for index in 0 ..< numBuffers {
+                    arrow_data.arrowData.buffers[index].append(to: 
&bufferData[index])
+                }
+            }
+
+            return .success(bufferData);
+        }
+        
+        self.getBufferDataSizes = {() -> Result<[Int], ArrowError> in
+            var bufferDataSizes = [Int]()
+            var numBuffers = 2;
+            
+            switch toFBTypeEnum(chunked.type) {
+            case .success(let fbType):
+                if !isFixedPrimitive(fbType) {
+                    numBuffers = 3
+                }
+            case .failure(let error):
+                return .failure(error)
+            }
+            
+            for _ in 0 ..< numBuffers {
+                bufferDataSizes.append(Int(0))
+            }
+            
+            for arrow_data in chunked.arrays {
+                for index in 0 ..< numBuffers {
+                    bufferDataSizes[index] += 
Int(arrow_data.arrowData.buffers[index].capacity)
+                }
+            }
+
+            return .success(bufferDataSizes)
+        }
+
+    }
+}
+
 public class ChunkedArray<T> : AsString {
     public let arrays: [ArrowArray<T>]
     public let type: ArrowType.Info
@@ -29,7 +96,7 @@ public class ChunkedArray<T> : AsString {
     
     public init(_ arrays: [ArrowArray<T>]) throws {
         if arrays.count == 0 {
-            throw ValidationError.arrayHasNoElements
+            throw ArrowError.arrayHasNoElements
         }
         
         self.type = arrays[0].arrowData.type
@@ -53,7 +120,7 @@ public class ChunkedArray<T> : AsString {
         var localIndex = index
         var arrayIndex = 0;
         var len: UInt = arrays[arrayIndex].length
-        while localIndex > len {
+        while localIndex > (len - 1) {
             arrayIndex += 1
             if arrayIndex > arrays.count {
                 return nil
diff --git a/swift/Arrow/Tests/ArrowTests/IPCTests.swift 
b/swift/Arrow/Tests/ArrowTests/IPCTests.swift
index f57f0435ad..1aa6873dcb 100644
--- a/swift/Arrow/Tests/ArrowTests/IPCTests.swift
+++ b/swift/Arrow/Tests/ArrowTests/IPCTests.swift
@@ -19,7 +19,16 @@ import XCTest
 import FlatBuffers
 @testable import Arrow
 
-func checkBoolRecordBatch(_ recordBatches: [RecordBatch]) {
+@discardableResult
+func checkBoolRecordBatch(_ result: Result<[RecordBatch], ArrowError>) throws 
-> [RecordBatch] {
+    let recordBatches: [RecordBatch]
+    switch result {
+    case .success(let rbBatches):
+        recordBatches = rbBatches
+    case .failure(let error):
+        throw error
+    }
+    
     XCTAssertEqual(recordBatches.count, 1)
     for recordBatch in recordBatches {
         XCTAssertEqual(recordBatch.length, 5)
@@ -31,7 +40,7 @@ func checkBoolRecordBatch(_ recordBatches: [RecordBatch]) {
         XCTAssertEqual(recordBatch.schema.fields[1].type, 
ArrowType.ArrowString)
         for index in 0..<recordBatch.length {
             let column = recordBatch.columns[0]
-            let str = column.holder as! AsString
+            let str = column.array as! AsString
             let val = "\(str.asString(index))"
             if index == 0 || index == 4 {
                 XCTAssertEqual(val, "true")
@@ -42,6 +51,8 @@ func checkBoolRecordBatch(_ recordBatches: [RecordBatch]) {
             }
         }
     }
+    
+    return recordBatches
 }
 
 func currentDirectory(path: String = #file) -> URL {
@@ -52,7 +63,15 @@ final class IPCFileReaderTests: XCTestCase {
     func testFileReader_double() throws {
         let fileURL = 
currentDirectory().appendingPathComponent("../../testdata_double.arrow")
         let arrowReader = ArrowReader()
-        let recordBatches = try arrowReader.fromFile(fileURL)
+        let result = arrowReader.fromFile(fileURL)
+        let recordBatches: [RecordBatch]
+        switch result {
+        case .success(let rbBatches):
+            recordBatches = rbBatches
+        case .failure(let error):
+            throw error
+        }
+
         XCTAssertEqual(recordBatches.count, 1)
         for recordBatch in recordBatches {
             XCTAssertEqual(recordBatch.length, 5)
@@ -64,7 +83,7 @@ final class IPCFileReaderTests: XCTestCase {
             XCTAssertEqual(recordBatch.schema.fields[1].type, 
ArrowType.ArrowString)
             for index in 0..<recordBatch.length {
                 let column = recordBatch.columns[1]
-                let str = column.holder as! AsString
+                let str = column.array as! AsString
                 let val = "\(str.asString(index))"
                 if index != 1 {
                     XCTAssertNotEqual(val, "")
@@ -78,28 +97,37 @@ final class IPCFileReaderTests: XCTestCase {
     func testFileReader_bool() throws {
         let fileURL = 
currentDirectory().appendingPathComponent("../../testdata_bool.arrow")
         let arrowReader = ArrowReader()
-        let fileRBs = try arrowReader.fromFile(fileURL)
-        checkBoolRecordBatch(fileRBs)
+        try checkBoolRecordBatch(arrowReader.fromFile(fileURL))
     }
     
+    
     func testFileWriter_bool() throws {
         //read existing file
         let fileURL = 
currentDirectory().appendingPathComponent("../../testdata_bool.arrow")
         let arrowReader = ArrowReader()
-        let fileRBs = try arrowReader.fromFile(fileURL)
-        checkBoolRecordBatch(fileRBs)
+        let fileRBs = try checkBoolRecordBatch(arrowReader.fromFile(fileURL))
         let arrowWriter = ArrowWriter()
         //write data from file to a stream
-        let writeData = try arrowWriter.toStream(fileRBs[0].schema, batches: 
fileRBs)
-        //read stream back into recordbatches
-        checkBoolRecordBatch(try arrowReader.fromStream(writeData))
+        switch arrowWriter.toStream(fileRBs[0].schema, batches: fileRBs) {
+        case .success(let writeData):
+            //read stream back into recordbatches
+            try checkBoolRecordBatch(arrowReader.fromStream(writeData))
+        case .failure(let error):
+            throw error
+        }
+
         //write file record batches to another file
         let outputUrl = 
currentDirectory().appendingPathComponent("../../testfilewriter_bool.arrow")
-        try arrowWriter.toFile(outputUrl, schema: fileRBs[0].schema, batches: 
fileRBs)
-        checkBoolRecordBatch(try arrowReader.fromFile(outputUrl))
+        switch arrowWriter.toFile(outputUrl, schema: fileRBs[0].schema, 
batches: fileRBs) {
+        case .success(_):
+            try checkBoolRecordBatch(arrowReader.fromFile(outputUrl))
+        case .failure(let error):
+            throw error
+        }
+        
     }
 
-    func makeSchema() throws -> ArrowSchema {
+    func makeSchema() -> ArrowSchema {
         let schemaBuilder = ArrowSchema.Builder();
         return schemaBuilder.addField("col1", type: ArrowType.ArrowUInt8, 
isNullable: true)
             .addField("col2", type: ArrowType.ArrowString, isNullable: false)
@@ -111,50 +139,74 @@ final class IPCFileReaderTests: XCTestCase {
         let uint8Builder: NumberArrayBuilder<UInt8> = try 
ArrowArrayBuilders.loadNumberArrayBuilder();
         uint8Builder.append(10)
         uint8Builder.append(22)
+        uint8Builder.append(33)
+        uint8Builder.append(44)
         let stringBuilder = try ArrowArrayBuilders.loadStringArrayBuilder();
         stringBuilder.append("test10")
         stringBuilder.append("test22")
+        stringBuilder.append("test33")
+        stringBuilder.append("test44")
         let date32Builder = try ArrowArrayBuilders.loadDate32ArrayBuilder();
         let date2 = Date(timeIntervalSinceReferenceDate: 86400 * 1)
         let date1 = Date(timeIntervalSinceReferenceDate: 86400 * 5000 + 352)
         date32Builder.append(date1)
         date32Builder.append(date2)
-        
-        let intHolder = ChunkedArrayHolder(try 
ChunkedArray([uint8Builder.finish()]))
-        let stringHolder = ChunkedArrayHolder(try 
ChunkedArray([stringBuilder.finish()]))
-        let date32Holder = ChunkedArrayHolder(try 
ChunkedArray([date32Builder.finish()]))
-        return RecordBatch.Builder()
-            .addColumn("col1", chunked: intHolder)
-            .addColumn("col2", chunked: stringHolder)
-            .addColumn("col3", chunked: date32Holder)
+        date32Builder.append(date1)
+        date32Builder.append(date2)
+
+        let intHolder = ArrowArrayHolder(try uint8Builder.finish())
+        let stringHolder = ArrowArrayHolder(try stringBuilder.finish())
+        let date32Holder = ArrowArrayHolder(try date32Builder.finish())
+        let result = RecordBatch.Builder()
+            .addColumn("col1", arrowArray: intHolder)
+            .addColumn("col2", arrowArray: stringHolder)
+            .addColumn("col3", arrowArray: date32Holder)
             .finish()
+        switch result {
+        case .success(let recordBatch):
+            return recordBatch
+        case .failure(let error):
+            throw error
+        }
     }
     
     func testInMemoryToFromStream() throws {
         //read existing file
-        let schema = try makeSchema()
+        let schema = makeSchema()
         let recordBatch = try makeRecordBatch()
         let arrowWriter = ArrowWriter()
-        let writeData = try arrowWriter.toStream(schema, batches: 
[recordBatch])
-        let arrowReader = ArrowReader()
-        let recordBatches = try arrowReader.fromStream(writeData)
-        XCTAssertEqual(recordBatches.count, 1)
-        for recordBatch in recordBatches {
-            XCTAssertEqual(recordBatch.length, 2)
-            XCTAssertEqual(recordBatch.columns.count, 3)
-            XCTAssertEqual(recordBatch.schema.fields.count, 3)
-            XCTAssertEqual(recordBatch.schema.fields[0].name, "col1")
-            XCTAssertEqual(recordBatch.schema.fields[0].type, 
ArrowType.ArrowUInt8)
-            XCTAssertEqual(recordBatch.schema.fields[1].name, "col2")
-            XCTAssertEqual(recordBatch.schema.fields[1].type, 
ArrowType.ArrowString)
-            XCTAssertEqual(recordBatch.schema.fields[2].name, "col3")
-            XCTAssertEqual(recordBatch.schema.fields[2].type, 
ArrowType.ArrowDate32)
-            let dateVal = "\((recordBatch.columns[2].holder as! 
AsString).asString(0))"
-            XCTAssertEqual(dateVal, "2014-09-10 00:00:00 +0000")
-            let stringVal = "\((recordBatch.columns[1].holder as! 
AsString).asString(1))"
-            XCTAssertEqual(stringVal, "test22")
-            let uintVal = "\((recordBatch.columns[0].holder as! 
AsString).asString(0))"
-            XCTAssertEqual(uintVal, "10")
+        switch arrowWriter.toStream(schema, batches: [recordBatch]) {
+        case .success(let writeData):
+            let arrowReader = ArrowReader()
+            switch arrowReader.fromStream(writeData) {
+            case .success(let recordBatches):
+                XCTAssertEqual(recordBatches.count, 1)
+                for recordBatch in recordBatches {
+                    XCTAssertEqual(recordBatch.length, 4)
+                    XCTAssertEqual(recordBatch.columns.count, 3)
+                    XCTAssertEqual(recordBatch.schema.fields.count, 3)
+                    XCTAssertEqual(recordBatch.schema.fields[0].name, "col1")
+                    XCTAssertEqual(recordBatch.schema.fields[0].type, 
ArrowType.ArrowUInt8)
+                    XCTAssertEqual(recordBatch.schema.fields[1].name, "col2")
+                    XCTAssertEqual(recordBatch.schema.fields[1].type, 
ArrowType.ArrowString)
+                    XCTAssertEqual(recordBatch.schema.fields[2].name, "col3")
+                    XCTAssertEqual(recordBatch.schema.fields[2].type, 
ArrowType.ArrowDate32)
+                    let dateVal = "\((recordBatch.columns[2].array as! 
AsString).asString(0))"
+                    XCTAssertEqual(dateVal, "2014-09-10 00:00:00 +0000")
+                    let stringVal = "\((recordBatch.columns[1].array as! 
AsString).asString(1))"
+                    XCTAssertEqual(stringVal, "test22")
+                    let uintVal = "\((recordBatch.columns[0].array as! 
AsString).asString(0))"
+                    XCTAssertEqual(uintVal, "10")
+                    let stringVal2 = "\((recordBatch.columns[1].array as! 
AsString).asString(3))"
+                    XCTAssertEqual(stringVal2, "test44")
+                    let uintVal2 = "\((recordBatch.columns[0].array as! 
AsString).asString(3))"
+                    XCTAssertEqual(uintVal2, "44")
+                }
+            case.failure(let error):
+                throw error
+            }
+        case .failure(let error):
+            throw error
         }
     }
 }
diff --git a/swift/Arrow/Tests/ArrowTests/RecordBatchTests.swift 
b/swift/Arrow/Tests/ArrowTests/RecordBatchTests.swift
index 8af34d5c9d..5da4461765 100644
--- a/swift/Arrow/Tests/ArrowTests/RecordBatchTests.swift
+++ b/swift/Arrow/Tests/ArrowTests/RecordBatchTests.swift
@@ -27,25 +27,29 @@ final class RecordBatchTests: XCTestCase {
         stringBuilder.append("test10")
         stringBuilder.append("test22")
         
-        let intHolder = ChunkedArrayHolder(try 
ChunkedArray([uint8Builder.finish()]))
-        let stringHolder = ChunkedArrayHolder(try 
ChunkedArray([stringBuilder.finish()]))
-        let recordBatch = RecordBatch.Builder()
-            .addColumn("col1", chunked: intHolder)
-            .addColumn("col2", chunked: stringHolder)
+        let intHolder = ArrowArrayHolder(try uint8Builder.finish())
+        let stringHolder = ArrowArrayHolder(try stringBuilder.finish())
+        let result = RecordBatch.Builder()
+            .addColumn("col1", arrowArray: intHolder)
+            .addColumn("col2", arrowArray: stringHolder)
             .finish()
-
-        let schema = recordBatch.schema
-        XCTAssertEqual(schema.fields.count, 2)
-        XCTAssertEqual(schema.fields[0].name, "col1")
-        XCTAssertEqual(schema.fields[0].type, ArrowType.ArrowUInt8)
-        XCTAssertEqual(schema.fields[0].isNullable, false)
-        XCTAssertEqual(schema.fields[1].name, "col2")
-        XCTAssertEqual(schema.fields[1].type, ArrowType.ArrowString)
-        XCTAssertEqual(schema.fields[1].isNullable, false)
-        XCTAssertEqual(recordBatch.columns.count, 2)
-        let col1: ChunkedArray<UInt8> = recordBatch.data(for: 0);
-        let col2: ChunkedArray<String> = recordBatch.data(for: 1);
-        XCTAssertEqual(col1.length, 2)
-        XCTAssertEqual(col2.length, 2)
+        switch result {
+        case .success(let recordBatch):
+            let schema = recordBatch.schema
+            XCTAssertEqual(schema.fields.count, 2)
+            XCTAssertEqual(schema.fields[0].name, "col1")
+            XCTAssertEqual(schema.fields[0].type, ArrowType.ArrowUInt8)
+            XCTAssertEqual(schema.fields[0].isNullable, false)
+            XCTAssertEqual(schema.fields[1].name, "col2")
+            XCTAssertEqual(schema.fields[1].type, ArrowType.ArrowString)
+            XCTAssertEqual(schema.fields[1].isNullable, false)
+            XCTAssertEqual(recordBatch.columns.count, 2)
+            let col1: ArrowArray<UInt8> = recordBatch.data(for: 0);
+            let col2: ArrowArray<String> = recordBatch.data(for: 1);
+            XCTAssertEqual(col1.length, 2)
+            XCTAssertEqual(col2.length, 2)
+        case .failure(let error):
+            throw error
+        }
     }
 }
diff --git a/swift/Arrow/Tests/ArrowTests/TableTests.swift 
b/swift/Arrow/Tests/ArrowTests/TableTests.swift
index 2d0a48e2d6..a3ed87d321 100644
--- a/swift/Arrow/Tests/ArrowTests/TableTests.swift
+++ b/swift/Arrow/Tests/ArrowTests/TableTests.swift
@@ -71,33 +71,96 @@ final class TableTests: XCTestCase {
         XCTAssertEqual(col2.length, 2)
         XCTAssertEqual(col3.length, 2)
     }
-    
-    func testTableToRecordBatch() throws {
+
+    func testTableWithChunkedData() throws {
         let uint8Builder: NumberArrayBuilder<UInt8> = try 
ArrowArrayBuilders.loadNumberArrayBuilder();
         uint8Builder.append(10)
         uint8Builder.append(22)
+        let uint8Builder2: NumberArrayBuilder<UInt8> = try 
ArrowArrayBuilders.loadNumberArrayBuilder();
+        uint8Builder2.append(33)
+        let uint8Builder3: NumberArrayBuilder<UInt8> = try 
ArrowArrayBuilders.loadNumberArrayBuilder();
+        uint8Builder3.append(44)
         let stringBuilder = try ArrowArrayBuilders.loadStringArrayBuilder();
         stringBuilder.append("test10")
         stringBuilder.append("test22")
+        let stringBuilder2 = try ArrowArrayBuilders.loadStringArrayBuilder();
+        stringBuilder.append("test33")
+        stringBuilder.append("test44")
         
-        let table = try ArrowTable.Builder()
-            .addColumn("col1", arrowArray: uint8Builder.finish())
-            .addColumn("col2", arrowArray: stringBuilder.finish())
-            .finish();
+        let date32Builder: Date32ArrayBuilder = try 
ArrowArrayBuilders.loadDate32ArrayBuilder();
+        let date2 = Date(timeIntervalSinceReferenceDate: 86400 * 1)
+        let date1 = Date(timeIntervalSinceReferenceDate: 86400 * 5000 + 352)
+        date32Builder.append(date1)
+        date32Builder.append(date2)
+        date32Builder.append(date1)
+        date32Builder.append(date2)
 
-        let recordBatch = table.toRecordBatch()
-        let schema = recordBatch.schema
-        XCTAssertEqual(schema.fields.count, 2)
+        let intArray = try ChunkedArray([uint8Builder.finish(), 
uint8Builder2.finish(), uint8Builder3.finish()])
+        let stringArray = try ChunkedArray([stringBuilder.finish(), 
stringBuilder2.finish()])
+        let dateArray = try ChunkedArray([date32Builder.finish()])
+        let table = ArrowTable.Builder()
+            .addColumn("col1", chunked: intArray)
+            .addColumn("col2", chunked: stringArray)
+            .addColumn("col3", chunked: dateArray)
+            .finish();
+        
+        let schema = table.schema
+        XCTAssertEqual(schema.fields.count, 3)
         XCTAssertEqual(schema.fields[0].name, "col1")
         XCTAssertEqual(schema.fields[0].type, ArrowType.ArrowUInt8)
         XCTAssertEqual(schema.fields[0].isNullable, false)
         XCTAssertEqual(schema.fields[1].name, "col2")
         XCTAssertEqual(schema.fields[1].type, ArrowType.ArrowString)
         XCTAssertEqual(schema.fields[1].isNullable, false)
-        XCTAssertEqual(recordBatch.columns.count, 2)
-        let col1: ChunkedArray<UInt8> = recordBatch.data(for: 0);
-        let col2: ChunkedArray<String> = recordBatch.data(for: 1);
-        XCTAssertEqual(col1.length, 2)
-        XCTAssertEqual(col2.length, 2)
+        XCTAssertEqual(schema.fields[1].name, "col2")
+        XCTAssertEqual(schema.fields[1].type, ArrowType.ArrowString)
+        XCTAssertEqual(schema.fields[1].isNullable, false)
+        XCTAssertEqual(table.columns.count, 3)
+        let col1: ChunkedArray<UInt8> = table.columns[0].data();
+        let col2: ChunkedArray<String> = table.columns[1].data();
+        let col3: ChunkedArray<Date> = table.columns[2].data();
+        XCTAssertEqual(col1.length, 4)
+        XCTAssertEqual(col2.length, 4)
+        XCTAssertEqual(col3.length, 4)
+        XCTAssertEqual(col1.asString(0), "10")
+        XCTAssertEqual(col1.asString(3), "44")
+        XCTAssertEqual(col2.asString(0), "test10")
+        XCTAssertEqual(col2.asString(2), "test33")
+    }
+
+    func testTableToRecordBatch() throws {
+        let uint8Builder: NumberArrayBuilder<UInt8> = try 
ArrowArrayBuilders.loadNumberArrayBuilder();
+        uint8Builder.append(10)
+        uint8Builder.append(22)
+        let stringBuilder = try ArrowArrayBuilders.loadStringArrayBuilder();
+        stringBuilder.append("test10")
+        stringBuilder.append("test22")
+        
+        let intHolder = ArrowArrayHolder(try uint8Builder.finish())
+        let stringHolder = ArrowArrayHolder(try stringBuilder.finish())
+        let result = RecordBatch.Builder()
+            .addColumn("col1", arrowArray: intHolder)
+            .addColumn("col2", arrowArray: stringHolder)
+            .finish().flatMap({ rb in
+                return ArrowTable.from(recordBatches: [rb])
+            })
+        switch result {
+        case .success(let table):
+            let schema = table.schema
+            XCTAssertEqual(schema.fields.count, 2)
+            XCTAssertEqual(schema.fields[0].name, "col1")
+            XCTAssertEqual(schema.fields[0].type, ArrowType.ArrowUInt8)
+            XCTAssertEqual(schema.fields[0].isNullable, false)
+            XCTAssertEqual(schema.fields[1].name, "col2")
+            XCTAssertEqual(schema.fields[1].type, ArrowType.ArrowString)
+            XCTAssertEqual(schema.fields[1].isNullable, false)
+            XCTAssertEqual(table.columns.count, 2)
+            let col1: ChunkedArray<UInt8> = table.columns[0].data();
+            let col2: ChunkedArray<String> = table.columns[1].data();
+            XCTAssertEqual(col1.length, 2)
+            XCTAssertEqual(col2.length, 2)
+        case .failure(let error):
+            throw error
+        }
     }
 }

Reply via email to