Skip to content

Commit d1ea608

Browse files
feat(sqlmigration): migrate invites table from bigint to uuid (#7428)
* feat(sqlmigration): added migration for schema cleanup * feat(sqlmigration): drop sites,licenses table and added uuid v7 for saved views * feat(sqlmigration): commit the transaction * feat(sqlmigration): address review comments * feat(sqlmigration): address review comments * feat(sqlmigration): frontend changes for saved views * feat(sqlmigration): frontend changes for saved views * feat(sqlmigration): frontend changes for saved views * feat(sqlmigration): frontend changes for saved views * feat(sqlmigration): frontend changes for saved views * feat(sqlmigration): migrate invites table from bigint to uuid * feat(sqlmigration): add support for idempotant dialect based migration * feat(sqlmigration): add support for idempotant dialect based migration * feat(sqlmigration): add foreign key constraints for all new tables
1 parent ac7ecac commit d1ea608

File tree

8 files changed

+297
-23
lines changed

8 files changed

+297
-23
lines changed

pkg/query-service/auth/auth.go

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
smtpservice "github.com/SigNoz/signoz/pkg/query-service/utils/smtpService"
2121
"github.com/SigNoz/signoz/pkg/types"
2222
"github.com/SigNoz/signoz/pkg/types/authtypes"
23+
"github.com/SigNoz/signoz/pkg/valuer"
2324
"go.uber.org/zap"
2425
"golang.org/x/crypto/bcrypt"
2526
)
@@ -87,12 +88,18 @@ func Invite(ctx context.Context, req *model.InviteRequest) (*model.InviteRespons
8788
}
8889

8990
inv := &types.Invite{
90-
Name: req.Name,
91-
Email: req.Email,
92-
Token: token,
93-
CreatedAt: time.Now(),
94-
Role: req.Role,
95-
OrgID: au.OrgID,
91+
Identifiable: types.Identifiable{
92+
ID: valuer.GenerateUUID(),
93+
},
94+
TimeAuditable: types.TimeAuditable{
95+
CreatedAt: time.Now(),
96+
UpdatedAt: time.Now(),
97+
},
98+
Name: req.Name,
99+
Email: req.Email,
100+
Token: token,
101+
Role: req.Role,
102+
OrgID: au.OrgID,
96103
}
97104

98105
if err := dao.DB().CreateInviteEntry(ctx, inv); err != nil {
@@ -188,12 +195,18 @@ func inviteUser(ctx context.Context, req *model.InviteRequest, au *types.Gettabl
188195
}
189196

190197
inv := &types.Invite{
191-
Name: req.Name,
192-
Email: req.Email,
193-
Token: token,
194-
CreatedAt: time.Now(),
195-
Role: req.Role,
196-
OrgID: au.OrgID,
198+
Identifiable: types.Identifiable{
199+
ID: valuer.GenerateUUID(),
200+
},
201+
TimeAuditable: types.TimeAuditable{
202+
CreatedAt: time.Now(),
203+
UpdatedAt: time.Now(),
204+
},
205+
Name: req.Name,
206+
Email: req.Email,
207+
Token: token,
208+
Role: req.Role,
209+
OrgID: au.OrgID,
197210
}
198211

199212
if err := dao.DB().CreateInviteEntry(ctx, inv); err != nil {

pkg/signoz/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ func NewSQLMigrationProviderFactories(sqlstore sqlstore.SQLStore) factory.NamedM
6363
sqlmigration.NewUpdatePatAndOrgDomainsFactory(sqlstore),
6464
sqlmigration.NewUpdatePipelines(sqlstore),
6565
sqlmigration.NewDropLicensesSitesFactory(sqlstore),
66+
sqlmigration.NewUpdateInvitesFactory(sqlstore),
6667
)
6768
}
6869

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package sqlmigration
2+
3+
import (
4+
"context"
5+
"database/sql"
6+
"time"
7+
8+
"github.com/SigNoz/signoz/pkg/factory"
9+
"github.com/SigNoz/signoz/pkg/sqlstore"
10+
"github.com/SigNoz/signoz/pkg/types"
11+
"github.com/SigNoz/signoz/pkg/valuer"
12+
"github.com/uptrace/bun"
13+
"github.com/uptrace/bun/migrate"
14+
)
15+
16+
type updateInvites struct {
17+
store sqlstore.SQLStore
18+
}
19+
20+
type existingInvite struct {
21+
bun.BaseModel `bun:"table:invites"`
22+
23+
OrgID string `bun:"org_id,type:text,notnull" json:"orgId"`
24+
ID int `bun:"id,pk,autoincrement" json:"id"`
25+
Name string `bun:"name,type:text,notnull" json:"name"`
26+
Email string `bun:"email,type:text,notnull,unique" json:"email"`
27+
Token string `bun:"token,type:text,notnull" json:"token"`
28+
CreatedAt time.Time `bun:"created_at,notnull" json:"createdAt"`
29+
Role string `bun:"role,type:text,notnull" json:"role"`
30+
}
31+
32+
type newInvite struct {
33+
bun.BaseModel `bun:"table:user_invite"`
34+
35+
types.Identifiable
36+
types.TimeAuditable
37+
Name string `bun:"name,type:text,notnull" json:"name"`
38+
Email string `bun:"email,type:text,notnull,unique" json:"email"`
39+
Token string `bun:"token,type:text,notnull" json:"token"`
40+
Role string `bun:"role,type:text,notnull" json:"role"`
41+
OrgID string `bun:"org_id,type:text,notnull" json:"orgId"`
42+
}
43+
44+
func NewUpdateInvitesFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
45+
return factory.
46+
NewProviderFactory(
47+
factory.MustNewName("update_invites"),
48+
func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
49+
return newUpdateInvites(ctx, ps, c, sqlstore)
50+
})
51+
}
52+
53+
func newUpdateInvites(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
54+
return &updateInvites{store: store}, nil
55+
}
56+
57+
func (migration *updateInvites) Register(migrations *migrate.Migrations) error {
58+
if err := migrations.
59+
Register(migration.Up, migration.Down); err != nil {
60+
return err
61+
}
62+
63+
return nil
64+
}
65+
66+
func (migration *updateInvites) Up(ctx context.Context, db *bun.DB) error {
67+
tx, err := db.
68+
BeginTx(ctx, nil)
69+
if err != nil {
70+
return err
71+
}
72+
73+
defer tx.Rollback()
74+
75+
err = migration.
76+
store.
77+
Dialect().
78+
RenameTableAndModifyModel(ctx, tx, new(existingInvite), new(newInvite), func(ctx context.Context) error {
79+
existingInvites := make([]*existingInvite, 0)
80+
err = tx.
81+
NewSelect().
82+
Model(&existingInvites).
83+
Scan(ctx)
84+
if err != nil {
85+
if err != sql.ErrNoRows {
86+
return err
87+
}
88+
}
89+
90+
if err == nil && len(existingInvites) > 0 {
91+
newInvites := migration.
92+
CopyOldInvitesToNewInvites(existingInvites)
93+
_, err = tx.
94+
NewInsert().
95+
Model(&newInvites).
96+
Exec(ctx)
97+
if err != nil {
98+
return err
99+
}
100+
}
101+
return nil
102+
})
103+
if err != nil {
104+
return err
105+
}
106+
107+
err = tx.Commit()
108+
if err != nil {
109+
return err
110+
}
111+
112+
return nil
113+
}
114+
115+
func (migration *updateInvites) Down(context.Context, *bun.DB) error {
116+
return nil
117+
}
118+
119+
func (migration *updateInvites) CopyOldInvitesToNewInvites(existingInvites []*existingInvite) []*newInvite {
120+
newInvites := make([]*newInvite, 0)
121+
for _, invite := range existingInvites {
122+
newInvites = append(newInvites, &newInvite{
123+
Identifiable: types.Identifiable{
124+
ID: valuer.GenerateUUID(),
125+
},
126+
TimeAuditable: types.TimeAuditable{
127+
CreatedAt: invite.CreatedAt,
128+
UpdatedAt: time.Now(),
129+
},
130+
Name: invite.Name,
131+
Email: invite.Email,
132+
Token: invite.Token,
133+
Role: invite.Role,
134+
OrgID: invite.OrgID,
135+
})
136+
}
137+
138+
return newInvites
139+
}

pkg/sqlstore/postgressqlstore/dialect.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package postgressqlstore
22

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

67
"github.com/uptrace/bun"
78
)
@@ -151,3 +152,60 @@ func (dialect *dialect) RenameColumn(ctx context.Context, bun bun.IDB, table str
151152
}
152153
return true, nil
153154
}
155+
156+
func (dialect *dialect) TableExists(ctx context.Context, bun bun.IDB, table interface{}) (bool, error) {
157+
158+
count := 0
159+
err := bun.
160+
NewSelect().
161+
ColumnExpr("count(*)").
162+
Table("pg_catalog.pg_tables").
163+
Where("tablename = ?", bun.Dialect().Tables().Get(reflect.TypeOf(table)).Name).
164+
Scan(ctx, &count)
165+
166+
if err != nil {
167+
return false, err
168+
}
169+
170+
if count == 0 {
171+
return false, nil
172+
}
173+
174+
return true, nil
175+
}
176+
177+
func (dialect *dialect) RenameTableAndModifyModel(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, cb func(context.Context) error) error {
178+
exists, err := dialect.TableExists(ctx, bun, newModel)
179+
if err != nil {
180+
return err
181+
}
182+
if exists {
183+
return nil
184+
}
185+
186+
_, err = bun.
187+
NewCreateTable().
188+
IfNotExists().
189+
Model(newModel).
190+
Exec(ctx)
191+
192+
if err != nil {
193+
return err
194+
}
195+
196+
err = cb(ctx)
197+
if err != nil {
198+
return err
199+
}
200+
201+
_, err = bun.
202+
NewDropTable().
203+
IfExists().
204+
Model(oldModel).
205+
Exec(ctx)
206+
if err != nil {
207+
return err
208+
}
209+
210+
return nil
211+
}

pkg/sqlstore/sqlitesqlstore/dialect.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package sqlitesqlstore
22

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

67
"github.com/uptrace/bun"
78
)
@@ -141,3 +142,62 @@ func (dialect *dialect) RenameColumn(ctx context.Context, bun bun.IDB, table str
141142
}
142143
return true, nil
143144
}
145+
146+
func (dialect *dialect) TableExists(ctx context.Context, bun bun.IDB, table interface{}) (bool, error) {
147+
148+
count := 0
149+
err := bun.
150+
NewSelect().
151+
ColumnExpr("count(*)").
152+
Table("sqlite_master").
153+
Where("type = ?", "table").
154+
Where("name = ?", bun.Dialect().Tables().Get(reflect.TypeOf(table)).Name).
155+
Scan(ctx, &count)
156+
157+
if err != nil {
158+
return false, err
159+
}
160+
161+
if count == 0 {
162+
return false, nil
163+
}
164+
165+
return true, nil
166+
}
167+
168+
func (dialect *dialect) RenameTableAndModifyModel(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, cb func(context.Context) error) error {
169+
exists, err := dialect.TableExists(ctx, bun, newModel)
170+
if err != nil {
171+
return err
172+
}
173+
if exists {
174+
return nil
175+
}
176+
177+
_, err = bun.
178+
NewCreateTable().
179+
IfNotExists().
180+
Model(newModel).
181+
ForeignKey(`("org_id") REFERENCES "organizations" ("id")`).
182+
Exec(ctx)
183+
184+
if err != nil {
185+
return err
186+
}
187+
188+
err = cb(ctx)
189+
if err != nil {
190+
return err
191+
}
192+
193+
_, err = bun.
194+
NewDropTable().
195+
IfExists().
196+
Model(oldModel).
197+
Exec(ctx)
198+
if err != nil {
199+
return err
200+
}
201+
202+
return nil
203+
}

pkg/sqlstore/sqlstore.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,5 @@ type SQLDialect interface {
4242
GetColumnType(context.Context, bun.IDB, string, string) (string, error)
4343
ColumnExists(context.Context, bun.IDB, string, string) (bool, error)
4444
RenameColumn(context.Context, bun.IDB, string, string, string) (bool, error)
45+
RenameTableAndModifyModel(context.Context, bun.IDB, interface{}, interface{}, func(context.Context) error) error
4546
}

pkg/sqlstore/sqlstoretest/dialect.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,7 @@ func (dialect *dialect) ColumnExists(ctx context.Context, bun bun.IDB, table str
2828
func (dialect *dialect) RenameColumn(ctx context.Context, bun bun.IDB, table string, oldColumnName string, newColumnName string) (bool, error) {
2929
return true, nil
3030
}
31+
32+
func (dialect *dialect) RenameTableAndModifyModel(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, cb func(context.Context) error) error {
33+
return nil
34+
}

pkg/types/user.go

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
package types
22

33
import (
4-
"time"
5-
64
"github.com/uptrace/bun"
75
)
86

97
type Invite struct {
10-
bun.BaseModel `bun:"table:invites"`
11-
12-
OrgID string `bun:"org_id,type:text,notnull" json:"orgId"`
13-
ID int `bun:"id,pk,autoincrement" json:"id"`
14-
Name string `bun:"name,type:text,notnull" json:"name"`
15-
Email string `bun:"email,type:text,notnull,unique" json:"email"`
16-
Token string `bun:"token,type:text,notnull" json:"token"`
17-
CreatedAt time.Time `bun:"created_at,notnull" json:"createdAt"`
18-
Role string `bun:"role,type:text,notnull" json:"role"`
8+
bun.BaseModel `bun:"table:user_invite"`
9+
10+
Identifiable
11+
TimeAuditable
12+
OrgID string `bun:"org_id,type:text,notnull" json:"orgId"`
13+
Name string `bun:"name,type:text,notnull" json:"name"`
14+
Email string `bun:"email,type:text,notnull,unique" json:"email"`
15+
Token string `bun:"token,type:text,notnull" json:"token"`
16+
Role string `bun:"role,type:text,notnull" json:"role"`
1917
}
2018

2119
type Group struct {

0 commit comments

Comments
 (0)