0

I'm trying to convert several of my apps to use GRDB.swift. Does anybody have or know where I can find a file to get me started? I've read over most of the GRDB docs but I'm not getting it. Below is a sample scenario.

This I was able to convert from SQLite.sift

class Database
{
    static let shared = Database()
    public let databaseConnection: DatabaseQueue?
    
    private init()
    {
        do
        {
            let fileUrl = try FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent("MyDaatbase.sqlite")
            
            // GRDB
            let databaseConnection = try DatabaseQueue(path: fileUrl.path)
            self.databaseConnection = databaseConnection
        } catch {
            databaseConnection = nil
            let nserror = error as NSError
            print("Cannot connect to Database. Error is: \(nserror), \(nserror.userInfo)")
        }
    }
}

Could someone please convert this to GRDB to help me get started?

static func isAnimation() -> Bool
    {
        let theTable = Table("Settings")
        let theColumn = Expression<String>("AnimateNav")
        var theStatus = false
        
        do {
            for theAnswer in try Database.shared.databaseConnection!.prepare(theTable.select(theColumn)) {
                //print(theAnswer[theColumn])
                let theStatusText = (theAnswer[theColumn])
                
                theStatus = theStatusText == "true" ? true : false
            }
        } catch {
            print("Getting the isAnimation Status failed! Error: \(error)")
        }
        return theStatus
    }

1 Answer 1

0

You can use raw SQL:

static func isAnimation() -> Bool {
    var theStatus = false
    do {
        let animateNav = try Database.shared.databaseConnection!.read { db in
            String.fetchOne(db, sql: "SELECT AnimateNav FROM Settings")
        }
        theStatus = animateNav == "true" ? true : false
    } catch {
        print("Getting the isAnimation Status failed! Error: \(error)")
    }
    return theStatus
}

You can also define a Record type for the Settings table, which is the preferred GRDB way:

// Settings.swift
struct Settings: Codable, FetchableRecord, TableRecord {
    var animateNav: String
    // other properties for other columns in the Settings table
    ...
}

// Your file
static func isAnimation() -> Bool {
    var theStatus = false
    do {
        let settings = try Database.shared.databaseConnection!.read { db in
            try Settings.fetchOne(db)
        }
        theStatus = settings?.animateNav == "true" ? true : false
    } catch {
        print("Getting the isAnimation Status failed! Error: \(error)")
    }
    return theStatus
}
Sign up to request clarification or add additional context in comments.

4 Comments

Thank you very much for the reply. I like the second set up using the Struct. Just one thing. LC made me include the full select statement: try Settings.fetchOne(db, sql: "SELECT AnimateNav FROM Settings"). I assume this is correct and you were just in a rush and left that out.
Glad you're getting comfortable. The Settings.fetchOne(db) (without raw sql) needs the Setting struct to conform to the TableRecord protocol, that I forgot to add in the sample code, yes. I have updated it.
Thanks again. Adding the TableRecord protocol made things much better. So how does Xcode/GRDB know what column to select in the table? Do the names of the items in the struct need to match the column in the table? sql: "SELECT AnimateNav FROM Settings"
TableRecord uses the name of the type in order to provide a default table name (you can override it), and selects all columns by default (you can override as well). Codable records provides a default init(row:) initializer which maps the coding keys generated by the compiler to the database columns. The answers to many questions are written in the documentation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.