Home > Software design >  Why do I get SQLite.swift error when inserting Int64 values?
Why do I get SQLite.swift error when inserting Int64 values?

Time:04-06

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.

CodePudding user response:

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.

  • Related