This is an automated email from the ASF dual-hosted git repository.
dongjoon pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/spark-connect-swift.git
The following commit(s) were added to refs/heads/main by this push:
new a9b267e [SPARK-52067] Add `Examples` directory
a9b267e is described below
commit a9b267eae59e7b4327ef5c90d178a965a3f01dfc
Author: Dongjoon Hyun <[email protected]>
AuthorDate: Sat May 10 10:20:18 2025 -0700
[SPARK-52067] Add `Examples` directory
### What changes were proposed in this pull request?
This PR aims to add `Examples` directory.
### Why are the changes needed?
To provide ASF-licensed examples officially.
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Manual review.
### Was this patch authored or co-authored using generative AI tooling?
No.
Closes #124 from dongjoon-hyun/SPARK-52067.
Authored-by: Dongjoon Hyun <[email protected]>
Signed-off-by: Dongjoon Hyun <[email protected]>
---
Examples/app/Package.swift | 37 +++++++++
Examples/app/README.md | 33 ++++++++
Examples/app/Sources/main.swift | 41 ++++++++++
Examples/web/Package.swift | 52 +++++++++++++
Examples/web/README.md | 89 ++++++++++++++++++++++
.../Sources/SparkConnectSwiftWeb/configure.swift | 26 +++++++
.../Sources/SparkConnectSwiftWeb/entrypoint.swift | 50 ++++++++++++
.../web/Sources/SparkConnectSwiftWeb/routes.swift | 40 ++++++++++
README.md | 5 +-
9 files changed, 369 insertions(+), 4 deletions(-)
diff --git a/Examples/app/Package.swift b/Examples/app/Package.swift
new file mode 100644
index 0000000..8afa325
--- /dev/null
+++ b/Examples/app/Package.swift
@@ -0,0 +1,37 @@
+// swift-tools-version: 6.0
+//
+// 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: "SparkConnectSwiftApp",
+ platforms: [
+ .macOS(.v15)
+ ],
+ dependencies: [
+ .package(url: "https://github.com/apache/spark-connect-swift.git", branch:
"v0.1.0")
+ ],
+ targets: [
+ .executableTarget(
+ name: "SparkConnectSwiftApp",
+ dependencies: [.product(name: "SparkConnect", package:
"spark-connect-swift")]
+ )
+ ]
+)
diff --git a/Examples/app/README.md b/Examples/app/README.md
new file mode 100644
index 0000000..285a0d3
--- /dev/null
+++ b/Examples/app/README.md
@@ -0,0 +1,33 @@
+# A Swift Application with Apache Spark Connect Swift Client
+
+This is an example Swift application to show how to use Apache Spark Connect
Swift Client library.
+
+## How to run
+
+Run this Swift application.
+
+```
+$ swift run
+...
+Connected to Apache Spark 4.0.0 Server
+EXECUTE: DROP TABLE IF EXISTS t
+EXECUTE: CREATE TABLE IF NOT EXISTS t(a INT) USING ORC
+EXECUTE: INSERT INTO t VALUES (1), (2), (3)
+SELECT * FROM t
++---+
+| a |
++---+
+| 2 |
+| 1 |
+| 3 |
++---+
++----+
+| id |
++----+
+| 2 |
+| 6 |
+| 0 |
+| 8 |
+| 4 |
++----+
+```
diff --git a/Examples/app/Sources/main.swift b/Examples/app/Sources/main.swift
new file mode 100644
index 0000000..c9ae2e2
--- /dev/null
+++ b/Examples/app/Sources/main.swift
@@ -0,0 +1,41 @@
+//
+// 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 SparkConnect
+
+let spark = try await SparkSession.builder.getOrCreate()
+print("Connected to Apache Spark \(await spark.version) Server")
+
+let statements = [
+ "DROP TABLE IF EXISTS t",
+ "CREATE TABLE IF NOT EXISTS t(a INT) USING ORC",
+ "INSERT INTO t VALUES (1), (2), (3)",
+]
+
+for s in statements {
+ print("EXECUTE: \(s)")
+ _ = try await spark.sql(s).count()
+}
+print("SELECT * FROM t")
+try await spark.sql("SELECT * FROM t").cache().show()
+
+try await spark.range(10).filter("id % 2 ==
0").write.mode("overwrite").orc("/tmp/orc")
+try await spark.read.orc("/tmp/orc").show()
+
+await spark.stop()
diff --git a/Examples/web/Package.swift b/Examples/web/Package.swift
new file mode 100644
index 0000000..7d793ab
--- /dev/null
+++ b/Examples/web/Package.swift
@@ -0,0 +1,52 @@
+// swift-tools-version:6.0
+//
+// 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: "SparkConnectSwiftWebapp",
+ platforms: [
+ .macOS(.v15)
+ ],
+ dependencies: [
+ // 💧 A server-side Swift web framework.
+ .package(url: "https://github.com/vapor/vapor.git", from: "4.110.1"),
+ // 🔵 Non-blocking, event-driven networking for Swift. Used for custom
executors
+ .package(url: "https://github.com/apple/swift-nio.git", from: "2.65.0"),
+ .package(url: "https://github.com/apache/spark-connect-swift.git", branch:
"v0.1.0"),
+ ],
+ targets: [
+ .executableTarget(
+ name: "SparkConnectSwiftWebapp",
+ dependencies: [
+ .product(name: "Vapor", package: "vapor"),
+ .product(name: "NIOCore", package: "swift-nio"),
+ .product(name: "NIOPosix", package: "swift-nio"),
+ .product(name: "SparkConnect", package: "spark-connect-swift"),
+ ],
+ swiftSettings: swiftSettings
+ )
+ ]
+)
+
+var swiftSettings: [SwiftSetting] {
+ [
+ .enableUpcomingFeature("ExistentialAny")
+ ]
+}
diff --git a/Examples/web/README.md b/Examples/web/README.md
new file mode 100644
index 0000000..3ae473e
--- /dev/null
+++ b/Examples/web/README.md
@@ -0,0 +1,89 @@
+# A Swift Application with Apache Spark Connect Swift Client
+
+This project is designed to illustrate a Swift-based HTTP WebServer with
Apache Spark Connect.
+
+- https://swiftpackageindex.com/apache/spark-connect-swift
+- https://swiftpackageindex.com/vapor/vapor
+
+## Create a Swift project
+
+```
+brew install vapor
+vapor new spark-connect-swift-web -n
+```
+
+## Use `Apache Spark Connect Swift Client` package.
+
+```
+$ git diff HEAD
+diff --git a/Package.swift b/Package.swift
+index 477bcbd..3e7bb06 100644
+--- a/Package.swift
++++ b/Package.swift
+@@ -4,13 +4,14 @@ import PackageDescription
+ let package = Package(
+ name: "SparkConnectSwiftWebapp",
+ platforms: [
+- .macOS(.v13)
++ .macOS(.v15)
+ ],
+ dependencies: [
+ // 💧 A server-side Swift web framework.
+ .package(url: "https://github.com/vapor/vapor.git", from: "4.110.1"),
+ // 🔵 Non-blocking, event-driven networking for Swift. Used for custom
executors
+ .package(url: "https://github.com/apple/swift-nio.git", from:
"2.65.0"),
++ .package(url: "https://github.com/apache/spark-connect-swift.git",
branch: "main"),
+ ],
+ targets: [
+ .executableTarget(
+@@ -19,6 +20,7 @@ let package = Package(
+ .product(name: "Vapor", package: "vapor"),
+ .product(name: "NIOCore", package: "swift-nio"),
+ .product(name: "NIOPosix", package: "swift-nio"),
++ .product(name: "SparkConnect", package:
"spark-connect-swift"),
+ ],
+ swiftSettings: swiftSettings
+ ),
+diff --git a/Sources/SparkConnectSwiftWebapp/routes.swift
b/Sources/SparkConnectSwiftWebapp/routes.swift
+index 2edcc8f..22313c8 100644
+--- a/Sources/SparkConnectSwiftWebapp/routes.swift
++++ b/Sources/SparkConnectSwiftWebapp/routes.swift
+@@ -1,4 +1,5 @@
+ import Vapor
++import SparkConnect
+
+ func routes(_ app: Application) throws {
+ app.get { req async in
+@@ -6,6 +7,15 @@ func routes(_ app: Application) throws {
+ }
+
+ app.get("hello") { req async -> String in
+- "Hello, world!"
++ return await Task {
++ do {
++ let spark = try await SparkSession.builder.getOrCreate()
++ let response = "Hi, this is powered by the Apache Spark
\(await spark.version)."
++ await spark.stop()
++ return response
++ } catch {
++ return "Fail to connect: \(error)"
++ }
++ }.value
+ }
+ }
+```
+
+## Run this Swift application.
+
+```
+$ swift run
+```
+
+## Connect to the Swift Web Server to talk with `Apache Spark`.
+
+```
+$ curl http://127.0.0.1:8080/
+Welcome to the Swift world. Say hello!%
+$ curl http://127.0.0.1:8080/hello
+Hi, this is powered by the Apache Spark 4.0.0.%
+```
diff --git a/Examples/web/Sources/SparkConnectSwiftWeb/configure.swift
b/Examples/web/Sources/SparkConnectSwiftWeb/configure.swift
new file mode 100644
index 0000000..cbc3edb
--- /dev/null
+++ b/Examples/web/Sources/SparkConnectSwiftWeb/configure.swift
@@ -0,0 +1,26 @@
+//
+// 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 Vapor
+
+// configures your application
+public func configure(_ app: Application) async throws {
+ // register routes
+ try routes(app)
+}
diff --git a/Examples/web/Sources/SparkConnectSwiftWeb/entrypoint.swift
b/Examples/web/Sources/SparkConnectSwiftWeb/entrypoint.swift
new file mode 100644
index 0000000..0be116f
--- /dev/null
+++ b/Examples/web/Sources/SparkConnectSwiftWeb/entrypoint.swift
@@ -0,0 +1,50 @@
+//
+// 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 Logging
+import NIOCore
+import NIOPosix
+import Vapor
+
+@main
+enum Entrypoint {
+ static func main() async throws {
+ var env = try Environment.detect()
+ try LoggingSystem.bootstrap(from: &env)
+
+ let app = try await Application.make(env)
+
+ // This attempts to install NIO as the Swift Concurrency global executor.
+ // You can enable it if you'd like to reduce the amount of context
switching between NIO and Swift Concurrency.
+ // Note: this has caused issues with some libraries that use `.wait()` and
cleanly shutting down.
+ // If enabled, you should be careful about calling async functions before
this point as it can cause assertion failures.
+ // let executorTakeoverSuccess =
NIOSingletons.unsafeTryInstallSingletonPosixEventLoopGroupAsConcurrencyGlobalExecutor()
+ // app.logger.debug("Tried to install SwiftNIO's EventLoopGroup as Swift's
global concurrency executor", metadata: ["success":
.stringConvertible(executorTakeoverSuccess)])
+
+ do {
+ try await configure(app)
+ try await app.execute()
+ } catch {
+ app.logger.report(error: error)
+ try? await app.asyncShutdown()
+ throw error
+ }
+ try await app.asyncShutdown()
+ }
+}
diff --git a/Examples/web/Sources/SparkConnectSwiftWeb/routes.swift
b/Examples/web/Sources/SparkConnectSwiftWeb/routes.swift
new file mode 100644
index 0000000..c6a1d91
--- /dev/null
+++ b/Examples/web/Sources/SparkConnectSwiftWeb/routes.swift
@@ -0,0 +1,40 @@
+//
+// 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 SparkConnect
+import Vapor
+
+func routes(_ app: Application) throws {
+ app.get { req async in
+ "Welcome to the Swift world. Say hello!"
+ }
+
+ app.get("hello") { req async -> String in
+ return await Task {
+ do {
+ let spark = try await SparkSession.builder.getOrCreate()
+ let response = "Hi, this is powered by the Apache Spark \(await
spark.version)."
+ await spark.stop()
+ return response
+ } catch {
+ return "Fail to connect: \(error)"
+ }
+ }.value
+ }
+}
diff --git a/README.md b/README.md
index eaf7148..395a6a0 100644
--- a/README.md
+++ b/README.md
@@ -108,10 +108,7 @@ SELECT * FROM t
+----+
```
-You can find this command line example and additional `Swift Web Server`
example in the following repositories.
-
-- <https://github.com/dongjoon-hyun/spark-connect-swift-app>
-- <https://github.com/dongjoon-hyun/spark-connect-swift-web>
+You can find more complete examples including Web Server application in the
`Examples` directory.
## How to use `Spark SQL REPL` via `Spark Connect for Swift`
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]