Search code examples
gogo-gorm

What other attribute should i add for my Gorm table?


My goal is to simply join three tables (Sorry my knowledge in sql is limited)

I'm building a community-based platform like Patreon where each community can have different plans (Free, Paid)

Example Code:

type User struct {
    Communities []Community `gorm:"many2many:user_communities" json:"communities"`
}

type Community struct {
    UserID `json:"userID"`
    Users []User `gorm:"many2many:user_communities" json:"users"`
    Plans []Plan `json:"plans"`
    // How do i add another attirbute to check for user with different plan?
}

type Plan struct {
    CommunityID uint `json:"communityID"`
    Name string `json:"name"`
    Price string `json:"price"`
}

Based on the model above

  1. One user can join many communities
  2. One community can have many users
  3. One user can own a community (creator)
  4. and for each community, one user can join for the different plans (Free, Paid)

I'm more focused on how to solve number 4

So the question here is what should I add for my community table to differentiate between the user who joins as Free plan or Paid plan?

because I can only query users who belong to a specific community not users who belong to that community based on a Free or Paid plan.

Example query

// Find whether that user belongs to a community
if err := database.Mysql.Table("users u").Joins("JOIN user_communities uc ON u.id = uc.user_id").Where("u.id = ? AND uc.community_id = ?", userID, communityID).Select("1").Scan(&found).Error; err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": "error happened"})
    return
}

Solution

  • One way could be to make the plan part of the many-to-many table.

    I don't know gorm really, but in plain SQL this could look something like this.

    schema:

    create table appUser (
      id serial not null,
      name text not null,
      primary key (id)
    );
    
    
    create table Community (
      id serial not null,
      owner_id int not null,
      name text not null,
      primary key (id),
      foreign key (owner_id) references appUser(id)
    );
    
    create table plan (
      id serial not null,
      community_id int not null,
      name text not null,
      price float not null,
      primary key (id),
      foreign key (community_id) references Community(id)
    );
    
    
    create table UserCommunity (
      user_id int not null,
      community_id int not null,
      plan_id int not null,
      primary key (user_id, community_id),
      foreign key (plan_id) references plan(id)
    );
    

    usage:

    insert into appUser (name) values ('maria'), ('jose'), ('clara');
    
    insert into Community (name, owner_id) values ('community1', 1);
    
    insert into plan (community_id, name, price) values 
    (1, 'free', 0.0), (1, 'paid', 10.0);
    
    insert into UserCommunity (user_id, community_id, plan_id) values
      (2, 1, 1), (3, 1, 2);
    
    select
      appUser.name as "user",
      community.name as "community",
      plan.name as "plan"
    from appUser
      join UserCommunity on appUser.id = UserCommunity.user_id
      join Community on Community.id = UserCommunity.community_id
      join plan on plan.id = UserCommunity.plan_id
    where plan.name = 'paid';
    

    Fiddle: https://dbfiddle.uk/?rdbms=postgres_13&fiddle=bd37832969396a40944f40ef17f18465