Files
data-lite-core/Sources/DataLiteCore/Docs.docc/Articles/SQLScripts.md

3.0 KiB
Raw Blame History

Running SQL Scripts

Execute and automate SQL migrations, seed data, and test fixtures with DataLiteCore.

SQLScript and ConnectionProtocol/execute(sql:) let you run sequences of prepared statements as a single script. The loader splits content by semicolons, removes comments and whitespace, and compiles each statement individually. Scripts run in autocommit mode by default — execution stops at the first failure and throws the corresponding SQLiteError.

Building Scripts

Create a script inline or load it from a bundled resource. SQLScript automatically strips comments and normalizes whitespace.

let script = SQLScript(string: """
    CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY,
        username TEXT NOT NULL UNIQUE
    );
    INSERT INTO users (username) VALUES ('ada'), ('grace');
""")

Load a script from your module or app bundle using SQLScript/init(byResource:extension:in:):

let bootstrap = try? SQLScript(
    byResource: "bootstrap",
    extension: "sql",
    in: .module
)

Executing Scripts

Run the script through ConnectionProtocol/execute(sql:). Statements execute sequentially in the order they appear.

let connection = try Connection(
    location: .file(path: dbPath),
    options: [.readwrite, .create]
)
try connection.execute(sql: script)

In autocommit mode, each statement commits as soon as it succeeds. If any statement fails, execution stops and previously executed statements remain committed. To ensure all-or-nothing execution, wrap the script in an explicit transaction:

try connection.beginTransaction(.immediate)
do {
    try connection.execute(sql: script)
    try connection.commitTransaction()
} catch {
    try? connection.rollbackTransaction()
    throw error
}
  • Important: SQLScript must not include BEGIN, COMMIT, or ROLLBACK. Always manage transactions at the connection level.

Executing Raw SQL

Use ConnectionProtocol/execute(raw:) to run multi-statement SQL directly, without parsing or preprocessing. This method executes the script exactly as provided, allowing you to manage transactions explicitly within the SQL itself.

let migrations = """
    BEGIN;
    CREATE TABLE categories (
        id INTEGER PRIMARY KEY,
        name TEXT NOT NULL UNIQUE
    );
    INSERT INTO categories (name) VALUES ('Swift'), ('SQLite');
    COMMIT;
"""

try connection.execute(raw: migrations)

Each statement runs in sequence until completion or until the first error occurs. If a statement fails, execution stops and remaining statements are skipped. Open transactions are not rolled back automatically — they must be handled explicitly inside the script or by the caller.

Handling Errors

Inspect the thrown SQLiteError to identify the failing statements result code and message. For longer scripts, wrap execution in logging to trace progress and isolate the exact statement that triggered the exception.

  • SeeAlso: SQLScript
  • SeeAlso: ConnectionProtocol/execute(sql:)
  • SeeAlso: ConnectionProtocol/execute(raw:)