🧡 SQLiteOrm-Swift is an ORM library for SQLite3 built with Swift 5

Overview

Sublime's custom image

SQLiteORM for Swift

example workflow

SQLiteOrm-Swift is an ORM library for SQLite3 built with Swift 5

Advantages

  • No raw string queries
  • Intuitive syntax
  • Comfortable interface - one call per single query
  • CRUD support
  • Does not depend on Codable protocol
  • The only dependency - SQLite3
  • In memory database support - provide :memory: or empty filename
  • Transactions support
  • Migrations functionality

SQLiteOrm library allows to create easy data model mappings to your database schema. It is built to manage (CRUD) objects with a primary key and without it. It also allows you to specify table names and column names explicitly no matter how your classes actually named. And it does not depend on Codable protocol. Take a look at example:

import SQLiteORM

struct User : Initializable {
    var id = 0
    var firstName = ""
    var lastName = ""
    var birthDate = ""
    var imageUrl: String?
    var typeId = 0
}

struct UserType: Initializable {
    var id = 0
    var name = ""
}

So we have database with predefined schema like

CREATE TABLE users (
    id INTEGER PRIMARY KEY NOT NULL, 
    first_name TEXT NOT NULL, 
    last_name TEXT NOT NULL, 
    birth_date INTEGER NOT NULL, 
    image_url TEXT, 
    type_id INTEGER NOT NULL)
    
CREATE TABLE user_types (
    id INTEGER PRIMARY KEY NOT NULL, 
    name TEXT NOT NULL)

Now we tell SQLiteOrm library about our schema and provide database filename. We create storage helper object that has CRUD interface. Also we create every table and every column. All code is intuitive and minimalistic.

(name: "users", columns: Column(name: "id", keyPath: \User.id, constraints: primaryKey(), notNull()), Column(name: "first_name", keyPath: \User.firstName, constraints: notNull()), Column(name: "last_name", keyPath: \User.lastName, constraints: notNull()), Column(name: "birth_date", keyPath: \User.birthDate, constraints: notNull()), Column(name: "image_url", keyPath: \User.imageUrl), Column(name: "type_id", keyPath: \User.typeId, constraints: notNull())), Table (name: "user_types", columns: Column(name: "id", keyPath: \UserType.id, constraints: primaryKey(), notNull()), Column(name: "name", keyPath: \UserType.name, constraints: notNull()))) }catch{ print("error happened \(error)") } ">
let path = getDocumentsDirectory() + "/db.sqlite"
do {
    let storage = try Storage(filename: path,
                              tables:
                                Table<User>(name: "users",
                                            columns:
                                               Column(name: "id", keyPath: \User.id, constraints: primaryKey(), notNull()),
                                               Column(name: "first_name", keyPath: \User.firstName, constraints: notNull()),
                                               Column(name: "last_name", keyPath: \User.lastName, constraints: notNull()),
                                               Column(name: "birth_date", keyPath: \User.birthDate, constraints: notNull()),
                                               Column(name: "image_url", keyPath: \User.imageUrl),
                                               Column(name: "type_id", keyPath: \User.typeId, constraints: notNull())),
                                Table<UserType>(name: "user_types",
                                                columns:
                                                    Column(name: "id", keyPath: \UserType.id, constraints: primaryKey(), notNull()),
                                                    Column(name: "name", keyPath: \UserType.name, constraints: notNull())))
}catch{
    print("error happened \(error)")
}

Too easy isn't it? To create a column you have to pass two arguments at least: its name in the table and your mapped class keypath. You can also add extra arguments to tell your storage about column's constraints like primaryKey(), notNull(), unique().

CRUD

Let's create and insert new User into our database. First we need to create a User object with any id and call insert function. It will return id of just created user or throw exception if something goes wrong. If you want to insert a user with id you specified then you need to use replace function instead of insert.

var user = User(id: 0, firstName: "John", lastName: "Doe", birthDate: 664416000, imageUrl: "url_to_heaven", typeId: 3)
let insertedId = try storage.insert(object: user)
print("insertedId = \(insertedId)")
user.id = Int(insertedId)

let secondUser = User(id: 2, firstName: "Alice", lastName: "Inwonder", birthDate: 831168000, imageUrl: nil, typeId: 2)
try storage.replace(object: secondUser) //  insert with 'id' 2

Next let's get our user by id.

if let user1: User = try storage.get(id: 1) {
    print("user = \(user1.firstName) \(user1.lastName)")
}else{
    print("user with id 1 does not exist")
}

We can also update our user. Storage updates row by id provided in user object and sets all other non primary_key fields to values stored in the passed user object. So you can just assign fields to user object you want and call update:

user.firstName = "Nicholas"
user.imageUrl = "https://cdn1.iconfinder.com/data/icons/man-icon-set/100/man_icon-21-512.png"
try storage.update(object: user)

And delete. To delete you have to pass a whole object.

try storage.delete(object: user)

Also we can extract all objects into Array:

let allUsers: [User] = try storage.getAll()
print("allUsers (\(allUsers.count):")
for user in allUsers {
    print(user)
}

Migrations functionality

There are no explicit up and down functions that are used to be used in migrations. Instead SQLiteORM offers syncSchema function that takes responsibility of comparing actual db file schema with one you specified in Storage init call and if something is not equal it alters or drops/creates schema.

try storage.syncSchema(preserve: true)

Please beware that syncSchema doesn't guarantee that data will be saved. It tries to save it only. Below you can see rules list that syncSchema follows during call:

  • if there are excess tables exist in db they are ignored (not dropped)
  • every table from storage is compared with it's db analog and
    • if table doesn't exist it is created
    • if table exists its colums are being compared with table_info from db and
      • if there are columns in db that do not exist in storage (excess) table will be dropped and recreated if preserve is false, and table will be copied into temporary table without excess columns, source table will be dropped, copied table will be renamed to source table (sqlite remove column technique) if preserve is true. Beware that setting it to true may take time for copying table rows.
      • if there are columns in storage that do not exist in db they will be added using 'ALTER TABLE ... ADD COLUMN ...' command and table data will not be dropped but if any of added columns is null but has not default value table will be dropped and recreated
      • if there is any column existing in both db and storage but differs by any of properties (pk, notnull) table will be dropped and recreated (dflt_value isn't checked cause there can be ambiguity in default values, please beware).

The best practice is to call this function right after storage creation.

Notes

To work well your data model class must inherit from Initializable which required only init() with no arguments existance and must not have const fields mapped to database cause they are assigned during queries. Otherwise code won't compile.

You might also like...
Prephirences is a Swift library that provides useful protocols and convenience methods to manage application preferences, configurations and app-state. UserDefaults
Prephirences is a Swift library that provides useful protocols and convenience methods to manage application preferences, configurations and app-state. UserDefaults

Prephirences - Preϕrences Prephirences is a Swift library that provides useful protocols and convenience methods to manage application preferences, co

A stand-alone Swift wrapper around the MySQL client library, enabling access to MySQL servers.
A stand-alone Swift wrapper around the MySQL client library, enabling access to MySQL servers.

Perfect - MySQL Connector This project provides a Swift wrapper around the MySQL client library, enabling access to MySQL database servers. This packa

A stand-alone Swift wrapper around the libpq client library, enabling access to PostgreSQL servers.
A stand-alone Swift wrapper around the libpq client library, enabling access to PostgreSQL servers.

Perfect - PostgreSQL Connector This project provides a Swift wrapper around the libpq client library, enabling access to PostgreSQL servers. This pack

Swift library that makes easier to serialize the user's preferences (app's settings) with system User Defaults or Property List file on disk.

PersistentStorageSerializable PersistentStorageSerializable is a protocol for automatic serialization and deserialization of Swift class, struct or NS

A PostgreSQL client library for Swift. Does not require libpq.

PostgresClientKit PostgresClientKit provides a friendly Swift API for operating against a PostgreSQL database. Features Doesn't require libpq. Postgre

Easiest local storage library in Swift
Easiest local storage library in Swift

SundeedQLite SundeedQLite is the easiest offline database integration, built using Swift language Requirements iOS 12.0+ XCode 10.3+ Swift 5+ Installa

A stand-alone Swift wrapper around the SQLite 3 client library.
A stand-alone Swift wrapper around the SQLite 3 client library.

Perfect - SQLite Connector This project provides a Swift wrapper around the SQLite 3 library. This package builds with Swift Package Manager and is pa

KeyPathKit is a library that provides the standard functions to manipulate data along with a call-syntax that relies on typed keypaths to make the call sites as short and clean as possible.

KeyPathKit Context Swift 4 has introduced a new type called KeyPath, with allows to access the properties of an object with a very nice syntax. For in

A library that provides the ability to import/export Realm files from a variety of data container formats.

Realm Converter Realm Converter is an open source software utility framework to make it easier to get data both in and out of Realm. It has been built

Comments
  • add Enum demo

    add Enum demo

    
    enum CompassPoint: Int {
        case none
        case north
        case south
        case east
        case west
    }
    
    extension CompassPoint : Bindable, ConstructableFromSQLiteValue {
        init(sqliteValue: SQLiteORM.SQLiteValue) {
            self = CompassPoint(rawValue: sqliteValue.integer) ?? .none
        }
        
        func bind(to binder: Binder) -> Int32 {
            return binder.bindInt(value: self.rawValue)
        }
        
        public static func sqliteTypeName() -> String {
            return "INTEGER"
        }
        
    }
    

    🤔

    example 
    opened by iOSleep 1
Releases(0.0.1)
Owner
Yevgeniy Zakharov
Mobile developer. Have experience in: C++, Objective-C, Swift, C#, Java. Frameworks: cocos2d-x, cocoa touch, cocoa, .NET, Android SDK/NDK, gtkmm
Yevgeniy Zakharov
SQLite.swift - A type-safe, Swift-language layer over SQLite3.

SQLite.swift provides compile-time confidence in SQL statement syntax and intent.

Stephen Celis 8.7k Jan 3, 2023
CRUD is an object-relational mapping (ORM) system for Swift 4+.

CRUD is an object-relational mapping (ORM) system for Swift 4+. CRUD takes Swift 4 Codable types and maps them to SQL database tables. CRUD can create tables based on Codable types and perform inserts and updates of objects in those tables. CRUD can also perform selects and joins of tables, all in a type-safe manner.

PerfectlySoft Inc. 61 Nov 18, 2022
🔥 🔥 🔥Support for ORM operation,Customize the PQL syntax for quick queries,Support dynamic query,Secure thread protection mechanism,Support native operation,Support for XML configuration operations,Support compression, backup, porting MySQL, SQL Server operation,Support transaction operations.

?? ?? ??Support for ORM operation,Customize the PQL syntax for quick queries,Support dynamic query,Secure thread protection mechanism,Support native operation,Support for XML configuration operations,Support compression, backup, porting MySQL, SQL Server operation,Support transaction operations.

null 60 Dec 12, 2022
PostgreSQL database adapter (ORM included)

PostgreSQL PostgreSQL adapter for Swift 3.0. Conforms to SQL, which provides a common interface and ORM. Documentation can be found there. Installatio

Zewo Graveyard 91 Sep 9, 2022
Disk is a powerful and simple file management library built with Apple's iOS Data Storage Guidelines in mind

Disk is a powerful and simple file management library built with Apple's iOS Data Storage Guidelines in mind

Saoud Rizwan 3k Jan 3, 2023
A fast, pure swift MongoDB driver based on Swift NIO built for Server Side Swift

A fast, pure swift MongoDB driver based on Swift NIO built for Server Side Swift. It features a great API and a battle-tested core. Supporting both MongoDB in server and embedded environments.

null 646 Dec 10, 2022
YapDB is a collection/key/value store with a plugin architecture. It's built atop sqlite, for Swift & objective-c developers.

YapDatabase is a collection/key/value store and so much more. It's built atop sqlite, for Swift & Objective-C developers, targeting macOS, iOS, tvOS &

Yap Studios 3.3k Dec 29, 2022
Steppe Payment Built With Swift

SteppePayment Example To run the example project, clone the repo, and run pod install from the Example directory first. Requirements Installation Step

null 0 Mar 21, 2022
A stand-alone Swift wrapper around the mongo-c client library, enabling access to MongoDB servers.

This package is deprecated in favour of the official Mongo Swift Driver. We advise users to switch to that pack

PerfectlySoft Inc. 54 Jul 9, 2022
Elegant library to manage the interactions between view and model in Swift

An assistant to manage the interactions between view and model ModelAssistant is a mediator between the view and model. This framework is tailored to

Seyed Samad Gholamzadeh 28 Jan 29, 2022