How to use Associations?

I'm trying to fetch a simple record with an association but I'm a little unclear about how the glue code works with the decoding of the QueryInterfaceRequest.

I have a request like

let request = CalendarEntryRecord.filter(Column("id") == entryID).including(optional: CalendarEntryRecord.bookmark)
and defined a temporary struct to decode into (following the docs) like so

 struct Response : Equatable, FetchableRecord, Decodable {
    let entry: CalendarEntryRecord
    let bookmark: CalendarEntryBookmarkRecord?
}

However, when I perform a Response.fetchAll(... the bookmark property alway comes back as nil.
I verified the table rows are present by using the Row.fetchAll(... form and printing the output:

[ [id:Data(16 bytes) date:"2021-07-17 00:00:00.000" wordID:Data(16 bytes) wordDefaultForm:"noun" wordSpellingUS:"test"]
  unadapted: [id:Data(16 bytes) date:"2021-07-17 00:00:00.000" wordID:Data(16 bytes) wordDefaultForm:"noun" wordSpellingUS:"test"]" id:1 entryID:Data(16 bytes) createdAt:"2021-07-17 14:26:22.791"]
  - entry_bookmark: [id:1 entryID:Data(16 bytes) createdAt:"2021-07-17 14:26:22.791"]]`

I can see the entry_bookmark is in that print output with the expected values but it's not decoding into the bookmark property on the response, that is always nil.

What am I doing wrong? I feel like it must have something to do with the names of the properties on Response or involves customising CodingKeys somehow, but I'm not sure how/exactly what is awry.

Note: The print output is abridged to exclude a bunch more properties on the CalendarEntryRecord type.

Hello @bzamayo,

Thanks for taking the time for displaying raw rows. We indeed see the entry_bookmark key that contains the columns for your bookmark record.

This entry_bookmark key is the association key of the CalendarEntryRecord.bookmark association. All associations come with a key (which defaults to the table name of the associated record). It is those keys that allow decoding with the Decodable protocol, when they match property names (coding keys, precisely).

Your solution is thus to make sure the coding key/property name matches the association key.

You can rename your bookmark property to entry_bookmark.

Or you can change the association key with the forKey(_:) method:

static let bookmark = belongsTo(...).forKey("bookmark")

The forKey(_:) method is useful, notably, when table names do not match the names of their Swift counterpart, such as entry_bookmark vs. bookmark

See The Structure of a Joined Request for more information about association keys and the forKey(_:) method.

2 Likes