Data Persistency with SQLite.Swift

Use SQLite.Swift on Android and iOS with zero code changes

Introduction

SCADE provides support for all necessary APIs, including Swift Foundation and linking of C libraries that are necessary for running SQLite.Swift:

All your pure SQLite.swift code compiles and runs on Android without modifications

📘

Download Sourcecode

Please see the UgSqliteSwift project for the source code created in this chapter. See Installing examples for information on how to download the examples. The URL is https://github.com/scadedoc/UgExamples/tree/master/UgSqlLiteSwift

Add SQLite libraries and modulemap file

The use of SQLite and SQLite.Swift is straightforward and easy:

1. Setup directory structure

Add the following directory structure below <project_root>

./lib/android/x86
./lib/android/x86_64
./lib/android/armeabi-v7a
./lib/android/arm64-v8a
./lib/include

2. Copy files

👍

File location

Please find all files in Examples section on GitHub here https://github.com/scadedoc/UgExamples/tree/master/UgSqlLiteSwift/lib/android

  • Copy to x86/libsqlite3.so to ./lib/android/x86
  • Copy to x86_64/libsqlite3.so to ./lib/android/x86_64
  • Copy to armeabi-v7a/libsqlite3.so to ./lib/android/armeabi-v7a
  • Copy to arm64-v8a/libsqlite3.so to ./lib/android/arm64-v8a
  • Copy header file sqlite3.h to ./lib/include
  • Copy module map file module.modulemap to ./lib/include
module SQLite3 [system] [extern_c] {
    header "sqlite3.h"
    link "sqlite3"
    export *
}

Your directory should now look like this

Add dependency for SQLite.Swift

Open your Package.swift file and add the dependency

Your Package.swift file should look similar to this now:

Replace main.page.swift with sample code

import ScadeKit
import SQLite

class MainPageAdapter: SCDLatticePageAdapter {

	// page adapter initialization
	override func load(_ path: String) {		
		super.load(path)
		
		do {
			let db = try Connection(NSHomeDirectory() + "/data.db")
	
			let users = Table("users")
			let id = Expression<Int64>("id")
			let name = Expression<String?>("name")
			let email = Expression<String>("email")
			
			_ = try? db.run(users.create { t in
			    t.column(id, primaryKey: true)
			    t.column(name)
			    t.column(email, unique: true)
			})
			// CREATE TABLE "users" (
			//     "id" INTEGER PRIMARY KEY NOT NULL,
			//     "name" TEXT,
			//     "email" TEXT NOT NULL UNIQUE
			// )
			
			let insert = users.insert(name <- "Alice", email <- "[email protected]")
			let rowid = try db.run(insert)
			// INSERT INTO "users" ("name", "email") VALUES ('Alice', '[email protected]')
			
			for user in try db.prepare(users) {
			    print("id: \(user[id]), name: \(user[name]), email: \(user[email])")
			    
			    // id: 1, name: Optional("Alice"), email: [email protected]
			}
			// SELECT * FROM "users"
			
			let alice = users.filter(id == rowid)
			
			try db.run(alice.update(email <- email.replace("mac.com", with: "me.com")))
			// UPDATE "users" SET "email" = replace("email", 'mac.com', 'me.com')
			// WHERE ("id" = 1)
			
			try db.run(alice.delete())
			// DELETE FROM "users" WHERE ("id" = 1)
			
			try db.scalar(users.count) // 0
			// SELECT count(*) FROM "users"
			
			}
		catch {
			print("ERROR: \(error)")
		}
		
	}
}

Run the project

You should see the following output in the console.