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

Polymorphic Through #160

Closed
connected-pjeri opened this issue Oct 11, 2017 · 10 comments
Closed

Polymorphic Through #160

connected-pjeri opened this issue Oct 11, 2017 · 10 comments

Comments

@connected-pjeri
Copy link

Using: "sequelize-typescript": "0.4.0-beta"

I'm having some trouble figuring out how to do polymorphic model definitions so that the queries work as expected. I'm trying to do a Subscription table eg:

Table: Subscription
integer: userId
integer: targertId
string: targetType  -> One of USER / POST / ETC

I'm focusing on getting USER to work first. I want to be able to get all the users a particular user has subscribed to. So I have something like this:

class User extends Model<User> {
...
    @HasMany(
    () => Subscription,
    {
      foreignKey: "targetId",
      scope: {
        targetType: "USER",
      },
    }
  )
  usersSubscribedTo: IUser[];
...
}
class Subscription extends Model<Subscription> {
...
  @ForeignKey(() => User)
  @AllowNull(false)
  @Column
  userId: number;

  @BelongsTo (
    () => User,
    "userId",
  )
  user: IUser;

  @AllowNull(false)
  @Column
  targetId: number;

  @AllowNull(false)
  @Column
  targetType: string;

  @BelongsTo (
    () => User,
    {
      foreignKey: "targetId",
      constraints: false,
      scope: { targetType: "USER" },
    },
  )
  userSubscribedTo: User;
...
}

This looks kind of ok to me, but with this I will get:

error TS2345: Argument of type '{ foreignKey: string; constraints: false; scope: { targetType: string; }; }' is not assignable to parameter of type 'AssociationOptionsBelongsTo | undefined'.
  Object literal may only specify known properties, and 'scope' does not exist in type 'AssociationOptionsBelongsTo | undefined'.
@connected-pjeri
Copy link
Author

connected-pjeri commented Oct 11, 2017

Update
How could I achieve it if I treat Subscription as a through table:

  @HasMany({
    () => User,
    through: () => Subscription,
    constraints: false,
    scope: { targetType: "USER" },
  }, "targetId")
  usersSubscribedTo: IUser[];

or like this but not knowing how to scope it:

  @BelongsToMany(
    () => User,
    () => Subscription,
    "userId",
    "targetId",
  )
  usersSubscribedTo: IUser[];

@connected-pjeri connected-pjeri changed the title Polymorphic Without Through Polymorphic Through Oct 11, 2017
@RobinBuschmann
Copy link
Member

So you want to implement a many-to-many relation, where the subscription table is the through table?

@connected-pjeri
Copy link
Author

connected-pjeri commented Oct 11, 2017

Correct. So that ultimately I can query things like:

user.subscribedUsers
user.subscribedPosts
post.subscribedUsers

Currently I'm making this queries independently and explicitly in service functions, so it's really not a big issue, but I was just wondering if this type of query can be configured through decorators.

@RobinBuschmann
Copy link
Member

Did you tried something like:

@Table
export class User extends Model<User> {

    @BelongsToMany(() => User, () => Subscription, 'subscriberId', 'userId')
    usersSubscribedTo: User[];
}

@Table
export class Subscription extends Model<Subscription> {

    @PrimaryKey
    @ForeignKey(() => User)
    @Column
    subscriberId: number;

    @PrimaryKey
    @ForeignKey(() => User)
    @Column
    userId: number;
}

@connected-pjeri
Copy link
Author

If you remove the subscriberType column then that's not polymorphic.

@RobinBuschmann
Copy link
Member

Ah, sry, my fault. This would be the proper way then:

@Table
export class User extends Model<User> {

    @Column
    name: string;

    @BelongsToMany(() => User, {
        through: () => Subscription,
        foreignKey:  'subscriberId',
        otherKey: 'targetId',
        constraints: false,
        foreignKeyConstraint: true,
        scope: {
            targetType: 'user'
        }
    })
    usersSubscribedTo: User[];

    @BelongsToMany(() => Post, {
        through: () => Subscription,
        foreignKey:  'subscriberId',
        otherKey: 'targetId',
        constraints: false,
        foreignKeyConstraint: true,
        scope: {
            targetType: 'post'
        }
    })
    postsSubscribedTo: Post[];
}

@Table
export class Subscription extends Model<Subscription> {

    @PrimaryKey
    @ForeignKey(() => User)
    @Column
    subscriberId: number;

    @PrimaryKey
    @Column
    targetId: number;

    @Column
    targetType: string;
}

But when querying the data, the created sql string doesn't seem to work unfortunately. I will look into this soon.

@RobinBuschmann
Copy link
Member

What I can already say is, that querying data with this model configuration doesn't work with pure sequelize, too.

@RobinBuschmann
Copy link
Member

RobinBuschmann commented Oct 14, 2017

OK, it is possible. But therefor it is necessary to set through options to the belongsToMany options, wich is currently not possible with sequelize-typescript. See #122

@connected-pjeri
Copy link
Author

I see. I appreciate you looking into this in such a short time @RobinBuschmann :)

@RobinBuschmann
Copy link
Member

ThroughOptions are now available since 0.6.0-beta.3 (latest release: 0.6.0-beta.5).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants