Non-blocking, event-driven Swift client for Oracle Databases built on SwiftNIO.
It's like PostgresNIO, but written for Oracle Databases.
- An
OracleConnectionwhich allows you to connect to, authorize with, query, and retrieve results from an Oracle database server - An async/await interface that supports backpressure
- Automatic conversions between Swift primitive types and the Oracle wire format
- Integrated with the Swift server ecosystem, including use of swift-log.
- Designed to run efficiently on all supported platforms (tested on Linux and Darwin systems)
- Support for
Network.frameworkwhen available (e.g. on Apple platforms) - An
OracleClientConnectionPool backed by DRCP (Database Resident Connection Pooling) if available
Oracle Database 12.1 or later.
- Username and password with service name
- Username and password with sid
- Oracle Cloud Infrastructure (OCI) Identity and Access Management (IAM) token based authentication with service name
- Open Authorization (OAuth 2.0) token based authentication with service name
- Open Authorization (OAuth 2.0) token based authentication with sid
Please note that all token based authentication methods are currently untested, because I (@lovetodream) do not have the infrastructure to test this. Contributions are welcome!
All connections can be TLS encrypted using OracleConnection.Configuration.TLS.
Check out the OracleNIO API docs for a detailed look at all of the classes, structs, protocols, and more.
Add OracleNIO as a dependency to your Package.swift:
dependencies: [
.package(url: "https://github.com/lovetodream/oracle-nio.git", from: "1.0.0-alpha"),
...
]Add OracleNIO to the target you want to use it in:
targets: [
.target(name: "MyFancyTarget", dependencies: [
.product(name: "OracleNIO", package: "oracle-nio"),
])
]To create a connection, first create a connection configuration object:
import OracleNIO
let config = OracleConnection.Configuration(
host: "127.0.0.1",
port: 1521,
service: .serviceName("my_service"), // or .sid("sid")
username: "my_username",
password: "my_password"
)To create a connection we need a Logger, that is used to log connection background events.
import Logging
let logger = Logger(label: "oracle-logger")Now we can put it together:
import OracleNIO
import Logging
let logger = Logger(label: "oracle-logger")
let config = OracleConnection.Configuration(
host: "127.0.0.1",
port: 1521,
service: .serviceName("my_service"),
username: "my_username",
password: "my_password"
)
let connection = try await OracleConnection.connect(
configuration: config,
id: 1,
logger: logger
)
// Close your connection once done
try await connection.close()Once a connection is established, statements can be sent to the server. This is very straightforward:
let rows = try await connection.execute("SELECT id, username, birthday FROM users", logger: logger)
execute(_:options:logger:file:line:)can run either aQuery,DML,DDLor evenPlSQL.
The statement will return a OracleRowSequence, which is an AsyncSequence of OracleRows. The rows can be iterated one-by-one:
for try await row in rows {
// do something with the row
}However, in most cases it is much easier to request a row's fields as a set of Swift types:
for try await (id, username, birthday) in rows.decode((Int, String, Date).self) {
// do something with the datatypes.
}A type must implement the OracleDecodable protocol in order to be decoded from a row. OracleNIO provides default implementations for most of Swift's builtin types, as well as some types provided by Foundation:
BoolBytes,ByteBuffer,DataDateUInt8,Int8,UInt16,Int16,UInt32,Int32,UInt64,Int64,UInt,IntFloat,DoubleStringUUID
OracleNIO does provide some types which are more specific to Oracle too.
CursorIntervalDSOracleNumberOracleVectorBinary,OracleVectorInt8,OracleVectorFloat32,OracleVectorFloat64OracleJSONRowID
Sending parameterized queries to the database is also supported (in the coolest way possible):
let id = 1
let username = "fancyuser"
let birthday = Date()
try await connection.execute("""
INSERT INTO users (id, username, birthday) VALUES (\(id), \(username), \(birthday))
""",
logger: logger
)While this looks at first glance like a classic case of SQL injection 😱, OracleNIO's API ensures that this usage is safe. The first parameter of the execute(_:options:logger:file:line:) method is not a plain String, but a OracleStatement, which implements Swift's ExpressibleByStringInterpolation protocol. OracleNIO uses the literal parts of the provided string as the SQL statement and replaces each interpolated value with a parameter binding. Only values which implement the OracleEncodable protocol may be interpolated in this way. As with OracleDecodable, OracleNIO provides default implementations for most common types.
Some queries do not receive any rows from the server (most often INSERT, UPDATE, and DELETE queries, not to mention most DDL queries). To support this, the execute(_:options:logger:file:line:) method is marked @discardableResult, so that the compiler does not issue a warning if the return value is not used.
SemVer changes are documented for each release on the releases page.
Oracle NIO is part of the Swift on Server Working Group ecosystem - currently recommended as Sandbox Maturity.
| Proposal | Pitch | Review | Vote |
|---|---|---|---|
| SSWG-0028 | 2023-12-20 | 2024-01-17 | 2024-04-07 |
Any given release of Oracle NIO will support at least the latest version of Swift on a given platform plus 1 previous version, at the time of the release.
Major version releases will be scheduled around official Swift releases, taking no longer 3 months from the Swift release.
Major version releases will drop support for any version of Swift older than the last 2 Swift versions.
This policy is to balance the desire for as much backwards compatibility as possible, while also being able to take advantage of new Swift features for the best API design possible.
Copyright (c) 2023-present, Timo Zacherl (@lovetodream)
This project contains code written by others not affliated with this project. All copyright claims are reserved by them. For a full list, with their claimed rights, see NOTICE.txt
Oracle is a registered trademark of Oracle Corporation. Any use of their trademark is under the established trademark guidelines and does not imply any affiliation with or endorsement by them, and all rights are reserved by them.
Swift is a registered trademark of Apple, Inc. Any use of their trademark does not imply any affiliation with or endorsement by them, and all rights are reserved by them.