0

As part of a migration effort, I am creating a SQLite DB for the first time.

Based on the example documentation from the site

SQLite.swift documentation

I am creating an Insert statement and then running it to insert the record.

I get the following error on each line that has an Int64 value:

Cannot convert value of type 'Expression<Int64>' to expected argument type 'Expression<Int?>'

I have no optional values in my code, it is being introduced in these lines.

I don't understand why, or what I should do to make the compiler happy.

import SQLite

extension Connection {
   /// Source could be a json file or a migration from Realm, for example
   static func insertAprilRecords(records: [AprilRecord]) {
      /// List target db's fields
  
      let id = Expression<Int64>(AprilRecord.Key.id.rawValue)
      let activity = Expression<Int64>(AprilRecord.Key.activity.rawValue)
      let timestamp = Expression<Double>(AprilRecord.Key.timestamp.rawValue)
      let details = Expression<String>(AprilRecord.Key.details.rawValue)
      let isCompleted = Expression<Bool>(AprilRecord.Key.isCompleted.rawValue)
      
      let table = Table("record") // equivalent of `Goal`
  
    do {
         let db = try Connection(DBSetup.dbURL.path)
         try db.transaction {
            for record in records {
               let insertionRecord = table.insert(
                  // error: Cannot convert value of type 'Expression<Int64>' to expected argument 
                  activity <- record.activity,
                  timestamp <- record.timestamp,
                  details <- record.details,
                  isCompleted <- record.isCompleted,
                  )
               let rowid = try db.run(insertionRecord)
            }
         }
      } catch {
         print("failed to add records to the DB")
         print(error)
         print(error.localizedDescription)
      }
   }
}

I don't have any optional fields:

public struct AprilRecord: Identifiable, Codable {

   public var id: Int
   var activity: Int
   var timestamp: Double
   var details: String
   var isCompleted: Bool
}

for completeness (so it will compile), here are my keys:

extension AprilRecord {
   enum Key: String, CaseIterable {
      case id, activity, timestamp, details, isCompleted
   }
}

Since I can't find any examples of this problem online I expect I'm doing something fundamentally wrong.

What is the correct way to insert non-optional Int64 values?

Edit:

If I modify the Expression definition to use an optional:

let category = Expression<Int64?>(AprilRecord.Key.category.rawValue)

I get an error message I don't expect for the line:

 category <- record.category,

Binary operator '<-' cannot be applied to operands of type 'Expression<Int64?>' and 'Int'

Shouldn't the left hand side be Expression<Int64?> at that point? Certainly not an Int.

Mozahler
  • 4,958
  • 6
  • 36
  • 56
  • Maybe [this question](https://stackoverflow.com/questions/27440100/what-is-the-difference-between-int-and-int32-in-swift) is relevant here? It could explain the optional if `Int(exactly:)` is used when converting from Int64 to Int. What happens if you use Int instead of Int64 in your declarations? – Joakim Danielson Apr 03 '22 at 17:28
  • Thanks for responding! I did see that. If you mean wrap record.activity as Int(exactly: record.activity) - nothing changes. the right hand side of that line does not contain an optional. Even the error message (which doesn't change) shows the compiler gets that the right hand side is not optional. The optional is introduced on the left hand side of the "<-" operator. In fact the type of activity in let activity = Expression(AprilRecord.Key.activity.rawValue) is the desired Expression. – Mozahler Apr 03 '22 at 18:18
  • No I meant that you could try and change the declaration of the columns, `let activity = Expression(AprilRecord.Key.activity.rawValue)`. I have no idea if it will help but it could be worth a try. – Joakim Danielson Apr 03 '22 at 18:33
  • Binary operator '<-' cannot be applied to operands of type 'Expression' and 'Int?' -- same exact issue with a different datatype. I don't understand why Double works and Int does not. I'm guessing that a failable initializer is involved. – Mozahler Apr 03 '22 at 18:41
  • Did you try without defining expressions ie : activity <- record.activity – Ptit Xav Apr 03 '22 at 21:00
  • Cannot find 'activity' in scope – Mozahler Apr 03 '22 at 21:19

1 Answers1

0

OK, I was doing something fundamentally wrong.

Although the documentation shows copious use of Expression<Int64>, I should be using Expression<Int>. As in:

      let activity = Expression<Int>(AprilRecord.Key.activity.rawValue)

from the documentation (same link as above):

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

It really does work transparently!

Thanks to Joakim and Ptit for responding.

Mozahler
  • 4,958
  • 6
  • 36
  • 56