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

Foreign key that references a column that is already part of another foreign key generates invalid code #41

Open
micampe opened this issue Nov 25, 2024 · 3 comments
Labels
bug Something isn't working

Comments

@micampe
Copy link
Contributor

micampe commented Nov 25, 2024

When you have a foreign key that references a column that is already part of a another fk the code generated to lookup the related records (parent → children and child → parent in this case) is invalid.

create table grandparent (
    id integer primary key,
    name text
);

create table parent (
    id integer primary key,
    name text,

    foreign key (id) references grandparent(id)
);

create table child (
    id integer primary key,
    name text,

    foreign key (id) references parent(id)
);

attaching complete sample project but the SQL should be all you need to reproduce.

ForeignKeys.zip

@helje5 helje5 added the bug Something isn't working label Nov 25, 2024
@helje5
Copy link
Member

helje5 commented Nov 25, 2024

This fails:

public extension SQLRecordFetchOperations
  where T == Parent, Ops: SQLDatabaseFetchOperations, Ops.RecordTypes == ForeignKeys.RecordTypes
{
  func find(`for` record: Child) throws -> Parent?
  {
    let x : SQLRecordFetchOperations<Ops, Child> = operations[dynamicMember: \.children]
    return try x.findTarget(for: \.id, in: record /* Child */) // No exact matches in call to instance method 'findTarget'
  }
}

Maybe because of ambiguous overloads?

public extension SQLRecordFetchOperations
  where T == Parent, Ops: SQLDatabaseFetchOperations & SQLDatabaseAsyncOperations, Ops.RecordTypes == ForeignKeys.RecordTypes
{
  func find(`for` record: Child) async throws -> Parent?
  {
    try await operations[dynamicMember: \.children].findTarget(for: \.id, in: record)
  }
}

@helje5
Copy link
Member

helje5 commented Nov 25, 2024

Hm, no, this doesn't match is not found:

public extension SQLRecordFetchOperations
                   where Ops: SQLDatabaseAsyncOperations
  func findTarget<FK>(for foreignKey: KeyPath<T.Schema, FK>, in record: T)
         async throws -> FK.Destination?
         where FK: SQLForeignKeyColumn, FK.T == T,
               FK.Value == FK.DestinationColumn.Value

@helje5
Copy link
Member

helje5 commented Nov 25, 2024

Just collecting data, Child (btw the pkey is optional / NULL):

public struct Child : Identifiable, SQLKeyedTableRecord, Codable, Sendable {
  public static let schema = Schema()
  public var id : Int?
  public var name : String?
  public init(id: Int? = nil, name: String? = nil)
}
public struct Parent : Identifiable, SQLKeyedTableRecord, Codable, Sendable {
  public static let schema = Schema()
  public var id : Int?
  public var name : String?
  public init(id: Int? = nil, name: String? = nil)
}
public struct Grandparent : Identifiable, SQLKeyedTableRecord, Codable, Sendable {
  public static let schema = Schema()
  public var id : Int?
  public var name : String?
  public init(id: Int? = nil, name: String? = nil)
}
public extension Grandparent {
  struct Schema : SQLKeyedTableSchema, SQLSwiftMatchableSchema, SQLCreatableSchema {
    
    public typealias PropertyIndices = ( idx_id: Int32, idx_name: Int32 )
    public typealias RecordType = Grandparent
    public typealias MatchClosureType = ( Grandparent ) -> Bool
    
    public static let externalName = "grandparent"
    
    public static let columnCount : Int32 = 2
    
    public static let primaryKeyColumn = MappedColumn<Grandparent, Int?>(
      externalName: "id",
      defaultValue: nil,
      keyPath: \Grandparent.id
    )
...
    public let id = MappedColumn<Grandparent, Int?>(
      externalName: "id",
      defaultValue: nil,
      keyPath: \Grandparent.id
    )
    public let name = MappedColumn<Grandparent, String?>(
      externalName: "name",
      defaultValue: nil,
      keyPath: \Grandparent.name
    )

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