Compare commits

...

3 Commits

Author SHA1 Message Date
vikrantgupta25
1900eb8455 chore(sqlmigration): make the timestamp column non nullable 2025-05-15 19:25:45 +05:30
vikrantgupta25
bbd21eba42 chore(sqlmigration): make the timestamp column non nullable 2025-05-15 19:12:44 +05:30
vikrantgupta25
f09d8734a1 chore(sqlmigration): make the timestamp column non nullable 2025-05-15 17:28:15 +05:30
17 changed files with 519 additions and 41 deletions

View File

@@ -5,15 +5,18 @@ import (
"fmt"
"reflect"
"slices"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/uptrace/bun"
)
var (
Identity = "id"
Integer = "bigint"
Text = "text"
Identity = "id"
Integer = "bigint"
Text = "text"
Timestamptz = "timestamptz"
)
var (
@@ -446,3 +449,92 @@ func (dialect *dialect) DropColumnWithForeignKeyConstraint(ctx context.Context,
return nil
}
func (dialect *dialect) MakeTimeAuditableTZAwareAndNonNullable(ctx context.Context, bunIDB bun.IDB, tableName string) error {
columnType, err := dialect.GetColumnType(ctx, bunIDB, tableName, "created_at")
if err != nil {
return err
}
if columnType == Timestamptz {
return nil
}
_, err = bunIDB.NewAddColumn().ColumnExpr("created_at_tz TIMESTAMPTZ").Exec(ctx)
if err != nil {
return err
}
_, err = bunIDB.NewAddColumn().ColumnExpr("updated_at_tz TIMESTAMPTZ").Exec(ctx)
if err != nil {
return err
}
type timeAuditableWithID struct {
ID valuer.UUID `bun:"id"`
CreatedAt time.Time `bun:"created_at,type:timestamptz,nullzero" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at,type:timestamptz,nullzero" json:"updatedAt"`
}
timeAuditables := make([]*timeAuditableWithID, 0)
err = bunIDB.
NewSelect().
Table(tableName).
Column("created_at").
Column("updated_at").
Scan(ctx, &timeAuditables)
if err != nil {
return err
}
now := time.Now()
for _, record := range timeAuditables {
if record.CreatedAt.IsZero() {
record.CreatedAt = now
}
if record.UpdatedAt.IsZero() {
record.UpdatedAt = now
}
}
if len(timeAuditables) > 0 {
_, err = bunIDB.
NewUpdate().
With("_data", bunIDB.NewValues(&timeAuditables)).
Set("created_at_tz = _data.created_at").
Set("updated_at_tz = _data.updated_at").
Table(tableName).Where("id = _data.id").
Exec(ctx)
if err != nil {
return err
}
}
err = dialect.DropColumn(ctx, bunIDB, tableName, "created_at")
if err != nil {
return err
}
err = dialect.DropColumn(ctx, bunIDB, tableName, "updated_at")
if err != nil {
return err
}
_, err = dialect.RenameColumn(ctx, bunIDB, tableName, "created_at_tz", "created_at")
if err != nil {
return err
}
_, err = dialect.RenameColumn(ctx, bunIDB, tableName, "updated_at_tz", "updated_at")
if err != nil {
return err
}
_, err = bunIDB.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s ALTER COLUMN created_at SET NOT NULL", tableName))
if err != nil {
return err
}
_, err = bunIDB.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s ALTER COLUMN updated_at SET NOT NULL", tableName))
if err != nil {
return err
}
return nil
}

View File

@@ -77,6 +77,7 @@ func NewSQLMigrationProviderFactories(sqlstore sqlstore.SQLStore) factory.NamedM
sqlmigration.NewCreateQuickFiltersFactory(sqlstore),
sqlmigration.NewUpdateQuickFiltersFactory(sqlstore),
sqlmigration.NewAuthRefactorFactory(sqlstore),
sqlmigration.NewAddTimestamptzFactory(sqlstore),
)
}

View File

@@ -17,6 +17,11 @@ type updateInvites struct {
store sqlstore.SQLStore
}
type timeAuditable19 struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
}
type existingInvite struct {
bun.BaseModel `bun:"table:invites"`
@@ -33,7 +38,7 @@ type newInvite struct {
bun.BaseModel `bun:"table:user_invite"`
types.Identifiable
types.TimeAuditable
timeAuditable19
Name string `bun:"name,type:text,notnull" json:"name"`
Email string `bun:"email,type:text,notnull,unique" json:"email"`
Token string `bun:"token,type:text,notnull" json:"token"`
@@ -117,7 +122,7 @@ func (migration *updateInvites) CopyOldInvitesToNewInvites(existingInvites []*ex
Identifiable: types.Identifiable{
ID: valuer.GenerateUUID(),
},
TimeAuditable: types.TimeAuditable{
timeAuditable19: timeAuditable19{
CreatedAt: invite.CreatedAt,
UpdatedAt: time.Now(),
},

View File

@@ -17,6 +17,11 @@ type updateAlertmanager struct {
store sqlstore.SQLStore
}
type timeAuditable21 struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
}
type existingChannel struct {
bun.BaseModel `bun:"table:notification_channels"`
ID int `json:"id" bun:"id,pk,autoincrement"`
@@ -31,7 +36,7 @@ type existingChannel struct {
type newChannel struct {
bun.BaseModel `bun:"table:notification_channel"`
types.Identifiable
types.TimeAuditable
timeAuditable21
Name string `json:"name" bun:"name"`
Type string `json:"type" bun:"type"`
Data string `json:"data" bun:"data"`
@@ -51,7 +56,7 @@ type existingAlertmanagerConfig struct {
type newAlertmanagerConfig struct {
bun.BaseModel `bun:"table:alertmanager_config_new"`
types.Identifiable
types.TimeAuditable
timeAuditable21
Config string `bun:"config,notnull,type:text"`
Hash string `bun:"hash,notnull,type:text"`
OrgID string `bun:"org_id,notnull,unique"`
@@ -70,7 +75,7 @@ type existingAlertmanagerState struct {
type newAlertmanagerState struct {
bun.BaseModel `bun:"table:alertmanager_state_new"`
types.Identifiable
types.TimeAuditable
timeAuditable21
Silences string `bun:"silences,nullzero,type:text"`
NFLog string `bun:"nflog,nullzero,type:text"`
OrgID string `bun:"org_id,notnull,unique"`
@@ -217,7 +222,7 @@ func (migration *updateAlertmanager) CopyOldChannelToNewChannel(existingChannels
Identifiable: types.Identifiable{
ID: valuer.GenerateUUID(),
},
TimeAuditable: types.TimeAuditable{
timeAuditable21: timeAuditable21{
CreatedAt: channel.CreatedAt,
UpdatedAt: channel.UpdatedAt,
},
@@ -238,7 +243,7 @@ func (migration *updateAlertmanager) CopyOldConfigToNewConfig(existingAlertmanag
Identifiable: types.Identifiable{
ID: valuer.GenerateUUID(),
},
TimeAuditable: types.TimeAuditable{
timeAuditable21: timeAuditable21{
CreatedAt: config.CreatedAt,
UpdatedAt: config.UpdatedAt,
},
@@ -258,7 +263,7 @@ func (migration *updateAlertmanager) CopyOldStateToNewState(existingAlertmanager
Identifiable: types.Identifiable{
ID: valuer.GenerateUUID(),
},
TimeAuditable: types.TimeAuditable{
timeAuditable21: timeAuditable21{
CreatedAt: state.CreatedAt,
UpdatedAt: state.UpdatedAt,
},

View File

@@ -19,6 +19,11 @@ type updateApdexTtl struct {
store sqlstore.SQLStore
}
type timeAuditable23 struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
}
type existingApdexSettings struct {
bun.BaseModel `bun:"table:apdex_settings"`
OrgID string `bun:"org_id,pk,type:text" json:"orgId"`
@@ -51,7 +56,7 @@ type existingTTLStatus struct {
type newTTLStatus struct {
bun.BaseModel `bun:"table:ttl_setting"`
types.Identifiable
types.TimeAuditable
timeAuditable23
TransactionID string `bun:"transaction_id,type:text,notnull"`
TableName string `bun:"table_name,type:text,notnull"`
TTL int `bun:"ttl,notnull,default:0"`
@@ -210,7 +215,7 @@ func (migration *updateApdexTtl) CopyExistingTTLStatusToNewTTLStatus(existingTTL
Identifiable: types.Identifiable{
ID: valuer.GenerateUUID(),
},
TimeAuditable: types.TimeAuditable{
timeAuditable23: timeAuditable23{
CreatedAt: ttl.CreatedAt,
UpdatedAt: ttl.UpdatedAt,
},

View File

@@ -3,6 +3,7 @@ package sqlmigration
import (
"context"
"database/sql"
"time"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/sqlstore"
@@ -16,6 +17,11 @@ type updateResetPassword struct {
store sqlstore.SQLStore
}
type timeAuditable24 struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
}
type existingResetPasswordRequest struct {
bun.BaseModel `bun:"table:reset_password_request"`
ID int `bun:"id,pk,autoincrement" json:"id"`
@@ -32,7 +38,7 @@ type newResetPasswordRequest struct {
type existingPersonalAccessToken struct {
bun.BaseModel `bun:"table:personal_access_tokens"`
types.TimeAuditable
timeAuditable24
OrgID string `json:"orgId" bun:"org_id,type:text,notnull"`
ID int `json:"id" bun:"id,pk,autoincrement"`
Role string `json:"role" bun:"role,type:text,notnull,default:'ADMIN'"`
@@ -48,7 +54,7 @@ type existingPersonalAccessToken struct {
type newPersonalAccessToken struct {
bun.BaseModel `bun:"table:personal_access_token"`
types.Identifiable
types.TimeAuditable
timeAuditable24
OrgID string `json:"orgId" bun:"org_id,type:text,notnull"`
Role string `json:"role" bun:"role,type:text,notnull,default:'ADMIN'"`
UserID string `json:"userId" bun:"user_id,type:text,notnull"`
@@ -174,7 +180,7 @@ func (migration *updateResetPassword) CopyExistingPATsToNewPATs(existingPATs []*
Identifiable: types.Identifiable{
ID: valuer.GenerateUUID(),
},
TimeAuditable: types.TimeAuditable{
timeAuditable24: timeAuditable24{
CreatedAt: pat.CreatedAt,
UpdatedAt: pat.UpdatedAt,
},

View File

@@ -2,6 +2,7 @@ package sqlmigration
import (
"context"
"time"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/types"
@@ -12,6 +13,11 @@ import (
type addVirtualFields struct{}
type timeAuditable25 struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
}
func NewAddVirtualFieldsFactory() factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("add_virtual_fields"), newAddVirtualFields)
}
@@ -35,7 +41,7 @@ func (migration *addVirtualFields) Up(ctx context.Context, db *bun.DB) error {
bun.BaseModel `bun:"table:virtual_field"`
types.Identifiable
types.TimeAuditable
timeAuditable25
types.UserAuditable
Name string `bun:"name,type:text,notnull"`

View File

@@ -19,6 +19,11 @@ type updateIntegrations struct {
store sqlstore.SQLStore
}
type timeAuditable26 struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
}
func NewUpdateIntegrationsFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("update_integrations"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
return newUpdateIntegrations(ctx, ps, c, sqlstore)
@@ -71,7 +76,7 @@ type newCloudIntegration struct {
bun.BaseModel `bun:"table:cloud_integration"`
types.Identifiable
types.TimeAuditable
timeAuditable26
Provider string `json:"provider" bun:"provider,type:text"`
Config string `json:"config" bun:"config,type:text"`
AccountID string `json:"account_id" bun:"account_id,type:text"`
@@ -94,7 +99,7 @@ type newCloudIntegrationService struct {
bun.BaseModel `bun:"table:cloud_integration_service,alias:cis"`
types.Identifiable
types.TimeAuditable
timeAuditable26
Type string `bun:"type,type:text,notnull,unique:cloud_integration_id_type"`
Config string `bun:"config,type:text"`
CloudIntegrationID string `bun:"cloud_integration_id,type:text,notnull,unique:cloud_integration_id_type"`
@@ -103,7 +108,7 @@ type newCloudIntegrationService struct {
type StorablePersonalAccessToken struct {
bun.BaseModel `bun:"table:personal_access_token"`
types.Identifiable
types.TimeAuditable
timeAuditable26
OrgID string `json:"orgId" bun:"org_id,type:text,notnull"`
Role string `json:"role" bun:"role,type:text,notnull,default:'ADMIN'"`
UserID string `json:"userId" bun:"user_id,type:text,notnull"`
@@ -298,7 +303,7 @@ func (migration *updateIntegrations) CopyOldCloudIntegrationsToNewCloudIntegrati
Identifiable: types.Identifiable{
ID: valuer.GenerateUUID(),
},
TimeAuditable: types.TimeAuditable{
timeAuditable26: timeAuditable26{
CreatedAt: integration.CreatedAt,
UpdatedAt: integration.CreatedAt,
},
@@ -337,7 +342,7 @@ func (migration *updateIntegrations) CopyOldCloudIntegrationServicesToNewCloudIn
Identifiable: types.Identifiable{
ID: valuer.GenerateUUID(),
},
TimeAuditable: types.TimeAuditable{
timeAuditable26: timeAuditable26{
CreatedAt: service.CreatedAt,
UpdatedAt: service.CreatedAt,
},
@@ -354,7 +359,7 @@ func (migration *updateIntegrations) copyOldAwsIntegrationUser(tx bun.IDB, orgID
type oldUser struct {
bun.BaseModel `bun:"table:users"`
types.TimeAuditable
timeAuditable26
ID string `bun:"id,pk,type:text" json:"id"`
Name string `bun:"name,type:text,notnull" json:"name"`
Email string `bun:"email,type:text,notnull,unique" json:"email"`
@@ -381,7 +386,7 @@ func (migration *updateIntegrations) copyOldAwsIntegrationUser(tx bun.IDB, orgID
// new user
newUser := &oldUser{
ID: uuid.New().String(),
TimeAuditable: types.TimeAuditable{
timeAuditable26: timeAuditable26{
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
},
@@ -410,7 +415,7 @@ func (migration *updateIntegrations) copyOldAwsIntegrationUser(tx bun.IDB, orgID
// new pat
newPAT := &StorablePersonalAccessToken{
Identifiable: types.Identifiable{ID: valuer.GenerateUUID()},
TimeAuditable: types.TimeAuditable{
timeAuditable26: timeAuditable26{
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
},

View File

@@ -21,6 +21,11 @@ type updateRules struct {
store sqlstore.SQLStore
}
type timeAuditable27 struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
}
type AlertIds []string
func (a *AlertIds) Scan(src interface{}) error {
@@ -48,7 +53,7 @@ type existingRule struct {
type newRule struct {
bun.BaseModel `bun:"table:rule"`
types.Identifiable
types.TimeAuditable
timeAuditable27
types.UserAuditable
Deleted int `bun:"deleted,notnull,default:0"`
Data string `bun:"data,type:text,notnull"`
@@ -71,7 +76,7 @@ type existingMaintenance struct {
type newMaintenance struct {
bun.BaseModel `bun:"table:planned_maintenance_new"`
types.Identifiable
types.TimeAuditable
timeAuditable27
types.UserAuditable
Name string `bun:"name,type:text,notnull"`
Description string `bun:"description,type:text"`
@@ -283,7 +288,7 @@ func (migration *updateRules) CopyExistingRulesToNewRules(existingRules []*exist
Identifiable: types.Identifiable{
ID: uuid,
},
TimeAuditable: types.TimeAuditable{
timeAuditable27: timeAuditable27{
CreatedAt: rule.CreatedAt,
UpdatedAt: rule.UpdatedAt,
},
@@ -310,7 +315,7 @@ func (migration *updateRules) CopyExistingMaintenancesToNewMaintenancesAndRules(
Identifiable: types.Identifiable{
ID: maintenanceUUID,
},
TimeAuditable: types.TimeAuditable{
timeAuditable27: timeAuditable27{
CreatedAt: maintenance.CreatedAt,
UpdatedAt: maintenance.UpdatedAt,
},

View File

@@ -2,10 +2,10 @@ package sqlmigration
import (
"context"
"time"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/sqlstore"
"github.com/SigNoz/signoz/pkg/types"
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
)
@@ -14,6 +14,11 @@ type dropGroups struct {
sqlstore sqlstore.SQLStore
}
type timeAuditable29 struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
}
func NewDropGroupsFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("drop_groups"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
return newDropGroups(ctx, providerSettings, config, sqlstore)
@@ -36,7 +41,7 @@ func (migration *dropGroups) Up(ctx context.Context, db *bun.DB) error {
type Group struct {
bun.BaseModel `bun:"table:groups"`
types.TimeAuditable
timeAuditable29
OrgID string `bun:"org_id,type:text"`
ID string `bun:"id,pk,type:text" json:"id"`
Name string `bun:"name,type:text,notnull,unique" json:"name"`
@@ -66,7 +71,7 @@ func (migration *dropGroups) Up(ctx context.Context, db *bun.DB) error {
type existingUser struct {
bun.BaseModel `bun:"table:users"`
types.TimeAuditable
timeAuditable29
ID string `bun:"id,pk,type:text" json:"id"`
Name string `bun:"name,type:text,notnull" json:"name"`
Email string `bun:"email,type:text,notnull,unique" json:"email"`
@@ -105,7 +110,7 @@ func (migration *dropGroups) Up(ctx context.Context, db *bun.DB) error {
if err := migration.sqlstore.Dialect().DropColumnWithForeignKeyConstraint(ctx, tx, new(struct {
bun.BaseModel `bun:"table:users"`
types.TimeAuditable
timeAuditable29
ID string `bun:"id,pk,type:text"`
Name string `bun:"name,type:text,notnull"`
Email string `bun:"email,type:text,notnull,unique"`

View File

@@ -3,6 +3,8 @@ package sqlmigration
import (
"context"
"database/sql"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/sqlstore"
@@ -17,13 +19,18 @@ type createQuickFilters struct {
store sqlstore.SQLStore
}
type timeAuditable30 struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
}
type quickFilter struct {
bun.BaseModel `bun:"table:quick_filter"`
types.Identifiable
OrgID string `bun:"org_id,notnull,unique:org_id_signal,type:text"`
Filter string `bun:"filter,notnull,type:text"`
Signal string `bun:"signal,notnull,unique:org_id_signal,type:text"`
types.TimeAuditable
timeAuditable30
types.UserAuditable
}

View File

@@ -3,6 +3,7 @@ package sqlmigration
import (
"context"
"database/sql"
"time"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/sqlstore"
@@ -16,6 +17,11 @@ type authRefactor struct {
store sqlstore.SQLStore
}
type timeAuditable32 struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
}
func NewAuthRefactorFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("auth_refactor"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
return newAuthRefactor(ctx, ps, c, sqlstore)
@@ -37,7 +43,7 @@ func (migration *authRefactor) Register(migrations *migrate.Migrations) error {
type existingUser32 struct {
bun.BaseModel `bun:"table:users"`
types.TimeAuditable
timeAuditable32
ID string `bun:"id,pk,type:text" json:"id"`
Name string `bun:"name,type:text,notnull" json:"name"`
Email string `bun:"email,type:text,notnull,unique" json:"email"`
@@ -51,7 +57,7 @@ type factorPassword32 struct {
bun.BaseModel `bun:"table:factor_password"`
types.Identifiable
types.TimeAuditable
timeAuditable32
Password string `bun:"password,type:text,notnull" json:"password"`
Temporary bool `bun:"temporary,type:boolean,notnull" json:"temporary"`
UserID string `bun:"user_id,type:text,notnull" json:"userID"`

View File

@@ -0,0 +1,229 @@
package sqlmigration
import (
"context"
"database/sql"
"fmt"
"reflect"
"time"
"github.com/SigNoz/signoz/pkg/factory"
"github.com/SigNoz/signoz/pkg/sqlstore"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
)
type addTimestamptz struct {
store sqlstore.SQLStore
}
type identifiable33 struct {
ID valuer.UUID `json:"id" bun:"id,pk,type:text"`
}
type existingTimeAuditable33 struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
}
type newTimeAuditable33 struct {
CreatedAt time.Time `bun:"created_at,type:timestamptz,nullzero,notnull" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at,type:timestamptz,nullzero,notnull" json:"updatedAt"`
}
type existingOrganization33 struct {
bun.BaseModel `bun:"table:organizations"`
existingTimeAuditable33
identifiable33
Name string `bun:"name,type:text,nullzero" json:"name"`
Alias string `bun:"alias,type:text,nullzero" json:"alias"`
DisplayName string `bun:"display_name,type:text,notnull" json:"displayName"`
}
type newOrganization33 struct {
bun.BaseModel `bun:"table:organizations_tmp"`
newTimeAuditable33
identifiable33
Name string `bun:"name,type:text,nullzero" json:"name"`
Alias string `bun:"alias,type:text,nullzero" json:"alias"`
DisplayName string `bun:"display_name,type:text,notnull" json:"displayName"`
}
type existingUser33 struct {
bun.BaseModel `bun:"table:users"`
identifiable33
existingTimeAuditable33
DisplayName string `bun:"display_name,type:text,notnull" json:"displayName"`
Email string `bun:"email,type:text,notnull,unique:org_email" json:"email"`
Role string `bun:"role,type:text,notnull" json:"role"`
OrgID string `bun:"org_id,type:text,notnull,unique:org_email,references:org(id),on_delete:CASCADE" json:"orgId"`
}
type newUser33 struct {
bun.BaseModel `bun:"table:users_tmp"`
identifiable33
newTimeAuditable33
DisplayName string `bun:"display_name,type:text,notnull" json:"displayName"`
Email string `bun:"email,type:text,notnull,unique:org_email" json:"email"`
Role string `bun:"role,type:text,notnull" json:"role"`
OrgID string `bun:"org_id,type:text,notnull,unique:org_email,references:org(id),on_delete:CASCADE" json:"orgId"`
}
func NewAddTimestamptzFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
return factory.NewProviderFactory(factory.MustNewName("add_timestamptz"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
return newAddTimestamptz(ctx, ps, c, sqlstore)
})
}
func newAddTimestamptz(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
return &addTimestamptz{store: store}, nil
}
func (migration *addTimestamptz) Register(migrations *migrate.Migrations) error {
if err := migrations.Register(migration.Up, migration.Down); err != nil {
return err
}
return nil
}
func (migration *addTimestamptz) Up(ctx context.Context, db *bun.DB) error {
err := migration.store.Dialect().ToggleForeignKeyConstraint(ctx, db, false)
if err != nil {
return err
}
tx, err := db.BeginTx(ctx, nil)
if err != nil {
return err
}
organizations := make([]*existingOrganization33, 0)
newOrganizations := make([]*newOrganization33, 0)
err = tx.NewSelect().Model(&organizations).Scan(ctx)
if err != nil && err != sql.ErrNoRows {
return err
}
for _, organization := range organizations {
if organization.CreatedAt.IsZero() {
organization.CreatedAt = time.Now()
}
if organization.UpdatedAt.IsZero() {
organization.UpdatedAt = time.Now()
}
newOrganizations = append(newOrganizations, &newOrganization33{
newTimeAuditable33: newTimeAuditable33{
CreatedAt: organization.CreatedAt,
UpdatedAt: organization.UpdatedAt,
},
identifiable33: identifiable33{
ID: organization.ID,
},
Name: organization.Name,
Alias: organization.Alias,
DisplayName: organization.DisplayName,
})
}
_, err = tx.NewCreateTable().IfNotExists().Model(new(newOrganization33)).Exec(ctx)
if err != nil {
return err
}
if len(newOrganizations) > 0 {
_, err = tx.NewInsert().Model(&newOrganizations).Exec(ctx)
if err != nil {
return err
}
}
_, err = tx.NewDropTable().Model(new(existingOrganization33)).IfExists().Exec(ctx)
if err != nil {
return err
}
oldTableName := tx.Dialect().Tables().Get(reflect.TypeOf(new(existingOrganization33))).Name
_, err = tx.
ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s RENAME TO %s", oldTableName+"_tmp", oldTableName))
if err != nil {
return err
}
/// ---
users := make([]*existingUser33, 0)
newUsers := make([]*newUser33, 0)
err = tx.NewSelect().Model(&users).Scan(ctx)
if err != nil && err != sql.ErrNoRows {
return err
}
for _, user := range users {
if user.CreatedAt.IsZero() {
user.CreatedAt = time.Now()
}
if user.UpdatedAt.IsZero() {
user.UpdatedAt = time.Now()
}
newUsers = append(newUsers, &newUser33{
newTimeAuditable33: newTimeAuditable33{
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
},
identifiable33: identifiable33{
ID: user.ID,
},
DisplayName: user.DisplayName,
Email: user.Email,
Role: user.Role,
OrgID: user.OrgID,
})
}
_, err = tx.NewCreateTable().IfNotExists().Model(new(newUser33)).Exec(ctx)
if err != nil {
return err
}
if len(newUsers) > 0 {
_, err = tx.NewInsert().Model(&newUsers).Exec(ctx)
if err != nil {
return err
}
}
_, err = tx.NewDropTable().Model(new(existingUser33)).IfExists().Exec(ctx)
if err != nil {
return err
}
oldTableName = tx.Dialect().Tables().Get(reflect.TypeOf(new(existingUser33))).Name
_, err = tx.
ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s RENAME TO %s", oldTableName+"_tmp", oldTableName))
if err != nil {
return err
}
defer tx.Rollback()
err = tx.Commit()
if err != nil {
return err
}
err = migration.store.Dialect().ToggleForeignKeyConstraint(ctx, db, true)
if err != nil {
return err
}
return nil
}
func (migration *addTimestamptz) Down(context.Context, *bun.DB) error {
return nil
}

View File

@@ -6,15 +6,18 @@ import (
"reflect"
"slices"
"strings"
"time"
"github.com/SigNoz/signoz/pkg/errors"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/uptrace/bun"
)
const (
Identity string = "id"
Integer string = "INTEGER"
Text string = "TEXT"
Identity string = "id"
Integer string = "INTEGER"
Text string = "TEXT"
Timestamptz string = "TIMESTAMPTZ"
)
const (
@@ -499,3 +502,95 @@ func (dialect *dialect) ToggleForeignKeyConstraint(ctx context.Context, bun *bun
_, err := bun.ExecContext(ctx, "PRAGMA foreign_keys = OFF")
return err
}
func (dialect *dialect) MakeTimeAuditableTZAwareAndNonNullable(ctx context.Context, bunIDB bun.IDB, tableName string) error {
columnType, err := dialect.GetColumnType(ctx, bunIDB, tableName, "created_at")
if err != nil {
return err
}
if columnType == Timestamptz {
return nil
}
_, err = bunIDB.NewAddColumn().Table(tableName).ColumnExpr("created_at_tz TIMESTAMPTZ").Exec(ctx)
if err != nil {
return err
}
_, err = bunIDB.NewAddColumn().Table(tableName).ColumnExpr("updated_at_tz TIMESTAMPTZ").Exec(ctx)
if err != nil {
return err
}
type timeAuditableWithID struct {
ID valuer.UUID `bun:"id"`
CreatedAt time.Time `bun:"created_at,type:timestamptz,nullzero" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at,type:timestamptz,nullzero" json:"updatedAt"`
}
timeAuditables := make([]*timeAuditableWithID, 0)
err = bunIDB.
NewSelect().
Table(tableName).
Column("created_at").
Column("updated_at").
Column("id").
Scan(ctx, &timeAuditables)
if err != nil {
return err
}
now := time.Now()
for _, record := range timeAuditables {
if record.CreatedAt.IsZero() {
record.CreatedAt = now
}
if record.UpdatedAt.IsZero() {
record.UpdatedAt = now
}
}
if len(timeAuditables) > 0 {
_, err = bunIDB.
NewUpdate().
With("updates", bunIDB.NewValues(&timeAuditables)).
ModelTableExpr(tableName + " AS t").
Table("updates").
Set("created_at_tz = updates.created_at").
Set("updated_at_tz = updates.updated_at").
Where("t.id = updates.id").
Exec(ctx)
if err != nil {
return err
}
}
err = dialect.DropColumn(ctx, bunIDB, tableName, "created_at")
if err != nil {
return err
}
err = dialect.DropColumn(ctx, bunIDB, tableName, "updated_at")
if err != nil {
return err
}
_, err = dialect.RenameColumn(ctx, bunIDB, tableName, "created_at_tz", "created_at")
if err != nil {
return err
}
_, err = dialect.RenameColumn(ctx, bunIDB, tableName, "updated_at_tz", "updated_at")
if err != nil {
return err
}
_, err = bunIDB.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s ALTER COLUMN created_at SET NOT NULL", tableName))
if err != nil {
return err
}
_, err = bunIDB.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s ALTER COLUMN updated_at SET NOT NULL", tableName))
if err != nil {
return err
}
return nil
}

View File

@@ -89,4 +89,6 @@ type SQLDialect interface {
// Toggles foreign key constraint for the given database. This makes sense only for sqlite. This cannot take a transaction as an argument and needs to take the db
// as an argument.
ToggleForeignKeyConstraint(ctx context.Context, bun *bun.DB, enable bool) error
MakeTimeAuditableTZAwareAndNonNullable(context.Context, bun.IDB, string) error
}

View File

@@ -68,3 +68,7 @@ func (dialect *dialect) TableExists(ctx context.Context, bun bun.IDB, table inte
func (dialect *dialect) ToggleForeignKeyConstraint(ctx context.Context, bun *bun.DB, enable bool) error {
return nil
}
func (dialect *dialect) MakeTimeAuditableTZAwareAndNonNullable(ctx context.Context, bunIDB bun.IDB, tableName string) error {
return nil
}

View File

@@ -3,8 +3,8 @@ package types
import "time"
type TimeAuditable struct {
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
CreatedAt time.Time `bun:"created_at,type:timestamptz,nullzero" json:"createdAt"`
UpdatedAt time.Time `bun:"updated_at,type:timestamptz,nullzero" json:"updatedAt"`
}
type UserAuditable struct {