{"id":20970286,"url":"https://github.com/sbooth/pipeline","last_synced_at":"2026-04-16T00:32:38.651Z","repository":{"id":41421207,"uuid":"385580867","full_name":"sbooth/Pipeline","owner":"sbooth","description":"A powerful and performant Swift interface to SQLite.","archived":false,"fork":false,"pushed_at":"2025-11-24T14:04:38.000Z","size":366,"stargazers_count":1,"open_issues_count":4,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-28T02:12:12.577Z","etag":null,"topics":["combine-framework","sqlite","sqlite3","swift"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sbooth.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-07-13T11:31:38.000Z","updated_at":"2025-11-24T14:10:50.000Z","dependencies_parsed_at":"2023-01-19T01:45:36.418Z","dependency_job_id":"277c68a0-dfce-4ac9-9dea-1842020b9025","html_url":"https://github.com/sbooth/Pipeline","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/sbooth/Pipeline","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbooth%2FPipeline","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbooth%2FPipeline/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbooth%2FPipeline/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbooth%2FPipeline/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sbooth","download_url":"https://codeload.github.com/sbooth/Pipeline/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sbooth%2FPipeline/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31866342,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-15T15:24:51.572Z","status":"ssl_error","status_checked_at":"2026-04-15T15:24:39.138Z","response_time":63,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["combine-framework","sqlite","sqlite3","swift"],"created_at":"2024-11-19T03:57:38.669Z","updated_at":"2026-04-16T00:32:38.632Z","avatar_url":"https://github.com/sbooth.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Pipeline\n\nPipeline is a powerful and performant Swift interface to [SQLite](https://sqlite.org) featuring:\n\n- Type-safe and type-agnostic database values.\n- Thread-safe synchronous and asynchronous database access.\n- Full support for [transactions](#perform-a-transaction) and savepoints.\n- [Custom SQL functions](#custom-sql-functions), including aggregate and window functions.\n- [Custom collating sequences](#custom-collating-sequences).\n- Custom commit, rollback, update, and busy handler hooks.\n- Custom virtual tables.\n- Custom FTS5 tokenizers.\n- Optional support for pre-update hooks and [sessions](https://www.sqlite.org/sessionintro.html).\n- [Combine](#combine) support.\n\nPipeline allows fast, easy database access with robust error handling.  It is not a general-purpose object-relational mapper.\n\n## Installation\n\n### Swift Package Manager\n\nAdd a package dependency to https://github.com/sbooth/Pipeline in Xcode.\n\n### Manual or Custom Build\n\n1. Clone the [Pipeline](https://github.com/sbooth/Pipeline) repository.\n2. `swift build`.\n\n## Quick Start\n\n```swift\n// Create a connection to an in-memory database\nlet connection = try Connection()\n\n// Create a table\ntry connection.execute(sql: \"CREATE TABLE t1(a,b);\")\n\n// Insert a row\ntry connection.execute(sql: \"INSERT INTO t1(a,b) VALUES (?,?);\", \n                       parameters: 33, \"lulu\")\n\n// Retrieve the values\ntry connection.execute(sql: \"SELECT a,b FROM t1;\") { row in\n    let a = try row.get(.int, at: 0)\n    let b = try row.get(.string, at: 1)\n}\n```\n\n### Segue to Thread Safety\n\nPipeline uses SQLite with thread safety disabled for improved performance. While this increases performance, it also means a `Connection` object may only be accessed from a single thread or dispatch queue at a time.\n\nMost applications should not create a `Connection` directly but instead should use a thread-safe `ConnectionQueue`.\n\n```swift\n// Create a queue serializing access to an in-memory database\nlet connectionQueue = try ConnectionQueue(\"myapp.database-connection-isolation-queue\")\n```\n\nThis creates a queue which may be used from multiple threads or dispatch queues safely.  The queue serializes access to the database connection ensuring only a single operation occurs at a time. Database operations may be performed synchronously or asynchronously.\n\n```swift\n// Perform a synchronous database access\ntry connectionQueue.sync { connection in\n    // Do something with `connection`\n}\n\n// Perform an asynchronous database access\nconnectionQueue.async { connection in\n    // Do something with `connection`\n} completion: { result in\n    switch result {\n        case .success:\n            // 🎉\n        case .failure(let error):\n            // Handle any errors that occurred\n    }\n}\n```\n\nFor databases using [Write-Ahead Logging](https://www.sqlite.org/wal.html) concurrent reading and writing is supported. Multiple read operations may be performed simultaneously using more than one `ConnectionReadQueue` instance.  Write operations must always be confined to a single `ConnectionQueue`.  A typical usage pattern is one global `ConnectionQueue` instance used for writing located in the application's delegate, with `ConnectionReadQueue` instances located in individual view or window controllers.  When used with long-running read transactions each `ConnectionReadQueue` maintains a separate, consistent snapshot of the database that may be updated in response to database changes.\n\n## Design\n\nThe core of Pipeline is the types `Connection`, `Statement`, and `Row`.\n\n- `Connection` is a connection to an SQLite database.\n\n- `Statement` is a compiled SQL statement.\n\n- `Row` is a single result row.\n\nThe fundamental type for a column value in a result row is `DatabaseValue`.\n\n- `DatabaseValue` objects contain an integer, floating-point, textual, null, or BLOB value.\n\n- `DatabaseValue` objects may be retrieved from result rows.\n\nType-safe column value access is provided by specializations of the `ColumnValueConverter` struct.\n\n- `ColumnValueConverter\u003cT\u003e` converts a column value in a result row to an object of type `T`.\n\nType-safe SQL parameter binding is provided by `SQLParameter` objects.\n\n- `SQLParameter` objects capture a value and bind it to an SQL parameter.\n\nThread-safe access to a database is provided by `ConnectionQueue`.\n\n- `ConnectionQueue` serializes work items on a database connection.\n- `ConnectionReadQueue` serializes read operations on a database connection.\n\n## Examples\n\n### Create a Connection to an In-Memory Database\n\n```swift\nlet connection = try Connection()\n```\n\nThis creates a connection for use on a single thread or dispatch queue only. Most applications should not create a `Connection` directly but instead should use a thread-safe `ConnectionQueue`.\n\n### Create a Table\n\n```swift\ntry connection.execute(sql: \"CREATE TABLE t1(a,b);\")\n```\n\nThe created table *t1* has two columns, *a* and *b*.\n\n### Insert Data\n\n```swift\nfor i in 0..\u003c5 {\n    try connection.execute(sql: \"INSERT INTO t1(a,b) VALUES (?,?);\",\n                           parameters: .int(2*i), .int(2*i+1))\n}\n```\nSQL parameters are passed as a sequence or series of values.  Named parameters are also supported.\n\n```swift\ntry connection.execute(sql: \"INSERT INTO t1(a,b) VALUES (:a,:b);\",\n                       parameters: [\":a\": 100, \":b\": 404])\n```\n\n### Insert Data Efficiently\n\nRather than parsing SQL each time a statement is executed, it is more efficient to prepare a statement and reuse it.\n\n```swift\nlet statement = try connection.prepare(sql: \"INSERT INTO t1(a,b) VALUES (?,?);\")\nfor i in 0..\u003c5 {\n    try statement.bind(.int(2*i), .int(2*i+1))\n    try statement.execute()\n    try statement.reset()\n    try statement.clearBindings()\n}\n```\n\n### Fetch Data\n\nThe closure passed to `execute()` will be called with each result row.\n\n```swift\ntry connection.execute(sql: \"SELECT * FROM t1;\") { row in\n    let x = try row.get(.int, at: 0)\n    let y = try row.optional(.int, at: 1)\n}\n```\n\n*row* is a `Row` instance.\n\n### Perform a Transaction\n\n```swift\ntry connection.transaction { connection, command in\n    // Do something with `connection`\n}\n```\n\nTransactions are committed by default after the transaction closure returns.\n\nTo roll back a transaction instead, set `command` to `.rollback`:\n\n```swift\ntry connection.transaction { connection, command in\n    // If a condition occurs that prevents the transaction from committing:\n    command = .rollback\n}\n```\n\nA rollback is not considered an error condition unless execution of the rollback fails.\n\nTransactions may also return a value:\n\n```swift\nlet (command, value) = try connection.transaction { connection, command -\u003e Int64 in\n    // ... some long and complex sequence of database commands inserting a row \n    return connection.lastInsertRowid\n}\n```\n\n`command` contains the result of the transaction (whether it was committed or rolled back), and `value` is the value returned from the transaction closure.\n\nDatabase transactions may also be performed asynchronously using `ConnectionQueue`.\n\n```swift\nconnectionQueue.asyncTransaction { connection, command in\n    // Do something with `connection`\n} completion: { result in\n    switch result {\n        case .success:\n            // 🎉\n        case .failure(let error):\n            // Handle any errors that occurred\n    }\n}\n```\n\n### Custom SQL Functions\n\n```swift\nlet rot13Mapping: [Character: Character] = [\n    \"A\": \"N\", \"B\": \"O\", \"C\": \"P\", \"D\": \"Q\", \"E\": \"R\", \"F\": \"S\", \"G\": \"T\", \"H\": \"U\", \"I\": \"V\", \"J\": \"W\", \"K\": \"X\", \"L\": \"Y\", \"M\": \"Z\",\n    \"N\": \"A\", \"O\": \"B\", \"P\": \"C\", \"Q\": \"D\", \"R\": \"E\", \"S\": \"F\", \"T\": \"G\", \"U\": \"H\", \"V\": \"I\", \"W\": \"J\", \"X\": \"K\", \"Y\": \"L\", \"Z\": \"M\",\n    \"a\": \"n\", \"b\": \"o\", \"c\": \"p\", \"d\": \"q\", \"e\": \"r\", \"f\": \"s\", \"g\": \"t\", \"h\": \"u\", \"i\": \"v\", \"j\": \"w\", \"k\": \"x\", \"l\": \"y\", \"m\": \"z\",\n    \"n\": \"a\", \"o\": \"b\", \"p\": \"c\", \"q\": \"d\", \"r\": \"e\", \"s\": \"f\", \"t\": \"g\", \"u\": \"h\", \"v\": \"i\", \"w\": \"j\", \"x\": \"k\", \"y\": \"l\", \"z\": \"m\"]\n\ntry connection.addFunction(\"rot13\", arity: 1) { values in\n    let value = values.first.unsafelyUnwrapped\n    switch value {\n        case .text(let t):\n            return .text(String(t.map { rot13Mapping[$0] ?? $0 }))\n        default:\n            return value\n    }\n}\n```\n\n*rot13* can now be used just like any other [SQL function](https://www.sqlite.org/lang_corefunc.html).\n\n```swift\nlet statement = try connection.prepare(sql: \"INSERT INTO t1(a) VALUES (rot13(?));\")\n```\n\n### Custom Collating Sequences\n\n```swift\ntry connection.addCollation(\"localized_compare\", { (lhs, rhs) -\u003e ComparisonResult in\n    lhs.localizedCompare(rhs)\n})\n```\n\n*localized_compare* is now available as a [collating sequence](https://www.sqlite.org/c3ref/create_collation.html).\n\n```swift\nlet statement = try connection.prepare(sql: \"SELECT * FROM t1 ORDER BY a COLLATE localized_compare;\")\n```\n\n## Combine\n\nPipeline provides a Combine publisher for SQLite query results, allowing you to write elegant and powerful data processing code.\n\n```swift\n// CREATE TABLE event(description TEXT NOT NULL, date REAL NOT NULL);\nstruct Event {\n    let description: String\n    let date: Date\n}\n\nlet eventConverter = RowConverter\u003cEvent\u003e { row in\n    let description = try row.text(at: 0)\n    let date = try row.get(.dateWithTimeIntervalSinceReferenceDate, at: 1)\n    return Event(description: description, date: date)\n}\n\nlet connection = try Connection()\n\nlet sevenDaysAgo = Date() - 7 * 24 * 60 * 60\n\nlet publisher = connection.rowPublisher(sql: \"SELECT description, date FROM event WHERE date \u003e= ?1;\") {\n    try $0.bind(.timeIntervalSinceReferenceDate(sevenDaysAgo), toParameter: 1)\n}\n\npublisher\n    .mapRows(eventConverter)\n```\n\n## Miscellaneous\n\n### CSQLite\n\nPipeline uses [CSQLite](https://github.com/sbooth/CSQLite), a Swift package of the SQLite [amalgamation](https://sqlite.org/amalgamation.html) with the [carray](https://www.sqlite.org/carray.html), [decimal](https://sqlite.org/src/file/ext/misc/decimal.c), [ieee754](https://sqlite.org/src/file/ext/misc/ieee754.c), [series](https://sqlite.org/src/file/ext/misc/series.c), [sha3](https://sqlite.org/src/file/ext/misc/shathree.c), and [uuid](https://sqlite.org/src/file/ext/misc/uuid.c) extensions added, along with wrappers for C functions not easily usable from Swift.\n\n### SQLite Build Options\n\nFor performance reasons CSQLite is built without pre-update hook support. Unfortunately there is no way using Swift Package Manager to expose [package features](https://forums.swift.org/t/my-swiftpm-wishlist-aka-proposal-proposals/35292) or build options, in this case the SQLite [pre-update hook](https://sqlite.org/c3ref/preupdate_count.html) and the [session](https://sqlite.org/sessionintro.html) extension. For this reason SQLite build options must be customized by changing to a local CSQLite package dependency and editing [CSQLite/Package.swift](https://github.com/sbooth/CSQLite/blob/main/Package.swift).\n\n## License\n\nPipeline is released under the [MIT License](https://github.com/sbooth/Pipeline/blob/main/LICENSE.txt).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbooth%2Fpipeline","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsbooth%2Fpipeline","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbooth%2Fpipeline/lists"}