{"id":18465939,"url":"https://github.com/relatedcode/relateddb","last_synced_at":"2025-09-13T08:42:07.809Z","repository":{"id":48180010,"uuid":"455249412","full_name":"relatedcode/RelatedDB","owner":"relatedcode","description":"RelatedDB is a lightweight Swift wrapper around SQLite.","archived":false,"fork":false,"pushed_at":"2025-06-05T16:12:31.000Z","size":3294,"stargazers_count":8,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-04T18:53:02.415Z","etag":null,"topics":["ios","macos","sqlite","swift","swift5","wrapper"],"latest_commit_sha":null,"homepage":"https://relatedcode.com","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/relatedcode.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-02-03T16:51:32.000Z","updated_at":"2025-06-05T16:12:33.000Z","dependencies_parsed_at":"2025-06-14T03:15:30.080Z","dependency_job_id":null,"html_url":"https://github.com/relatedcode/RelatedDB","commit_stats":{"total_commits":10,"total_committers":1,"mean_commits":10.0,"dds":0.0,"last_synced_commit":"6550a81ddd63fc711be3771c5614bec8cefe8d9d"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/relatedcode/RelatedDB","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/relatedcode%2FRelatedDB","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/relatedcode%2FRelatedDB/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/relatedcode%2FRelatedDB/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/relatedcode%2FRelatedDB/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/relatedcode","download_url":"https://codeload.github.com/relatedcode/RelatedDB/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/relatedcode%2FRelatedDB/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274941151,"owners_count":25378186,"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","status":"online","status_checked_at":"2025-09-13T02:00:10.085Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["ios","macos","sqlite","swift","swift5","wrapper"],"created_at":"2024-11-06T09:14:32.291Z","updated_at":"2025-09-13T08:42:07.777Z","avatar_url":"https://github.com/relatedcode.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"## What is this?\n\nRelatedDB is a lightweight Swift wrapper for [SQLite](https://sqlite.org/faq.html) that simplifies database operations in iOS applications.\n\n## Requirements\n\n- iOS 13.0+\n- Xcode 12.0+\n- Swift 5.0+\n\n## Installation\n\n### CocoaPods\n\n[CocoaPods](https://cocoapods.org) is a dependency manager for Swift and Objective-C Cocoa projects.\n\nTo integrate **RelatedDB** into your Xcode project using CocoaPods, add the following line to your `Podfile`:\n\n```ruby\npod 'RelatedDB'\n```\n\n### Swift Package Manager\n\n[Swift Package Manager](https://swift.org/package-manager) is a tool for managing the distribution of Swift code.\n\nTo add **RelatedDB** using Swift Package Manager, include it in the dependencies section of your `Package.swift` file:\n\n```swift\ndependencies: [ .package(url: \"https://github.com/relatedcode/RelatedDB.git\", from: \"1.1.8\") ]\n```\n\n### Manually\n\nIf you prefer not to use any of the dependency managers, you can integrate **RelatedDB** into your project manually. Just copy all the `*.swift` files from the `RelatedDB/Sources` folder into your Xcode project.\n\n## Usage\n\n### Connect to a Database\n\n```swift\nimport RelatedDB\n\nlet db = RDatabase()\n```\n\nYou can also specify a custom database filename or the complete file path. The default filename is `database.sqlite`, and the default directory is `Library/Application Support`.\n\n\n```swift\nlet db = RDatabase(file: \"db.sqlite\")\n```\n\n```swift\nlet db = RDatabase(path: \"yourpath/db.sqlite\")\n```\n\n### Define an Object\n\nRelatedDB provides a protocol that allows you to manipulate database rows as regular objects.\n\n```swift\nclass User: NSObject, RDObject {\n\n  @objc var userId = 0\n  @objc var name = \"\"\n  @objc var age = 0\n  @objc var approved = false\n\n  class func primaryKey() -\u003e String {\n    return \"userId\"\n  }\n}\n```\n\nBased on the User class definition above, RelatedDB will automatically create the following SQLite table:\n\n```sql\nCREATE TABLE IF NOT EXISTS User (userId INTEGER PRIMARY KEY NOT NULL, name TEXT, age INTEGER, approved INTEGER);\n```\n\n\u003e **Note**: Since all the RDObject class property names will be used in SQLite commands, try to avoid using [SQLite keywords](https://sqlite.org/lang_keywords.html) in your class definition.\n\n### Insert Object\n\nUsing the User class above, creating an object would look like this:\n\n```swift\nlet user = User()\n\nuser.userId = 1001\nuser.name = \"John Smith\"\nuser.age = 42\nuser.approved = false\n\nuser.insert(db)\n```\n\n### Update Object\n\nAn existing object can be updated:\n\n```swift\nuser.age = 43\n\nuser.update(db)\n```\n\n### Insert vs. Update\n\nIf you're unsure whether an object already exists in the database, you can use the following methods:\n\n```swift\nuser.insertUpdate(db)\n```\n\nIt will try to execute the INSERT command first and if it fails (silently), then executes the UPDATE command.\n\nAlso, you can use\n\n```swift\nuser.updateInsert(db)\n```\n\nwhich will try to execute the UPDATE command first and if it fails (silently), then executes the INSERT command.\n\n### Delete Object\n\nAn existing object can be deleted:\n\n```swift\nuser.delete(db)\n```\n\n### Fetch Object(s)\n\nFetching one object would look like:\n\n```swift\nlet user = User.fetchOne(db, key: 1001)\n```\n\nFetching multiple objects can be done in the following ways:\n\n```swift\nlet users = User.fetchAll(db)\n\nlet users = User.fetchAll(db, \"age \u003e 40\")\n\nlet users = User.fetchAll(db, \"age = ?\", [42])\n\nlet users = User.fetchAll(db, \"age \u003e= :min AND age \u003c= :max\", [\":min\": 18, \":max\": 99])\n```\n\nYou can also use the `limit` and `offset` parameters.\n\n```swift\nlet users = User.fetchAll(db, limit: 10)\n\nlet users = User.fetchAll(db, \"age \u003e 40\", limit: 5, offset: 10)\n```\n\n### Serial Execution, Thread Safety\n\nDatabase write operations are serialized, meaning Insert, Update, and Delete actions are executed sequentially (automatically managed by RelatedDB).\n\nFetch methods are thread-safe, ensuring that results are returned on the same thread from which the request was initiated.\n\n\u003e **Note**: You can initiate both read and write actions from any thread you like.\n\n### Data Types\n\nRelatedDB can manage the following data types: `Bool`, `Int8`, `Int16`, `Int32`, `Int64`, `Int`, `Float`, `Double`, `String`, `Date`, `Data`.\n\n### Date Format\n\nThe `Date` values will be stored in the database as ISO formatted `String`. The default format is ISO 8601 (\"1970-01-01T01:01:01.000Z\"), produced by the `ISO8601DateFormatter` class.\n\nYou can also specify your own date format by using:\n\n```swift\nlet formatter = DateFormatter()\nformatter.locale = Locale(identifier: \"en_US_POSIX\")\nformatter.timeZone = TimeZone(secondsFromGMT: 0)\nformatter.dateFormat = \"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'\"\n\nRDDate.custom(formatter)\n```\n\n\u003e **Note**: You only need to specify the date format once in your codebase. Practically before doing any database action.\n\n### Values Dictionary\n\nAlthough managing the database rows as objects is an easy and elegant way, you might want to manage the data as `Dictionary` instead.\n\n**Insert** *(using Dictionary)*\n\nInsert a new object as Dictionary:\n\n```swift\nlet values: [String: Any] = [\"userId\": 1001, \"name\": \"John Smith\", \"age\": 42, \"approved\": false]\n\ndb.insert(\"User\", values)\n```\n\n**Update** *(using Dictionary)*\n\nUpdate an existing object as Dictionary:\n\n```swift\nlet values: [String: Any] = [\"userId\": 1001, \"age\": 43]\n\ndb.update(\"User\", values)\n```\n\nThe primary key must be included in the values Dictionary. Otherwise, nothing will happen.\n\n**Fetch Result(s)** *(as Dictionary)*\n\nFetching one object as Dictionary:\n\n```swift\nlet user = db.fetchOne(\"User\", key: 1001)\n```\n\nIn this case, the result type will be a `[String: Any]`.\n\nFetching multiple objects as Dictionary:\n\n```swift\nlet users = db.fetchAll(\"User\")\n\nlet users = db.fetchAll(\"User\", \"age \u003e 40\")\n\nlet users = db.fetchAll(\"User\", \"age = ?\", [42])\n\nlet users = db.fetchAll(\"User\", \"age \u003e= :min AND age \u003c= :max\", [\":min\": 18, \":max\": 99])\n```\n\nIn the cases above, the result types will be a `[[String: Any]]`.\n\n**Convert Object** *(to Dictionary)*\n\nConvert an existing object to a Dictionary:\n\n```swift\nlet values = user.values()\n```\n\n**Date Values** (in Dictionary)\n\nWhen using a values dictionary (for inserting or updating data), Date values can be provided as either `Date` objects or ISO-formatted `String` values.\n\nWhen fetching data (as dictionary), the Date values will always be represented in the Dictionary as ISO formatted `String`.\n\n### Batch Update\n\nYou can update multiple objects by specifying a condition.\n\n```swift\nlet values = [\"approved\": true]\n\nUser.updateAll(db, values, \"age \u003e= ? AND age \u003c= ?\", [30, 35])\n```\n\nAlternatively, update one object by specifying the primary key value.\n\n```swift\nlet values = [\"approved\": true]\n\nUser.updateOne(db, values, key: 1001)\n```\n\n### Batch Delete\n\nYou can delete multiple objects by specifying a condition.\n\n```swift\nUser.deleteAll(db, \"age \u003e= ? AND age \u003c= ?\", [30, 35])\n```\n\nAlternatively delete one object by specifying the primary key value.\n\n```swift\nUser.deleteOne(db, key: 1001)\n```\n\n### Count Objects\n\nYou can get the number of objects by specifying a condition.\n\n```swift\nlet count = User.count(db)\n\nlet count = User.count(db, \"age \u003e 40\")\n\nlet count = User.count(db, \"age \u003e= ? AND age \u003c= ?\", [30, 35])\n```\n\n### Check Objects\n\nYou can check whether an object exists or not (by specifying the primary key value).\n\n```swift\nif (User.check(db, key: 1001)) {\n  // do something \n}\n```\n\nOr you can check whether a set of objects exist or not (by specifying a condition).\n\n```swift\nif (User.check(db, \"age \u003e= ? AND age \u003c= ?\", [30, 35])) {\n  // do something \n}\n```\n\n### Create Observer\n\nTo refresh the user interface when database changes occur, you can use Database Observers.\n\nTo observe all possible changes for the User class:\n\n```swift\nlet types: [RDObserverType] = [.insert, .update, .delete]\n\nlet observerId = User.createObserver(db, types) { method, objectId in\n  // do something\n}\n```\n\nHowever, you can narrow down the number of changes by using a condition:\n\n```swift\nlet observerId = User.createObserver(db, types, \"OBJ.age \u003e 40\") { method, objectId in\n  // do something\n}\n```\n\nAlso you can check only specific database changes (separated or combined) by using the following Observer types: `.insert`, `.update`, `.delete`.\n\nTo get notified about new users, but not updated and/or deleted ones:\n\n```swift\nlet observerId = User.createObserver(db, .insert) { method, objectId in\n  // do something\n}\n```\n\nOr to get notified about deleted users only:\n\n```swift\nlet observerId = User.createObserver(db, .delete) { method, objectId in\n  // do something\n}\n```\n\n### Remove Observer\n\nOnce a Database Observer is no longer required, you can remove it by using:\n\n```swift\nUser.removeObserver(db, observerId)\n```\n\n### Execute Plain SQL\n\nIf needed, you can execute plain SQL commands.\n\n```swift\ndb.execute(\"DELETE FROM User WHERE age = 42;\")\n```\n\n### Drop Table, Create Table\n\nAlthough the SQLite tables are created automatically, you can also DROP and/or CREATE tables manually.\n\n```swift\ndb.dropTable(\"User\")\n\ndb.createTable(\"User\")\n```\n\nIn these cases, the `User` class also needs to be defined first.\n\n### Cleanup Database\n\nIf needed, all tables can be destroyed and recreated using:\n\n```swift\ndb.cleanupDatabase()\n```\n\n### Error Handling\n\nCritical issues will trigger a `fatalError`, while other situations will be logged to the Xcode output window.\n\nYou can alter the debug level by using:\n\n```swift\nRDDebug.level(.none)\n\nRDDebug.level(.error)\n\nRDDebug.level(.all)\n```\n\n## Limitations\n\nThe RelatedDB toolkit is in its initial release. It is functional and can handle most workloads. However, there are some features that are currently not supported:\n\n- Database migration\n- Database encryption\n- Combine framework integration\n\n---\n\n© Related Code 2025 - All Rights Reserved\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frelatedcode%2Frelateddb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frelatedcode%2Frelateddb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frelatedcode%2Frelateddb/lists"}