Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failing to decode models when querying foreign tables #322

Open
bstillitano opened this issue Apr 3, 2024 · 11 comments
Open

Failing to decode models when querying foreign tables #322

bstillitano opened this issue Apr 3, 2024 · 11 comments
Labels
bug Something isn't working

Comments

@bstillitano
Copy link

Bug report

Describe the bug

When providing a .select modifier that points to a foreign table, values fail to decode.

To Reproduce

Models

struct Transaction: Codable {
    var id: UUID
    var name: String
    var subtitle: String?
    var merchant: String?
    var amount: Decimal
    var tax_deductible: Bool = false
    var date: Date
    var account: TransactionAccount?
}

enum AccountType: String, Codable, CaseIterable {
    case debit
    case savings
    case loan
    case credit
    case cash
}

struct TransactionAccount: Codable, Hashable {
    var id: UUID
    var name: String
    var description: String?
    var type: AccountType
    var color: String
}

SDK Usage

do {
            return try await Database.shared
                .client
                .database
                .from("transactions")
                .select("*, account(*)")
                .in("type", value: scope.transactionTypes.map({ $0.rawValue }))
                .execute()
                .value
        } catch {
            return []
        }

Swift Error

Printing description of error:
▿ DecodingError
  ▿ typeMismatch : 2 elements
    - .0 : Swift.Dictionary<Swift.String, Any>
    ▿ .1 : Context
      ▿ codingPath : 2 elements
        ▿ 0 : _JSONKey(stringValue: "Index 2", intValue: 2)
          ▿ rep : Rep
            - index : 2
        - 1 : CodingKeys(stringValue: "account", intValue: nil)
      - debugDescription : "Expected to decode Dictionary<String, Any> but found a string instead."
      - underlyingError : nil

Expected behavior

The docs make it clear that I should be able to do this and get back the full object from the foreign table. https://supabase.com/docs/reference/swift/select?example=querying-foreign-table-with-count

Additional context

If I add every value to my query individually, the request works as expected:

do {
            return try await Database.shared
                .client
                .database
                .from("transactions")
                .select(
                """
            id,
            description,
            amount,
            type,
            date,
            name,
            tax_deductible,
            account(*)
            """
            )
                .in("type", value: scope.transactionTypes.map({ $0.rawValue }))
                .execute()
                .value
        } catch {
            return []
        }
    }
@bstillitano bstillitano added the bug Something isn't working label Apr 3, 2024
@bstillitano
Copy link
Author

bstillitano commented Apr 3, 2024

Digging a little deeper into this, it seems like the value being decoded, is not the value being returned from the server. Looking at the response from the url request, I can see that it is not the value that execute().data returns. In the screenshot below, you can see on the left you can see the raw response from the API, whereas on the right, you can see the value when I print data

Screenshot 2024-04-03 at 3 05 45 pm

@grdsdev
Copy link
Collaborator

grdsdev commented Apr 3, 2024

Hi @bstillitano thanks for opening the issue, I'll investigate it.

The foreign key to account schema is named account, and then when you query for the account(*), I think it breaks because the query result and the foreign key has the same name account. I'd suggest you rename the foreign key to something like account_id and then retry the same query using the *,account(*).

While that, I'll investigate to check if there is any other issue.

Thanks again.

@bstillitano
Copy link
Author

bstillitano commented Apr 3, 2024

Thanks for getting back to me @grdsdev , I'm not quite sure how to do that. Are you able to point me in the right direction on how to do that? I can't see it in the GUI anywhere.
Screenshot 2024-04-04 at 8 34 41 am

@grdsdev
Copy link
Collaborator

grdsdev commented Apr 4, 2024

Sure, see the account column? Rename it to account_id, as it holds the reference for the account through its id.

@bstillitano
Copy link
Author

bstillitano commented Apr 5, 2024

@grdsdev have done that and get the following error:

{
  "code" : "PGRST200",
  "message" : "Could not find a relationship between 'transactions' and 'account' in the schema cache",
  "details" : "Searched for a foreign key relationship between 'transactions' and 'account' in the schema 'public', but no matches were found.",
  "hint" : "Perhaps you meant 'accounts' instead of 'account'."
}

For what it's worth:

  1. Table is named accounts
  2. Passing account(*) into the query (notice no s on the end)

It's worth noting also, that if I pass accounts that works fine, however the value comes back as accounts in the JSON response, whereas my column in Postgres as well as my local model has account (no s on the end)

@grdsdev
Copy link
Collaborator

grdsdev commented Apr 5, 2024

When you pass account(*) it tries to loads the relationship for account schema which is wrong, as it is named accounts.

To fix that, you need to use field aliasing, use account:accounts(*) the first part before the : is the alias you want.

@grdsdev
Copy link
Collaborator

grdsdev commented Apr 8, 2024

@bstillitano I hope that helped you, I'll be closing this issue for know, if you're still having issues with it, feel free to re-open it.

Thanks.

@grdsdev grdsdev closed this as completed Apr 8, 2024
@bstillitano
Copy link
Author

Apologies, this issue is unresolved. That didn't help, I've just had to provide the entire query as a string for now to work around this

@grdsdev
Copy link
Collaborator

grdsdev commented Apr 10, 2024

@bstillitano can you provide me the full schema for the transactions and account table?

@grdsdev grdsdev reopened this Apr 10, 2024
@bstillitano
Copy link
Author

@grdsdev sure, see attached
Screenshot 2024-04-11 at 16 38 13

@grdsdev
Copy link
Collaborator

grdsdev commented Apr 11, 2024

@bstillitano I was able to make it work by applying the following changes:

  1. Rename the account column in the transactions table to account_id.
alter table transactions rename column account to account_id;
  1. Define your struct field as var account: TransactionAccount?
  2. Query using *,account:accounts(*)

I'll chat with the team to add some best practices to the docs regarding the implementation of relationships.

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants