Skip to content

Commit cc712a7

Browse files
committed
many-2-many for sqlx and sqlc
1 parent ec03eea commit cc712a7

File tree

10 files changed

+274
-31
lines changed

10 files changed

+274
-31
lines changed

Diff for: Makefile

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ run:
2020

2121
all: init sqlboiler
2222
go mod tidy
23+
go generate ./...
24+
sqlc generate
2325
go vet ./...
2426
go fmt ./...
25-
go generate ./...
2627
go run main.go

Diff for: database/query.sql

+17-1
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,20 @@ ORDER BY c.id;
4343

4444

4545
-- name: CountriesWithAddressAggregate :many
46-
select row_to_json(row) from (select * from country_address) row;
46+
select row_to_json(row) from (select * from country_address) row;
47+
48+
-- name: SelectUsers :many
49+
SELECT u.id, u.first_name, u.middle_name, u.last_name, u.email
50+
FROM "users" u
51+
LIMIT 30;
52+
53+
-- name: SelectUserAddresses :many
54+
SELECT DISTINCT ua.user_id, ua.address_id
55+
FROM "addresses" a
56+
LEFT JOIN "user_addresses" ua ON a.id = ua.address_id
57+
WHERE ua.user_id = ANY($1::int[]);;
58+
59+
-- name: SelectAddress :many
60+
SELECT a.*
61+
FROM addresses a
62+
WHERE a.id = ANY($1::int[]);

Diff for: db/ent/database.go

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"entgo.io/ent/dialect"
1111
entsql "entgo.io/ent/dialect/sql"
12+
_ "godb/db/ent/ent/gen/runtime"
1213

1314
"godb/config"
1415
"godb/db/ent/ent/gen"

Diff for: db/sqlboiler/oneToMany.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ func getAddress(addresses models.AddressSlice) []sqlx.AddressForCountry {
3838
ID: uint(address.ID),
3939
Line1: address.Line1,
4040
Line2: address.Line2.String,
41-
Postcode: address.Postcode.Int,
41+
Postcode: int32(address.Postcode.Int),
4242
City: address.City.String,
4343
State: address.State.String,
4444
})

Diff for: db/sqlc/manyToMany.go

+79-2
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,87 @@ package sqlc
22

33
import (
44
"context"
5+
"fmt"
56

67
"godb/db/sqlx"
78
)
89

9-
func (r *database) ListM2M(ctx context.Context) (*sqlx.UserResponseWithAddress, error) {
10-
return nil, nil
10+
func (r *database) ListM2M(ctx context.Context) ([]*sqlx.UserResponseWithAddressesSqlx, error) {
11+
users, err := r.db.SelectUsers(ctx)
12+
if err != nil {
13+
return nil, fmt.Errorf("error selecting users")
14+
}
15+
16+
var all []*sqlx.UserResponseWithAddressesSqlx
17+
for _, u := range users {
18+
all = append(all, &sqlx.UserResponseWithAddressesSqlx{
19+
ID: uint(u.ID),
20+
FirstName: u.FirstName,
21+
MiddleName: u.MiddleName.String,
22+
LastName: u.LastName,
23+
Email: u.Email,
24+
})
25+
}
26+
27+
userIDs := getUserIDs(users)
28+
29+
uas, err := r.db.SelectUserAddresses(ctx, userIDs)
30+
if err != nil {
31+
return nil, fmt.Errorf("error selecting user address pivot")
32+
}
33+
34+
addressIDs := getAddressIDs(uas)
35+
36+
address, err := r.db.SelectAddress(ctx, addressIDs)
37+
if err != nil {
38+
return nil, fmt.Errorf("error selecting address")
39+
}
40+
41+
// now we attach address to the user
42+
for _, u := range uas {
43+
for _, user := range all {
44+
if u.UserID.Int64 == int64(user.ID) {
45+
for _, addr := range address {
46+
if addr.ID == u.AddressID.Int64 {
47+
user.Address = append(user.Address, sqlx.AddressForCountry{
48+
ID: uint(addr.ID),
49+
Line1: addr.Line1,
50+
Line2: addr.Line2.String,
51+
Postcode: addr.Postcode.Int32,
52+
City: addr.City.String,
53+
State: addr.State.String,
54+
})
55+
}
56+
}
57+
}
58+
}
59+
}
60+
61+
return all, nil
62+
}
63+
64+
func getUserIDs(users []SelectUsersRow) (ids []int32) {
65+
seen := make(map[int]bool)
66+
for _, user := range users {
67+
ok := seen[int(user.ID)]
68+
if !ok {
69+
ids = append(ids, int32(user.ID))
70+
seen[int(user.ID)] = true
71+
}
72+
}
73+
74+
return ids
75+
}
76+
77+
func getAddressIDs(uas []SelectUserAddressesRow) (ids []int32) {
78+
seen := make(map[int64]bool)
79+
for _, item := range uas {
80+
ok := seen[item.UserID.Int64]
81+
if !ok {
82+
ids = append(ids, int32(item.UserID.Int64))
83+
seen[item.UserID.Int64] = true
84+
}
85+
}
86+
87+
return ids
1188
}

Diff for: db/sqlc/query.sql.go

+117
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: db/sqlx/manyToMany.go

+34-16
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@ const (
1818
Users = `
1919
SELECT u.id, u.first_name, u.middle_name, u.last_name, u.email
2020
FROM "users" u
21-
LIMIT 30;`
21+
LIMIT 30;
22+
`
2223
UsersAddress = `
23-
SELECT DISTINCT ua.address_id
24+
SELECT DISTINCT ua.user_id AS user_id, ua.address_id AS address_id
2425
FROM "addresses" a
2526
LEFT JOIN "user_addresses" ua ON a.id = ua.address_id
26-
WHERE ua.user_id IN (?);`
27+
WHERE ua.user_id IN (?);
28+
`
2729
Address = `
2830
SELECT a.*
2931
FROM addresses a
@@ -32,23 +34,24 @@ const (
3234
)
3335

3436
type userAddress struct {
35-
ID int `db:"id"`
37+
UserID int `db:"user_id"`
38+
AddressID int `db:"address_id"`
3639
}
3740

38-
func (r *database) ListM2M(ctx context.Context) (*UserResponseWithAddress, error) {
41+
func (r *database) ListM2M(ctx context.Context) ([]*UserResponseWithAddressesSqlx, error) {
3942
users, err := r.db.QueryContext(ctx, Users)
4043
if err != nil {
4144
return nil, fmt.Errorf("db error")
4245
}
4346
defer users.Close()
4447

45-
var all []*UserResponseWithAddress
48+
var all []*UserResponseWithAddressesSqlx
4649
for users.Next() {
4750
var u user
4851
if err := users.Scan(&u.ID, &u.FirstName, &u.MiddleName, &u.LastName, &u.Email); err != nil {
4952
return nil, fmt.Errorf("db scanning error")
5053
}
51-
all = append(all, &UserResponseWithAddress{
54+
all = append(all, &UserResponseWithAddressesSqlx{
5255
ID: u.ID,
5356
FirstName: u.FirstName,
5457
MiddleName: u.MiddleName.String,
@@ -73,7 +76,7 @@ func (r *database) ListM2M(ctx context.Context) (*UserResponseWithAddress, error
7376
var uas []*userAddress
7477
for userAddresses.Next() {
7578
var ua userAddress
76-
if err := userAddresses.Scan(&ua.ID); err != nil {
79+
if err := userAddresses.Scan(&ua.UserID, &ua.AddressID); err != nil {
7780
return nil, fmt.Errorf("db scanning error")
7881
}
7982
uas = append(uas, &ua)
@@ -101,28 +104,43 @@ func (r *database) ListM2M(ctx context.Context) (*UserResponseWithAddress, error
101104
allAddresses = append(allAddresses, &a)
102105
}
103106

104-
// now we attach address to the user
105-
for _, u := range all {
106-
print(u)
107+
// now we attach address to the user
108+
for _, u := range uas {
109+
for _, user := range all {
110+
if u.UserID == int(user.ID) {
111+
for _, addr := range allAddresses {
112+
if addr.ID == uint(u.AddressID) {
113+
user.Address = append(user.Address, AddressForCountry{
114+
ID: addr.ID,
115+
Line1: addr.Line1,
116+
Line2: addr.Line2.String,
117+
Postcode: addr.Postcode.Int32,
118+
City: addr.City.String,
119+
State: addr.State.String,
120+
})
121+
}
122+
}
123+
}
124+
}
107125
}
108126

109-
return nil, nil
127+
return all, nil
110128
}
111129

112130
func getAddressIDs(uas []*userAddress) (ids []int) {
113131
seen := make(map[int]bool)
114132
for _, item := range uas {
115-
ok := seen[item.ID]
133+
ok := seen[item.AddressID]
116134
if !ok {
117-
ids = append(ids, item.ID)
118-
seen[item.ID] = true
135+
ids = append(ids, item.AddressID)
136+
seen[item.AddressID] = true
119137
}
120138
}
121139

122140
return ids
123141
}
124142

125-
func getUserIDs(users []*UserResponseWithAddress) (ids []int) {
143+
func getUserIDs(users []*UserResponseWithAddressesSqlx) (ids []interface{}) {
126144
seen := make(map[int]bool)
127145
for _, user := range users {
128146
ok := seen[int(user.ID)]

0 commit comments

Comments
 (0)