Closed wildthink closed 6 years ago
@wildthink it definitively should work. Thanks for reporting this issue!
@wildthink, I did exactly what you said:
I tried adding a var tags: [String] property to the Player struct definition in the DemoiOSApp. I also added a tags column to the db create and also to the CodingKeys of Player.
And GRDB would happily insert and update JSON arrays. The demo app just works.
So I can't really reproduce your issue.
Please give more details about your issue, so that it can be addressed.
Is there a special sqlite data type required? I tried .text as well.
diff --git a/DemoApps/GRDBDemoiOS/GRDBDemoiOS/AppDatabase.swift b/DemoApps/GRDBDemoiOS/GRDBDemoiOS/AppDatabase.swift
index dd39c279..8f9aa08d 100644
--- a/DemoApps/GRDBDemoiOS/GRDBDemoiOS/AppDatabase.swift
+++ b/DemoApps/GRDBDemoiOS/GRDBDemoiOS/AppDatabase.swift
@@ -37,6 +37,7 @@ struct AppDatabase {
t.column("name", .text).notNull().collate(.localizedCaseInsensitiveCompare)
t.column("score", .integer).notNull()
+ t.column("tags")
}
}
diff --git a/DemoApps/GRDBDemoiOS/GRDBDemoiOS/Player.swift b/DemoApps/GRDBDemoiOS/GRDBDemoiOS/Player.swift
index 06838bb0..7283fc42 100644
--- a/DemoApps/GRDBDemoiOS/GRDBDemoiOS/Player.swift
+++ b/DemoApps/GRDBDemoiOS/GRDBDemoiOS/Player.swift
@@ -4,6 +4,14 @@ struct Player {
var id: Int64? // Auto-incremented database ids are Int64
var name: String
var score: Int
+ var tags: [String] = []
+
+ init (id: Int64?, name: String, score: Int, tags: [String] = ["a", "b"]) {
+ self.id = id
+ self.name = name
+ self.score = score
+ self.tags = tags
+ }
}
// MARK: - Persistence
@@ -15,7 +23,7 @@ extension Player: Codable, FetchableRecord, MutablePersistableRecord {
// See https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types
// for more information about CodingKeys.
private enum CodingKeys: String, CodingKey, ColumnExpression {
- case id, name, score
+ case id, name, score, tags
}
@wildthink. Please provide the stack trace of the crash.
Thread 1 Queue : com.apple.main-thread (serial)
@wildthink I'm still unable to reproduce your crash. I cloned the GRDB repo in its latest version, opened the GRDB.xcworkspace, modified files in the GRDBDemo target according to your comment, run the app, which did not exhibit any problem.
There sure is a fatalError("unkeyed decoding from database row is not supported")
line in GRDB. But it is not supposed to be reached under normal operations.
I'm not saying there is no issue. I'm just saying I'm unable to exhibit any. Would you please provide a reproducible way to exhibit your crash? Thanks.
No news is good news: happy GRDB, @wildthink! Just reopen the issue if you need more support.
@groue can you provide a link for example of storing arrays?? didn't find any in Demo App
i have array [Int] in an object of Record to store but in
override func encode(to container: inout PersistenceContainer)
i'm getting error Cannot assign value of type '[Int]' to type 'DatabaseValueConvertible?'
XCode 10.2 Swift 5 GRDB.swift (3.7.0)
class TodoStates: Record {
var id : String = ""
var title : String = ""
var color : String = ""
var access : Int = 0
var workareas : [Int] = []
var isclosestate : Int = 0
override class var databaseTableName: String {
return "TodoStates"
}
enum CodingKeys: String, CodingKey, ColumnExpression {
case id = "id"
case title = "title"
case color = "color"
case access = "access"
case workareas = "workareas"
case isclosestate = "isclosestate"
}
override func encode(to container: inout PersistenceContainer) {
container[CodingKeys.id] = id
container[CodingKeys.title] = title
container[CodingKeys.color] = color
container[CodingKeys.access] = access
container[CodingKeys.workareas] = workareas -> Error
container[CodingKeys.isclosestate] = isclosestate
}
required init(json: JSON) {
id = json["id"].stringValue
title = json["title"].stringValue
color = json["color"].stringValue
access = json["access"].intValue
workareas = json["workareas"].arrayValue.map { $0.intValue}
isclosestate = json["isclosestate"].intValue
super.init()
}
required init(row: Row) {
id = row[CodingKeys.id]
title = row[CodingKeys.title]
color = row[CodingKeys.color]
access = row[CodingKeys.access]
workareas = row[CodingKeys.workareas] -> Error
isclosestate = row[CodingKeys.isclosestate]
super.init(row: row)
}
}
Hello @sameer4,
Automatic JSON encoding of arrays and other complex types are reserved to Codable records (search this term in the main README).
When you perform manual encoding (with encode(to:)
, as in your sample code, you have to perform your own JSON encoding into String or Data. See the documentation of the standard JSONEncoder for further information.
if i remove encode(to:), app crashes with
Thread 2: Fatal error: AppIcons: invalid empty persistence container
If you remove encode(to:), your record type inherits the encode(to:) method from its Record superclass, which does fill anything in the container. Consequence: GRDB does not know which value should be stored in database columns, and it rightfully complains.
I understand that this is not easy to guess.
Here is my advice: if you use Codable Records, don't subclass the Record class. It just doesn't provide any useful service any more, and, on the contrary, creates the inheritance problems you are experiencing.
Don't rush, and have another read of the documentation of record types if necessary.
The documentation indicates/implies that a JSON compatible structure (e.g. Dictionary or Array) will automatically encoded/decoded into a
JSON Column
What did you do?
I tried adding a
var tags: [String]
property to the Player struct definition in the DemoiOSApp. I also added atags
column to the db create and also to the CodingKeys of Player.What did you expect to happen?
I expected the app to function and to be able to see the tags in the sqlite database.
What happened instead?
I observed a fatal error at
Environment
Standard GRDB v3.3.1 as configured in the Example application. Xcode Version 10.0 (10A255) Swift 4.3 macOS 10.14
Demo Project
I modified the DemoiSOapp