7

The SQLite.swift documentation says about executing arbitrary SQL:

let stmt = try db.prepare("SELECT id, email FROM users")
for row in stmt {
    for (index, name) in stmt.columnNames.enumerate() {
        print ("\(name)=\(row[index]!)")
        // id: Optional(1), email: Optional("alice@mac.com")
    }
}

I wanted to get the values directly like this

let stmt = try db.prepare("SELECT id, email FROM users")
for row in stmt {
    let myInt: Int64 = row[0] // error: Cannot convert value of type 'Binding?' to specified type 'Int64'
    let myString: String = row[1] // error: Cannot convert value of type 'Binding?' to specified type 'String'
}

but the row index is of type Binding? and I can't figure out how to convert that to the type I need. I see there is a Statement.bind method in the source code but I am still not discovering how to apply it.

Suragch
  • 484,302
  • 314
  • 1,365
  • 1,393
  • Did you try using `Expression`?, (eg. `let myInt: Expression = ...`) – l'L'l Aug 15 '16 at 17:37
  • @l'L'l, Good idea. Unfortunately it gives the same error (can't convert `Binding?` to `Expression`). I've been successful using `Expression` in the past but now that I am trying to get arbitrary SQL to work (because of my problem with [this](http://stackoverflow.com/q/38936230)), I've been having a lot of trouble. – Suragch Aug 15 '16 at 18:19

1 Answers1

8

You can retrieve correctly typed selected columns from a table like this:

// The database.
let db = try Connection(...)

// The table.
let users = Table("users")

// Typed column expressions.
let id = Expression<Int64>("id")
let email = Expression<String>("email")

// The query: "SELECT id, email FROM users"
for user in try db.prepare(users.select(id, email)) {
    let id = user[id]       // Int64
    let mail = user[email]  // String
    print(id, mail)
}

An alternative is to (optionally) cast the Binding values to the correct type:

let stmt = try db.prepare("SELECT id, email FROM users")
for row in stmt {
    if let id = row[0] as? Int64,
        let mail = row[1] as? String {
        print(id, mail)
    }
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • The second part of your answer solved my problem. The first part of your answer is surely better for the standard case (and I have done it like this before), but I am specifically wondering how to do it when executing arbitrary SQL. (I updated my question slightly to reflect that.) The reason I am resorting to arbitrary SQL is because of [this as of yet unsolved problem](http://stackoverflow.com/q/38936230). – Suragch Aug 16 '16 at 00:21
  • Is there any way to bind the column names using `Expression` when accessing the row data after an arbitrary SQL query? I can see bugs coming in the future when I forget to update the hard coded column index numbers. – Suragch Aug 16 '16 at 00:25
  • @Suragch: I doubt it. That would require to *analyze* the query string. – Martin R Aug 18 '16 at 19:46