Skip to content

Correct way to define self-referencing many-to-many relationship using typescript? #944

Open

Description

@play4uman

Hello, I've been banging my head against this issue for a good day or so: what's the proper way to define a many-to-many self-referencing relationship using strongly typed models and typescript? I tried following the JS examples and translating them to typescript but I keep getting different errors. For example if I try to add many-to-many relationship representing friendship, i.e. each Person has multiple friends and is a friend to multiple people with this piece of code:

export type PersonProps = {
    index: number;
    name: string;
    related_people_1: MutableQuerySet<Person>;
    related_people_2: MutableQuerySet<Person>;
  }
  
  export class Person extends Model<typeof Person, PersonProps> {
    static modelName = 'Person' as const;
    static fields = {
        index: attr(),
        name: attr(),
        related_persons_1: many({to: 'Person', relatedName: 'related_people_2', through: 'PersonRelation', throughFields: ['person_1', 'person_2']})
    };
    static options = {
        idAttribute: 'index' as const
    };
  }
  
  export type PersonRelationProps = {
    person_1: Person;
    person_2: Person;
  }
  
  export class PersonRelation extends Model<typeof Person, PersonRelationProps>{
    static modelName = 'PersonRelation' as const;
    static fields = {
      person_1: fk('Person'),
      person_2: fk('Person')
    }
  }

I get the following error:
Error: Reverse field personrelationSet already defined on model Person. To fix, set a custom related name on PersonRelation.person_2., js engine: hermes
which makes sense because

  export class PersonRelation extends Model<typeof Person, PersonRelationProps>{
    static modelName = 'PersonRelation' as const;
    static fields = {
      person_1: fk('Person'),
      person_2: fk('Person')
    }

have no defined through fields, so they auto-generated the same personrelationSet field on the Person model.
Then I tried pointing to the two fields in Person explicitly:

  export class PersonRelation extends Model<typeof Person, PersonRelationProps>{
    static modelName = 'PersonRelation' as const;
    static fields = {
      person_1: fk('Person', 'related_people_1'),
      person_2: fk('Person', 'related_people_2')
    }

and I get the error:
Reverse field related_people_2 already defined on model Person. To fix, set a custom related name on PersonRelation.person_2.
which again makes sense since the "many" definition in my Person model already defines a "relatedName" for this field:
many({to: 'Publisher', relatedName: 'related_publishers_2', through: 'Publisher', throughFields: ['publisher_1', 'publisher_2']})

Ok so then I decided to remove either the "many" relation in the Person model or both "fk" relations in the PersonRelation model but both of them resulted in my selectors throwing "undefined" exceptions when accessing methods of the Person model, e.g.
TypeError: Cannot read property 'all' of undefined

So what's the correct way to achieve that with using typescript and strong typing?

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions