go-rel / go-rel/rel

Support association using join table such as Many to Many

Open
#104 6 comments 2 reactions 2 assignees Claimed by @bickyeric View on GitHub
help wanted
Dominant language
Go
Stars
786
Forks
61
Avg merge
4d 11h
Merged PRs (30d)
2

Description

## Idea 2

### Example

```go

type Channel struct {
ID int
Name string

// mapped to singular version of field name defined in "db" (subscriber) inside through association.
// impicitly trigger two preload: Preload("subscriptions") and Preload("subscriptions.subscriber")
// the result than flattened and mapped to subscribers.
Subscribers []User `db:"subscribers" through:subscriptions"`
Subscriptions []Subscription `ref:"id" fk:"channel_d"`
}

type User struct {
ID int
Name string

Subscriptions []Subscription
Channels []Channel `through:subscriptions"`

// self-referencing needs two intermediate reference to be set up.
// trigger Preload("user_followings") and Preload("user_followings.following")
Followings []User `through:"user_followings"` // map to following field
UserFollowings []Follow `ref:"id" fk:"follower_id"`

// trigger Preload("user_followers") and Preload("user_follwers.follower")
UserFollowers []Follow `ref:"id" fk:"following_id"`
Followers []User `through:"user_followers"` // map to follower field
}

type Follow struct {
Follower User
FollowerID int `db:",primary"`
Following User
FollowingID int `db:",primary"`
Accepted bool // this way, it may contains additional data
}

type Subscription struct {
ID int `db:",primary"`
Subscriber User
SubscriberID int
Channel Channel
ChannelID int
CreatedAt time.Time
UpdatedAt time.Time
}
```

### Specifications

- [x] Join association is defined using tag called`through` and doesn't support nested through.
- [x] It's a read only association (all modification will be ignored)
- [ ] Every preload of has through assoc will implicitly trigger two preload, the first one is the association defined by `through` tag, the second one is association inside `through` field that has the singular name as has through field. The result then flattened and mapped to the final association.
- [ ] Preload has many through
- [ ] Preload has one through

### Merit/Demerit

(+) Support has one and has many through
(+) Can be made read only and still accessible for update.
(+) We can have metadata on join table.
(-) Require additional association defined (especially verbose for self referencing association).

## ~Idea 1~

### Example:

```go
// Table subscription_users: user_id(int), subscription_id(int)
// Table followers: followed_id(int), following_id(int)

type Subscription struct {
ID int
Name string

// 1. basic declaration:
// subscription:id <- subscription_id:subscription_users:user_id -> user:id
Users []User `ref:"id:subscription_id" fk:"id:user_id" through:"subscription_users"`
}

type User struct {
ID int
Name string

// 2. back ref
// user:id <- user_id:subscription_users:subscription_id -> subscriptions:id
Subscriptions []Subscription `ref:"id:user_id" fk:"id:subscription_id" through:"subscription_users"`

// 3. omitting ref and fk tag, will be guessed based on table name:
// user:id <- user_id:subscription_users:subscription_id -> subscriptions:id (the same as 2)
// Subscriptions []Subscription through:"subscription_users"`

// 4. Self-referencing many to many
Followers []User `ref:"id:following_id" fk:"id:follower_id" through:"followers"`
Followings []User `ref:"id:follower_id" fk:"id:following_id" through:"followers"`
}
```

### Specifications

- Join table is defined using tag called`through`.
- `subscription:id <- subscription_id:subscription_users:user_id -> user:id`
is declared as:
`ref:"id:subscription_id" fk:"id:user_id" through:"subscription_users"`
- ref and fk can be completely omitted, and will be guessed as many to many when through tag is available, otherwise has many rule applied.
- Preloading support.
- ~Insert/Update support~ Edit: to complex and to magic to implement

### Merit/Demerit
(+) Can implement many to many without additional struct.
(-) Doesn't work for has one through.
(-) Can't be made fully readonly(can update but only the join data).

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.