rgamber
rgamber

Reputation: 5849

Using variables in Filters in SQLite.swift

I am using SQLite.swift (Branch Swift-1-2) in my app in XCode 6.3 beta. I am able to create the Database/Tables and insert entries into the tables.

So far so good.

Now when I have a simple scenario as follows:

class Foo {
   var id: Int?
   var name: String?
   /* constructor to create an instance ... */
}

// This is how the table column is defined
var id = Expression<Int64>("id")

// Function to update data in the table
func updateFoo(foo: Foo) -> Int? {
    // 'foos' is the table name
    let candidateFoo = foos.filter(super.id == foo.id!) //<----ERROR!!!
    let (rowsUpdated, statement) = candidateFoo.update(name <- foo.name!)

    if  let rowsUpdated = rowsUpdated {
        println("Succesfully updated \(rowsUpdated) row(s)")
        return rowsUpdated
    } else if statement.failed {
        println("Update failed. Reason: \(statement.reason)")
    }

    return nil
}

On the line commented \\ <----ERROR!!!, I get the compile-time error: Binary operator '==' cannot be applied to operands of type Expression< Int64 > and Int

If I use an Int directly on that line, then that works fine. Eg.

let candidateFoo = foos.filter(super.id == 3) // No Error!

But, if I simply do this, it fails with the same error again:

var i = 3
let candidateFoo = foos.filter(super.id == i) // <----ERROR!!!

I understand what the error is, but I am not able to resolve it. I looked at the documentation but I am still stuck. So any help is appreciated.

Update:

Explicitly declaring the variable as Int64 solves the issue:

var i:Int64 = 3
let candidateFoo = foos.filter(super.id == i) // No Error!

Now I am wondering if I have to change my class definition, which will require changes at multiple places in the code. Also official swift documentation recommends using Int unless an explicit size is required.

You should use the word-sized Int type to store integer values, unless you require a type with a specific size or signedness.

Also, the SQLite.swift documentation states that:

While Int64 is the basic, raw type (to preserve 64-bit integers on 32-bit platforms), Int and Bool work transparently.

So should I be using the Int64 here explicitly in my class definition, since its mapped to a DB?

Upvotes: 5

Views: 2471

Answers (1)

stephencelis
stephencelis

Reputation: 4964

You're mapping your Foo structure directly to the underlying types in SQL, so you should use the same type in both places. If you need 64-bit precision on 32-bit devices (to avoid overflow, etc.), you should use Int64. If you're not worried, use Int both places:

var id = Expression<Int>("id")

If I use an Int directly on that line, then that works fine. Eg.

This is because that's actually an Int64, which conforms to IntegerLiteralConvertible so the literal's underlying type is inferred (you can read more about Swift's literal convertibles here: http://nshipster.com/swift-literal-convertible/).

So should I be using the Int64 here explicitly in my class definition, since its mapped to a DB?

Keep in mind that the SQLite.swift expression layer gives you the flexibility to refer to the underlying column types however you want to (assuming you conform it to its Value protocol), so again: you can use Int freely if that's how you're treating the value throughout your code.

Beyond all this, when you work with different integer types in Swift, you can cast them inline. E.g.,

let candidateFoo = foos.filter(super.id == Int64(foo.id!))

Upvotes: 4

Related Questions