From 2b698b9944ab30e2a2daf08ffd191f264b2add36 Mon Sep 17 00:00:00 2001 From: Alva Bandy Date: Tue, 5 Nov 2024 19:35:42 -0500 Subject: [PATCH] GH-40488: [Swift] Add simple get swift example --- http/get_simple/swift/.gitignore | 9 +++ http/get_simple/swift/Client/Package.swift | 41 ++++++++++ http/get_simple/swift/Client/README.md | 45 +++++++++++ .../swift/Client/Sources/main.swift | 52 +++++++++++++ http/get_simple/swift/Server/Package.swift | 43 +++++++++++ http/get_simple/swift/Server/README.md | 44 +++++++++++ .../swift/Server/Sources/main.swift | 75 +++++++++++++++++++ 7 files changed, 309 insertions(+) create mode 100644 http/get_simple/swift/.gitignore create mode 100644 http/get_simple/swift/Client/Package.swift create mode 100644 http/get_simple/swift/Client/README.md create mode 100644 http/get_simple/swift/Client/Sources/main.swift create mode 100644 http/get_simple/swift/Server/Package.swift create mode 100644 http/get_simple/swift/Server/README.md create mode 100644 http/get_simple/swift/Server/Sources/main.swift diff --git a/http/get_simple/swift/.gitignore b/http/get_simple/swift/.gitignore new file mode 100644 index 0000000..d561187 --- /dev/null +++ b/http/get_simple/swift/.gitignore @@ -0,0 +1,9 @@ +.DS_Store +/.build +/Packages +/*.xcodeproj +xcuserdata/ +DerivedData/ +.swiftpm/ +.netrc +Package.resolved \ No newline at end of file diff --git a/http/get_simple/swift/Client/Package.swift b/http/get_simple/swift/Client/Package.swift new file mode 100644 index 0000000..d12a3a3 --- /dev/null +++ b/http/get_simple/swift/Client/Package.swift @@ -0,0 +1,41 @@ +// swift-tools-version: 6.0 +// The swift-tools-version declares the minimum version of Swift required to build this package. + +// 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. + +import PackageDescription + +let package = Package( + name: "GetSimpleClient", + platforms: [ + .macOS(.v14) + ], + dependencies: [ + .package(name: "Arrow", path: "vendor/Arrow") + ], + targets: [ + // Targets are the basic building blocks of a package, defining a module or a test suite. + // Targets can depend on other targets in this package and products from dependencies. + .executableTarget( + name: "GetSimpleClient", + dependencies: [ + .product(name: "Arrow", package: "Arrow") + ] + ), + ] +) diff --git a/http/get_simple/swift/Client/README.md b/http/get_simple/swift/Client/README.md new file mode 100644 index 0000000..f0207ec --- /dev/null +++ b/http/get_simple/swift/Client/README.md @@ -0,0 +1,45 @@ + + +# HTTP GET Arrow Data: Simple Swift Client Example + +This directory contains a minimal example of an HTTP client implemented in Swift. The client: +1. Sends an HTTP GET request to a server. +2. Receives an HTTP 200 response from the server, with the response body containing an Arrow IPC stream record batch. +3. Prints some of the record batches attributes and data to the terminal + +To run this example, first start one of the server examples in the parent directory, then: +1. download and copy Apache Arrow Swift's Arrow folder into the vendor/Arrow folder: + +```sh +git clone --filter=blob:none --no-checkout --depth 1 --sparse https://github.com/apache/arrow.git +pushd arrow +git sparse-checkout add swift/Arrow +git checkout +popd +mkdir -p vendor/Arrow +mv arrow/swift/Arrow vendor +rm -rf arrow +``` + +2. run: + +```sh +swift run +``` \ No newline at end of file diff --git a/http/get_simple/swift/Client/Sources/main.swift b/http/get_simple/swift/Client/Sources/main.swift new file mode 100644 index 0000000..e11ce30 --- /dev/null +++ b/http/get_simple/swift/Client/Sources/main.swift @@ -0,0 +1,52 @@ +/* + * 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. + */ + +import Foundation +import Arrow + +let sem = DispatchSemaphore(value: 0) +let url = URL(string: "http://127.0.0.1:8081")! +print("sending request to server") +let task = URLSession.shared.dataTask(with: url) { data, response, error in + defer {sem.signal()} + if let writeData = data { + let arrowReader = ArrowReader() + switch arrowReader.fromStream(writeData) { + case .success(let result): + let recordBatches = result.batches + print("recordBatch: \(recordBatches.count)") + let rb = recordBatches[0] + print("recordBatch values: \(rb.length)") + print("recordBatch columns: \(rb.columnCount)") + for (idx, column) in rb.columns.enumerated() { + print("col \(idx)") + let array = column.array + for idx in 0.. + +# HTTP GET Arrow Data: Simple Swift Server Example + +This directory contains a minimal example of an HTTP server implemented in Swift. The server: + +1. Creates a record batches and populates it with synthesized data. +2. Listens for HTTP requests from clients. +3. Upon receiving a request, sends an HTTP 200 response with the body containing an Arrow IPC stream of record batches. +To run this example: + +```sh +git clone --filter=blob:none --no-checkout --depth 1 --sparse https://github.com/apache/arrow.git +pushd arrow +git sparse-checkout add swift/Arrow +git checkout +popd +mkdir -p vendor/Arrow +mv arrow/swift/Arrow vendor +rm -rf arrow +``` + +2. run: + +```sh +swift run +``` \ No newline at end of file diff --git a/http/get_simple/swift/Server/Sources/main.swift b/http/get_simple/swift/Server/Sources/main.swift new file mode 100644 index 0000000..82f5086 --- /dev/null +++ b/http/get_simple/swift/Server/Sources/main.swift @@ -0,0 +1,75 @@ +/* + * 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. + */ + +import Foundation +import Arrow +import Hummingbird + +func makeRecordBatch(_ numRecords: UInt32) throws -> RecordBatch { + let doubleBuilder: NumberArrayBuilder = try ArrowArrayBuilders.loadNumberArrayBuilder() + let stringBuilder = try ArrowArrayBuilders.loadStringArrayBuilder() + let date32Builder = try ArrowArrayBuilders.loadDate32ArrayBuilder() + let date2 = Date(timeIntervalSinceReferenceDate: 86400 * 1) + let date1 = Date(timeIntervalSinceReferenceDate: 86400 * 5000 + 352) + for idx in 0.. ByteBuffer in + print("received request from client") + let recordBatchs = [try makeRecordBatch(4), try makeRecordBatch(3)] + let arrowWriter = ArrowWriter() + let writerInfo = ArrowWriter.Info(.recordbatch, schema: recordBatchs[0].schema, batches: recordBatchs) + switch arrowWriter.toStream(writerInfo) { + case .success(let writeData): + print("sending recordBatchs: \(recordBatchs.count)") + return ByteBuffer(data: writeData) + case.failure(let error): + throw error + } +} + +// create application using router +let app = Application( + router: router, + configuration: .init(address: .hostname("127.0.0.1", port: 8081)) +) + +try await app.runService()