{"id":13872218,"url":"https://github.com/michaelnisi/skull","last_synced_at":"2025-04-10T04:12:25.207Z","repository":{"id":22878597,"uuid":"26226602","full_name":"michaelnisi/skull","owner":"michaelnisi","description":"Swift SQLite","archived":false,"fork":false,"pushed_at":"2021-04-11T08:51:37.000Z","size":134,"stargazers_count":6,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2024-05-02T05:35:44.926Z","etag":null,"topics":["ios","sqlite","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/michaelnisi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-11-05T15:46:59.000Z","updated_at":"2022-09-21T13:36:12.000Z","dependencies_parsed_at":"2022-08-21T16:10:33.499Z","dependency_job_id":null,"html_url":"https://github.com/michaelnisi/skull","commit_stats":null,"previous_names":[],"tags_count":31,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelnisi%2Fskull","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelnisi%2Fskull/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelnisi%2Fskull/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/michaelnisi%2Fskull/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/michaelnisi","download_url":"https://codeload.github.com/michaelnisi/skull/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248154994,"owners_count":21056543,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["ios","sqlite","swift"],"created_at":"2024-08-05T23:00:37.055Z","updated_at":"2025-04-10T04:12:25.189Z","avatar_url":"https://github.com/michaelnisi.png","language":"Swift","funding_links":[],"categories":["Swift"],"sub_categories":[],"readme":"[![Build Status](https://secure.travis-ci.org/michaelnisi/skull.svg)](http://travis-ci.org/michaelnisi/skull)\n\n# Skull - Swift SQLite\n\n\u003e Everything should be made as simple as possible, but no simpler.\u003cbr\u003e—*Albert Einstein*\n\nThe [Skull Swift package](https://swiftpackageindex.com/michaelnisi/skull) offers a bare bones (400 LOC) interface for [SQLite](https://www.sqlite.org/). Emphasising simplicity, its synchronous API implements a minimal set of functions for interacting with SQLite.\n\n## Example\n\n```swift\nimport Foundation\nimport Skull\n\nlet skull: DispatchQueue = DispatchQueue(label: \"ink.codes.skull\")\nlet db = skull.sync {\n  return try! Skull()\n}\n\nskull.async {\n  let sql = \"create table planets (id integer primary key, au double, name text);\"\n\n  try! db.exec(sql)\n}\n\nskull.async {\n  let sql = \"insert into planets values (?, ?, ?);\"\n\n  try! db.update(sql, 0, 0.4, \"Mercury\")\n  try! db.update(sql, 1, 0.7, \"Venus\")\n  try! db.update(sql, 2, 1, \"Earth\")\n  try! db.update(sql, 3, 1.5, \"Mars\")\n}\n\nskull.sync {\n  let sql = \"select name from planets where au=1;\"\n\n  try! db.query(sql) { er, row in\n    assert(er == nil)\n\n    let name = row?[\"name\"] as! String\n\n    assert(name == \"Earth\")\n    print(name)\n\n    return 0\n  }\n}\n```\n\nSkull is deliberately thin, its tiny API leaves access serialization to users. Leveraging a dedicated serial queue, as shown in the example above, intuitively ensures serialized access.\n\n## Types\n\n```swift\nenum SkullError: Error\n```\n\n`SkullError` enumerates explicit errors.\n\n- `alreadyOpen(String)`\n- `failedToFinalize(Array\u003cError\u003e)`\n- `invalidURL`\n- `notOpen`\n- `sqliteError(Int, String)`\n- `sqliteMessage(String)`\n- `unsupportedType`\n\n```swift\ntypealias SkullRow = Dictionary\u003cString, Any\u003e\n```\n\n`SkullRow` models a `row` within a SQLite table. Being a `Dictionary`, it offers subscript access to column values, which can be of three essential types:\n\n- `String`\n- `Int`\n- `Double`\n\nFor example:\n\n```swift\nrow[\"a\"] as String == \"500.0\"\nrow[\"b\"] as Int == 500\nrow[\"c\"] as Double == 500.0\n```\n\n```swift\nclass Skull: SQLDatabase\n```\n\n`Skull`, the main object of this module, represents a SQLite database connection. It adopts the `SQLDatabase` protocol, which defines its interface:\n\n```swift\nprotocol SQLDatabase {\n  var url: URL? { get }\n\n  func flush() throws\n  func exec(_ sql: String, cb: @escaping (SkullError?, [String : String]) -\u003e Int) throws\n  func query(_ sql: String, cb: (SkullError?, SkullRow?) -\u003e Int) throws\n  func update(_ sql: String, _ params: Any?...) throws\n}\n```\n\n## Exports\n\n### Opening a Database Connection\n\nTo open a database connection you initialize a new `Skull` object.\n\n```swift\ninit(_ url: URL? = nil) throws\n```\n\n- `url` The location of the database file to open.\n\nOpens the database located at file `url`. If the file does not exist, it is created. Skipping `url` or passing `nil` opens an in-memory database.\n\n### Accessing the Database\n\nA `Skull` object, representing a database connection, offers following methods for accessing the database.\n\n```swift\nfunc exec(sql: String, cb: ((SkullError?, [String:String]) -\u003e Int)?)) throws\n```\n\n- `sql` Zero or more UTF-8 encoded, semicolon-separated SQL statements.\n- `cb` A callback to handle results or abort by returning non-zero.\n\nExecutes SQL statements and applies the callback for each result, limited to strings in this case. The callback is optional, if provided, it can abort execution by returning non-zero. The callback doesn't just handle results, it can also monitor execution and, if need be, abort the operation; it is applied zero or more times.\n\n```swift\nfunc query(sql: String, cb: (SkullError?, SkullRow?) -\u003e Int) throws\n```\n\n- `sql` The SQL statement to query the database with.\n- `cb` The callback to handle resuting errors and rows.\n\nQueries the database with the specified *selective* SQL statement and applies the callback for each resulting row or occuring error.\n\n```swift\nfunc update(sql: String, params: Any?...) throws\n```\n\n- `sql` The SQL statement to apply.\n- `params` The parameters to bind to the statement.\n\nUpdates the database by binding the specified parameters to an SQLite statement, for example:\n\n```swift\nlet sql = \"insert into planets values (?, ?, ?);\"\ntry! db.update(sql, 0, 0.4, \"Mercury\")\n```\n\nThis method may throw `SkullError.sqliteError(Int, String)` or `SkullError.unsupportedType`.\n\n### Managing the Database\n\n```swift\nfunc flush() throws\n```\n\nRemoves and finalizes all cached prepared statements.\n\n```swift\nvar url: URL? { get }\n```\n\nThe location of the database file.\n\n### Closing the Database\n\nClose the database by simply dismissing the `Skull` object.\n\n## Install\n\n📦 Add `https://github.com/michaelnisi/skull` to your package manifest.\n\n## License\n\n[MIT](https://raw.github.com/michaelnisi/skull/master/LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichaelnisi%2Fskull","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmichaelnisi%2Fskull","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmichaelnisi%2Fskull/lists"}