DataLiteCore swift package
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
# ``DataLiteCore/Connection/init(location:options:)``
|
||||
|
||||
Initializes a new connection to an SQLite database.
|
||||
|
||||
This initializer opens a connection to the SQLite database at the specified `location`
|
||||
with the provided `options`. If the location is a file path, it ensures the necessary
|
||||
directory exists, creating intermediate directories if needed.
|
||||
|
||||
```swift
|
||||
do {
|
||||
let connection = try Connection(
|
||||
location: .file(path: "~/example.db"),
|
||||
options: .readwrite
|
||||
)
|
||||
// Use the connection to execute queries
|
||||
} catch {
|
||||
print("Error establishing connection: \(error)")
|
||||
}
|
||||
```
|
||||
|
||||
- Parameters:
|
||||
- location: Specifies where the database is located.
|
||||
Can be a file path, an in-memory database, or a temporary database.
|
||||
- options: Configures connection behavior,
|
||||
such as read-only or read-write access and cache mode.
|
||||
|
||||
- Throws: ``Connection/Error`` if the connection fails to open due to SQLite errors,
|
||||
invalid path, permission issues, or other underlying failures.
|
||||
|
||||
- Throws: An error if directory creation fails for file-based database locations.
|
||||
@@ -0,0 +1,31 @@
|
||||
# ``DataLiteCore/Connection/init(path:options:)``
|
||||
|
||||
Initializes a new connection to an SQLite database using a file path.
|
||||
|
||||
This convenience initializer sets up a connection to the SQLite database located at the
|
||||
specified `path` with the provided `options`. It internally calls the main initializer
|
||||
to manage the connection setup.
|
||||
|
||||
### Usage Example
|
||||
|
||||
```swift
|
||||
do {
|
||||
let connection = try Connection(
|
||||
path: "~/example.db",
|
||||
options: .readwrite
|
||||
)
|
||||
// Use the connection to execute queries
|
||||
} catch {
|
||||
print("Error establishing connection: \(error)")
|
||||
}
|
||||
```
|
||||
|
||||
- Parameters:
|
||||
- path: A string representing the file path to the SQLite database.
|
||||
- options: Configures the connection behavior,
|
||||
such as read-only or read-write access and cache mode.
|
||||
|
||||
- Throws: ``Connection/Error`` if the connection fails to open due to SQLite errors,
|
||||
invalid path, permission issues, or other underlying failures.
|
||||
|
||||
- Throws: An error if subdirectories for the database file cannot be created.
|
||||
298
Sources/DataLiteCore/Docs.docc/Connection/Connection.md
Normal file
298
Sources/DataLiteCore/Docs.docc/Connection/Connection.md
Normal file
@@ -0,0 +1,298 @@
|
||||
# ``DataLiteCore/Connection``
|
||||
|
||||
A class representing a connection to an SQLite database.
|
||||
|
||||
## Overview
|
||||
|
||||
The `Connection` class manages the connection to an SQLite database. It provides an interface
|
||||
for preparing SQL queries, managing transactions, and handling errors. This class serves as the
|
||||
main object for interacting with the database.
|
||||
|
||||
## Opening a New Connection
|
||||
|
||||
Use the ``init(location:options:)`` initializer to open a database connection. Specify the
|
||||
database's location using the ``Location`` parameter and configure connection settings with the
|
||||
``Options`` parameter.
|
||||
|
||||
```swift
|
||||
do {
|
||||
let connection = try Connection(
|
||||
location: .file(path: "~/example.db"),
|
||||
options: [.readwrite, .create]
|
||||
)
|
||||
print("Connection established")
|
||||
} catch {
|
||||
print("Failed to connect: \(error)")
|
||||
}
|
||||
```
|
||||
|
||||
## Closing the Connection
|
||||
|
||||
The `Connection` class automatically closes the database connection when the object is
|
||||
deallocated (`deinit`). This ensures proper cleanup even if the object goes out of scope.
|
||||
|
||||
## Delegate
|
||||
|
||||
The `Connection` class can optionally use a delegate to handle specific events during the
|
||||
connection lifecycle, such as tracing SQL statements or responding to transaction actions.
|
||||
The delegate must conform to the ``ConnectionDelegate`` protocol, which provides methods for
|
||||
handling these events.
|
||||
|
||||
## Custom SQL Functions
|
||||
|
||||
The `Connection` class allows you to add custom SQL functions using subclasses of ``Function``.
|
||||
You can create either **scalar** functions (which return a single value) or **aggregate**
|
||||
functions (which perform operations across multiple rows). Both types can be used directly in
|
||||
SQL queries.
|
||||
|
||||
To add or remove custom functions, use the ``add(function:)`` and ``remove(function:)`` methods
|
||||
of the `Connection` class.
|
||||
|
||||
## Preparing SQL Statements
|
||||
|
||||
The `Connection` class provides functionality for preparing SQL statements that can be
|
||||
executed multiple times with different parameter values. The ``prepare(sql:options:)`` method
|
||||
takes a SQL query as a string and an optional ``Statement/Options`` parameter to configure
|
||||
the behavior of the statement. It returns a ``Statement`` object that can be executed.
|
||||
|
||||
```swift
|
||||
do {
|
||||
let statement = try connection.prepare(
|
||||
sql: "SELECT * FROM users WHERE age > ?",
|
||||
options: [.persistent]
|
||||
)
|
||||
// Bind parameters and execute the statement
|
||||
} catch {
|
||||
print("Error preparing statement: \(error)")
|
||||
}
|
||||
```
|
||||
|
||||
## Executing SQL Scripts
|
||||
|
||||
The `Connection` class allows you to execute a series of SQL statements using the ``SQLScript``
|
||||
structure. The ``SQLScript`` structure is designed to load and process multiple SQL queries
|
||||
from a file, URL, or string.
|
||||
|
||||
You can create an instance of ``SQLScript`` with the SQL script content and then pass it to the
|
||||
``execute(sql:)`` method of the `Connection` class to execute the script.
|
||||
|
||||
```swift
|
||||
let script: SQLScript = """
|
||||
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT);
|
||||
INSERT INTO users (name) VALUES ('Alice');
|
||||
INSERT INTO users (name) VALUES ('Bob');
|
||||
"""
|
||||
|
||||
do {
|
||||
try connection.execute(sql: script)
|
||||
print("Script executed successfully")
|
||||
} catch {
|
||||
print("Error executing script: \(error)")
|
||||
}
|
||||
```
|
||||
|
||||
## Transaction Handling
|
||||
|
||||
By default, the `Connection` class operates in **autocommit mode**, where each SQL statement is
|
||||
automatically committed after execution. In this mode, each statement is treated as a separate
|
||||
transaction, eliminating the need for explicit transaction management. To determine whether the
|
||||
connection is in autocommit mode, use the ``isAutocommit`` property.
|
||||
|
||||
For manual transaction management, use ``beginTransaction(_:)`` to start a transaction, and
|
||||
``commitTransaction()`` or ``rollbackTransaction()`` to either commit or roll back the
|
||||
transaction.
|
||||
|
||||
```swift
|
||||
do {
|
||||
try connection.beginTransaction()
|
||||
try connection.execute(sql: "INSERT INTO users (name) VALUES ('Alice')")
|
||||
try connection.execute(sql: "INSERT INTO users (name) VALUES ('Bob')")
|
||||
try connection.commitTransaction()
|
||||
print("Transaction committed successfully")
|
||||
} catch {
|
||||
try? connection.rollbackTransaction()
|
||||
print("Error during transaction: \(error)")
|
||||
}
|
||||
```
|
||||
|
||||
Learn more in the [SQLite Transaction Documentation](https://www.sqlite.org/lang_transaction.html).
|
||||
|
||||
## Error Handling
|
||||
|
||||
The `Connection` class uses Swift's throwing mechanism to handle errors. Errors in database
|
||||
operations are propagated using `throws`, allowing you to catch and handle specific issues in
|
||||
your application.
|
||||
|
||||
SQLite-related errors, such as invalid SQL queries, connection failures, or issues with
|
||||
transaction management, throw an ``Connection/Error`` struct. These errors conform to the
|
||||
`Error` protocol, and you can handle them using Swift's `do-catch` syntax to manage exceptions
|
||||
in your code.
|
||||
|
||||
```swift
|
||||
do {
|
||||
let statement = try connection.prepare(
|
||||
sql: "SELECT * FROM users WHERE age > ?",
|
||||
options: []
|
||||
)
|
||||
} catch let error as Error {
|
||||
print("SQLite error: \(error.mesg), Code: \(error.code)")
|
||||
} catch {
|
||||
print("Unexpected error: \(error)")
|
||||
}
|
||||
```
|
||||
|
||||
## Multithreading
|
||||
|
||||
The `Connection` class supports multithreading, but its behavior depends on the selected
|
||||
thread-safety mode. You can configure the desired mode using the ``Options`` parameter in the
|
||||
``init(location:options:)`` method.
|
||||
|
||||
**Multi-thread** (``Options/nomutex``): This mode allows SQLite to be used across multiple
|
||||
threads. However, it requires that no `Connection` instance or its derived objects (e.g.,
|
||||
prepared statements) are accessed simultaneously by multiple threads.
|
||||
|
||||
```swift
|
||||
let connection = try Connection(
|
||||
location: .file(path: "~/example.db"),
|
||||
options: [.readwrite, .nomutex]
|
||||
)
|
||||
```
|
||||
|
||||
**Serialized** (``Options/fullmutex``): In this mode, SQLite uses internal mutexes to ensure
|
||||
thread safety. This allows multiple threads to safely share `Connection` instances and their
|
||||
derived objects.
|
||||
|
||||
```swift
|
||||
let connection = try Connection(
|
||||
location: .file(path: "~/example.db"),
|
||||
options: [.readwrite, .fullmutex]
|
||||
)
|
||||
```
|
||||
|
||||
- Important: The `Connection` class does not include built-in synchronization for shared
|
||||
resources. Developers must implement custom synchronization mechanisms, such as using
|
||||
`DispatchQueue`, when sharing resources across threads.
|
||||
|
||||
For more details, see the [Using SQLite in Multi-Threaded Applications](https://www.sqlite.org/threadsafe.html).
|
||||
|
||||
## Encryption
|
||||
|
||||
The `Connection` class supports transparent encryption and re-encryption of databases using the
|
||||
``apply(_:name:)`` and ``rekey(_:name:)`` methods. This allows sensitive data to be securely
|
||||
stored on disk.
|
||||
|
||||
### Applying an Encryption Key
|
||||
|
||||
To open an encrypted database or encrypt a new one, call ``apply(_:name:)`` immediately after
|
||||
initializing the connection, and before executing any SQL statements.
|
||||
|
||||
```swift
|
||||
let connection = try Connection(
|
||||
path: "~/secure.db",
|
||||
options: [.readwrite, .create]
|
||||
)
|
||||
try connection.apply(Key.passphrase("secret-password"))
|
||||
```
|
||||
|
||||
- If the database is already encrypted, the key must match the one previously used.
|
||||
- If the database is unencrypted, applying a key will encrypt it on first write.
|
||||
|
||||
You can use either a **passphrase**, which is internally transformed into a key,
|
||||
or a **raw key**:
|
||||
|
||||
```swift
|
||||
try connection.apply(Key.raw(data: rawKeyData))
|
||||
```
|
||||
|
||||
- Important: The encryption key must be applied *before* any SQL queries are executed.
|
||||
Otherwise, the database may remain unencrypted or unreadable.
|
||||
|
||||
### Rekeying the Database
|
||||
|
||||
To change the encryption key of an existing database, you must first apply the current key
|
||||
using ``apply(_:name:)``, then call ``rekey(_:name:)`` with the new key.
|
||||
|
||||
```swift
|
||||
let connection = try Connection(
|
||||
path: "~/secure.db",
|
||||
options: [.readwrite]
|
||||
)
|
||||
try connection.apply(Key.passphrase("old-password"))
|
||||
try connection.rekey(Key.passphrase("new-password"))
|
||||
```
|
||||
|
||||
- Important: ``rekey(_:name:)`` requires that the correct current key has already been applied
|
||||
via ``apply(_:name:)``. If the wrong key is used, the operation will fail with an error.
|
||||
|
||||
### Attached Databases
|
||||
|
||||
Both ``apply(_:name:)`` and ``rekey(_:name:)`` accept an optional `name` parameter to operate
|
||||
on an attached database. If omitted, they apply to the main database.
|
||||
|
||||
## Topics
|
||||
|
||||
### Errors
|
||||
|
||||
- ``Error``
|
||||
|
||||
### Initializers
|
||||
|
||||
- ``Location``
|
||||
- ``Options``
|
||||
- ``init(location:options:)``
|
||||
- ``init(path:options:)``
|
||||
|
||||
### Delegation
|
||||
|
||||
- ``ConnectionDelegate``
|
||||
- ``delegate``
|
||||
|
||||
### Connection State
|
||||
|
||||
- ``isAutocommit``
|
||||
- ``isReadonly``
|
||||
- ``busyTimeout``
|
||||
|
||||
### PRAGMA Accessors
|
||||
|
||||
- ``applicationID``
|
||||
- ``foreignKeys``
|
||||
- ``journalMode``
|
||||
- ``synchronous``
|
||||
- ``userVersion``
|
||||
|
||||
### SQLite Lifecycle
|
||||
|
||||
- ``initialize()``
|
||||
- ``shutdown()``
|
||||
|
||||
### Custom SQL Functions
|
||||
|
||||
- ``add(function:)``
|
||||
- ``remove(function:)``
|
||||
|
||||
### Statement Preparation
|
||||
|
||||
- ``prepare(sql:options:)``
|
||||
|
||||
### Script Execution
|
||||
|
||||
- ``execute(sql:)``
|
||||
- ``execute(raw:)``
|
||||
|
||||
### PRAGMA Execution
|
||||
|
||||
- ``get(pragma:)``
|
||||
- ``set(pragma:value:)``
|
||||
|
||||
### Transactions
|
||||
|
||||
- ``beginTransaction(_:)``
|
||||
- ``commitTransaction()``
|
||||
- ``rollbackTransaction()``
|
||||
|
||||
### Encryption Keys
|
||||
|
||||
- ``Connection/Key``
|
||||
- ``apply(_:name:)``
|
||||
- ``rekey(_:name:)``
|
||||
7
Sources/DataLiteCore/Docs.docc/DataLiteCore.md
Normal file
7
Sources/DataLiteCore/Docs.docc/DataLiteCore.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# ``DataLiteCore``
|
||||
|
||||
**DataLiteCore** is an intuitive library for working with SQLite in Swift applications.
|
||||
|
||||
## Overview
|
||||
|
||||
**DataLiteCore** provides an object-oriented API over the C interface, allowing developers to easily integrate SQLite functionality into their projects. The library offers powerful capabilities for database management and executing SQL queries while maintaining the simplicity and flexibility of the native Swift interface.
|
||||
Reference in New Issue
Block a user