Grdb.swift: Having troubles with decoding a composite type

Created on 19 Jul 2018  Â·  4Comments  Â·  Source: groue/GRDB.swift

What did you do?

struct BookInfo {
  var book: Book
  var author: Author
}

extension BookInfo: FetchableRecord {
  init(row: Row) {
//    print("BookInfo.init(row:)", row)
    author = Author(name: "asdf")
    book = Book(row: row)
  }
}

try dbQueue.read { db in
  let request = Book.including(required: Book.author).asRequest(of: BookInfo.self)
  let rows = try Row.fetchAll(db, request)
  print(rows[0])
}

What did you expect to happen?

For rows[0] to also contain author's info in rows[0]["author"] or maybe rows[0]["authors"].

What happened instead?

Instead, it seems to only have the book's info [id:1 title:"Bible" author_id:1].

Environment

GRDB flavor(s): GRDB
GRDB version: v3.2.0
Installation method: Carthage, but I copied the checked out GRDB.xcodeproj into the workspace instead of the built framework, so it's more like "manual".
Xcode version: Version 9.4.1 (9F2000)
Swift version: 4.1.2
Platform(s) running GRDB: iOS (playground)
macOS version running Xcode: 10.13.5

Demo Project

Playground page
Migration
Book type
Author type

I suspect the problem is with me using plural table names ("authors" and "books") and snake cased column names books.author_id ... The logged SQL however seems to be correct

SELECT "books".*, "authors".*
FROM "books"
JOIN "authors" ON ("authors"."id" = "books"."author_id")
question

Most helpful comment

Here is the BookInfo row initializer:

extension BookInfo: FetchableRecord {
  init(row: Row) {
    book = Book(row: row)
    author = row["author"]
  }
}

The row indeed only contains book columns: Book.including(required: Book.author) is a book request.

But the row also contains author information. Try printing row.debugDescription.

All 4 comments

I suspect the problem is with me using plural table names ("authors" and "books") and snake cased column names books.author_id

I renamed the tables to "author" and "book", renamed the referencing column to authorId, and the problem persisted, BookInfo.init(row:) receives just [id:1 title:"Bible" author_id:1]. Maybe it's the expected behaviour? But then how can I get the author data?

Here is the BookInfo row initializer:

extension BookInfo: FetchableRecord {
  init(row: Row) {
    book = Book(row: row)
    author = row["author"]
  }
}

The row indeed only contains book columns: Book.including(required: Book.author) is a book request.

But the row also contains author information. Try printing row.debugDescription.

But the row also contains author information. Try printing row.debugDescription.

Indeed

try dbQueue.read { db in
  let request = Book.including(required: Book.author).asRequest(of: BookInfo.self)
  let rows = try Row.fetchAll(db, request)
  print(rows[0].debugDescription)
}

prints

â–¿ [id:1 title:"Bible" authorId:1]
  unadapted: [id:1 title:"Bible" authorId:1 id:1 name:"Unknown"]
  - author: [id:1 name:"Unknown"]

Didn't know about debugDescription.

The row indeed only contains book columns: Book.including(required: Book.author) is a book request.

extension BookInfo: FetchableRecord {
  init(row: Row) {
    book = Book(row: row)
    author = row["author"]
  }
}

try dbQueue.read { db in
  let bookInfos = try Book
    .including(required: Book.author)
    .asRequest(of: BookInfo.self)
    .fetchAll(db)
  print(bookInfos)
}

This seems to work.

The documentation for associations will improve over time, as it gets clear which sections are lacking.

Was this page helpful?
0 / 5 - 0 ratings