Compare commits
15 Commits
main
...
platform-p
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55cc534504 | ||
|
|
c86dee537f | ||
|
|
9ba031cd68 | ||
|
|
4ca3d8df4d | ||
|
|
da0a2b8f01 | ||
|
|
39c4a6e321 | ||
|
|
113e26a1d2 | ||
|
|
352cbbb874 | ||
|
|
6dba3e97c7 | ||
|
|
77cb2be656 | ||
|
|
b26b2fe0c8 | ||
|
|
082151a5fd | ||
|
|
850be46f7e | ||
|
|
bd3c8c62f8 | ||
|
|
7661e9af36 |
@@ -1,10 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
|
||||
"github.com/SigNoz/signoz/cmd"
|
||||
"github.com/SigNoz/signoz/ee/sqlschema/postgressqlschema"
|
||||
"github.com/SigNoz/signoz/ee/sqlstore/postgressqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/instrumentation"
|
||||
"github.com/SigNoz/signoz/pkg/signoz"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore/sqlstorehook"
|
||||
)
|
||||
|
||||
func main() {
|
||||
@@ -14,5 +22,21 @@ func main() {
|
||||
// register a list of commands to the root command
|
||||
registerServer(cmd.RootCmd, logger)
|
||||
|
||||
// TODO(grandwizard28): DRY this code
|
||||
sqlstoreFactories := signoz.NewSQLStoreProviderFactories()
|
||||
if err := sqlstoreFactories.Add(postgressqlstore.NewFactory(sqlstorehook.NewLoggingFactory())); err != nil {
|
||||
logger.ErrorContext(context.TODO(), "failed to add postgressqlstore factory", "error", err)
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cmd.RegisterSQL(cmd.RootCmd, logger, func(sqlstore sqlstore.SQLStore) factory.NamedMap[factory.ProviderFactory[sqlschema.SQLSchema, sqlschema.Config]] {
|
||||
existingFactories := signoz.NewSQLSchemaProviderFactories(sqlstore)
|
||||
if err := existingFactories.Add(postgressqlschema.NewFactory(sqlstore)); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return existingFactories
|
||||
}, sqlstoreFactories)
|
||||
|
||||
cmd.Execute(logger)
|
||||
}
|
||||
|
||||
155
cmd/sql.go
Normal file
155
cmd/sql.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/instrumentation"
|
||||
"github.com/SigNoz/signoz/pkg/signoz"
|
||||
"github.com/SigNoz/signoz/pkg/sqlmigration"
|
||||
"github.com/SigNoz/signoz/pkg/sqlmigrator"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/version"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// TODO(grandwizard28): DRY this code
|
||||
func RegisterSQL(parentCmd *cobra.Command, logger *slog.Logger, sqlSchemaProviderFactories func(sqlstore.SQLStore) factory.NamedMap[factory.ProviderFactory[sqlschema.SQLSchema, sqlschema.Config]], sqlstoreProviderFactories factory.NamedMap[factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config]]) {
|
||||
sqlCmd := &cobra.Command{
|
||||
Use: "sql",
|
||||
Short: "Run commands to interact with the SQL",
|
||||
}
|
||||
|
||||
migrateCmd := &cobra.Command{
|
||||
Use: "migrate",
|
||||
Short: "Run migrations for the SQL database",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
config, err := NewSigNozConfig(ctx, logger, signoz.DeprecatedFlags{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize instrumentation
|
||||
instrumentation, err := instrumentation.New(ctx, config.Instrumentation, version.Info, "signoz")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the provider settings from instrumentation
|
||||
providerSettings := instrumentation.ToProviderSettings()
|
||||
|
||||
// Initialize sqlstore from the available sqlstore provider factories
|
||||
sqlstore, err := factory.NewProviderFromNamedMap(
|
||||
ctx,
|
||||
providerSettings,
|
||||
config.SQLStore,
|
||||
sqlstoreProviderFactories,
|
||||
config.SQLStore.Provider,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize sqlschema from the available sqlschema provider factories
|
||||
sqlschema, err := factory.NewProviderFromNamedMap(
|
||||
ctx,
|
||||
providerSettings,
|
||||
config.SQLSchema,
|
||||
sqlSchemaProviderFactories(sqlstore),
|
||||
config.SQLStore.Provider,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Run migrations on the sqlstore
|
||||
sqlmigrations, err := sqlmigration.New(
|
||||
ctx,
|
||||
providerSettings,
|
||||
config.SQLMigration,
|
||||
signoz.NewSQLMigrationProviderFactories(sqlstore, sqlschema),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = sqlmigrator.New(ctx, providerSettings, sqlstore, sqlmigrations, config.SQLMigrator).Migrate(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
rollbackCmd := &cobra.Command{
|
||||
Use: "rollback",
|
||||
Short: "Rollback the last migration",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
ctx := cmd.Context()
|
||||
|
||||
config, err := NewSigNozConfig(ctx, logger, signoz.DeprecatedFlags{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize instrumentation
|
||||
instrumentation, err := instrumentation.New(ctx, config.Instrumentation, version.Info, "signoz")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the provider settings from instrumentation
|
||||
providerSettings := instrumentation.ToProviderSettings()
|
||||
|
||||
// Initialize sqlstore from the available sqlstore provider factories
|
||||
sqlstore, err := factory.NewProviderFromNamedMap(
|
||||
ctx,
|
||||
providerSettings,
|
||||
config.SQLStore,
|
||||
sqlstoreProviderFactories,
|
||||
config.SQLStore.Provider,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize sqlschema from the available sqlschema provider factories
|
||||
sqlschema, err := factory.NewProviderFromNamedMap(
|
||||
ctx,
|
||||
providerSettings,
|
||||
config.SQLSchema,
|
||||
sqlSchemaProviderFactories(sqlstore),
|
||||
config.SQLStore.Provider,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Run migrations on the sqlstore
|
||||
sqlmigrations, err := sqlmigration.New(
|
||||
ctx,
|
||||
providerSettings,
|
||||
config.SQLMigration,
|
||||
signoz.NewSQLMigrationProviderFactories(sqlstore, sqlschema),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = sqlmigrator.New(ctx, providerSettings, sqlstore, sqlmigrations, config.SQLMigrator).Rollback(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
sqlCmd.AddCommand(migrateCmd)
|
||||
sqlCmd.AddCommand(rollbackCmd)
|
||||
parentCmd.AddCommand(sqlCmd)
|
||||
}
|
||||
@@ -78,13 +78,12 @@ All tables follow a consistent primary key pattern using a `id` column (referenc
|
||||
|
||||
## How to write migrations?
|
||||
|
||||
For schema migrations, use the [SQLMigration](/pkg/sqlmigration/sqlmigration.go) interface and write the migration in the same package. When creating migrations, adhere to these guidelines:
|
||||
For schema migrations, use the [SQLMigration](/pkg/sqlmigration/sqlmigration.go) interface. The migrations are split into multiple packages based on the starting number of the series of the migration. For example, migrations with starting number `100` are in the `s100sqlmigration` package (read as series 100 sql migrations), migrations with starting number `200` are in the `s200sqlmigration` package, and so on. When creating migrations, adhere to these guidelines:
|
||||
|
||||
- Do not implement **`ON CASCADE` foreign key constraints**. Deletion operations should be handled explicitly in application logic rather than delegated to the database.
|
||||
- Use the [SQLSchema](/pkg/sqlschema/sqlschema.go) interface to write migrations. SQLSchema is responsible for generating idempotent SQL statements to alter the database schema. For instance, if you want to add a column to the `users` table, you can use the `AddColumn` method to add the column. If the column already exists, the method will return no SQL statements.
|
||||
- Do not **import types from the types package** in the `sqlmigration` package. Instead, define the required types within the migration package itself. This practice ensures migration stability as the core types evolve over time.
|
||||
- Do not implement **`Down` migrations**. As the codebase matures, we may introduce this capability, but for now, the `Down` function should remain empty.
|
||||
- Always write **idempotent** migrations. This means that if the migration is run multiple times, it should not cause an error.
|
||||
- A migration which is **dependent on the underlying dialect** (sqlite, postgres, etc) should be written as part of the [SQLDialect](/pkg/sqlstore/sqlstore.go) interface. The implementation needs to go in the dialect specific package of the respective database.
|
||||
|
||||
## What should I remember?
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ func (formatter Formatter) DataTypeOf(dataType string) sqlschema.DataType {
|
||||
case "BOOL", "BOOLEAN":
|
||||
return sqlschema.DataTypeBoolean
|
||||
case "VARCHAR", "CHARACTER VARYING", "CHARACTER":
|
||||
return sqlschema.DataTypeText
|
||||
return sqlschema.DataTypeVarchar
|
||||
}
|
||||
|
||||
return formatter.Formatter.DataTypeOf(dataType)
|
||||
|
||||
@@ -2,13 +2,19 @@ package postgressqlschema
|
||||
|
||||
import (
|
||||
"context"
|
||||
"regexp"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
var (
|
||||
columnDefaultValuePattern = regexp.MustCompile(`^(.*?)(?:::.*)?$`)
|
||||
)
|
||||
|
||||
type provider struct {
|
||||
settings factory.ScopedProviderSettings
|
||||
fmter sqlschema.SQLFormatter
|
||||
@@ -31,9 +37,9 @@ func New(ctx context.Context, providerSettings factory.ProviderSettings, config
|
||||
fmter: fmter,
|
||||
settings: settings,
|
||||
operator: sqlschema.NewOperator(fmter, sqlschema.OperatorSupport{
|
||||
DropConstraint: true,
|
||||
ColumnIfNotExistsExists: true,
|
||||
AlterColumnSetNotNull: true,
|
||||
SCreateAndDropConstraint: true,
|
||||
SAlterTableAddAndDropColumnIfNotExistsAndExists: true,
|
||||
SAlterTableAlterColumnSetAndDrop: true,
|
||||
}),
|
||||
}, nil
|
||||
}
|
||||
@@ -61,7 +67,7 @@ FROM
|
||||
WHERE
|
||||
c.table_name = ?`, string(tableName))
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, provider.sqlstore.WrapNotFoundErrf(err, errors.CodeNotFound, "table (%s) not found", tableName)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
@@ -84,7 +90,7 @@ WHERE
|
||||
|
||||
columnDefault := ""
|
||||
if defaultVal != nil {
|
||||
columnDefault = *defaultVal
|
||||
columnDefault = columnDefaultValuePattern.ReplaceAllString(*defaultVal, "$1")
|
||||
}
|
||||
|
||||
columns = append(columns, &sqlschema.Column{
|
||||
@@ -224,7 +230,8 @@ SELECT
|
||||
ci.relname AS index_name,
|
||||
i.indisunique AS unique,
|
||||
i.indisprimary AS primary,
|
||||
a.attname AS column_name
|
||||
a.attname AS column_name,
|
||||
array_position(i.indkey, a.attnum) AS column_position
|
||||
FROM
|
||||
pg_index i
|
||||
LEFT JOIN pg_class ct ON ct.oid = i.indrelid
|
||||
@@ -235,9 +242,10 @@ WHERE
|
||||
a.attnum = ANY(i.indkey)
|
||||
AND con.oid IS NULL
|
||||
AND ct.relkind = 'r'
|
||||
AND ct.relname = ?`, string(name))
|
||||
AND ct.relname = ?
|
||||
ORDER BY index_name, column_position`, string(name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, provider.sqlstore.WrapNotFoundErrf(err, errors.CodeNotFound, "no indices for table (%s) found", name)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
@@ -254,9 +262,11 @@ WHERE
|
||||
unique bool
|
||||
primary bool
|
||||
columnName string
|
||||
// starts from 0 and is unused in this function, this is to ensure that the column names are in the correct order
|
||||
columnPosition int
|
||||
)
|
||||
|
||||
if err := rows.Scan(&tableName, &indexName, &unique, &primary, &columnName); err != nil {
|
||||
if err := rows.Scan(&tableName, &indexName, &unique, &primary, &columnName, &columnPosition); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -273,8 +283,12 @@ WHERE
|
||||
}
|
||||
|
||||
indices := make([]sqlschema.Index, 0)
|
||||
for _, index := range uniqueIndicesMap {
|
||||
indices = append(indices, index)
|
||||
for indexName, index := range uniqueIndicesMap {
|
||||
if index.Name() == indexName {
|
||||
indices = append(indices, index)
|
||||
} else {
|
||||
indices = append(indices, index.Named(indexName))
|
||||
}
|
||||
}
|
||||
|
||||
return indices, nil
|
||||
|
||||
@@ -1,456 +0,0 @@
|
||||
package postgressqlstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
var (
|
||||
Identity = "id"
|
||||
Integer = "bigint"
|
||||
Text = "text"
|
||||
)
|
||||
|
||||
var (
|
||||
Org = "org"
|
||||
User = "user"
|
||||
UserNoCascade = "user_no_cascade"
|
||||
FactorPassword = "factor_password"
|
||||
CloudIntegration = "cloud_integration"
|
||||
AgentConfigVersion = "agent_config_version"
|
||||
)
|
||||
|
||||
var (
|
||||
OrgReference = `("org_id") REFERENCES "organizations" ("id")`
|
||||
UserReference = `("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE`
|
||||
UserReferenceNoCascade = `("user_id") REFERENCES "users" ("id")`
|
||||
FactorPasswordReference = `("password_id") REFERENCES "factor_password" ("id")`
|
||||
CloudIntegrationReference = `("cloud_integration_id") REFERENCES "cloud_integration" ("id") ON DELETE CASCADE`
|
||||
AgentConfigVersionReference = `("version_id") REFERENCES "agent_config_version" ("id")`
|
||||
)
|
||||
|
||||
type dialect struct{}
|
||||
|
||||
func (dialect *dialect) IntToTimestamp(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// bigint for postgres and INTEGER for sqlite
|
||||
if columnType != "bigint" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if the columns is integer then do this
|
||||
if _, err := bun.
|
||||
ExecContext(ctx, `ALTER TABLE `+table+` RENAME COLUMN `+column+` TO `+column+`_old`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add new timestamp column
|
||||
if _, err := bun.
|
||||
NewAddColumn().
|
||||
Table(table).
|
||||
ColumnExpr(column + " TIMESTAMP").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := bun.
|
||||
NewUpdate().
|
||||
Table(table).
|
||||
Set(column + " = to_timestamp(cast(" + column + "_old as INTEGER))").
|
||||
Where("1=1").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// drop old column
|
||||
if _, err := bun.
|
||||
NewDropColumn().
|
||||
Table(table).
|
||||
Column(column + "_old").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) IntToBoolean(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
columnExists, err := dialect.ColumnExists(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !columnExists {
|
||||
return nil
|
||||
}
|
||||
|
||||
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if columnType != "bigint" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := bun.
|
||||
ExecContext(ctx, `ALTER TABLE `+table+` RENAME COLUMN `+column+` TO `+column+`_old`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add new boolean column
|
||||
if _, err := bun.
|
||||
NewAddColumn().
|
||||
Table(table).
|
||||
ColumnExpr(column + " BOOLEAN").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// copy data from old column to new column, converting from int to boolean
|
||||
if _, err := bun.NewUpdate().
|
||||
Table(table).
|
||||
Set(column + " = CASE WHEN " + column + "_old = 1 THEN true ELSE false END").
|
||||
Where("1=1").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// drop old column
|
||||
if _, err := bun.NewDropColumn().Table(table).Column(column + "_old").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) GetColumnType(ctx context.Context, bun bun.IDB, table string, column string) (string, error) {
|
||||
var columnType string
|
||||
|
||||
err := bun.NewSelect().
|
||||
ColumnExpr("data_type").
|
||||
TableExpr("information_schema.columns").
|
||||
Where("table_name = ?", table).
|
||||
Where("column_name = ?", column).
|
||||
Scan(ctx, &columnType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return columnType, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) ColumnExists(ctx context.Context, bun bun.IDB, table string, column string) (bool, error) {
|
||||
var count int
|
||||
err := bun.NewSelect().
|
||||
ColumnExpr("COUNT(*)").
|
||||
TableExpr("information_schema.columns").
|
||||
Where("table_name = ?", table).
|
||||
Where("column_name = ?", column).
|
||||
Scan(ctx, &count)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) AddColumn(ctx context.Context, bun bun.IDB, table string, column string, columnExpr string) error {
|
||||
exists, err := dialect.ColumnExists(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
_, err = bun.
|
||||
NewAddColumn().
|
||||
Table(table).
|
||||
ColumnExpr(column + " " + columnExpr).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) RenameColumn(ctx context.Context, bun bun.IDB, table string, oldColumnName string, newColumnName string) (bool, error) {
|
||||
oldColumnExists, err := dialect.ColumnExists(ctx, bun, table, oldColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
newColumnExists, err := dialect.ColumnExists(ctx, bun, table, newColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if newColumnExists {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if !oldColumnExists {
|
||||
return false, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "old column: %s doesn't exist", oldColumnName)
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
ExecContext(ctx, "ALTER TABLE "+table+" RENAME COLUMN "+oldColumnName+" TO "+newColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) DropColumn(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
exists, err := dialect.ColumnExists(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
_, err = bun.
|
||||
NewDropColumn().
|
||||
Table(table).
|
||||
Column(column).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) TableExists(ctx context.Context, bun bun.IDB, table interface{}) (bool, error) {
|
||||
|
||||
count := 0
|
||||
err := bun.
|
||||
NewSelect().
|
||||
ColumnExpr("count(*)").
|
||||
Table("pg_catalog.pg_tables").
|
||||
Where("tablename = ?", bun.Dialect().Tables().Get(reflect.TypeOf(table)).Name).
|
||||
Scan(ctx, &count)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) RenameTableAndModifyModel(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, references []string, cb func(context.Context) error) error {
|
||||
if len(references) == 0 {
|
||||
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "cannot run migration without reference")
|
||||
}
|
||||
exists, err := dialect.TableExists(ctx, bun, newModel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
var fkReferences []string
|
||||
for _, reference := range references {
|
||||
if reference == Org && !slices.Contains(fkReferences, OrgReference) {
|
||||
fkReferences = append(fkReferences, OrgReference)
|
||||
} else if reference == User && !slices.Contains(fkReferences, UserReference) {
|
||||
fkReferences = append(fkReferences, UserReference)
|
||||
} else if reference == UserNoCascade && !slices.Contains(fkReferences, UserReferenceNoCascade) {
|
||||
fkReferences = append(fkReferences, UserReferenceNoCascade)
|
||||
} else if reference == FactorPassword && !slices.Contains(fkReferences, FactorPasswordReference) {
|
||||
fkReferences = append(fkReferences, FactorPasswordReference)
|
||||
} else if reference == CloudIntegration && !slices.Contains(fkReferences, CloudIntegrationReference) {
|
||||
fkReferences = append(fkReferences, CloudIntegrationReference)
|
||||
} else if reference == AgentConfigVersion && !slices.Contains(fkReferences, AgentConfigVersionReference) {
|
||||
fkReferences = append(fkReferences, AgentConfigVersionReference)
|
||||
}
|
||||
}
|
||||
|
||||
createTable := bun.
|
||||
NewCreateTable().
|
||||
IfNotExists().
|
||||
Model(newModel)
|
||||
|
||||
for _, fk := range fkReferences {
|
||||
createTable = createTable.ForeignKey(fk)
|
||||
}
|
||||
|
||||
_, err = createTable.Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cb(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Model(oldModel).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) AddNotNullDefaultToColumn(ctx context.Context, bun bun.IDB, table string, column, columnType, defaultValue string) error {
|
||||
query := fmt.Sprintf("ALTER TABLE %s ALTER COLUMN %s SET DEFAULT %s, ALTER COLUMN %s SET NOT NULL", table, column, defaultValue, column)
|
||||
if _, err := bun.ExecContext(ctx, query); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) UpdatePrimaryKey(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, reference string, cb func(context.Context) error) error {
|
||||
if reference == "" {
|
||||
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "cannot run migration without reference")
|
||||
}
|
||||
oldTableName := bun.Dialect().Tables().Get(reflect.TypeOf(oldModel)).Name
|
||||
newTableName := bun.Dialect().Tables().Get(reflect.TypeOf(newModel)).Name
|
||||
|
||||
columnType, err := dialect.GetColumnType(ctx, bun, oldTableName, Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if columnType == Text {
|
||||
return nil
|
||||
}
|
||||
|
||||
fkReference := ""
|
||||
if reference == Org {
|
||||
fkReference = OrgReference
|
||||
} else if reference == User {
|
||||
fkReference = UserReference
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
NewCreateTable().
|
||||
IfNotExists().
|
||||
Model(newModel).
|
||||
ForeignKey(fkReference).
|
||||
Exec(ctx)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cb(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Model(oldModel).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s RENAME TO %s", newTableName, oldTableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) AddPrimaryKey(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, reference string, cb func(context.Context) error) error {
|
||||
if reference == "" {
|
||||
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "cannot run migration without reference")
|
||||
}
|
||||
oldTableName := bun.Dialect().Tables().Get(reflect.TypeOf(oldModel)).Name
|
||||
newTableName := bun.Dialect().Tables().Get(reflect.TypeOf(newModel)).Name
|
||||
|
||||
identityExists, err := dialect.ColumnExists(ctx, bun, oldTableName, Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if identityExists {
|
||||
return nil
|
||||
}
|
||||
|
||||
fkReference := ""
|
||||
if reference == Org {
|
||||
fkReference = OrgReference
|
||||
} else if reference == User {
|
||||
fkReference = UserReference
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
NewCreateTable().
|
||||
IfNotExists().
|
||||
Model(newModel).
|
||||
ForeignKey(fkReference).
|
||||
Exec(ctx)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cb(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Model(oldModel).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s RENAME TO %s", newTableName, oldTableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) DropColumnWithForeignKeyConstraint(ctx context.Context, bunIDB bun.IDB, model interface{}, column string) error {
|
||||
existingTable := bunIDB.Dialect().Tables().Get(reflect.TypeOf(model))
|
||||
columnExists, err := dialect.ColumnExists(ctx, bunIDB, existingTable.Name, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !columnExists {
|
||||
return nil
|
||||
}
|
||||
|
||||
_, err = bunIDB.
|
||||
NewDropColumn().
|
||||
Model(model).
|
||||
Column(column).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -18,7 +18,6 @@ type provider struct {
|
||||
settings factory.ScopedProviderSettings
|
||||
sqldb *sql.DB
|
||||
bundb *sqlstore.BunDB
|
||||
dialect *dialect
|
||||
}
|
||||
|
||||
func NewFactory(hookFactories ...factory.ProviderFactory[sqlstore.SQLStoreHook, sqlstore.Config]) factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config] {
|
||||
@@ -59,7 +58,6 @@ func New(ctx context.Context, providerSettings factory.ProviderSettings, config
|
||||
settings: settings,
|
||||
sqldb: sqldb,
|
||||
bundb: sqlstore.NewBunDB(settings, sqldb, pgdialect.New(), hooks),
|
||||
dialect: new(dialect),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -71,10 +69,6 @@ func (provider *provider) SQLDB() *sql.DB {
|
||||
return provider.sqldb
|
||||
}
|
||||
|
||||
func (provider *provider) Dialect() sqlstore.SQLDialect {
|
||||
return provider.dialect
|
||||
}
|
||||
|
||||
func (provider *provider) BunDBCtx(ctx context.Context) bun.IDB {
|
||||
return provider.bundb.BunDBCtx(ctx)
|
||||
}
|
||||
@@ -99,7 +93,3 @@ func (provider *provider) WrapAlreadyExistsErrf(err error, code errors.Code, for
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (dialect *dialect) ToggleForeignKeyConstraint(ctx context.Context, bun *bun.DB, enable bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
2
go.mod
2
go.mod
@@ -76,7 +76,6 @@ require (
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/crypto v0.41.0
|
||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b
|
||||
golang.org/x/net v0.43.0
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.17.0
|
||||
golang.org/x/text v0.28.0
|
||||
@@ -93,6 +92,7 @@ require (
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 // indirect
|
||||
go.yaml.in/yaml/v2 v2.4.2 // indirect
|
||||
golang.org/x/net v0.43.0 // indirect
|
||||
modernc.org/libc v1.66.3 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/http/render"
|
||||
"github.com/SigNoz/signoz/pkg/modules/dashboard"
|
||||
"github.com/SigNoz/signoz/pkg/transition"
|
||||
"github.com/SigNoz/signoz/pkg/types/authtypes"
|
||||
"github.com/SigNoz/signoz/pkg/types/ctxtypes"
|
||||
"github.com/SigNoz/signoz/pkg/types/dashboardtypes"
|
||||
@@ -50,11 +49,6 @@ func (handler *handler) Create(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
dashboardMigrator := transition.NewDashboardMigrateV5(handler.providerSettings.Logger, nil, nil)
|
||||
if req["version"] != "v5" {
|
||||
dashboardMigrator.Migrate(ctx, req)
|
||||
}
|
||||
|
||||
dashboard, err := handler.module.Create(ctx, orgID, claims.Email, valuer.MustNewUUID(claims.UserID), req)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
|
||||
@@ -176,7 +176,7 @@ func (r *cloudProviderAccountsSQLRepository) upsert(
|
||||
onConflictClause := ""
|
||||
if len(onConflictSetStmts) > 0 {
|
||||
onConflictClause = fmt.Sprintf(
|
||||
"conflict(id, provider, org_id) do update SET\n%s",
|
||||
"conflict(id) do update SET\n%s",
|
||||
strings.Join(onConflictSetStmts, ",\n"),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"github.com/SigNoz/signoz/pkg/sharder/noopsharder"
|
||||
"github.com/SigNoz/signoz/pkg/sharder/singlesharder"
|
||||
"github.com/SigNoz/signoz/pkg/sqlmigration"
|
||||
"github.com/SigNoz/signoz/pkg/sqlmigration/s100sqlmigration"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema/sqlitesqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
@@ -84,60 +85,9 @@ func NewSQLSchemaProviderFactories(sqlstore sqlstore.SQLStore) factory.NamedMap[
|
||||
func NewSQLMigrationProviderFactories(
|
||||
sqlstore sqlstore.SQLStore,
|
||||
sqlschema sqlschema.SQLSchema,
|
||||
telemetryStore telemetrystore.TelemetryStore,
|
||||
providerSettings factory.ProviderSettings,
|
||||
) factory.NamedMap[factory.ProviderFactory[sqlmigration.SQLMigration, sqlmigration.Config]] {
|
||||
return factory.MustNewNamedMap(
|
||||
sqlmigration.NewAddDataMigrationsFactory(),
|
||||
sqlmigration.NewAddOrganizationFactory(),
|
||||
sqlmigration.NewAddPreferencesFactory(),
|
||||
sqlmigration.NewAddDashboardsFactory(),
|
||||
sqlmigration.NewAddSavedViewsFactory(),
|
||||
sqlmigration.NewAddAgentsFactory(),
|
||||
sqlmigration.NewAddPipelinesFactory(),
|
||||
sqlmigration.NewAddIntegrationsFactory(),
|
||||
sqlmigration.NewAddLicensesFactory(),
|
||||
sqlmigration.NewAddPatsFactory(),
|
||||
sqlmigration.NewModifyDatetimeFactory(),
|
||||
sqlmigration.NewModifyOrgDomainFactory(),
|
||||
sqlmigration.NewUpdateOrganizationFactory(sqlstore),
|
||||
sqlmigration.NewAddAlertmanagerFactory(sqlstore),
|
||||
sqlmigration.NewUpdateDashboardAndSavedViewsFactory(sqlstore),
|
||||
sqlmigration.NewUpdatePatAndOrgDomainsFactory(sqlstore),
|
||||
sqlmigration.NewUpdatePipelines(sqlstore),
|
||||
sqlmigration.NewDropLicensesSitesFactory(sqlstore),
|
||||
sqlmigration.NewUpdateInvitesFactory(sqlstore),
|
||||
sqlmigration.NewUpdatePatFactory(sqlstore),
|
||||
sqlmigration.NewUpdateAlertmanagerFactory(sqlstore),
|
||||
sqlmigration.NewUpdatePreferencesFactory(sqlstore),
|
||||
sqlmigration.NewUpdateApdexTtlFactory(sqlstore),
|
||||
sqlmigration.NewUpdateResetPasswordFactory(sqlstore),
|
||||
sqlmigration.NewUpdateRulesFactory(sqlstore),
|
||||
sqlmigration.NewAddVirtualFieldsFactory(),
|
||||
sqlmigration.NewUpdateIntegrationsFactory(sqlstore),
|
||||
sqlmigration.NewUpdateOrganizationsFactory(sqlstore),
|
||||
sqlmigration.NewDropGroupsFactory(sqlstore),
|
||||
sqlmigration.NewCreateQuickFiltersFactory(sqlstore),
|
||||
sqlmigration.NewUpdateQuickFiltersFactory(sqlstore),
|
||||
sqlmigration.NewAuthRefactorFactory(sqlstore),
|
||||
sqlmigration.NewUpdateLicenseFactory(sqlstore),
|
||||
sqlmigration.NewMigratePATToFactorAPIKey(sqlstore),
|
||||
sqlmigration.NewUpdateApiMonitoringFiltersFactory(sqlstore),
|
||||
sqlmigration.NewAddKeyOrganizationFactory(sqlstore),
|
||||
sqlmigration.NewAddTraceFunnelsFactory(sqlstore),
|
||||
sqlmigration.NewUpdateDashboardFactory(sqlstore),
|
||||
sqlmigration.NewDropFeatureSetFactory(),
|
||||
sqlmigration.NewDropDeprecatedTablesFactory(),
|
||||
sqlmigration.NewUpdateAgentsFactory(sqlstore),
|
||||
sqlmigration.NewUpdateUsersFactory(sqlstore, sqlschema),
|
||||
sqlmigration.NewUpdateUserInviteFactory(sqlstore, sqlschema),
|
||||
sqlmigration.NewUpdateOrgDomainFactory(sqlstore, sqlschema),
|
||||
sqlmigration.NewAddFactorIndexesFactory(sqlstore, sqlschema),
|
||||
sqlmigration.NewQueryBuilderV5MigrationFactory(sqlstore, telemetryStore),
|
||||
sqlmigration.NewAddMeterQuickFiltersFactory(sqlstore, sqlschema),
|
||||
sqlmigration.NewUpdateTTLSettingForCustomRetentionFactory(sqlstore, sqlschema),
|
||||
sqlmigration.NewAddRoutePolicyFactory(sqlstore, sqlschema),
|
||||
sqlmigration.NewAddAuthTokenFactory(sqlstore, sqlschema),
|
||||
s100sqlmigration.NewV100Factory(sqlstore, sqlschema),
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -45,8 +45,6 @@ func TestNewProviderFactories(t *testing.T) {
|
||||
NewSQLMigrationProviderFactories(
|
||||
sqlstoretest.New(sqlstore.Config{Provider: "sqlite"}, sqlmock.QueryMatcherEqual),
|
||||
sqlschematest.New(map[string]*sqlschema.Table{}, map[string][]*sqlschema.UniqueConstraint{}, map[string]sqlschema.Index{}),
|
||||
telemetrystoretest.New(telemetrystore.Config{Provider: "clickhouse"}, sqlmock.QueryMatcherEqual),
|
||||
instrumentationtest.New().ToProviderSettings(),
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -205,7 +205,7 @@ func New(
|
||||
ctx,
|
||||
providerSettings,
|
||||
config.SQLMigration,
|
||||
NewSQLMigrationProviderFactories(sqlstore, sqlschema, telemetrystore, providerSettings),
|
||||
NewSQLMigrationProviderFactories(sqlstore, sqlschema),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addDataMigrations struct{}
|
||||
|
||||
func NewAddDataMigrationsFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_data_migrations"), newAddDataMigrations)
|
||||
}
|
||||
|
||||
func newAddDataMigrations(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &addDataMigrations{}, nil
|
||||
}
|
||||
|
||||
func (migration *addDataMigrations) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addDataMigrations) Up(ctx context.Context, db *bun.DB) error {
|
||||
// table:data_migrations
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:data_migrations"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
Version string `bun:"version,unique,notnull,type:VARCHAR(255)"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp"`
|
||||
Succeeded bool `bun:"succeeded,notnull,default:false"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addDataMigrations) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addOrganization struct{}
|
||||
|
||||
func NewAddOrganizationFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_organization"), newAddOrganization)
|
||||
}
|
||||
|
||||
func newAddOrganization(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &addOrganization{}, nil
|
||||
}
|
||||
|
||||
func (migration *addOrganization) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addOrganization) Up(ctx context.Context, db *bun.DB) error {
|
||||
|
||||
// table:organizations
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:organizations"`
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
Name string `bun:"name,type:text,notnull"`
|
||||
CreatedAt int `bun:"created_at,notnull"`
|
||||
IsAnonymous int `bun:"is_anonymous,notnull,default:0"`
|
||||
HasOptedUpdates int `bun:"has_opted_updates,notnull,default:1"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:groups
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:groups"`
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
Name string `bun:"name,type:text,notnull,unique"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:users
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:users"`
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
Name string `bun:"name,type:text,notnull"`
|
||||
Email string `bun:"email,type:text,notnull,unique"`
|
||||
Password string `bun:"password,type:text,notnull"`
|
||||
CreatedAt int `bun:"created_at,notnull"`
|
||||
ProfilePictureURL string `bun:"profile_picture_url,type:text"`
|
||||
GroupID string `bun:"group_id,type:text,notnull"`
|
||||
OrgID string `bun:"org_id,type:text,notnull"`
|
||||
}{}).
|
||||
ForeignKey(`("org_id") REFERENCES "organizations" ("id")`).
|
||||
ForeignKey(`("group_id") REFERENCES "groups" ("id")`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:invites
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:invites"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
Name string `bun:"name,type:text,notnull"`
|
||||
Email string `bun:"email,type:text,notnull,unique"`
|
||||
Token string `bun:"token,type:text,notnull"`
|
||||
CreatedAt int `bun:"created_at,notnull"`
|
||||
Role string `bun:"role,type:text,notnull"`
|
||||
OrgID string `bun:"org_id,type:text,notnull"`
|
||||
}{}).
|
||||
ForeignKey(`("org_id") REFERENCES "organizations" ("id")`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:reset_password_request
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:reset_password_request"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
Token string `bun:"token,type:text,notnull"`
|
||||
UserID string `bun:"user_id,type:text,notnull"`
|
||||
}{}).
|
||||
ForeignKey(`("user_id") REFERENCES "users" ("id")`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:user_flags
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:user_flags"`
|
||||
UserID string `bun:"user_id,pk,type:text,notnull"`
|
||||
Flags string `bun:"flags,type:text"`
|
||||
}{}).
|
||||
ForeignKey(`("user_id") REFERENCES "users" ("id")`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:apdex_settings
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:apdex_settings"`
|
||||
ServiceName string `bun:"service_name,pk,type:text"`
|
||||
Threshold float64 `bun:"threshold,type:float,notnull"`
|
||||
ExcludeStatusCodes string `bun:"exclude_status_codes,type:text,notnull"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:ingestion_keys
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:ingestion_keys"`
|
||||
KeyId string `bun:"key_id,pk,type:text"`
|
||||
Name string `bun:"name,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,default:current_timestamp"`
|
||||
IngestionKey string `bun:"ingestion_key,type:text,notnull"`
|
||||
IngestionURL string `bun:"ingestion_url,type:text,notnull"`
|
||||
DataRegion string `bun:"data_region,type:text,notnull"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addOrganization) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addPreferences struct{}
|
||||
|
||||
func NewAddPreferencesFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_preferences"), newAddPreferences)
|
||||
}
|
||||
|
||||
func newAddPreferences(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &addPreferences{}, nil
|
||||
}
|
||||
|
||||
func (migration *addPreferences) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addPreferences) Up(ctx context.Context, db *bun.DB) error {
|
||||
// table:user_preference
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:user_preference"`
|
||||
PreferenceID string `bun:"preference_id,type:text,pk"`
|
||||
PreferenceValue string `bun:"preference_value,type:text"`
|
||||
UserID string `bun:"user_id,type:text,pk"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
ForeignKey(`("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE`).
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:org_preference
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:org_preference"`
|
||||
PreferenceID string `bun:"preference_id,pk,type:text,notnull"`
|
||||
PreferenceValue string `bun:"preference_value,type:text,notnull"`
|
||||
OrgID string `bun:"org_id,pk,type:text,notnull"`
|
||||
}{}).
|
||||
ForeignKey(`("org_id") REFERENCES "organizations" ("id") ON DELETE CASCADE ON UPDATE CASCADE`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addPreferences) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addDashboards struct{}
|
||||
|
||||
func NewAddDashboardsFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_dashboards"), newAddDashboards)
|
||||
}
|
||||
|
||||
func newAddDashboards(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &addDashboards{}, nil
|
||||
}
|
||||
|
||||
func (migration *addDashboards) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addDashboards) Up(ctx context.Context, db *bun.DB) error {
|
||||
// table:dashboards
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:dashboards"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
UUID string `bun:"uuid,type:text,notnull,unique"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull"`
|
||||
CreatedBy string `bun:"created_by,type:text,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
||||
UpdatedBy string `bun:"updated_by,type:text,notnull"`
|
||||
Data string `bun:"data,type:text,notnull"`
|
||||
Locked int `bun:"locked,notnull,default:0"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:rules
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:rules"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull"`
|
||||
CreatedBy string `bun:"created_by,type:text,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
||||
UpdatedBy string `bun:"updated_by,type:text,notnull"`
|
||||
Deleted int `bun:"deleted,notnull,default:0"`
|
||||
Data string `bun:"data,type:text,notnull"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:notification_channels
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:notification_channels"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
||||
Name string `bun:"name,type:text,notnull,unique"`
|
||||
Type string `bun:"type,type:text,notnull"`
|
||||
Deleted int `bun:"deleted,notnull,default:0"`
|
||||
Data string `bun:"data,type:text,notnull"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:planned_maintenance
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:planned_maintenance"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
Name string `bun:"name,type:text,notnull"`
|
||||
Description string `bun:"description,type:text"`
|
||||
AlertIDs string `bun:"alert_ids,type:text"`
|
||||
Schedule string `bun:"schedule,type:text,notnull"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull"`
|
||||
CreatedBy string `bun:"created_by,type:text,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
||||
UpdatedBy string `bun:"updated_by,type:text,notnull"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// table:ttl_status
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:ttl_status"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
TransactionID string `bun:"transaction_id,type:text,notnull"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
||||
TableName string `bun:"table_name,type:text,notnull"`
|
||||
TTL int `bun:"ttl,notnull,default:0"`
|
||||
ColdStorageTTL int `bun:"cold_storage_ttl,notnull,default:0"`
|
||||
Status string `bun:"status,type:text,notnull"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addDashboards) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addSavedViews struct{}
|
||||
|
||||
func NewAddSavedViewsFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_saved_views"), newAddSavedViews)
|
||||
}
|
||||
|
||||
func newAddSavedViews(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &addSavedViews{}, nil
|
||||
}
|
||||
|
||||
func (migration *addSavedViews) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addSavedViews) Up(ctx context.Context, db *bun.DB) error {
|
||||
// table:saved_views op:create
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:saved_views"`
|
||||
UUID string `bun:"uuid,pk,type:text"`
|
||||
Name string `bun:"name,type:text,notnull"`
|
||||
Category string `bun:"category,type:text,notnull"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull"`
|
||||
CreatedBy string `bun:"created_by,type:text"`
|
||||
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
||||
UpdatedBy string `bun:"updated_by,type:text"`
|
||||
SourcePage string `bun:"source_page,type:text,notnull"`
|
||||
Tags string `bun:"tags,type:text"`
|
||||
Data string `bun:"data,type:text,notnull"`
|
||||
ExtraData string `bun:"extra_data,type:text"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addSavedViews) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addAgents struct{}
|
||||
|
||||
func NewAddAgentsFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_agents"), newAddAgents)
|
||||
}
|
||||
|
||||
func newAddAgents(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &addAgents{}, nil
|
||||
}
|
||||
|
||||
func (migration *addAgents) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addAgents) Up(ctx context.Context, db *bun.DB) error {
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:agents"`
|
||||
AgentID string `bun:"agent_id,pk,type:text,unique"`
|
||||
StartedAt time.Time `bun:"started_at,notnull"`
|
||||
TerminatedAt time.Time `bun:"terminated_at"`
|
||||
CurrentStatus string `bun:"current_status,type:text,notnull"`
|
||||
EffectiveConfig string `bun:"effective_config,type:text,notnull"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:agent_config_versions"`
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
CreatedBy string `bun:"created_by,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,default:CURRENT_TIMESTAMP"`
|
||||
UpdatedBy string `bun:"updated_by,type:text"`
|
||||
UpdatedAt time.Time `bun:"updated_at,default:CURRENT_TIMESTAMP"`
|
||||
Version int `bun:"version,default:1,unique:element_version_idx"`
|
||||
Active int `bun:"active"`
|
||||
IsValid int `bun:"is_valid"`
|
||||
Disabled int `bun:"disabled"`
|
||||
ElementType string `bun:"element_type,notnull,type:varchar(120),unique:element_version_idx"`
|
||||
DeployStatus string `bun:"deploy_status,notnull,type:varchar(80),default:'DIRTY'"`
|
||||
DeploySequence int `bun:"deploy_sequence"`
|
||||
DeployResult string `bun:"deploy_result,type:text"`
|
||||
LastHash string `bun:"last_hash,type:text"`
|
||||
LastConfig string `bun:"last_config,type:text"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add an index on the last_hash column
|
||||
if _, err := db.NewCreateIndex().
|
||||
Table("agent_config_versions").
|
||||
Column("last_hash").
|
||||
Index("idx_agent_config_versions_last_hash").
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:agent_config_elements"`
|
||||
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
CreatedBy string `bun:"created_by,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,default:CURRENT_TIMESTAMP"`
|
||||
UpdatedBy string `bun:"updated_by,type:text"`
|
||||
UpdatedAt time.Time `bun:"updated_at,default:CURRENT_TIMESTAMP"`
|
||||
ElementID string `bun:"element_id,type:text,notnull,unique:agent_config_elements_u1"`
|
||||
ElementType string `bun:"element_type,type:varchar(120),notnull,unique:agent_config_elements_u1"`
|
||||
VersionID string `bun:"version_id,type:text,notnull,unique:agent_config_elements_u1"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addAgents) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addPipelines struct{}
|
||||
|
||||
func NewAddPipelinesFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_pipelines"), newAddPipelines)
|
||||
}
|
||||
|
||||
func newAddPipelines(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &addPipelines{}, nil
|
||||
}
|
||||
|
||||
func (migration *addPipelines) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addPipelines) Up(ctx context.Context, db *bun.DB) error {
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:pipelines"`
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
OrderID int `bun:"order_id"`
|
||||
Enabled bool `bun:"enabled"`
|
||||
CreatedBy string `bun:"created_by,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,default:current_timestamp"`
|
||||
Name string `bun:"name,type:varchar(400),notnull"`
|
||||
Alias string `bun:"alias,type:varchar(20),notnull"`
|
||||
Description string `bun:"description,type:text"`
|
||||
Filter string `bun:"filter,type:text,notnull"`
|
||||
ConfigJSON string `bun:"config_json,type:text"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addPipelines) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addIntegrations struct{}
|
||||
|
||||
func NewAddIntegrationsFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_integrations"), newAddIntegrations)
|
||||
}
|
||||
|
||||
func newAddIntegrations(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &addIntegrations{}, nil
|
||||
}
|
||||
|
||||
func (migration *addIntegrations) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addIntegrations) Up(ctx context.Context, db *bun.DB) error {
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:integrations_installed"`
|
||||
|
||||
IntegrationID string `bun:"integration_id,pk,type:text"`
|
||||
ConfigJSON string `bun:"config_json,type:text"`
|
||||
InstalledAt time.Time `bun:"installed_at,default:current_timestamp"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:cloud_integrations_accounts"`
|
||||
CloudProvider string `bun:"cloud_provider,type:text,unique:cloud_provider_id"`
|
||||
ID string `bun:"id,type:text,notnull,unique:cloud_provider_id"`
|
||||
ConfigJSON string `bun:"config_json,type:text"`
|
||||
CloudAccountID string `bun:"cloud_account_id,type:text"`
|
||||
LastAgentReportJSON string `bun:"last_agent_report_json,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp"`
|
||||
RemovedAt time.Time `bun:"removed_at,type:timestamp"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:cloud_integrations_service_configs"`
|
||||
CloudProvider string `bun:"cloud_provider,type:text,notnull,unique:service_cloud_provider_account"`
|
||||
CloudAccountID string `bun:"cloud_account_id,type:text,notnull,unique:service_cloud_provider_account"`
|
||||
ServiceID string `bun:"service_id,type:text,notnull,unique:service_cloud_provider_account"`
|
||||
ConfigJSON string `bun:"config_json,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,default:current_timestamp"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addIntegrations) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addLicenses struct{}
|
||||
|
||||
func NewAddLicensesFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_licenses"), newAddLicenses)
|
||||
}
|
||||
|
||||
func newAddLicenses(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &addLicenses{}, nil
|
||||
}
|
||||
|
||||
func (migration *addLicenses) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addLicenses) Up(ctx context.Context, db *bun.DB) error {
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:licenses"`
|
||||
Key string `bun:"key,pk,type:text"`
|
||||
CreatedAt time.Time `bun:"createdAt,default:current_timestamp"`
|
||||
UpdatedAt time.Time `bun:"updatedAt,default:current_timestamp"`
|
||||
PlanDetails string `bun:"planDetails,type:text"`
|
||||
ActivationID string `bun:"activationId,type:text"`
|
||||
ValidationMessage string `bun:"validationMessage,type:text"`
|
||||
LastValidated time.Time `bun:"lastValidated,default:current_timestamp"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:sites"`
|
||||
|
||||
UUID string `bun:"uuid,pk,type:text"`
|
||||
Alias string `bun:"alias,type:varchar(180),default:'PROD'"`
|
||||
URL string `bun:"url,type:varchar(300)"`
|
||||
CreatedAt time.Time `bun:"createdAt,default:current_timestamp"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:feature_status"`
|
||||
Name string `bun:"name,pk,type:text"`
|
||||
Active bool `bun:"active"`
|
||||
Usage int `bun:"usage,default:0"`
|
||||
UsageLimit int `bun:"usage_limit,default:0"`
|
||||
Route string `bun:"route,type:text"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:licenses_v3"`
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
Key string `bun:"key,type:text,notnull,unique"`
|
||||
Data string `bun:"data,type:text"`
|
||||
}{}).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addLicenses) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addPats struct{}
|
||||
|
||||
func NewAddPatsFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_pats"), newAddPats)
|
||||
}
|
||||
|
||||
func newAddPats(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &addPats{}, nil
|
||||
}
|
||||
|
||||
func (migration *addPats) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addPats) Up(ctx context.Context, db *bun.DB) error {
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:org_domains"`
|
||||
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
OrgID string `bun:"org_id,type:text,notnull"`
|
||||
Name string `bun:"name,type:varchar(50),notnull,unique"`
|
||||
CreatedAt int `bun:"created_at,notnull"`
|
||||
UpdatedAt int `bun:"updated_at"`
|
||||
Data string `bun:"data,type:text,notnull"`
|
||||
}{}).
|
||||
ForeignKey(`("org_id") REFERENCES "organizations" ("id")`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:personal_access_tokens"`
|
||||
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
Role string `bun:"role,type:text,notnull,default:'ADMIN'"`
|
||||
UserID string `bun:"user_id,type:text,notnull"`
|
||||
Token string `bun:"token,type:text,notnull,unique"`
|
||||
Name string `bun:"name,type:text,notnull"`
|
||||
CreatedAt int `bun:"created_at,notnull,default:0"`
|
||||
ExpiresAt int `bun:"expires_at,notnull,default:0"`
|
||||
UpdatedAt int `bun:"updated_at,notnull,default:0"`
|
||||
LastUsed int `bun:"last_used,notnull,default:0"`
|
||||
Revoked bool `bun:"revoked,notnull,default:false"`
|
||||
UpdatedByUserID string `bun:"updated_by_user_id,type:text,notnull,default:''"`
|
||||
}{}).
|
||||
ForeignKey(`("user_id") REFERENCES "users" ("id")`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addPats) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type modifyDatetime struct{}
|
||||
|
||||
func NewModifyDatetimeFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("modify_datetime"), newModifyDatetime)
|
||||
}
|
||||
|
||||
func newModifyDatetime(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &modifyDatetime{}, nil
|
||||
}
|
||||
|
||||
func (migration *modifyDatetime) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *modifyDatetime) Up(ctx context.Context, db *bun.DB) error {
|
||||
// only run this for old sqlite db
|
||||
if db.Dialect().Name().String() != "sqlite" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// begin transaction
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
tables := []string{"dashboards", "rules", "planned_maintenance", "ttl_status", "saved_views"}
|
||||
columns := []string{"created_at", "updated_at"}
|
||||
for _, table := range tables {
|
||||
for _, column := range columns {
|
||||
if err := modifyColumn(ctx, tx, table, column); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, column := range []string{"started_at", "terminated_at"} {
|
||||
if err := modifyColumn(ctx, tx, "agents", column); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func modifyColumn(ctx context.Context, tx bun.Tx, table string, column string) error {
|
||||
// rename old column
|
||||
if _, err := tx.ExecContext(ctx, `ALTER TABLE `+table+` RENAME COLUMN `+column+` TO `+column+`_old`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// cannot add not null constraint to the column
|
||||
if _, err := tx.ExecContext(ctx, `ALTER TABLE `+table+` ADD COLUMN `+column+` TIMESTAMP`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// update the new column with the value of the old column
|
||||
if _, err := tx.ExecContext(ctx, `UPDATE `+table+` SET `+column+` = `+column+`_old`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// drop the old column
|
||||
if _, err := tx.ExecContext(ctx, `ALTER TABLE `+table+` DROP COLUMN `+column+`_old`); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *modifyDatetime) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/dialect"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type modifyOrgDomain struct{}
|
||||
|
||||
func NewModifyOrgDomainFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("modify_org_domain"), newModifyOrgDomain)
|
||||
}
|
||||
|
||||
func newModifyOrgDomain(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &modifyOrgDomain{}, nil
|
||||
}
|
||||
|
||||
func (migration *modifyOrgDomain) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *modifyOrgDomain) Up(ctx context.Context, db *bun.DB) error {
|
||||
// only run this for old sqlite db
|
||||
if db.Dialect().Name() != dialect.SQLite {
|
||||
return nil
|
||||
}
|
||||
|
||||
// begin transaction
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
// rename old column
|
||||
if _, err := tx.ExecContext(ctx, `ALTER TABLE org_domains RENAME COLUMN updated_at TO updated_at_old`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.ExecContext(ctx, `ALTER TABLE org_domains ADD COLUMN updated_at INTEGER`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.ExecContext(ctx, `UPDATE org_domains SET updated_at = CAST(updated_at_old AS INTEGER)`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// drop the old column
|
||||
if _, err := tx.ExecContext(ctx, `ALTER TABLE org_domains DROP COLUMN updated_at_old`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *modifyOrgDomain) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateOrganization struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewUpdateOrganizationFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_organization"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateOrganization(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateOrganization(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateOrganization{
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *updateOrganization) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateOrganization) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
// update apdex settings table
|
||||
if err := updateApdexSettings(ctx, tx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// drop user_flags table
|
||||
if _, err := tx.NewDropTable().IfExists().Table("user_flags").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add org id to groups table
|
||||
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, "groups", "org_id"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := tx.NewAddColumn().Table("groups").ColumnExpr("org_id TEXT").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// add created_at to groups table
|
||||
for _, table := range []string{"groups"} {
|
||||
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, table, "created_at"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := tx.NewAddColumn().Table(table).ColumnExpr("created_at TIMESTAMP").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add updated_at to organizations, users, groups table
|
||||
for _, table := range []string{"organizations", "users", "groups"} {
|
||||
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, table, "updated_at"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := tx.NewAddColumn().Table(table).ColumnExpr("updated_at TIMESTAMP").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// since organizations, users has created_at as integer instead of timestamp
|
||||
for _, table := range []string{"organizations", "users", "invites"} {
|
||||
if err := migration.store.Dialect().IntToTimestamp(ctx, tx, table, "created_at"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// migrate is_anonymous and has_opted_updates to boolean from int
|
||||
for _, column := range []string{"is_anonymous", "has_opted_updates"} {
|
||||
if err := migration.store.Dialect().IntToBoolean(ctx, tx, "organizations", column); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateOrganization) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateApdexSettings(ctx context.Context, tx bun.Tx) error {
|
||||
if _, err := tx.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:apdex_settings_new"`
|
||||
OrgID string `bun:"org_id,pk,type:text"`
|
||||
ServiceName string `bun:"service_name,pk,type:text"`
|
||||
Threshold float64 `bun:"threshold,type:float,notnull"`
|
||||
ExcludeStatusCodes string `bun:"exclude_status_codes,type:text,notnull"`
|
||||
}{}).
|
||||
ForeignKey(`("org_id") REFERENCES "organizations" ("id")`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get org id from organizations table
|
||||
var orgID string
|
||||
if err := tx.QueryRowContext(ctx, `SELECT id FROM organizations LIMIT 1`).Scan(&orgID); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return err
|
||||
}
|
||||
|
||||
if orgID != "" {
|
||||
// copy old data
|
||||
if _, err := tx.ExecContext(ctx, `INSERT INTO apdex_settings_new (org_id, service_name, threshold, exclude_status_codes) SELECT ?, service_name, threshold, exclude_status_codes FROM apdex_settings`, orgID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// drop old table
|
||||
if _, err := tx.NewDropTable().IfExists().Table("apdex_settings").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// rename new table to old table
|
||||
if _, err := tx.ExecContext(ctx, `ALTER TABLE apdex_settings_new RENAME TO apdex_settings`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/alertmanager/alertmanagerserver"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types/alertmanagertypes"
|
||||
"github.com/prometheus/alertmanager/config"
|
||||
"github.com/tidwall/gjson"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addAlertmanager struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewAddAlertmanagerFactory(store sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_alertmanager"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newAddAlertmanager(ctx, ps, c, store)
|
||||
})
|
||||
}
|
||||
|
||||
func newAddAlertmanager(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &addAlertmanager{
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *addAlertmanager) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addAlertmanager) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, "notification_channels", "deleted"); err != nil {
|
||||
return err
|
||||
} else if exists {
|
||||
if _, err := tx.
|
||||
NewDropColumn().
|
||||
Table("notification_channels").
|
||||
ColumnExpr("deleted").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, "notification_channels", "org_id"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := tx.
|
||||
NewAddColumn().
|
||||
Table("notification_channels").
|
||||
ColumnExpr("org_id TEXT REFERENCES organizations(id) ON DELETE CASCADE").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := tx.
|
||||
NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:alertmanager_config"`
|
||||
ID uint64 `bun:"id,pk,autoincrement"`
|
||||
Config string `bun:"config,notnull,type:text"`
|
||||
Hash string `bun:"hash,notnull,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
||||
OrgID string `bun:"org_id,notnull,unique"`
|
||||
}{}).
|
||||
ForeignKey(`("org_id") REFERENCES "organizations" ("id")`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.
|
||||
NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:alertmanager_state"`
|
||||
ID uint64 `bun:"id,pk,autoincrement"`
|
||||
Silences string `bun:"silences,nullzero,type:text"`
|
||||
NFLog string `bun:"nflog,nullzero,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
||||
OrgID string `bun:"org_id,notnull,unique"`
|
||||
}{}).
|
||||
ForeignKey(`("org_id") REFERENCES "organizations" ("id")`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var orgID string
|
||||
err = tx.
|
||||
NewSelect().
|
||||
ColumnExpr("id").
|
||||
Table("organizations").
|
||||
Limit(1).
|
||||
Scan(ctx, &orgID)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
if err := migration.populateOrgIDInChannels(ctx, tx, orgID); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migration.populateAlertmanagerConfig(ctx, tx, orgID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addAlertmanager) populateOrgIDInChannels(ctx context.Context, tx bun.Tx, orgID string) error {
|
||||
if _, err := tx.
|
||||
NewUpdate().
|
||||
Table("notification_channels").
|
||||
Set("org_id = ?", orgID).
|
||||
Where("org_id IS NULL").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addAlertmanager) populateAlertmanagerConfig(ctx context.Context, tx bun.Tx, orgID string) error {
|
||||
var channels []*alertmanagertypes.Channel
|
||||
|
||||
err := tx.
|
||||
NewSelect().
|
||||
Model(&channels).
|
||||
Where("org_id = ?", orgID).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var receiversFromChannels []string
|
||||
for _, channel := range channels {
|
||||
receiversFromChannels = append(receiversFromChannels, channel.Name)
|
||||
}
|
||||
|
||||
type matcher struct {
|
||||
bun.BaseModel `bun:"table:rules"`
|
||||
ID int `bun:"id,pk"`
|
||||
Data string `bun:"data"`
|
||||
}
|
||||
|
||||
matchers := []matcher{}
|
||||
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Column("id", "data").
|
||||
Model(&matchers).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
matchersMap := make(map[string][]string)
|
||||
for _, matcher := range matchers {
|
||||
receivers := gjson.Get(matcher.Data, "preferredChannels").Array()
|
||||
for _, receiver := range receivers {
|
||||
matchersMap[strconv.Itoa(matcher.ID)] = append(matchersMap[strconv.Itoa(matcher.ID)], receiver.String())
|
||||
}
|
||||
|
||||
if len(receivers) == 0 {
|
||||
matchersMap[strconv.Itoa(matcher.ID)] = append(matchersMap[strconv.Itoa(matcher.ID)], receiversFromChannels...)
|
||||
}
|
||||
}
|
||||
|
||||
for _, channel := range channels {
|
||||
if err := migration.msTeamsChannelToMSTeamsV2Channel(channel); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
config, err := alertmanagertypes.NewConfigFromChannels(alertmanagerserver.NewConfig().Global, alertmanagerserver.NewConfig().Route, channels, orgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for ruleID, receivers := range matchersMap {
|
||||
err = config.CreateRuleIDMatcher(ruleID, receivers)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := tx.
|
||||
NewInsert().
|
||||
Model(config.StoreableConfig()).
|
||||
On("CONFLICT (org_id) DO UPDATE").
|
||||
Set("config = ?", config.StoreableConfig().Config).
|
||||
Set("hash = ?", config.StoreableConfig().Hash).
|
||||
Set("updated_at = ?", config.StoreableConfig().UpdatedAt).
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, channel := range channels {
|
||||
if channel.Type == "msteamsv2" {
|
||||
if _, err := tx.
|
||||
NewUpdate().
|
||||
Model(channel).
|
||||
WherePK().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addAlertmanager) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addAlertmanager) msTeamsChannelToMSTeamsV2Channel(c *alertmanagertypes.Channel) error {
|
||||
if c.Type != "msteams" {
|
||||
return nil
|
||||
}
|
||||
|
||||
receiver, err := alertmanagertypes.NewReceiver(c.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
receiver = migration.msTeamsReceiverToMSTeamsV2Receiver(receiver)
|
||||
data, err := json.Marshal(receiver)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.Type = "msteamsv2"
|
||||
c.Data = string(data)
|
||||
c.UpdatedAt = time.Now()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addAlertmanager) msTeamsReceiverToMSTeamsV2Receiver(receiver alertmanagertypes.Receiver) alertmanagertypes.Receiver {
|
||||
if receiver.MSTeamsConfigs == nil {
|
||||
return receiver
|
||||
}
|
||||
|
||||
var msTeamsV2Configs []*config.MSTeamsV2Config
|
||||
for _, cfg := range receiver.MSTeamsConfigs {
|
||||
msTeamsV2Configs = append(msTeamsV2Configs, &config.MSTeamsV2Config{
|
||||
NotifierConfig: cfg.NotifierConfig,
|
||||
HTTPConfig: cfg.HTTPConfig,
|
||||
WebhookURL: cfg.WebhookURL,
|
||||
WebhookURLFile: cfg.WebhookURLFile,
|
||||
Title: cfg.Title,
|
||||
Text: cfg.Text,
|
||||
})
|
||||
}
|
||||
|
||||
receiver.MSTeamsConfigs = nil
|
||||
receiver.MSTeamsV2Configs = msTeamsV2Configs
|
||||
|
||||
return receiver
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
type updateDashboardAndSavedViews struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewUpdateDashboardAndSavedViewsFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_group"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateDashboardAndSavedViews(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateDashboardAndSavedViews(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateDashboardAndSavedViews{
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *updateDashboardAndSavedViews) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateDashboardAndSavedViews) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
// get all org ids
|
||||
var orgIDs []string
|
||||
if err := migration.store.BunDB().NewSelect().Model((*types.Organization)(nil)).Column("id").Scan(ctx, &orgIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add org id to dashboards table
|
||||
for _, table := range []string{"dashboards", "saved_views"} {
|
||||
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, table, "org_id"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := tx.NewAddColumn().Table(table).ColumnExpr("org_id TEXT REFERENCES organizations(id) ON DELETE CASCADE").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if there is one org ID if yes then set it to all dashboards.
|
||||
if len(orgIDs) == 1 {
|
||||
orgID := orgIDs[0]
|
||||
if _, err := tx.NewUpdate().Table(table).Set("org_id = ?", orgID).Where("org_id IS NULL").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateDashboardAndSavedViews) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
type updatePatAndOrgDomains struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewUpdatePatAndOrgDomainsFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_pat_and_org_domains"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdatePatAndOrgDomains(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdatePatAndOrgDomains(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updatePatAndOrgDomains{
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *updatePatAndOrgDomains) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updatePatAndOrgDomains) Up(ctx context.Context, db *bun.DB) error {
|
||||
// begin transaction
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
// get all org ids
|
||||
var orgIDs []string
|
||||
if err := tx.NewSelect().Model((*types.Organization)(nil)).Column("id").Scan(ctx, &orgIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add org id to pat and org_domains table
|
||||
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, "personal_access_tokens", "org_id"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := tx.NewAddColumn().Table("personal_access_tokens").ColumnExpr("org_id TEXT REFERENCES organizations(id) ON DELETE CASCADE").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if there is one org ID if yes then set it to all personal_access_tokens.
|
||||
if len(orgIDs) == 1 {
|
||||
orgID := orgIDs[0]
|
||||
if _, err := tx.NewUpdate().Table("personal_access_tokens").Set("org_id = ?", orgID).Where("org_id IS NULL").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := updateOrgId(ctx, tx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// change created_at and updated_at from integer to timestamp
|
||||
for _, table := range []string{"personal_access_tokens", "org_domains"} {
|
||||
if err := migration.store.Dialect().IntToTimestamp(ctx, tx, table, "created_at"); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := migration.store.Dialect().IntToTimestamp(ctx, tx, table, "updated_at"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// drop table if exists ingestion_keys
|
||||
if _, err := tx.NewDropTable().IfExists().Table("ingestion_keys").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updatePatAndOrgDomains) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func updateOrgId(ctx context.Context, tx bun.Tx) error {
|
||||
if _, err := tx.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:org_domains_new"`
|
||||
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
OrgID string `bun:"org_id,type:text,notnull"`
|
||||
Name string `bun:"name,type:varchar(50),notnull,unique"`
|
||||
CreatedAt int `bun:"created_at,notnull"`
|
||||
UpdatedAt int `bun:"updated_at"`
|
||||
Data string `bun:"data,type:text,notnull"`
|
||||
}{}).
|
||||
ForeignKey(`("org_id") REFERENCES "organizations" ("id") ON DELETE CASCADE`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// copy data from org_domains to org_domains_new
|
||||
if _, err := tx.ExecContext(ctx, `INSERT INTO org_domains_new (id, org_id, name, created_at, updated_at, data) SELECT id, org_id, name, created_at, updated_at, data FROM org_domains`); err != nil {
|
||||
return err
|
||||
}
|
||||
// delete old table
|
||||
if _, err := tx.NewDropTable().IfExists().Table("org_domains").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// rename new table to org_domains
|
||||
if _, err := tx.ExecContext(ctx, `ALTER TABLE org_domains_new RENAME TO org_domains`); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
type updatePipelines struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewUpdatePipelines(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_pipelines"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdatePipelines(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdatePipelines(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updatePipelines{
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *updatePipelines) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updatePipelines) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
// get all org ids
|
||||
var orgIDs []string
|
||||
if err := migration.store.BunDB().NewSelect().Model((*types.Organization)(nil)).Column("id").Scan(ctx, &orgIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add org id to pipelines table
|
||||
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, "pipelines", "org_id"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := tx.NewAddColumn().Table("pipelines").ColumnExpr("org_id TEXT REFERENCES organizations(id) ON DELETE CASCADE").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// check if there is one org ID if yes then set it to all pipelines.
|
||||
if len(orgIDs) == 1 {
|
||||
orgID := orgIDs[0]
|
||||
if _, err := tx.NewUpdate().Table("pipelines").Set("org_id = ?", orgID).Where("org_id IS NULL").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add updated_by to pipelines table
|
||||
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, "pipelines", "updated_by"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := tx.NewAddColumn().Table("pipelines").ColumnExpr("updated_by TEXT").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// add updated_at to pipelines table
|
||||
if exists, err := migration.store.Dialect().ColumnExists(ctx, tx, "pipelines", "updated_at"); err != nil {
|
||||
return err
|
||||
} else if !exists {
|
||||
if _, err := tx.NewAddColumn().Table("pipelines").ColumnExpr("updated_at TIMESTAMP").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updatePipelines) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type dropLicensesSites struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewDropLicensesSitesFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("drop_licenses_sites"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newDropLicensesSites(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newDropLicensesSites(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &dropLicensesSites{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *dropLicensesSites) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *dropLicensesSites) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
if _, err := tx.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Table("sites").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Table("licenses").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameColumn(ctx, tx, "saved_views", "uuid", "id")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *dropLicensesSites) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,135 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateInvites struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
type existingInvite struct {
|
||||
bun.BaseModel `bun:"table:invites"`
|
||||
|
||||
OrgID string `bun:"org_id,type:text,notnull" json:"orgId"`
|
||||
ID int `bun:"id,pk,autoincrement" json:"id"`
|
||||
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"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull" json:"createdAt"`
|
||||
Role string `bun:"role,type:text,notnull" json:"role"`
|
||||
}
|
||||
|
||||
type newInvite struct {
|
||||
bun.BaseModel `bun:"table:user_invite"`
|
||||
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
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"`
|
||||
Role string `bun:"role,type:text,notnull" json:"role"`
|
||||
OrgID string `bun:"org_id,type:text,notnull" json:"orgId"`
|
||||
}
|
||||
|
||||
func NewUpdateInvitesFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_invites"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateInvites(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateInvites(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateInvites{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *updateInvites) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateInvites) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingInvite), new(newInvite), []string{OrgReference}, func(ctx context.Context) error {
|
||||
existingInvites := make([]*existingInvite, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingInvites).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingInvites) > 0 {
|
||||
newInvites := migration.CopyOldInvitesToNewInvites(existingInvites)
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newInvites).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateInvites) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateInvites) CopyOldInvitesToNewInvites(existingInvites []*existingInvite) []*newInvite {
|
||||
newInvites := make([]*newInvite, 0)
|
||||
for _, invite := range existingInvites {
|
||||
newInvites = append(newInvites, &newInvite{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: invite.CreatedAt,
|
||||
UpdatedAt: time.Now(),
|
||||
},
|
||||
Name: invite.Name,
|
||||
Email: invite.Email,
|
||||
Token: invite.Token,
|
||||
Role: invite.Role,
|
||||
OrgID: invite.OrgID,
|
||||
})
|
||||
}
|
||||
|
||||
return newInvites
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updatePat struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewUpdatePatFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_pat"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdatePat(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdatePat(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updatePat{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *updatePat) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updatePat) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
for _, column := range []string{"last_used", "expires_at"} {
|
||||
if err := migration.
|
||||
store.
|
||||
Dialect().
|
||||
AddNotNullDefaultToColumn(ctx, tx, "personal_access_tokens", column, "INTEGER", "0"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := migration.
|
||||
store.
|
||||
Dialect().
|
||||
AddNotNullDefaultToColumn(ctx, tx, "personal_access_tokens", "revoked", "BOOLEAN", "false"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migration.
|
||||
store.
|
||||
Dialect().
|
||||
AddNotNullDefaultToColumn(ctx, tx, "personal_access_tokens", "updated_by_user_id", "TEXT", "''"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updatePat) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,274 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateAlertmanager struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
type existingChannel struct {
|
||||
bun.BaseModel `bun:"table:notification_channels"`
|
||||
ID int `json:"id" bun:"id,pk,autoincrement"`
|
||||
Name string `json:"name" bun:"name"`
|
||||
Type string `json:"type" bun:"type"`
|
||||
Data string `json:"data" bun:"data"`
|
||||
CreatedAt time.Time `json:"created_at" bun:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at" bun:"updated_at"`
|
||||
OrgID string `json:"org_id" bun:"org_id"`
|
||||
}
|
||||
|
||||
type newChannel struct {
|
||||
bun.BaseModel `bun:"table:notification_channel"`
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
Name string `json:"name" bun:"name"`
|
||||
Type string `json:"type" bun:"type"`
|
||||
Data string `json:"data" bun:"data"`
|
||||
OrgID string `json:"org_id" bun:"org_id"`
|
||||
}
|
||||
|
||||
type existingAlertmanagerConfig struct {
|
||||
bun.BaseModel `bun:"table:alertmanager_config"`
|
||||
ID uint64 `bun:"id,pk,autoincrement"`
|
||||
Config string `bun:"config,notnull,type:text"`
|
||||
Hash string `bun:"hash,notnull,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
||||
OrgID string `bun:"org_id,notnull,unique"`
|
||||
}
|
||||
|
||||
type newAlertmanagerConfig struct {
|
||||
bun.BaseModel `bun:"table:alertmanager_config_new"`
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
Config string `bun:"config,notnull,type:text"`
|
||||
Hash string `bun:"hash,notnull,type:text"`
|
||||
OrgID string `bun:"org_id,notnull,unique"`
|
||||
}
|
||||
|
||||
type existingAlertmanagerState struct {
|
||||
bun.BaseModel `bun:"table:alertmanager_state"`
|
||||
ID uint64 `bun:"id,pk,autoincrement"`
|
||||
Silences string `bun:"silences,nullzero,type:text"`
|
||||
NFLog string `bun:"nflog,nullzero,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,notnull"`
|
||||
OrgID string `bun:"org_id,notnull,unique"`
|
||||
}
|
||||
|
||||
type newAlertmanagerState struct {
|
||||
bun.BaseModel `bun:"table:alertmanager_state_new"`
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
Silences string `bun:"silences,nullzero,type:text"`
|
||||
NFLog string `bun:"nflog,nullzero,type:text"`
|
||||
OrgID string `bun:"org_id,notnull,unique"`
|
||||
}
|
||||
|
||||
func NewUpdateAlertmanagerFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_alertmanager"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateAlertmanager(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateAlertmanager(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateAlertmanager{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *updateAlertmanager) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateAlertmanager) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingChannel), new(newChannel), []string{OrgReference}, func(ctx context.Context) error {
|
||||
existingChannels := make([]*existingChannel, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingChannels).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingChannels) > 0 {
|
||||
newChannels := migration.
|
||||
CopyOldChannelToNewChannel(existingChannels)
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newChannels).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
UpdatePrimaryKey(ctx, tx, new(existingAlertmanagerConfig), new(newAlertmanagerConfig), OrgReference, func(ctx context.Context) error {
|
||||
existingAlertmanagerConfigs := make([]*existingAlertmanagerConfig, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingAlertmanagerConfigs).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingAlertmanagerConfigs) > 0 {
|
||||
newAlertmanagerConfigs := migration.
|
||||
CopyOldConfigToNewConfig(existingAlertmanagerConfigs)
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newAlertmanagerConfigs).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
UpdatePrimaryKey(ctx, tx, new(existingAlertmanagerState), new(newAlertmanagerState), OrgReference, func(ctx context.Context) error {
|
||||
existingAlertmanagerStates := make([]*existingAlertmanagerState, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingAlertmanagerStates).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingAlertmanagerStates) > 0 {
|
||||
newAlertmanagerStates := migration.
|
||||
CopyOldStateToNewState(existingAlertmanagerStates)
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newAlertmanagerStates).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateAlertmanager) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateAlertmanager) CopyOldChannelToNewChannel(existingChannels []*existingChannel) []*newChannel {
|
||||
newChannels := make([]*newChannel, 0)
|
||||
for _, channel := range existingChannels {
|
||||
newChannels = append(newChannels, &newChannel{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: channel.CreatedAt,
|
||||
UpdatedAt: channel.UpdatedAt,
|
||||
},
|
||||
Name: channel.Name,
|
||||
Type: channel.Type,
|
||||
Data: channel.Data,
|
||||
OrgID: channel.OrgID,
|
||||
})
|
||||
}
|
||||
|
||||
return newChannels
|
||||
}
|
||||
|
||||
func (migration *updateAlertmanager) CopyOldConfigToNewConfig(existingAlertmanagerConfigs []*existingAlertmanagerConfig) []*newAlertmanagerConfig {
|
||||
newAlertmanagerConfigs := make([]*newAlertmanagerConfig, 0)
|
||||
for _, config := range existingAlertmanagerConfigs {
|
||||
newAlertmanagerConfigs = append(newAlertmanagerConfigs, &newAlertmanagerConfig{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: config.CreatedAt,
|
||||
UpdatedAt: config.UpdatedAt,
|
||||
},
|
||||
Config: config.Config,
|
||||
Hash: config.Hash,
|
||||
OrgID: config.OrgID,
|
||||
})
|
||||
}
|
||||
|
||||
return newAlertmanagerConfigs
|
||||
}
|
||||
|
||||
func (migration *updateAlertmanager) CopyOldStateToNewState(existingAlertmanagerStates []*existingAlertmanagerState) []*newAlertmanagerState {
|
||||
newAlertmanagerStates := make([]*newAlertmanagerState, 0)
|
||||
for _, state := range existingAlertmanagerStates {
|
||||
newAlertmanagerStates = append(newAlertmanagerStates, &newAlertmanagerState{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: state.CreatedAt,
|
||||
UpdatedAt: state.UpdatedAt,
|
||||
},
|
||||
Silences: state.Silences,
|
||||
NFLog: state.NFLog,
|
||||
OrgID: state.OrgID,
|
||||
})
|
||||
}
|
||||
|
||||
return newAlertmanagerStates
|
||||
}
|
||||
@@ -1,198 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"reflect"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updatePreferences struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
type existingOrgPreference struct {
|
||||
bun.BaseModel `bun:"table:org_preference"`
|
||||
PreferenceID string `bun:"preference_id,pk,type:text,notnull"`
|
||||
PreferenceValue string `bun:"preference_value,type:text,notnull"`
|
||||
OrgID string `bun:"org_id,pk,type:text,notnull"`
|
||||
}
|
||||
|
||||
type newOrgPreference struct {
|
||||
bun.BaseModel `bun:"table:org_preference_new"`
|
||||
types.Identifiable
|
||||
PreferenceID string `bun:"preference_id,type:text,notnull"`
|
||||
PreferenceValue string `bun:"preference_value,type:text,notnull"`
|
||||
OrgID string `bun:"org_id,type:text,notnull"`
|
||||
}
|
||||
|
||||
type existingUserPreference struct {
|
||||
bun.BaseModel `bun:"table:user_preference"`
|
||||
PreferenceID string `bun:"preference_id,type:text,pk"`
|
||||
PreferenceValue string `bun:"preference_value,type:text"`
|
||||
UserID string `bun:"user_id,type:text,pk"`
|
||||
}
|
||||
|
||||
type newUserPreference struct {
|
||||
bun.BaseModel `bun:"table:user_preference_new"`
|
||||
types.Identifiable
|
||||
PreferenceID string `bun:"preference_id,type:text,notnull"`
|
||||
PreferenceValue string `bun:"preference_value,type:text,notnull"`
|
||||
UserID string `bun:"user_id,type:text,notnull"`
|
||||
}
|
||||
|
||||
func NewUpdatePreferencesFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_preferences"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdatePreferences(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdatePreferences(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updatePreferences{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *updatePreferences) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updatePreferences) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
AddPrimaryKey(ctx, tx, new(existingOrgPreference), new(newOrgPreference), OrgReference, func(ctx context.Context) error {
|
||||
existingOrgPreferences := make([]*existingOrgPreference, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingOrgPreferences).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingOrgPreferences) > 0 {
|
||||
newOrgPreferences := migration.
|
||||
CopyOldOrgPreferencesToNewOrgPreferences(existingOrgPreferences)
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newOrgPreferences).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tableName := tx.Dialect().Tables().Get(reflect.TypeOf(new(existingOrgPreference))).Name
|
||||
_, err = tx.
|
||||
ExecContext(ctx, fmt.Sprintf("CREATE UNIQUE INDEX IF NOT EXISTS %s_unique_idx ON %s (preference_id, org_id)", tableName, fmt.Sprintf("%s_new", tableName)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
AddPrimaryKey(ctx, tx, new(existingUserPreference), new(newUserPreference), UserReference, func(ctx context.Context) error {
|
||||
existingUserPreferences := make([]*existingUserPreference, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingUserPreferences).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingUserPreferences) > 0 {
|
||||
newUserPreferences := migration.CopyOldUserPreferencesToNewUserPreferences(existingUserPreferences)
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newUserPreferences).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tableName := tx.Dialect().Tables().Get(reflect.TypeOf(new(existingUserPreference))).Name
|
||||
_, err = tx.
|
||||
ExecContext(ctx, fmt.Sprintf("CREATE UNIQUE INDEX IF NOT EXISTS %s_unique_idx ON %s (preference_id, user_id)", tableName, fmt.Sprintf("%s_new", tableName)))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updatePreferences) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updatePreferences) CopyOldOrgPreferencesToNewOrgPreferences(existingOrgPreferences []*existingOrgPreference) []*newOrgPreference {
|
||||
newOrgPreferences := make([]*newOrgPreference, 0)
|
||||
for _, preference := range existingOrgPreferences {
|
||||
newOrgPreferences = append(newOrgPreferences, &newOrgPreference{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
PreferenceID: preference.PreferenceID,
|
||||
PreferenceValue: preference.PreferenceValue,
|
||||
OrgID: preference.OrgID,
|
||||
})
|
||||
}
|
||||
return newOrgPreferences
|
||||
}
|
||||
|
||||
func (migration *updatePreferences) CopyOldUserPreferencesToNewUserPreferences(existingUserPreferences []*existingUserPreference) []*newUserPreference {
|
||||
newUserPreferences := make([]*newUserPreference, 0)
|
||||
for _, preference := range existingUserPreferences {
|
||||
newUserPreferences = append(newUserPreferences, &newUserPreference{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
PreferenceID: preference.PreferenceID,
|
||||
PreferenceValue: preference.PreferenceValue,
|
||||
UserID: preference.UserID,
|
||||
})
|
||||
}
|
||||
return newUserPreferences
|
||||
}
|
||||
@@ -1,229 +0,0 @@
|
||||
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/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateApdexTtl struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
type existingApdexSettings struct {
|
||||
bun.BaseModel `bun:"table:apdex_settings"`
|
||||
OrgID string `bun:"org_id,pk,type:text" json:"orgId"`
|
||||
ServiceName string `bun:"service_name,pk,type:text" json:"serviceName"`
|
||||
Threshold float64 `bun:"threshold,type:float,notnull" json:"threshold"`
|
||||
ExcludeStatusCodes string `bun:"exclude_status_codes,type:text,notnull" json:"excludeStatusCodes"`
|
||||
}
|
||||
|
||||
type newApdexSettings struct {
|
||||
bun.BaseModel `bun:"table:apdex_setting"`
|
||||
types.Identifiable
|
||||
OrgID string `bun:"org_id,type:text" json:"orgId"`
|
||||
ServiceName string `bun:"service_name,type:text" json:"serviceName"`
|
||||
Threshold float64 `bun:"threshold,type:float,notnull" json:"threshold"`
|
||||
ExcludeStatusCodes string `bun:"exclude_status_codes,type:text,notnull" json:"excludeStatusCodes"`
|
||||
}
|
||||
|
||||
type existingTTLStatus struct {
|
||||
bun.BaseModel `bun:"table:ttl_status"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
TransactionID string `bun:"transaction_id,type:text,notnull"`
|
||||
CreatedAt time.Time `bun:"created_at,type:datetime,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,type:datetime,notnull"`
|
||||
TableName string `bun:"table_name,type:text,notnull"`
|
||||
TTL int `bun:"ttl,notnull,default:0"`
|
||||
ColdStorageTTL int `bun:"cold_storage_ttl,notnull,default:0"`
|
||||
Status string `bun:"status,type:text,notnull"`
|
||||
}
|
||||
|
||||
type newTTLStatus struct {
|
||||
bun.BaseModel `bun:"table:ttl_setting"`
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
TransactionID string `bun:"transaction_id,type:text,notnull"`
|
||||
TableName string `bun:"table_name,type:text,notnull"`
|
||||
TTL int `bun:"ttl,notnull,default:0"`
|
||||
ColdStorageTTL int `bun:"cold_storage_ttl,notnull,default:0"`
|
||||
Status string `bun:"status,type:text,notnull"`
|
||||
OrgID string `json:"-" bun:"org_id,notnull"`
|
||||
}
|
||||
|
||||
func NewUpdateApdexTtlFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_apdex_ttl"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateApdexTtl(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateApdexTtl(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateApdexTtl{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *updateApdexTtl) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateApdexTtl) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingApdexSettings), new(newApdexSettings), []string{OrgReference}, func(ctx context.Context) error {
|
||||
existingApdexSettings := make([]*existingApdexSettings, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingApdexSettings).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingApdexSettings) > 0 {
|
||||
newSettings := migration.
|
||||
CopyExistingApdexSettingsToNewApdexSettings(existingApdexSettings)
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newSettings).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tableName := tx.Dialect().Tables().Get(reflect.TypeOf(new(newApdexSettings))).Name
|
||||
_, err = tx.
|
||||
ExecContext(ctx, fmt.Sprintf("CREATE UNIQUE INDEX IF NOT EXISTS %s_unique_idx ON %s (service_name, org_id)", tableName, tableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingTTLStatus), new(newTTLStatus), []string{OrgReference}, func(ctx context.Context) error {
|
||||
existingTTLStatus := make([]*existingTTLStatus, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingTTLStatus).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingTTLStatus) > 0 {
|
||||
var orgID string
|
||||
err := migration.
|
||||
store.
|
||||
BunDB().
|
||||
NewSelect().
|
||||
Model((*types.Organization)(nil)).
|
||||
Column("id").
|
||||
Scan(ctx, &orgID)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
newTTLStatus := migration.CopyExistingTTLStatusToNewTTLStatus(existingTTLStatus, orgID)
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newTTLStatus).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateApdexTtl) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateApdexTtl) CopyExistingApdexSettingsToNewApdexSettings(existingApdexSettings []*existingApdexSettings) []*newApdexSettings {
|
||||
newSettings := make([]*newApdexSettings, 0)
|
||||
for _, apdexSetting := range existingApdexSettings {
|
||||
newSettings = append(newSettings, &newApdexSettings{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
ServiceName: apdexSetting.ServiceName,
|
||||
Threshold: apdexSetting.Threshold,
|
||||
ExcludeStatusCodes: apdexSetting.ExcludeStatusCodes,
|
||||
OrgID: apdexSetting.OrgID,
|
||||
})
|
||||
}
|
||||
|
||||
return newSettings
|
||||
}
|
||||
|
||||
func (migration *updateApdexTtl) CopyExistingTTLStatusToNewTTLStatus(existingTTLStatus []*existingTTLStatus, orgID string) []*newTTLStatus {
|
||||
newTTLStatuses := make([]*newTTLStatus, 0)
|
||||
|
||||
for _, ttl := range existingTTLStatus {
|
||||
newTTLStatuses = append(newTTLStatuses, &newTTLStatus{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: ttl.CreatedAt,
|
||||
UpdatedAt: ttl.UpdatedAt,
|
||||
},
|
||||
TransactionID: ttl.TransactionID,
|
||||
TTL: ttl.TTL,
|
||||
TableName: ttl.TableName,
|
||||
ColdStorageTTL: ttl.ColdStorageTTL,
|
||||
Status: ttl.Status,
|
||||
OrgID: orgID,
|
||||
})
|
||||
}
|
||||
|
||||
return newTTLStatuses
|
||||
}
|
||||
@@ -1,195 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateResetPassword struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
type existingResetPasswordRequest struct {
|
||||
bun.BaseModel `bun:"table:reset_password_request"`
|
||||
ID int `bun:"id,pk,autoincrement" json:"id"`
|
||||
Token string `bun:"token,type:text,notnull" json:"token"`
|
||||
UserID string `bun:"user_id,type:text,notnull" json:"userId"`
|
||||
}
|
||||
|
||||
type newResetPasswordRequest struct {
|
||||
bun.BaseModel `bun:"table:reset_password_request_new"`
|
||||
types.Identifiable
|
||||
Token string `bun:"token,type:text,notnull" json:"token"`
|
||||
UserID string `bun:"user_id,type:text,notnull" json:"userId"`
|
||||
}
|
||||
|
||||
type existingPersonalAccessToken struct {
|
||||
bun.BaseModel `bun:"table:personal_access_tokens"`
|
||||
types.TimeAuditable
|
||||
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'"`
|
||||
UserID string `json:"userId" bun:"user_id,type:text,notnull"`
|
||||
Token string `json:"token" bun:"token,type:text,notnull,unique"`
|
||||
Name string `json:"name" bun:"name,type:text,notnull"`
|
||||
ExpiresAt int64 `json:"expiresAt" bun:"expires_at,notnull,default:0"`
|
||||
LastUsed int64 `json:"lastUsed" bun:"last_used,notnull,default:0"`
|
||||
Revoked bool `json:"revoked" bun:"revoked,notnull,default:false"`
|
||||
UpdatedByUserID string `json:"updatedByUserId" bun:"updated_by_user_id,type:text,notnull,default:''"`
|
||||
}
|
||||
|
||||
type newPersonalAccessToken struct {
|
||||
bun.BaseModel `bun:"table:personal_access_token"`
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
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"`
|
||||
Token string `json:"token" bun:"token,type:text,notnull,unique"`
|
||||
Name string `json:"name" bun:"name,type:text,notnull"`
|
||||
ExpiresAt int64 `json:"expiresAt" bun:"expires_at,notnull,default:0"`
|
||||
LastUsed int64 `json:"lastUsed" bun:"last_used,notnull,default:0"`
|
||||
Revoked bool `json:"revoked" bun:"revoked,notnull,default:false"`
|
||||
UpdatedByUserID string `json:"updatedByUserId" bun:"updated_by_user_id,type:text,notnull,default:''"`
|
||||
}
|
||||
|
||||
func NewUpdateResetPasswordFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_reset_password"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateResetPassword(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateResetPassword(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateResetPassword{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *updateResetPassword) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateResetPassword) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
err = migration.store.Dialect().UpdatePrimaryKey(ctx, tx, new(existingResetPasswordRequest), new(newResetPasswordRequest), UserReference, func(ctx context.Context) error {
|
||||
existingResetPasswordRequests := make([]*existingResetPasswordRequest, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingResetPasswordRequests).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingResetPasswordRequests) > 0 {
|
||||
newResetPasswordRequests := migration.CopyExistingResetPasswordRequestsToNewResetPasswordRequests(existingResetPasswordRequests)
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newResetPasswordRequests).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = migration.store.Dialect().RenameTableAndModifyModel(ctx, tx, new(existingPersonalAccessToken), new(newPersonalAccessToken), []string{OrgReference, UserReference}, func(ctx context.Context) error {
|
||||
existingPersonalAccessTokens := make([]*existingPersonalAccessToken, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingPersonalAccessTokens).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingPersonalAccessTokens) > 0 {
|
||||
newPersonalAccessTokens := migration.CopyExistingPATsToNewPATs(existingPersonalAccessTokens)
|
||||
_, err = tx.NewInsert().Model(&newPersonalAccessTokens).Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateResetPassword) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateResetPassword) CopyExistingResetPasswordRequestsToNewResetPasswordRequests(existingPasswordRequests []*existingResetPasswordRequest) []*newResetPasswordRequest {
|
||||
newResetPasswordRequests := make([]*newResetPasswordRequest, 0)
|
||||
for _, request := range existingPasswordRequests {
|
||||
newResetPasswordRequests = append(newResetPasswordRequests, &newResetPasswordRequest{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
Token: request.Token,
|
||||
UserID: request.UserID,
|
||||
})
|
||||
}
|
||||
return newResetPasswordRequests
|
||||
}
|
||||
|
||||
func (migration *updateResetPassword) CopyExistingPATsToNewPATs(existingPATs []*existingPersonalAccessToken) []*newPersonalAccessToken {
|
||||
newPATs := make([]*newPersonalAccessToken, 0)
|
||||
for _, pat := range existingPATs {
|
||||
newPATs = append(newPATs, &newPersonalAccessToken{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: pat.CreatedAt,
|
||||
UpdatedAt: pat.UpdatedAt,
|
||||
},
|
||||
Role: pat.Role,
|
||||
Name: pat.Name,
|
||||
ExpiresAt: pat.ExpiresAt,
|
||||
LastUsed: pat.LastUsed,
|
||||
UserID: pat.UserID,
|
||||
Token: pat.Token,
|
||||
Revoked: pat.Revoked,
|
||||
UpdatedByUserID: pat.UpdatedByUserID,
|
||||
OrgID: pat.OrgID,
|
||||
})
|
||||
}
|
||||
return newPATs
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/telemetrytypes"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addVirtualFields struct{}
|
||||
|
||||
func NewAddVirtualFieldsFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_virtual_fields"), newAddVirtualFields)
|
||||
}
|
||||
|
||||
func newAddVirtualFields(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &addVirtualFields{}, nil
|
||||
}
|
||||
|
||||
func (migration *addVirtualFields) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addVirtualFields) Up(ctx context.Context, db *bun.DB) error {
|
||||
// table:virtual_field op:create
|
||||
if _, err := db.NewCreateTable().
|
||||
Model(&struct {
|
||||
bun.BaseModel `bun:"table:virtual_field"`
|
||||
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
types.UserAuditable
|
||||
|
||||
Name string `bun:"name,type:text,notnull"`
|
||||
Expression string `bun:"expression,type:text,notnull"`
|
||||
Description string `bun:"description,type:text"`
|
||||
Signal telemetrytypes.Signal `bun:"signal,type:text,notnull"`
|
||||
OrgID string `bun:"org_id,type:text,notnull"`
|
||||
}{}).
|
||||
ForeignKey(`("org_id") REFERENCES "organizations" ("id") ON DELETE CASCADE`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addVirtualFields) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,446 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/google/uuid"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateIntegrations struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateIntegrations(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateIntegrations{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *updateIntegrations) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type existingInstalledIntegration struct {
|
||||
bun.BaseModel `bun:"table:integrations_installed"`
|
||||
|
||||
IntegrationID string `bun:"integration_id,pk,type:text"`
|
||||
ConfigJSON string `bun:"config_json,type:text"`
|
||||
InstalledAt time.Time `bun:"installed_at,default:current_timestamp"`
|
||||
}
|
||||
|
||||
type newInstalledIntegration struct {
|
||||
bun.BaseModel `bun:"table:installed_integration"`
|
||||
|
||||
types.Identifiable
|
||||
Type string `json:"type" bun:"type,type:text,unique:org_id_type"`
|
||||
Config string `json:"config" bun:"config,type:text"`
|
||||
InstalledAt time.Time `json:"installed_at" bun:"installed_at,default:current_timestamp"`
|
||||
OrgID string `json:"org_id" bun:"org_id,type:text,unique:org_id_type"`
|
||||
}
|
||||
|
||||
type existingCloudIntegration struct {
|
||||
bun.BaseModel `bun:"table:cloud_integrations_accounts"`
|
||||
|
||||
CloudProvider string `bun:"cloud_provider,type:text,unique:cloud_provider_id"`
|
||||
ID string `bun:"id,type:text,notnull,unique:cloud_provider_id"`
|
||||
ConfigJSON string `bun:"config_json,type:text"`
|
||||
CloudAccountID string `bun:"cloud_account_id,type:text"`
|
||||
LastAgentReportJSON string `bun:"last_agent_report_json,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,notnull,default:current_timestamp"`
|
||||
RemovedAt *time.Time `bun:"removed_at,type:timestamp"`
|
||||
}
|
||||
|
||||
type newCloudIntegration struct {
|
||||
bun.BaseModel `bun:"table:cloud_integration"`
|
||||
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
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"`
|
||||
LastAgentReport string `json:"last_agent_report" bun:"last_agent_report,type:text"`
|
||||
RemovedAt *time.Time `json:"removed_at" bun:"removed_at,type:timestamp"`
|
||||
OrgID string `json:"org_id" bun:"org_id,type:text"`
|
||||
}
|
||||
|
||||
type existingCloudIntegrationService struct {
|
||||
bun.BaseModel `bun:"table:cloud_integrations_service_configs,alias:c1"`
|
||||
|
||||
CloudProvider string `bun:"cloud_provider,type:text,notnull,unique:service_cloud_provider_account"`
|
||||
CloudAccountID string `bun:"cloud_account_id,type:text,notnull,unique:service_cloud_provider_account"`
|
||||
ServiceID string `bun:"service_id,type:text,notnull,unique:service_cloud_provider_account"`
|
||||
ConfigJSON string `bun:"config_json,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,default:current_timestamp"`
|
||||
}
|
||||
|
||||
type newCloudIntegrationService struct {
|
||||
bun.BaseModel `bun:"table:cloud_integration_service,alias:cis"`
|
||||
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
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"`
|
||||
}
|
||||
|
||||
type StorablePersonalAccessToken struct {
|
||||
bun.BaseModel `bun:"table:personal_access_token"`
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
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"`
|
||||
Token string `json:"token" bun:"token,type:text,notnull,unique"`
|
||||
Name string `json:"name" bun:"name,type:text,notnull"`
|
||||
ExpiresAt int64 `json:"expiresAt" bun:"expires_at,notnull,default:0"`
|
||||
LastUsed int64 `json:"lastUsed" bun:"last_used,notnull,default:0"`
|
||||
Revoked bool `json:"revoked" bun:"revoked,notnull,default:false"`
|
||||
UpdatedByUserID string `json:"updatedByUserId" bun:"updated_by_user_id,type:text,notnull,default:''"`
|
||||
}
|
||||
|
||||
func (migration *updateIntegrations) Up(ctx context.Context, db *bun.DB) error {
|
||||
|
||||
// begin transaction
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
// don't run the migration if there are multiple org ids
|
||||
orgIDs := make([]string, 0)
|
||||
err = migration.store.BunDB().NewSelect().Model((*types.Organization)(nil)).Column("id").Scan(ctx, &orgIDs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(orgIDs) > 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// installed integrations
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingInstalledIntegration), new(newInstalledIntegration), []string{OrgReference}, func(ctx context.Context) error {
|
||||
existingIntegrations := make([]*existingInstalledIntegration, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingIntegrations).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingIntegrations) > 0 {
|
||||
newIntegrations := migration.
|
||||
CopyOldIntegrationsToNewIntegrations(tx, orgIDs[0], existingIntegrations)
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newIntegrations).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// cloud integrations
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingCloudIntegration), new(newCloudIntegration), []string{OrgReference}, func(ctx context.Context) error {
|
||||
existingIntegrations := make([]*existingCloudIntegration, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingIntegrations).
|
||||
Where("removed_at IS NULL"). // we will only copy the accounts that are not removed
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingIntegrations) > 0 {
|
||||
newIntegrations := migration.
|
||||
CopyOldCloudIntegrationsToNewCloudIntegrations(tx, orgIDs[0], existingIntegrations)
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newIntegrations).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add unique constraint to cloud_integration table
|
||||
_, err = tx.ExecContext(ctx, `CREATE UNIQUE INDEX IF NOT EXISTS unique_cloud_integration ON cloud_integration (id, provider, org_id)`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// cloud integration service
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingCloudIntegrationService), new(newCloudIntegrationService), []string{CloudIntegrationReference}, func(ctx context.Context) error {
|
||||
existingServices := make([]*existingCloudIntegrationService, 0)
|
||||
|
||||
// only one service per provider,account id and type
|
||||
// so there won't be any duplicates.
|
||||
// just that these will be enabled as soon as the integration for the account is enabled
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingServices).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingServices) > 0 {
|
||||
newServices := migration.
|
||||
CopyOldCloudIntegrationServicesToNewCloudIntegrationServices(tx, orgIDs[0], existingServices)
|
||||
if len(newServices) > 0 {
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newServices).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(orgIDs) == 0 {
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// copy the old aws integration user to the new user
|
||||
err = migration.copyOldAwsIntegrationUser(tx, orgIDs[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateIntegrations) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateIntegrations) CopyOldIntegrationsToNewIntegrations(tx bun.IDB, orgID string, existingIntegrations []*existingInstalledIntegration) []*newInstalledIntegration {
|
||||
newIntegrations := make([]*newInstalledIntegration, 0)
|
||||
|
||||
for _, integration := range existingIntegrations {
|
||||
newIntegrations = append(newIntegrations, &newInstalledIntegration{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
Type: integration.IntegrationID,
|
||||
Config: integration.ConfigJSON,
|
||||
InstalledAt: integration.InstalledAt,
|
||||
OrgID: orgID,
|
||||
})
|
||||
}
|
||||
|
||||
return newIntegrations
|
||||
}
|
||||
|
||||
func (migration *updateIntegrations) CopyOldCloudIntegrationsToNewCloudIntegrations(tx bun.IDB, orgID string, existingIntegrations []*existingCloudIntegration) []*newCloudIntegration {
|
||||
newIntegrations := make([]*newCloudIntegration, 0)
|
||||
|
||||
for _, integration := range existingIntegrations {
|
||||
newIntegrations = append(newIntegrations, &newCloudIntegration{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: integration.CreatedAt,
|
||||
UpdatedAt: integration.CreatedAt,
|
||||
},
|
||||
Provider: integration.CloudProvider,
|
||||
AccountID: integration.CloudAccountID,
|
||||
Config: integration.ConfigJSON,
|
||||
LastAgentReport: integration.LastAgentReportJSON,
|
||||
RemovedAt: integration.RemovedAt,
|
||||
OrgID: orgID,
|
||||
})
|
||||
}
|
||||
|
||||
return newIntegrations
|
||||
}
|
||||
|
||||
func (migration *updateIntegrations) CopyOldCloudIntegrationServicesToNewCloudIntegrationServices(tx bun.IDB, orgID string, existingServices []*existingCloudIntegrationService) []*newCloudIntegrationService {
|
||||
newServices := make([]*newCloudIntegrationService, 0)
|
||||
|
||||
for _, service := range existingServices {
|
||||
var cloudIntegrationID string
|
||||
err := tx.NewSelect().
|
||||
Model((*newCloudIntegration)(nil)).
|
||||
Column("id").
|
||||
Where("account_id = ?", service.CloudAccountID).
|
||||
Where("provider = ?", service.CloudProvider).
|
||||
Where("org_id = ?", orgID).
|
||||
Scan(context.Background(), &cloudIntegrationID)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
continue
|
||||
}
|
||||
return nil
|
||||
}
|
||||
newServices = append(newServices, &newCloudIntegrationService{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: service.CreatedAt,
|
||||
UpdatedAt: service.CreatedAt,
|
||||
},
|
||||
Type: service.ServiceID,
|
||||
Config: service.ConfigJSON,
|
||||
CloudIntegrationID: cloudIntegrationID,
|
||||
})
|
||||
}
|
||||
|
||||
return newServices
|
||||
}
|
||||
|
||||
func (migration *updateIntegrations) copyOldAwsIntegrationUser(tx bun.IDB, orgID string) error {
|
||||
type oldUser struct {
|
||||
bun.BaseModel `bun:"table:users"`
|
||||
|
||||
types.TimeAuditable
|
||||
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"`
|
||||
Password string `bun:"password,type:text,notnull" json:"-"`
|
||||
ProfilePictureURL string `bun:"profile_picture_url,type:text" json:"profilePictureURL"`
|
||||
GroupID string `bun:"group_id,type:text,notnull" json:"groupId"`
|
||||
OrgID string `bun:"org_id,type:text,notnull" json:"orgId"`
|
||||
}
|
||||
|
||||
user := &oldUser{}
|
||||
err := tx.NewSelect().Model(user).Where("email = ?", "aws-integration@signoz.io").Scan(context.Background())
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// check if the id is already an uuid
|
||||
if _, err := uuid.Parse(user.ID); err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// new user
|
||||
newUser := &oldUser{
|
||||
ID: uuid.New().String(),
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
},
|
||||
OrgID: orgID,
|
||||
Name: user.Name,
|
||||
Email: user.Email,
|
||||
GroupID: user.GroupID,
|
||||
Password: user.Password,
|
||||
}
|
||||
|
||||
// get the pat for old user
|
||||
pat := &StorablePersonalAccessToken{}
|
||||
err = tx.NewSelect().Model(pat).Where("user_id = ? and revoked = false", "aws-integration").Scan(context.Background())
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// delete the old user
|
||||
_, err = tx.ExecContext(context.Background(), `DELETE FROM users WHERE id = ?`, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// new pat
|
||||
newPAT := &StorablePersonalAccessToken{
|
||||
Identifiable: types.Identifiable{ID: valuer.GenerateUUID()},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
},
|
||||
OrgID: orgID,
|
||||
UserID: newUser.ID,
|
||||
Token: pat.Token,
|
||||
Name: pat.Name,
|
||||
ExpiresAt: pat.ExpiresAt,
|
||||
LastUsed: pat.LastUsed,
|
||||
Revoked: pat.Revoked,
|
||||
Role: pat.Role,
|
||||
}
|
||||
|
||||
// delete old user
|
||||
_, err = tx.ExecContext(context.Background(), `DELETE FROM users WHERE id = ?`, user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// insert the new user
|
||||
_, err = tx.NewInsert().Model(newUser).Exec(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// insert the new pat
|
||||
_, err = tx.NewInsert().Model(newPAT).Exec(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,345 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
ruletypes "github.com/SigNoz/signoz/pkg/types/ruletypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateRules struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
type AlertIds []string
|
||||
|
||||
func (a *AlertIds) Scan(src interface{}) error {
|
||||
if data, ok := src.([]byte); ok {
|
||||
return json.Unmarshal(data, a)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *AlertIds) Value() (driver.Value, error) {
|
||||
return json.Marshal(a)
|
||||
}
|
||||
|
||||
type existingRule struct {
|
||||
bun.BaseModel `bun:"table:rules"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
CreatedAt time.Time `bun:"created_at,type:datetime,notnull"`
|
||||
CreatedBy string `bun:"created_by,type:text,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,type:datetime,notnull"`
|
||||
UpdatedBy string `bun:"updated_by,type:text,notnull"`
|
||||
Deleted int `bun:"deleted,notnull,default:0"`
|
||||
Data string `bun:"data,type:text,notnull"`
|
||||
}
|
||||
|
||||
type newRule struct {
|
||||
bun.BaseModel `bun:"table:rule"`
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
types.UserAuditable
|
||||
Deleted int `bun:"deleted,notnull,default:0"`
|
||||
Data string `bun:"data,type:text,notnull"`
|
||||
OrgID string `bun:"org_id,type:text"`
|
||||
}
|
||||
|
||||
type existingMaintenance struct {
|
||||
bun.BaseModel `bun:"table:planned_maintenance"`
|
||||
ID int `bun:"id,pk,autoincrement"`
|
||||
Name string `bun:"name,type:text,notnull"`
|
||||
Description string `bun:"description,type:text"`
|
||||
AlertIDs *AlertIds `bun:"alert_ids,type:text"`
|
||||
Schedule *ruletypes.Schedule `bun:"schedule,type:text,notnull"`
|
||||
CreatedAt time.Time `bun:"created_at,type:datetime,notnull"`
|
||||
CreatedBy string `bun:"created_by,type:text,notnull"`
|
||||
UpdatedAt time.Time `bun:"updated_at,type:datetime,notnull"`
|
||||
UpdatedBy string `bun:"updated_by,type:text,notnull"`
|
||||
}
|
||||
|
||||
type newMaintenance struct {
|
||||
bun.BaseModel `bun:"table:planned_maintenance_new"`
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
types.UserAuditable
|
||||
Name string `bun:"name,type:text,notnull"`
|
||||
Description string `bun:"description,type:text"`
|
||||
Schedule *ruletypes.Schedule `bun:"schedule,type:text,notnull"`
|
||||
OrgID string `bun:"org_id,type:text"`
|
||||
}
|
||||
|
||||
type storablePlannedMaintenanceRule struct {
|
||||
bun.BaseModel `bun:"table:planned_maintenance_rule"`
|
||||
types.Identifiable
|
||||
PlannedMaintenanceID valuer.UUID `bun:"planned_maintenance_id,type:text"`
|
||||
RuleID valuer.UUID `bun:"rule_id,type:text"`
|
||||
}
|
||||
|
||||
type ruleHistory struct {
|
||||
bun.BaseModel `bun:"table:rule_history"`
|
||||
RuleID int `bun:"rule_id"`
|
||||
RuleUUID valuer.UUID `bun:"rule_uuid"`
|
||||
}
|
||||
|
||||
func NewUpdateRulesFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_rules"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateRules(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateRules(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateRules{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *updateRules) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateRules) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
ruleIDToRuleUUIDMap := map[int]valuer.UUID{}
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingRule), new(newRule), []string{OrgReference}, func(ctx context.Context) error {
|
||||
existingRules := make([]*existingRule, 0)
|
||||
err := tx.
|
||||
NewSelect().
|
||||
Model(&existingRules).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err == nil && len(existingRules) > 0 {
|
||||
var orgID string
|
||||
err := migration.
|
||||
store.
|
||||
BunDB().
|
||||
NewSelect().
|
||||
Model((*types.Organization)(nil)).
|
||||
Column("id").
|
||||
Scan(ctx, &orgID)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
newRules, idUUIDMap := migration.CopyExistingRulesToNewRules(existingRules, orgID)
|
||||
ruleIDToRuleUUIDMap = idUUIDMap
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newRules).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
err = migration.store.Dialect().UpdatePrimaryKey(ctx, tx, new(existingMaintenance), new(newMaintenance), OrgReference, func(ctx context.Context) error {
|
||||
_, err := tx.
|
||||
NewCreateTable().
|
||||
IfNotExists().
|
||||
Model(new(storablePlannedMaintenanceRule)).
|
||||
ForeignKey(`("planned_maintenance_id") REFERENCES "planned_maintenance_new" ("id") ON DELETE CASCADE ON UPDATE CASCADE`).
|
||||
ForeignKey(`("rule_id") REFERENCES "rule" ("id")`).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
existingMaintenances := make([]*existingMaintenance, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingMaintenances).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err == nil && len(existingMaintenances) > 0 {
|
||||
var orgID string
|
||||
err := migration.
|
||||
store.
|
||||
BunDB().
|
||||
NewSelect().
|
||||
Model((*types.Organization)(nil)).
|
||||
Column("id").
|
||||
Scan(ctx, &orgID)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
newMaintenances, newMaintenancesRules, err := migration.CopyExistingMaintenancesToNewMaintenancesAndRules(existingMaintenances, orgID, ruleIDToRuleUUIDMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newMaintenances).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(newMaintenancesRules) > 0 {
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newMaintenancesRules).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ruleHistories := make([]*ruleHistory, 0)
|
||||
for ruleID, ruleUUID := range ruleIDToRuleUUIDMap {
|
||||
ruleHistories = append(ruleHistories, &ruleHistory{
|
||||
RuleID: ruleID,
|
||||
RuleUUID: ruleUUID,
|
||||
})
|
||||
}
|
||||
|
||||
_, err = tx.
|
||||
NewCreateTable().
|
||||
IfNotExists().
|
||||
Model(&ruleHistories).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(ruleHistories) > 0 {
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&ruleHistories).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateRules) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateRules) CopyExistingRulesToNewRules(existingRules []*existingRule, orgID string) ([]*newRule, map[int]valuer.UUID) {
|
||||
newRules := make([]*newRule, 0)
|
||||
idUUIDMap := map[int]valuer.UUID{}
|
||||
for _, rule := range existingRules {
|
||||
uuid := valuer.GenerateUUID()
|
||||
idUUIDMap[rule.ID] = uuid
|
||||
newRules = append(newRules, &newRule{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: uuid,
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: rule.CreatedAt,
|
||||
UpdatedAt: rule.UpdatedAt,
|
||||
},
|
||||
UserAuditable: types.UserAuditable{
|
||||
CreatedBy: rule.CreatedBy,
|
||||
UpdatedBy: rule.UpdatedBy,
|
||||
},
|
||||
Deleted: rule.Deleted,
|
||||
Data: rule.Data,
|
||||
OrgID: orgID,
|
||||
})
|
||||
}
|
||||
return newRules, idUUIDMap
|
||||
}
|
||||
|
||||
func (migration *updateRules) CopyExistingMaintenancesToNewMaintenancesAndRules(existingMaintenances []*existingMaintenance, orgID string, ruleIDToRuleUUIDMap map[int]valuer.UUID) ([]*newMaintenance, []*storablePlannedMaintenanceRule, error) {
|
||||
newMaintenances := make([]*newMaintenance, 0)
|
||||
newMaintenanceRules := make([]*storablePlannedMaintenanceRule, 0)
|
||||
|
||||
for _, maintenance := range existingMaintenances {
|
||||
ruleIDs := maintenance.AlertIDs
|
||||
maintenanceUUID := valuer.GenerateUUID()
|
||||
newMaintenance := newMaintenance{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: maintenanceUUID,
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: maintenance.CreatedAt,
|
||||
UpdatedAt: maintenance.UpdatedAt,
|
||||
},
|
||||
UserAuditable: types.UserAuditable{
|
||||
CreatedBy: maintenance.CreatedBy,
|
||||
UpdatedBy: maintenance.UpdatedBy,
|
||||
},
|
||||
Name: maintenance.Name,
|
||||
Description: maintenance.Description,
|
||||
Schedule: maintenance.Schedule,
|
||||
OrgID: orgID,
|
||||
}
|
||||
newMaintenances = append(newMaintenances, &newMaintenance)
|
||||
for _, ruleIDStr := range *ruleIDs {
|
||||
ruleID, err := strconv.Atoi(ruleIDStr)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
newMaintenanceRules = append(newMaintenanceRules, &storablePlannedMaintenanceRule{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
PlannedMaintenanceID: maintenanceUUID,
|
||||
RuleID: ruleIDToRuleUUIDMap[ruleID],
|
||||
})
|
||||
}
|
||||
}
|
||||
return newMaintenances, newMaintenanceRules, nil
|
||||
}
|
||||
@@ -1,117 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateOrganizations struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewUpdateOrganizationsFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_organizations"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateOrganizations(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateOrganizations(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateOrganizations{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *updateOrganizations) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateOrganizations) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
DropColumn(ctx, tx, "organizations", "is_anonymous")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
DropColumn(ctx, tx, "organizations", "has_opted_updates")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameColumn(ctx, tx, "organizations", "name", "display_name")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
AddColumn(ctx, tx, "organizations", "name", "TEXT")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.
|
||||
NewCreateIndex().
|
||||
Unique().
|
||||
IfNotExists().
|
||||
Index("idx_unique_name").
|
||||
Table("organizations").
|
||||
Column("name").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
AddColumn(ctx, tx, "organizations", "alias", "TEXT")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.
|
||||
NewCreateIndex().
|
||||
Unique().
|
||||
IfNotExists().
|
||||
Index("idx_unique_alias").
|
||||
Table("organizations").
|
||||
Column("alias").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateOrganizations) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
type dropGroups struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
func newDropGroups(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &dropGroups{sqlstore: sqlstore}, nil
|
||||
}
|
||||
|
||||
func (migration *dropGroups) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *dropGroups) Up(ctx context.Context, db *bun.DB) error {
|
||||
type Group struct {
|
||||
bun.BaseModel `bun:"table:groups"`
|
||||
|
||||
types.TimeAuditable
|
||||
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"`
|
||||
}
|
||||
|
||||
exists, err := migration.sqlstore.Dialect().TableExists(ctx, db, new(Group))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Disable foreign keys temporarily
|
||||
if err := migration.sqlstore.Dialect().ToggleForeignKeyConstraint(ctx, db, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
type existingUser struct {
|
||||
bun.BaseModel `bun:"table:users"`
|
||||
|
||||
types.TimeAuditable
|
||||
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"`
|
||||
Password string `bun:"password,type:text,notnull" json:"-"`
|
||||
ProfilePictureURL string `bun:"profile_picture_url,type:text" json:"profilePictureURL"`
|
||||
GroupID string `bun:"group_id,type:text,notnull" json:"groupId"`
|
||||
OrgID string `bun:"org_id,type:text,notnull" json:"orgId"`
|
||||
}
|
||||
|
||||
var existingUsers []*existingUser
|
||||
if err := tx.
|
||||
NewSelect().
|
||||
Model(&existingUsers).
|
||||
Scan(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var groups []*Group
|
||||
if err := tx.
|
||||
NewSelect().
|
||||
Model(&groups).
|
||||
Scan(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
groupIDToRoleMap := make(map[string]string)
|
||||
for _, group := range groups {
|
||||
groupIDToRoleMap[group.ID] = group.Name
|
||||
}
|
||||
|
||||
roleToUserIDMap := make(map[string][]string)
|
||||
for _, user := range existingUsers {
|
||||
roleToUserIDMap[groupIDToRoleMap[user.GroupID]] = append(roleToUserIDMap[groupIDToRoleMap[user.GroupID]], user.ID)
|
||||
}
|
||||
|
||||
if err := migration.sqlstore.Dialect().DropColumnWithForeignKeyConstraint(ctx, tx, new(struct {
|
||||
bun.BaseModel `bun:"table:users"`
|
||||
|
||||
types.TimeAuditable
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
Name string `bun:"name,type:text,notnull"`
|
||||
Email string `bun:"email,type:text,notnull,unique"`
|
||||
Password string `bun:"password,type:text,notnull"`
|
||||
ProfilePictureURL string `bun:"profile_picture_url,type:text"`
|
||||
OrgID string `bun:"org_id,type:text,notnull"`
|
||||
}), "group_id"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migration.sqlstore.Dialect().AddColumn(ctx, tx, "users", "role", "TEXT"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for role, userIDs := range roleToUserIDMap {
|
||||
if _, err := tx.
|
||||
NewUpdate().
|
||||
Table("users").
|
||||
Set("role = ?", role).
|
||||
Where("id IN (?)", bun.In(userIDs)).
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := migration.sqlstore.Dialect().AddNotNullDefaultToColumn(ctx, tx, "users", "role", "TEXT", "'VIEWER'"); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.
|
||||
NewDropTable().
|
||||
Table("groups").
|
||||
IfExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Enable foreign keys
|
||||
if err := migration.sqlstore.Dialect().ToggleForeignKeyConstraint(ctx, db, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *dropGroups) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/quickfiltertypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type createQuickFilters struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
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
|
||||
types.UserAuditable
|
||||
}
|
||||
|
||||
func NewCreateQuickFiltersFactory(store sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("create_quick_filters"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return &createQuickFilters{store: store}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (m *createQuickFilters) Register(migrations *migrate.Migrations) error {
|
||||
return migrations.Register(m.Up, m.Down)
|
||||
}
|
||||
|
||||
func (m *createQuickFilters) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
// Create table if not exists
|
||||
_, err = tx.NewCreateTable().
|
||||
Model((*quickFilter)(nil)).
|
||||
IfNotExists().
|
||||
ForeignKey(`("org_id") REFERENCES "organizations" ("id") ON DELETE CASCADE ON UPDATE CASCADE`).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get default organization ID
|
||||
var defaultOrg valuer.UUID
|
||||
err = tx.NewSelect().Table("organizations").Column("id").Limit(1).Scan(ctx, &defaultOrg)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// No organizations found, nothing to insert, commit and return
|
||||
err := tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Get the default quick filters
|
||||
storableQuickFilters, err := quickfiltertypes.NewDefaultQuickFilter(defaultOrg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Insert all filters at once
|
||||
_, err = tx.NewInsert().
|
||||
Model(&storableQuickFilters).
|
||||
Exec(ctx)
|
||||
|
||||
if err != nil {
|
||||
if errors.Ast(m.store.WrapAlreadyExistsErrf(err, errors.CodeAlreadyExists, "Quick Filter already exists"), errors.TypeAlreadyExists) {
|
||||
err := tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// Commit the transaction
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (m *createQuickFilters) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types/quickfiltertypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateQuickFilters struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewUpdateQuickFiltersFactory(store sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_quick_filters"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateQuickFilters(ctx, ps, c, store)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateQuickFilters(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateQuickFilters{
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *updateQuickFilters) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateQuickFilters) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
// Delete all existing quick filters
|
||||
_, err = tx.NewDelete().
|
||||
Table("quick_filter").
|
||||
Where("1=1"). // Delete all rows
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get all organization IDs as strings
|
||||
var orgIDs []string
|
||||
err = tx.NewSelect().
|
||||
Table("organizations").
|
||||
Column("id").
|
||||
Scan(ctx, &orgIDs)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
// No organizations found, commit the transaction (deletion is done) and return
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// For each organization, create new quick filters with the updated NewDefaultQuickFilter function
|
||||
for _, orgID := range orgIDs {
|
||||
// Get the updated default quick filters
|
||||
storableQuickFilters, err := quickfiltertypes.NewDefaultQuickFilter(valuer.MustNewUUID(orgID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Insert all filters for this organization
|
||||
_, err = tx.NewInsert().
|
||||
Model(&storableQuickFilters).
|
||||
Exec(ctx)
|
||||
|
||||
if err != nil {
|
||||
if errors.Ast(migration.store.WrapAlreadyExistsErrf(err, errors.CodeAlreadyExists, "Quick Filter already exists"), errors.TypeAlreadyExists) {
|
||||
// Skip if filters already exist for this org
|
||||
continue
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateQuickFilters) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,235 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type authRefactor struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
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)
|
||||
})
|
||||
}
|
||||
|
||||
func newAuthRefactor(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &authRefactor{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *authRefactor) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type existingUser32 struct {
|
||||
bun.BaseModel `bun:"table:users"`
|
||||
|
||||
types.TimeAuditable
|
||||
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"`
|
||||
Password string `bun:"password,type:text,notnull" json:"-"`
|
||||
ProfilePictureURL string `bun:"profile_picture_url,type:text" json:"profilePictureURL"`
|
||||
Role string `bun:"role,type:text,notnull" json:"role"`
|
||||
OrgID string `bun:"org_id,type:text,notnull" json:"orgId"`
|
||||
}
|
||||
|
||||
type factorPassword32 struct {
|
||||
bun.BaseModel `bun:"table:factor_password"`
|
||||
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
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"`
|
||||
}
|
||||
|
||||
type existingResetPasswordRequest32 struct {
|
||||
bun.BaseModel `bun:"table:reset_password_request"`
|
||||
|
||||
types.Identifiable
|
||||
Token string `bun:"token,type:text,notnull" json:"token"`
|
||||
UserID string `bun:"user_id,type:text,notnull,unique" json:"userId"`
|
||||
}
|
||||
|
||||
type newResetPasswordRequest32 struct {
|
||||
bun.BaseModel `bun:"table:reset_password_token"`
|
||||
|
||||
types.Identifiable
|
||||
Token string `bun:"token,type:text,notnull" json:"token"`
|
||||
PasswordID string `bun:"password_id,type:text,notnull" json:"passwordID"`
|
||||
}
|
||||
|
||||
func (migration *authRefactor) Up(ctx context.Context, db *bun.DB) error {
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
if _, err := tx.NewCreateTable().
|
||||
Model(new(factorPassword32)).
|
||||
ForeignKey(`("user_id") REFERENCES "users" ("id")`).
|
||||
IfNotExists().
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// copy passwords from users table to factor_password table
|
||||
err = migration.CopyOldPasswordToNewPassword(ctx, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// delete profile picture url
|
||||
err = migration.store.Dialect().DropColumn(ctx, tx, "users", "profile_picture_url")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// delete password
|
||||
err = migration.store.Dialect().DropColumn(ctx, tx, "users", "password")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// rename name to display name
|
||||
_, err = migration.store.Dialect().RenameColumn(ctx, tx, "users", "name", "display_name")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingResetPasswordRequest32), new(newResetPasswordRequest32), []string{FactorPasswordReference}, func(ctx context.Context) error {
|
||||
existingRequests := make([]*existingResetPasswordRequest32, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingRequests).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingRequests) > 0 {
|
||||
// copy users and their passwords to new table
|
||||
newRequests, err := migration.
|
||||
CopyOldResetPasswordToNewResetPassword(ctx, tx, existingRequests)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newRequests).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *authRefactor) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *authRefactor) CopyOldPasswordToNewPassword(ctx context.Context, tx bun.IDB) error {
|
||||
// check if data already in factor_password table
|
||||
var count int64
|
||||
err := tx.NewSelect().Model(new(factorPassword32)).ColumnExpr("COUNT(*)").Scan(ctx, &count)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// check if password column exist in the users table.
|
||||
exists, err := migration.store.Dialect().ColumnExists(ctx, tx, "users", "password")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
// get all users from users table
|
||||
existingUsers := make([]*existingUser32, 0)
|
||||
err = tx.NewSelect().Model(&existingUsers).Scan(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newPasswords := make([]*factorPassword32, 0)
|
||||
for _, user := range existingUsers {
|
||||
newPasswords = append(newPasswords, &factorPassword32{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
Password: user.Password,
|
||||
Temporary: false,
|
||||
UserID: user.ID,
|
||||
})
|
||||
}
|
||||
|
||||
// insert
|
||||
if len(newPasswords) > 0 {
|
||||
_, err = tx.NewInsert().Model(&newPasswords).Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *authRefactor) CopyOldResetPasswordToNewResetPassword(ctx context.Context, tx bun.IDB, existingRequests []*existingResetPasswordRequest32) ([]*newResetPasswordRequest32, error) {
|
||||
newRequests := make([]*newResetPasswordRequest32, 0)
|
||||
for _, request := range existingRequests {
|
||||
// get password id from user id
|
||||
var passwordID string
|
||||
err := tx.NewSelect().Table("factor_password").Column("id").Where("user_id = ?", request.UserID).Scan(ctx, &passwordID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newRequests = append(newRequests, &newResetPasswordRequest32{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
Token: request.Token,
|
||||
PasswordID: passwordID,
|
||||
})
|
||||
}
|
||||
return newRequests, nil
|
||||
}
|
||||
@@ -1,164 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"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"
|
||||
)
|
||||
|
||||
type migratePATToFactorAPIKey struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewMigratePATToFactorAPIKey(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("migrate_pat_to_factor_api_key"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newMigratePATToFactorAPIKey(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newMigratePATToFactorAPIKey(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &migratePATToFactorAPIKey{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *migratePATToFactorAPIKey) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type existingPersonalAccessToken33 struct {
|
||||
bun.BaseModel `bun:"table:personal_access_token"`
|
||||
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
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"`
|
||||
Token string `json:"token" bun:"token,type:text,notnull,unique"`
|
||||
Name string `json:"name" bun:"name,type:text,notnull"`
|
||||
ExpiresAt int64 `json:"expiresAt" bun:"expires_at,notnull,default:0"`
|
||||
LastUsed int64 `json:"lastUsed" bun:"last_used,notnull,default:0"`
|
||||
Revoked bool `json:"revoked" bun:"revoked,notnull,default:false"`
|
||||
UpdatedByUserID string `json:"updatedByUserId" bun:"updated_by_user_id,type:text,notnull,default:''"`
|
||||
}
|
||||
|
||||
// we are removing the connection with org,
|
||||
// the reason we are doing this is the api keys should just have
|
||||
// one foreign key, we don't want a dangling state where, an API key
|
||||
// belongs to one org and some user which doesn't belong to that org.
|
||||
// so going ahead with directly attaching it to user will help dangling states.
|
||||
type newFactorAPIKey33 struct {
|
||||
bun.BaseModel `bun:"table:factor_api_key"`
|
||||
|
||||
types.Identifiable
|
||||
CreatedAt time.Time `bun:"created_at,notnull,nullzero,type:timestamptz" json:"createdAt"`
|
||||
UpdatedAt time.Time `bun:"updated_at,notnull,nullzero,type:timestamptz" json:"updatedAt"`
|
||||
CreatedBy string `bun:"created_by,notnull" json:"createdBy"`
|
||||
UpdatedBy string `bun:"updated_by,notnull" json:"updatedBy"`
|
||||
Token string `json:"token" bun:"token,type:text,notnull,unique"`
|
||||
Role string `json:"role" bun:"role,type:text,notnull"`
|
||||
Name string `json:"name" bun:"name,type:text,notnull"`
|
||||
ExpiresAt time.Time `json:"expiresAt" bun:"expires_at,notnull,nullzero,type:timestamptz"`
|
||||
LastUsed time.Time `json:"lastUsed" bun:"last_used,notnull,nullzero,type:timestamptz"`
|
||||
Revoked bool `json:"revoked" bun:"revoked,notnull,default:false"`
|
||||
UserID string `json:"userId" bun:"user_id,type:text,notnull"`
|
||||
}
|
||||
|
||||
func (migration *migratePATToFactorAPIKey) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingPersonalAccessToken33), new(newFactorAPIKey33), []string{UserReferenceNoCascade}, func(ctx context.Context) error {
|
||||
existingAPIKeys := make([]*existingPersonalAccessToken33, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingAPIKeys).
|
||||
Scan(ctx)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
|
||||
if err == nil && len(existingAPIKeys) > 0 {
|
||||
newAPIKeys, err := migration.
|
||||
CopyOldPatToFactorAPIKey(ctx, tx, existingAPIKeys)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newAPIKeys).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *migratePATToFactorAPIKey) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *migratePATToFactorAPIKey) CopyOldPatToFactorAPIKey(ctx context.Context, tx bun.IDB, existingAPIKeys []*existingPersonalAccessToken33) ([]*newFactorAPIKey33, error) {
|
||||
newAPIKeys := make([]*newFactorAPIKey33, 0)
|
||||
for _, apiKey := range existingAPIKeys {
|
||||
|
||||
if apiKey.CreatedAt.IsZero() {
|
||||
apiKey.CreatedAt = time.Now()
|
||||
}
|
||||
if apiKey.UpdatedAt.IsZero() {
|
||||
apiKey.UpdatedAt = time.Now()
|
||||
}
|
||||
|
||||
// convert expiresAt and lastUsed to time.Time
|
||||
expiresAt := time.Unix(apiKey.ExpiresAt, 0)
|
||||
lastUsed := time.Unix(apiKey.LastUsed, 0)
|
||||
if apiKey.LastUsed == 0 {
|
||||
lastUsed = apiKey.CreatedAt
|
||||
}
|
||||
|
||||
newAPIKeys = append(newAPIKeys, &newFactorAPIKey33{
|
||||
Identifiable: apiKey.Identifiable,
|
||||
CreatedAt: apiKey.CreatedAt,
|
||||
UpdatedAt: apiKey.UpdatedAt,
|
||||
CreatedBy: apiKey.UserID,
|
||||
UpdatedBy: apiKey.UpdatedByUserID,
|
||||
Token: apiKey.Token,
|
||||
Role: apiKey.Role,
|
||||
Name: apiKey.Name,
|
||||
ExpiresAt: expiresAt,
|
||||
LastUsed: lastUsed,
|
||||
Revoked: apiKey.Revoked,
|
||||
UserID: apiKey.UserID,
|
||||
})
|
||||
}
|
||||
return newAPIKeys, nil
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateLicense struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
type existingLicense34 struct {
|
||||
bun.BaseModel `bun:"table:licenses_v3"`
|
||||
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
Key string `bun:"key,type:text,notnull,unique"`
|
||||
Data string `bun:"data,type:text"`
|
||||
}
|
||||
|
||||
type newLicense34 struct {
|
||||
bun.BaseModel `bun:"table:license"`
|
||||
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
Key string `bun:"key,type:text,notnull,unique"`
|
||||
Data map[string]any `bun:"data,type:text"`
|
||||
LastValidatedAt time.Time `bun:"last_validated_at,notnull"`
|
||||
OrgID string `bun:"org_id,type:text,notnull" json:"orgID"`
|
||||
}
|
||||
|
||||
func NewUpdateLicenseFactory(store sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_license"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateLicense(ctx, ps, c, store)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateLicense(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateLicense{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *updateLicense) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateLicense) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
err = migration.store.Dialect().RenameTableAndModifyModel(ctx, tx, new(existingLicense34), new(newLicense34), []string{OrgReference}, func(ctx context.Context) error {
|
||||
existingLicenses := make([]*existingLicense34, 0)
|
||||
err = tx.NewSelect().Model(&existingLicenses).Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingLicenses) > 0 {
|
||||
var orgID string
|
||||
err := migration.
|
||||
store.
|
||||
BunDB().
|
||||
NewSelect().
|
||||
Model((*types.Organization)(nil)).
|
||||
Column("id").
|
||||
Scan(ctx, &orgID)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err == nil {
|
||||
newLicenses, err := migration.CopyExistingLicensesToNewLicenses(existingLicenses, orgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newLicenses).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateLicense) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateLicense) CopyExistingLicensesToNewLicenses(existingLicenses []*existingLicense34, orgID string) ([]*newLicense34, error) {
|
||||
newLicenses := make([]*newLicense34, len(existingLicenses))
|
||||
for idx, existingLicense := range existingLicenses {
|
||||
licenseID, err := valuer.NewUUID(existingLicense.ID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, errors.CodeInvalidInput, "license id is not a valid UUID: %s", existingLicense.ID)
|
||||
}
|
||||
licenseData := map[string]any{}
|
||||
err = json.Unmarshal([]byte(existingLicense.Data), &licenseData)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, errors.TypeInvalidInput, errors.CodeInvalidInput, "unable to unmarshal license data in map[string]any")
|
||||
}
|
||||
newLicenses[idx] = &newLicense34{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: licenseID,
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
},
|
||||
Key: existingLicense.Key,
|
||||
Data: licenseData,
|
||||
LastValidatedAt: time.Now(),
|
||||
OrgID: orgID,
|
||||
}
|
||||
}
|
||||
return newLicenses, nil
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types/quickfiltertypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateApiMonitoringFilters struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewUpdateApiMonitoringFiltersFactory(store sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_api_monitoring_filters"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateApiMonitoringFilters(ctx, ps, c, store)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateApiMonitoringFilters(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateApiMonitoringFilters{
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *updateApiMonitoringFilters) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateApiMonitoringFilters) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
// Get all organization IDs as strings
|
||||
var orgIDs []string
|
||||
err = tx.NewSelect().
|
||||
Table("organizations").
|
||||
Column("id").
|
||||
Scan(ctx, &orgIDs)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
for _, orgID := range orgIDs {
|
||||
// Get the updated default quick filters which includes the new API monitoring filters
|
||||
storableQuickFilters, err := quickfiltertypes.NewDefaultQuickFilter(valuer.MustNewUUID(orgID))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Find the API monitoring filter from the storable quick filters
|
||||
var apiMonitoringFilterJSON string
|
||||
for _, filter := range storableQuickFilters {
|
||||
if filter.Signal == quickfiltertypes.SignalApiMonitoring {
|
||||
apiMonitoringFilterJSON = filter.Filter
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if apiMonitoringFilterJSON != "" {
|
||||
_, err = tx.NewUpdate().
|
||||
Table("quick_filter").
|
||||
Set("filter = ?, updated_at = ?", apiMonitoringFilterJSON, time.Now()).
|
||||
Where("signal = ? AND org_id = ?", quickfiltertypes.SignalApiMonitoring, orgID).
|
||||
Exec(ctx)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateApiMonitoringFilters) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"hash/fnv"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addKeyOrganization struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewAddKeyOrganizationFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_key_organization"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||
return newAddKeyOrganization(ctx, providerSettings, config, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newAddKeyOrganization(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &addKeyOrganization{
|
||||
sqlstore: sqlstore,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *addKeyOrganization) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addKeyOrganization) Up(ctx context.Context, db *bun.DB) error {
|
||||
ok, err := migration.sqlstore.Dialect().ColumnExists(ctx, db, "organizations", "key")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
if _, err := tx.
|
||||
NewAddColumn().
|
||||
Table("organizations").
|
||||
ColumnExpr("key BIGINT").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var existingOrgIDs []string
|
||||
if err := tx.NewSelect().
|
||||
Table("organizations").
|
||||
Column("id").
|
||||
Scan(ctx, &existingOrgIDs); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, orgID := range existingOrgIDs {
|
||||
key := migration.getHash(ctx, orgID)
|
||||
if _, err := tx.
|
||||
NewUpdate().
|
||||
Table("organizations").
|
||||
Set("key = ?", key).
|
||||
Where("id = ?", orgID).
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := tx.
|
||||
NewCreateIndex().
|
||||
Unique().
|
||||
IfNotExists().
|
||||
Index("idx_unique_key").
|
||||
Table("organizations").
|
||||
Column("key").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addKeyOrganization) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addKeyOrganization) getHash(_ context.Context, orgID string) uint32 {
|
||||
hasher := fnv.New32a()
|
||||
|
||||
// Hasher never returns err.
|
||||
_, _ = hasher.Write([]byte(orgID))
|
||||
return hasher.Sum32()
|
||||
}
|
||||
@@ -1,89 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
// funnel Core Data Structure (funnel and funnelStep)
|
||||
type funnel struct {
|
||||
bun.BaseModel `bun:"table:trace_funnel"`
|
||||
types.Identifiable // funnel id
|
||||
types.TimeAuditable
|
||||
types.UserAuditable
|
||||
Name string `json:"funnel_name" bun:"name,type:text,notnull"` // funnel name
|
||||
Description string `json:"description" bun:"description,type:text"` // funnel description
|
||||
OrgID valuer.UUID `json:"org_id" bun:"org_id,type:varchar,notnull"`
|
||||
Steps []funnelStep `json:"steps" bun:"steps,type:text,notnull"`
|
||||
Tags string `json:"tags" bun:"tags,type:text"`
|
||||
CreatedByUser *types.User `json:"user" bun:"rel:belongs-to,join:created_by=id"`
|
||||
}
|
||||
|
||||
type funnelStep struct {
|
||||
types.Identifiable
|
||||
Name string `json:"name,omitempty"` // step name
|
||||
Description string `json:"description,omitempty"` // step description
|
||||
Order int64 `json:"step_order"`
|
||||
ServiceName string `json:"service_name"`
|
||||
SpanName string `json:"span_name"`
|
||||
Filters string `json:"filters,omitempty"`
|
||||
LatencyPointer string `json:"latency_pointer,omitempty"`
|
||||
LatencyType string `json:"latency_type,omitempty"`
|
||||
HasErrors bool `json:"has_errors"`
|
||||
}
|
||||
|
||||
type addTraceFunnels struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
}
|
||||
|
||||
func NewAddTraceFunnelsFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_trace_funnels"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||
return newAddTraceFunnels(ctx, providerSettings, config, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newAddTraceFunnels(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &addTraceFunnels{sqlstore: sqlstore}, nil
|
||||
}
|
||||
|
||||
func (migration *addTraceFunnels) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addTraceFunnels) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
_, err = tx.NewCreateTable().
|
||||
Model(new(funnel)).
|
||||
ForeignKey(`("org_id") REFERENCES "organizations" ("id") ON DELETE CASCADE`).
|
||||
IfNotExists().
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addTraceFunnels) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,141 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateDashboard struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
|
||||
type existingDashboard36 struct {
|
||||
bun.BaseModel `bun:"table:dashboards"`
|
||||
|
||||
types.TimeAuditable
|
||||
types.UserAuditable
|
||||
OrgID string `json:"-" bun:"org_id,notnull"`
|
||||
ID int `json:"id" bun:"id,pk,autoincrement"`
|
||||
UUID string `json:"uuid" bun:"uuid,type:text,notnull,unique"`
|
||||
Data map[string]interface{} `json:"data" bun:"data,type:text,notnull"`
|
||||
Locked *int `json:"isLocked" bun:"locked,notnull,default:0"`
|
||||
}
|
||||
|
||||
type newDashboard36 struct {
|
||||
bun.BaseModel `bun:"table:dashboard"`
|
||||
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
types.UserAuditable
|
||||
Data map[string]interface{} `bun:"data,type:text,notnull"`
|
||||
Locked bool `bun:"locked,notnull,default:false"`
|
||||
OrgID valuer.UUID `bun:"org_id,type:text,notnull"`
|
||||
}
|
||||
|
||||
func NewUpdateDashboardFactory(store sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_dashboards"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateDashboard(ctx, ps, c, store)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateDashboard(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateDashboard{store: store}, nil
|
||||
}
|
||||
|
||||
func (migration *updateDashboard) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateDashboard) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
err = migration.store.Dialect().RenameTableAndModifyModel(ctx, tx, new(existingDashboard36), new(newDashboard36), []string{OrgReference}, func(ctx context.Context) error {
|
||||
existingDashboards := make([]*existingDashboard36, 0)
|
||||
err = tx.NewSelect().Model(&existingDashboards).Scan(ctx)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil && len(existingDashboards) > 0 {
|
||||
newDashboards, err := migration.CopyExistingDashboardsToNewDashboards(existingDashboards)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newDashboards).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
func (migration *updateDashboard) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateDashboard) CopyExistingDashboardsToNewDashboards(existingDashboards []*existingDashboard36) ([]*newDashboard36, error) {
|
||||
newDashboards := make([]*newDashboard36, len(existingDashboards))
|
||||
|
||||
for idx, existingDashboard := range existingDashboards {
|
||||
dashboardID, err := valuer.NewUUID(existingDashboard.UUID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orgID, err := valuer.NewUUID(existingDashboard.OrgID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
locked := false
|
||||
if existingDashboard.Locked != nil && *existingDashboard.Locked == 1 {
|
||||
locked = true
|
||||
}
|
||||
|
||||
newDashboards[idx] = &newDashboard36{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: dashboardID,
|
||||
},
|
||||
TimeAuditable: existingDashboard.TimeAuditable,
|
||||
UserAuditable: existingDashboard.UserAuditable,
|
||||
Data: existingDashboard.Data,
|
||||
Locked: locked,
|
||||
OrgID: orgID,
|
||||
}
|
||||
}
|
||||
|
||||
return newDashboards, nil
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type dropFeatureSet struct{}
|
||||
|
||||
func NewDropFeatureSetFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("drop_feature_set"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newDropFeatureSet(ctx, ps, c)
|
||||
})
|
||||
}
|
||||
|
||||
func newDropFeatureSet(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &dropFeatureSet{}, nil
|
||||
}
|
||||
|
||||
func (migration *dropFeatureSet) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *dropFeatureSet) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
if _, err := tx.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Table("feature_status").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *dropFeatureSet) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type dropDeprecatedTables struct{}
|
||||
|
||||
func NewDropDeprecatedTablesFactory() factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("drop_deprecated_tables"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newDropDeprecatedTables(ctx, ps, c)
|
||||
})
|
||||
}
|
||||
|
||||
func newDropDeprecatedTables(_ context.Context, _ factory.ProviderSettings, _ Config) (SQLMigration, error) {
|
||||
return &dropDeprecatedTables{}, nil
|
||||
}
|
||||
|
||||
func (migration *dropDeprecatedTables) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *dropDeprecatedTables) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
if _, err := tx.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Table("rule_history").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Table("data_migrations").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *dropDeprecatedTables) Down(context.Context, *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,278 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/opamptypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateAgents struct {
|
||||
store sqlstore.SQLStore
|
||||
}
|
||||
type newAgent41 struct {
|
||||
bun.BaseModel `bun:"table:agent"`
|
||||
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
// AgentID is needed as the ID from opamp client is ULID and not UUID, so we are keeping it like this
|
||||
AgentID string `json:"agentId" yaml:"agentId" bun:"agent_id,type:text,notnull,unique"`
|
||||
OrgID string `json:"orgId" yaml:"orgId" bun:"org_id,type:text,notnull"`
|
||||
TerminatedAt time.Time `json:"terminatedAt" yaml:"terminatedAt" bun:"terminated_at"`
|
||||
Status opamptypes.AgentStatus `json:"currentStatus" yaml:"currentStatus" bun:"status,type:text,notnull"`
|
||||
Config string `bun:"config,type:text,notnull"`
|
||||
}
|
||||
|
||||
type existingAgentConfigVersions41 struct {
|
||||
bun.BaseModel `bun:"table:agent_config_versions"`
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
CreatedBy string `bun:"created_by,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,default:CURRENT_TIMESTAMP"`
|
||||
UpdatedBy string `bun:"updated_by,type:text"`
|
||||
UpdatedAt time.Time `bun:"updated_at,default:CURRENT_TIMESTAMP"`
|
||||
Version int `bun:"version,default:1,unique:element_version_idx"`
|
||||
Active int `bun:"active"`
|
||||
IsValid int `bun:"is_valid"`
|
||||
Disabled int `bun:"disabled"`
|
||||
ElementType opamptypes.ElementType `bun:"element_type,notnull,type:varchar(120),unique:element_version_idx"`
|
||||
DeployStatus opamptypes.DeployStatus `bun:"deploy_status,notnull,type:varchar(80),default:'DIRTY'"`
|
||||
DeploySequence int `bun:"deploy_sequence"`
|
||||
DeployResult string `bun:"deploy_result,type:text"`
|
||||
LastHash string `bun:"last_hash,type:text"`
|
||||
LastConfig string `bun:"last_config,type:text"`
|
||||
}
|
||||
|
||||
type newAgentConfigVersion41 struct {
|
||||
bun.BaseModel `bun:"table:agent_config_version"`
|
||||
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
types.UserAuditable
|
||||
OrgID string `json:"orgId" bun:"org_id,type:text,notnull,unique:element_version_org_idx"`
|
||||
Version int `json:"version" bun:"version,unique:element_version_org_idx"`
|
||||
ElementType opamptypes.ElementType `json:"elementType" bun:"element_type,type:text,notnull,unique:element_version_org_idx"`
|
||||
DeployStatus opamptypes.DeployStatus `json:"deployStatus" bun:"deploy_status,type:text,notnull,default:'dirty'"`
|
||||
DeploySequence int `json:"deploySequence" bun:"deploy_sequence"`
|
||||
DeployResult string `json:"deployResult" bun:"deploy_result,type:text"`
|
||||
Hash string `json:"lastHash" bun:"hash,type:text"`
|
||||
Config string `json:"config" bun:"config,type:text"`
|
||||
}
|
||||
|
||||
type existingAgentConfigElement41 struct {
|
||||
bun.BaseModel `bun:"table:agent_config_elements"`
|
||||
|
||||
ID string `bun:"id,pk,type:text"`
|
||||
CreatedBy string `bun:"created_by,type:text"`
|
||||
CreatedAt time.Time `bun:"created_at,default:CURRENT_TIMESTAMP"`
|
||||
UpdatedBy string `bun:"updated_by,type:text"`
|
||||
UpdatedAt time.Time `bun:"updated_at,default:CURRENT_TIMESTAMP"`
|
||||
ElementID string `bun:"element_id,type:text,notnull,unique:agent_config_elements_u1"`
|
||||
ElementType string `bun:"element_type,type:varchar(120),notnull,unique:agent_config_elements_u1"`
|
||||
VersionID string `bun:"version_id,type:text,notnull,unique:agent_config_elements_u1"`
|
||||
}
|
||||
|
||||
type newAgentConfigElement41 struct {
|
||||
bun.BaseModel `bun:"table:agent_config_element"`
|
||||
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
ElementID string `bun:"element_id,type:text,notnull,unique:element_type_version_idx"`
|
||||
ElementType string `bun:"element_type,type:text,notnull,unique:element_type_version_idx"`
|
||||
VersionID string `bun:"version_id,type:text,notnull,unique:element_type_version_idx"`
|
||||
}
|
||||
|
||||
func NewUpdateAgentsFactory(sqlstore sqlstore.SQLStore) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_agents"), func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newUpdateAgents(ctx, ps, c, sqlstore)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateAgents(_ context.Context, _ factory.ProviderSettings, _ Config, store sqlstore.SQLStore) (SQLMigration, error) {
|
||||
return &updateAgents{
|
||||
store: store,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *updateAgents) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateAgents) Up(ctx context.Context, db *bun.DB) error {
|
||||
|
||||
// begin transaction
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
var orgID string
|
||||
err = tx.
|
||||
NewSelect().
|
||||
ColumnExpr("id").
|
||||
Table("organizations").
|
||||
Limit(1).
|
||||
Scan(ctx, &orgID)
|
||||
if err != nil {
|
||||
if err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := tx.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Table("agents").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := tx.
|
||||
NewCreateTable().
|
||||
IfNotExists().
|
||||
Model(new(newAgent41)).
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingAgentConfigVersions41), new(newAgentConfigVersion41), []string{OrgReference}, func(ctx context.Context) error {
|
||||
existingAgentConfigVersions := make([]*existingAgentConfigVersions41, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingAgentConfigVersions).
|
||||
Scan(ctx)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
|
||||
if err == nil && len(existingAgentConfigVersions) > 0 {
|
||||
newAgentConfigVersions, err := migration.
|
||||
CopyOldAgentConfigVersionToNewAgentConfigVersion(ctx, tx, existingAgentConfigVersions, orgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newAgentConfigVersions).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = migration.
|
||||
store.
|
||||
Dialect().
|
||||
RenameTableAndModifyModel(ctx, tx, new(existingAgentConfigElement41), new(newAgentConfigElement41), []string{AgentConfigVersionReference}, func(ctx context.Context) error {
|
||||
existingAgentConfigElements := make([]*existingAgentConfigElement41, 0)
|
||||
err = tx.
|
||||
NewSelect().
|
||||
Model(&existingAgentConfigElements).
|
||||
Scan(ctx)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
|
||||
if err == nil && len(existingAgentConfigElements) > 0 {
|
||||
newAgentConfigElements, err := migration.
|
||||
CopyOldAgentConfigElementToNewAgentConfigElement(ctx, tx, existingAgentConfigElements, orgID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = tx.
|
||||
NewInsert().
|
||||
Model(&newAgentConfigElements).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateAgents) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateAgents) CopyOldAgentConfigVersionToNewAgentConfigVersion(ctx context.Context, tx bun.IDB, existingAgentConfigVersions []*existingAgentConfigVersions41, orgID string) ([]*newAgentConfigVersion41, error) {
|
||||
newAgentConfigVersions := make([]*newAgentConfigVersion41, 0)
|
||||
for _, existingAgentConfigVersion := range existingAgentConfigVersions {
|
||||
versionID, err := valuer.NewUUID(existingAgentConfigVersion.ID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newAgentConfigVersions = append(newAgentConfigVersions, &newAgentConfigVersion41{
|
||||
Identifiable: types.Identifiable{ID: versionID},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: time.Unix(existingAgentConfigVersion.CreatedAt.Unix(), 0),
|
||||
UpdatedAt: time.Unix(existingAgentConfigVersion.UpdatedAt.Unix(), 0),
|
||||
},
|
||||
UserAuditable: types.UserAuditable{
|
||||
CreatedBy: existingAgentConfigVersion.CreatedBy,
|
||||
UpdatedBy: existingAgentConfigVersion.UpdatedBy,
|
||||
},
|
||||
OrgID: orgID,
|
||||
Version: existingAgentConfigVersion.Version,
|
||||
ElementType: existingAgentConfigVersion.ElementType,
|
||||
DeployStatus: existingAgentConfigVersion.DeployStatus,
|
||||
DeploySequence: existingAgentConfigVersion.DeploySequence,
|
||||
DeployResult: existingAgentConfigVersion.DeployResult,
|
||||
Hash: orgID + existingAgentConfigVersion.LastHash,
|
||||
Config: existingAgentConfigVersion.LastConfig,
|
||||
})
|
||||
}
|
||||
return newAgentConfigVersions, nil
|
||||
}
|
||||
|
||||
func (migration *updateAgents) CopyOldAgentConfigElementToNewAgentConfigElement(ctx context.Context, tx bun.IDB, existingAgentConfigElements []*existingAgentConfigElement41, orgID string) ([]*newAgentConfigElement41, error) {
|
||||
newAgentConfigElements := make([]*newAgentConfigElement41, 0)
|
||||
for _, existingAgentConfigElement := range existingAgentConfigElements {
|
||||
elementID, err := valuer.NewUUID(existingAgentConfigElement.ElementID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
newAgentConfigElements = append(newAgentConfigElements, &newAgentConfigElement41{
|
||||
Identifiable: types.Identifiable{ID: elementID},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: time.Unix(existingAgentConfigElement.CreatedAt.Unix(), 0),
|
||||
UpdatedAt: time.Unix(existingAgentConfigElement.UpdatedAt.Unix(), 0),
|
||||
},
|
||||
VersionID: existingAgentConfigElement.VersionID,
|
||||
ElementID: existingAgentConfigElement.ElementID,
|
||||
ElementType: existingAgentConfigElement.ElementType,
|
||||
})
|
||||
}
|
||||
return newAgentConfigElements, nil
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateUsers struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
sqlschema sqlschema.SQLSchema
|
||||
}
|
||||
|
||||
func NewUpdateUsersFactory(sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_users"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||
return newUpdateUsers(ctx, providerSettings, config, sqlstore, sqlschema)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateUsers(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) (SQLMigration, error) {
|
||||
return &updateUsers{
|
||||
sqlstore: sqlstore,
|
||||
sqlschema: sqlschema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *updateUsers) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateUsers) Up(ctx context.Context, db *bun.DB) error {
|
||||
if err := migration.sqlschema.ToggleFKEnforcement(ctx, db, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
table, uniqueConstraints, err := migration.sqlschema.GetTable(ctx, sqlschema.TableName("users"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sqls := [][]byte{}
|
||||
|
||||
dropSQLs := migration.sqlschema.Operator().DropConstraint(table, uniqueConstraints, &sqlschema.UniqueConstraint{ColumnNames: []sqlschema.ColumnName{"email"}})
|
||||
sqls = append(sqls, dropSQLs...)
|
||||
|
||||
indexSQLs := migration.sqlschema.Operator().CreateIndex(&sqlschema.UniqueIndex{TableName: "users", ColumnNames: []sqlschema.ColumnName{"email", "org_id"}})
|
||||
sqls = append(sqls, indexSQLs...)
|
||||
|
||||
for _, sql := range sqls {
|
||||
if _, err := tx.ExecContext(ctx, string(sql)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migration.sqlschema.ToggleFKEnforcement(ctx, db, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateUsers) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateUserInvite struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
sqlschema sqlschema.SQLSchema
|
||||
}
|
||||
|
||||
func NewUpdateUserInviteFactory(sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_user_invite"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||
return newUpdateUserInvite(ctx, providerSettings, config, sqlstore, sqlschema)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateUserInvite(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) (SQLMigration, error) {
|
||||
return &updateUserInvite{
|
||||
sqlstore: sqlstore,
|
||||
sqlschema: sqlschema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *updateUserInvite) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateUserInvite) Up(ctx context.Context, db *bun.DB) error {
|
||||
if err := migration.sqlschema.ToggleFKEnforcement(ctx, db, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
table, uniqueConstraints, err := migration.sqlschema.GetTable(ctx, sqlschema.TableName("user_invite"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sqls := [][]byte{}
|
||||
|
||||
dropSQLs := migration.sqlschema.Operator().DropConstraint(table, uniqueConstraints, &sqlschema.UniqueConstraint{ColumnNames: []sqlschema.ColumnName{"email"}})
|
||||
sqls = append(sqls, dropSQLs...)
|
||||
|
||||
indexSQLs := migration.sqlschema.Operator().CreateIndex(&sqlschema.UniqueIndex{TableName: "user_invite", ColumnNames: []sqlschema.ColumnName{"email", "org_id"}})
|
||||
sqls = append(sqls, indexSQLs...)
|
||||
|
||||
indexSQLs = migration.sqlschema.Operator().CreateIndex(&sqlschema.UniqueIndex{TableName: "user_invite", ColumnNames: []sqlschema.ColumnName{"token"}})
|
||||
sqls = append(sqls, indexSQLs...)
|
||||
|
||||
for _, sql := range sqls {
|
||||
if _, err := tx.ExecContext(ctx, string(sql)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migration.sqlschema.ToggleFKEnforcement(ctx, db, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateUserInvite) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateOrgDomain struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
sqlschema sqlschema.SQLSchema
|
||||
}
|
||||
|
||||
func NewUpdateOrgDomainFactory(sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_org_domain"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||
return newUpdateOrgDomain(ctx, providerSettings, config, sqlstore, sqlschema)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateOrgDomain(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) (SQLMigration, error) {
|
||||
return &updateOrgDomain{
|
||||
sqlstore: sqlstore,
|
||||
sqlschema: sqlschema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *updateOrgDomain) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateOrgDomain) Up(ctx context.Context, db *bun.DB) error {
|
||||
if err := migration.sqlschema.ToggleFKEnforcement(ctx, db, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
table, uniqueConstraints, err := migration.sqlschema.GetTable(ctx, sqlschema.TableName("org_domains"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sqls := [][]byte{}
|
||||
|
||||
dropSQLs := migration.sqlschema.Operator().DropConstraint(table, uniqueConstraints, &sqlschema.UniqueConstraint{ColumnNames: []sqlschema.ColumnName{"name"}})
|
||||
sqls = append(sqls, dropSQLs...)
|
||||
|
||||
indexSQLs := migration.sqlschema.Operator().CreateIndex(&sqlschema.UniqueIndex{TableName: "org_domains", ColumnNames: []sqlschema.ColumnName{"name", "org_id"}})
|
||||
sqls = append(sqls, indexSQLs...)
|
||||
|
||||
for _, sql := range sqls {
|
||||
if _, err := tx.ExecContext(ctx, string(sql)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migration.sqlschema.ToggleFKEnforcement(ctx, db, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateOrgDomain) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addFactorIndexes struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
sqlschema sqlschema.SQLSchema
|
||||
}
|
||||
|
||||
func NewAddFactorIndexesFactory(sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_factor_indexes"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||
return newAddFactorIndexes(ctx, providerSettings, config, sqlstore, sqlschema)
|
||||
})
|
||||
}
|
||||
|
||||
func newAddFactorIndexes(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) (SQLMigration, error) {
|
||||
return &addFactorIndexes{
|
||||
sqlstore: sqlstore,
|
||||
sqlschema: sqlschema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *addFactorIndexes) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addFactorIndexes) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
sqls := [][]byte{}
|
||||
|
||||
indexSQLs := migration.sqlschema.Operator().CreateIndex(&sqlschema.UniqueIndex{TableName: "factor_password", ColumnNames: []sqlschema.ColumnName{"user_id"}})
|
||||
sqls = append(sqls, indexSQLs...)
|
||||
|
||||
indexSQLs = migration.sqlschema.Operator().CreateIndex(&sqlschema.UniqueIndex{TableName: "reset_password_token", ColumnNames: []sqlschema.ColumnName{"password_id"}})
|
||||
sqls = append(sqls, indexSQLs...)
|
||||
|
||||
indexSQLs = migration.sqlschema.Operator().CreateIndex(&sqlschema.UniqueIndex{TableName: "reset_password_token", ColumnNames: []sqlschema.ColumnName{"token"}})
|
||||
sqls = append(sqls, indexSQLs...)
|
||||
|
||||
for _, sql := range sqls {
|
||||
if _, err := tx.ExecContext(ctx, string(sql)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addFactorIndexes) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,302 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"log/slog"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/telemetrystore"
|
||||
"github.com/SigNoz/signoz/pkg/transition"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type queryBuilderV5Migration struct {
|
||||
store sqlstore.SQLStore
|
||||
telemetryStore telemetrystore.TelemetryStore
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func NewQueryBuilderV5MigrationFactory(
|
||||
store sqlstore.SQLStore,
|
||||
telemetryStore telemetrystore.TelemetryStore,
|
||||
) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(
|
||||
factory.MustNewName("query_builder_v5_migration"),
|
||||
func(ctx context.Context, ps factory.ProviderSettings, c Config) (SQLMigration, error) {
|
||||
return newQueryBuilderV5Migration(ctx, c, store, telemetryStore, ps.Logger)
|
||||
})
|
||||
}
|
||||
|
||||
func newQueryBuilderV5Migration(
|
||||
_ context.Context,
|
||||
_ Config, store sqlstore.SQLStore,
|
||||
telemetryStore telemetrystore.TelemetryStore,
|
||||
logger *slog.Logger,
|
||||
) (SQLMigration, error) {
|
||||
return &queryBuilderV5Migration{store: store, telemetryStore: telemetryStore, logger: logger}, nil
|
||||
}
|
||||
|
||||
func (migration *queryBuilderV5Migration) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *queryBuilderV5Migration) getTraceDuplicateKeys(ctx context.Context) ([]string, error) {
|
||||
query := `
|
||||
SELECT tagKey
|
||||
FROM signoz_traces.distributed_span_attributes_keys
|
||||
WHERE tagType IN ('tag', 'resource')
|
||||
GROUP BY tagKey
|
||||
HAVING COUNT(DISTINCT tagType) > 1
|
||||
ORDER BY tagKey
|
||||
`
|
||||
|
||||
rows, err := migration.telemetryStore.ClickhouseDB().Query(ctx, query)
|
||||
if err != nil {
|
||||
migration.logger.WarnContext(ctx, "failed to query trace duplicate keys", "error", err)
|
||||
return nil, nil
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var keys []string
|
||||
for rows.Next() {
|
||||
var key string
|
||||
if err := rows.Scan(&key); err != nil {
|
||||
migration.logger.WarnContext(ctx, "failed to scan trace duplicate key", "error", err)
|
||||
continue
|
||||
}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (migration *queryBuilderV5Migration) getLogDuplicateKeys(ctx context.Context) ([]string, error) {
|
||||
query := `
|
||||
SELECT name
|
||||
FROM (
|
||||
SELECT DISTINCT name FROM signoz_logs.distributed_logs_attribute_keys
|
||||
INTERSECT
|
||||
SELECT DISTINCT name FROM signoz_logs.distributed_logs_resource_keys
|
||||
)
|
||||
ORDER BY name
|
||||
`
|
||||
|
||||
rows, err := migration.telemetryStore.ClickhouseDB().Query(ctx, query)
|
||||
if err != nil {
|
||||
migration.logger.WarnContext(ctx, "failed to query log duplicate keys", "error", err)
|
||||
return nil, nil
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var keys []string
|
||||
for rows.Next() {
|
||||
var key string
|
||||
if err := rows.Scan(&key); err != nil {
|
||||
migration.logger.WarnContext(ctx, "failed to scan log duplicate key", "error", err)
|
||||
continue
|
||||
}
|
||||
keys = append(keys, key)
|
||||
}
|
||||
|
||||
return keys, nil
|
||||
}
|
||||
|
||||
func (migration *queryBuilderV5Migration) Up(ctx context.Context, db *bun.DB) error {
|
||||
|
||||
// fetch keys that have both attribute and resource attribute types
|
||||
logsKeys, err := migration.getLogDuplicateKeys(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tracesKeys, err := migration.getTraceDuplicateKeys(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
if err := migration.migrateDashboards(ctx, tx, logsKeys, tracesKeys); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migration.migrateSavedViews(ctx, tx, logsKeys, tracesKeys); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migration.migrateRules(ctx, tx, logsKeys, tracesKeys); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
func (migration *queryBuilderV5Migration) Down(ctx context.Context, db *bun.DB) error {
|
||||
// this migration is not reversible as we're transforming the structure
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *queryBuilderV5Migration) migrateDashboards(
|
||||
ctx context.Context,
|
||||
tx bun.Tx,
|
||||
logsKeys []string,
|
||||
tracesKeys []string,
|
||||
) error {
|
||||
var dashboards []struct {
|
||||
ID string `bun:"id"`
|
||||
Data map[string]any `bun:"data"`
|
||||
}
|
||||
|
||||
err := tx.NewSelect().
|
||||
Table("dashboard").
|
||||
Column("id", "data").
|
||||
Scan(ctx, &dashboards)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
dashboardMigrator := transition.NewDashboardMigrateV5(migration.logger, logsKeys, tracesKeys)
|
||||
|
||||
for _, dashboard := range dashboards {
|
||||
|
||||
updated := dashboardMigrator.Migrate(ctx, dashboard.Data)
|
||||
|
||||
if updated {
|
||||
dataJSON, err := json.Marshal(dashboard.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.NewUpdate().
|
||||
Table("dashboard").
|
||||
Set("data = ?", string(dataJSON)).
|
||||
Where("id = ?", dashboard.ID).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *queryBuilderV5Migration) migrateSavedViews(
|
||||
ctx context.Context,
|
||||
tx bun.Tx,
|
||||
logsKeys []string,
|
||||
tracesKeys []string,
|
||||
) error {
|
||||
var savedViews []struct {
|
||||
ID string `bun:"id"`
|
||||
Data string `bun:"data"`
|
||||
}
|
||||
|
||||
err := tx.NewSelect().
|
||||
Table("saved_views").
|
||||
Column("id", "data").
|
||||
Scan(ctx, &savedViews)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
savedViewsMigrator := transition.NewSavedViewMigrateV5(migration.logger, logsKeys, tracesKeys)
|
||||
|
||||
for _, savedView := range savedViews {
|
||||
var data map[string]any
|
||||
if err := json.Unmarshal([]byte(savedView.Data), &data); err != nil {
|
||||
continue // invalid JSON
|
||||
}
|
||||
|
||||
updated := savedViewsMigrator.Migrate(ctx, data)
|
||||
|
||||
if updated {
|
||||
dataJSON, err := json.Marshal(data)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.NewUpdate().
|
||||
Table("saved_views").
|
||||
Set("data = ?", string(dataJSON)).
|
||||
Where("id = ?", savedView.ID).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *queryBuilderV5Migration) migrateRules(
|
||||
ctx context.Context,
|
||||
tx bun.Tx,
|
||||
logsKeys []string,
|
||||
tracesKeys []string,
|
||||
) error {
|
||||
// Fetch all rules
|
||||
var rules []struct {
|
||||
ID string `bun:"id"`
|
||||
Data map[string]any `bun:"data"`
|
||||
}
|
||||
|
||||
err := tx.NewSelect().
|
||||
Table("rule").
|
||||
Column("id", "data").
|
||||
Scan(ctx, &rules)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
alertsMigrator := transition.NewAlertMigrateV5(migration.logger, logsKeys, tracesKeys)
|
||||
|
||||
for _, rule := range rules {
|
||||
migration.logger.InfoContext(ctx, "migrating rule", "rule_id", rule.ID)
|
||||
|
||||
updated := alertsMigrator.Migrate(ctx, rule.Data)
|
||||
|
||||
if updated {
|
||||
dataJSON, err := json.Marshal(rule.Data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.NewUpdate().
|
||||
Table("rule").
|
||||
Set("data = ?", string(dataJSON)).
|
||||
Where("id = ?", rule.ID).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addMeterQuickFilters struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
sqlschema sqlschema.SQLSchema
|
||||
}
|
||||
|
||||
func NewAddMeterQuickFiltersFactory(sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_meter_quick_filters"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||
return newAddMeterQuickFilters(ctx, providerSettings, config, sqlstore, sqlschema)
|
||||
})
|
||||
}
|
||||
|
||||
func newAddMeterQuickFilters(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) (SQLMigration, error) {
|
||||
return &addMeterQuickFilters{
|
||||
sqlstore: sqlstore,
|
||||
sqlschema: sqlschema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *addMeterQuickFilters) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addMeterQuickFilters) Up(ctx context.Context, db *bun.DB) error {
|
||||
meterFilters := []map[string]interface{}{
|
||||
{"key": "deployment.environment", "dataType": "float64", "type": "Sum"},
|
||||
{"key": "service.name", "dataType": "float64", "type": "Sum"},
|
||||
{"key": "host.name", "dataType": "float64", "type": "Sum"},
|
||||
}
|
||||
|
||||
meterJSON, err := json.Marshal(meterFilters)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, errors.TypeInternal, errors.CodeInternal, "failed to marshal meter filters")
|
||||
}
|
||||
|
||||
type signal struct {
|
||||
valuer.String
|
||||
}
|
||||
|
||||
type identifiable struct {
|
||||
ID valuer.UUID `json:"id" bun:"id,pk,type:text"`
|
||||
}
|
||||
|
||||
type timeAuditable struct {
|
||||
CreatedAt time.Time `bun:"created_at" json:"createdAt"`
|
||||
UpdatedAt time.Time `bun:"updated_at" json:"updatedAt"`
|
||||
}
|
||||
|
||||
type quickFilterType struct {
|
||||
bun.BaseModel `bun:"table:quick_filter"`
|
||||
identifiable
|
||||
OrgID valuer.UUID `bun:"org_id,type:text,notnull"`
|
||||
Filter string `bun:"filter,type:text,notnull"`
|
||||
Signal signal `bun:"signal,type:text,notnull"`
|
||||
timeAuditable
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
var orgIDs []string
|
||||
err = tx.NewSelect().
|
||||
Table("organizations").
|
||||
Column("id").
|
||||
Scan(ctx, &orgIDs)
|
||||
if err != nil && err != sql.ErrNoRows {
|
||||
return err
|
||||
}
|
||||
|
||||
var meterFiltersToInsert []quickFilterType
|
||||
for _, orgIDStr := range orgIDs {
|
||||
orgID, err := valuer.NewUUID(orgIDStr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
meterFiltersToInsert = append(meterFiltersToInsert, quickFilterType{
|
||||
identifiable: identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
OrgID: orgID,
|
||||
Filter: string(meterJSON),
|
||||
Signal: signal{valuer.NewString("meter")},
|
||||
timeAuditable: timeAuditable{
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
if len(meterFiltersToInsert) > 0 {
|
||||
_, err = tx.NewInsert().
|
||||
Model(&meterFiltersToInsert).
|
||||
On("CONFLICT (org_id, signal) DO UPDATE").
|
||||
Set("filter = EXCLUDED.filter, updated_at = EXCLUDED.updated_at").
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addMeterQuickFilters) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type updateTTLSettingForCustomRetention struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
sqlschema sqlschema.SQLSchema
|
||||
}
|
||||
|
||||
func NewUpdateTTLSettingForCustomRetentionFactory(sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("update_ttl_setting"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||
return newUpdateTTLSettingForCustomRetention(ctx, providerSettings, config, sqlstore, sqlschema)
|
||||
})
|
||||
}
|
||||
|
||||
func newUpdateTTLSettingForCustomRetention(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) (SQLMigration, error) {
|
||||
return &updateTTLSettingForCustomRetention{
|
||||
sqlstore: sqlstore,
|
||||
sqlschema: sqlschema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *updateTTLSettingForCustomRetention) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateTTLSettingForCustomRetention) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
// Get the table and its constraints
|
||||
table, _, err := migration.sqlschema.GetTable(ctx, sqlschema.TableName("ttl_setting"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Define the new column
|
||||
column := &sqlschema.Column{
|
||||
Name: sqlschema.ColumnName("condition"),
|
||||
DataType: sqlschema.DataTypeText,
|
||||
Nullable: true,
|
||||
}
|
||||
|
||||
sqls := migration.sqlschema.Operator().AddColumn(table, nil, column, nil)
|
||||
for _, sql := range sqls {
|
||||
if _, err := tx.ExecContext(ctx, string(sql)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *updateTTLSettingForCustomRetention) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,260 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/SigNoz/signoz/pkg/types"
|
||||
"github.com/SigNoz/signoz/pkg/types/ruletypes"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
"log/slog"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Shared types for migration
|
||||
|
||||
type expressionRoute struct {
|
||||
bun.BaseModel `bun:"table:route_policy"`
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
types.UserAuditable
|
||||
|
||||
Expression string `bun:"expression,type:text"`
|
||||
ExpressionKind string `bun:"kind,type:text"`
|
||||
|
||||
Channels []string `bun:"channels,type:text"`
|
||||
|
||||
Name string `bun:"name,type:text"`
|
||||
Description string `bun:"description,type:text"`
|
||||
Enabled bool `bun:"enabled,type:boolean,default:true"`
|
||||
Tags []string `bun:"tags,type:text"`
|
||||
|
||||
OrgID string `bun:"org_id,type:text"`
|
||||
}
|
||||
|
||||
type rule struct {
|
||||
bun.BaseModel `bun:"table:rule"`
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
types.UserAuditable
|
||||
Deleted int `bun:"deleted,default:0"`
|
||||
Data string `bun:"data,type:text"`
|
||||
OrgID string `bun:"org_id,type:text"`
|
||||
}
|
||||
|
||||
type addRoutePolicies struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
sqlschema sqlschema.SQLSchema
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func NewAddRoutePolicyFactory(sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_route_policy"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||
return newAddRoutePolicy(ctx, providerSettings, config, sqlstore, sqlschema)
|
||||
})
|
||||
}
|
||||
|
||||
func newAddRoutePolicy(_ context.Context, settings factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) (SQLMigration, error) {
|
||||
return &addRoutePolicies{
|
||||
sqlstore: sqlstore,
|
||||
sqlschema: sqlschema,
|
||||
logger: settings.Logger,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *addRoutePolicies) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addRoutePolicies) Up(ctx context.Context, db *bun.DB) error {
|
||||
_, _, err := migration.sqlschema.GetTable(ctx, sqlschema.TableName("route_policy"))
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
sqls := [][]byte{}
|
||||
|
||||
// Create the route_policy table
|
||||
table := &sqlschema.Table{
|
||||
Name: "route_policy",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: "id", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "created_at", DataType: sqlschema.DataTypeTimestamp, Nullable: false},
|
||||
{Name: "updated_at", DataType: sqlschema.DataTypeTimestamp, Nullable: false},
|
||||
{Name: "created_by", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "updated_by", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "expression", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "kind", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "channels", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "name", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "description", DataType: sqlschema.DataTypeText, Nullable: true},
|
||||
{Name: "enabled", DataType: sqlschema.DataTypeBoolean, Nullable: false, Default: "true"},
|
||||
{Name: "tags", DataType: sqlschema.DataTypeText, Nullable: true},
|
||||
{Name: "org_id", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{
|
||||
ColumnNames: []sqlschema.ColumnName{"id"},
|
||||
},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{
|
||||
ReferencingColumnName: "org_id",
|
||||
ReferencedTableName: "organizations",
|
||||
ReferencedColumnName: "id",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
tableSQLs := migration.sqlschema.Operator().CreateTable(table)
|
||||
sqls = append(sqls, tableSQLs...)
|
||||
|
||||
for _, sqlStmt := range sqls {
|
||||
if _, err := tx.ExecContext(ctx, string(sqlStmt)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = migration.migrateRulesToRoutePolicies(ctx, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addRoutePolicies) migrateRulesToRoutePolicies(ctx context.Context, tx bun.Tx) error {
|
||||
var rules []*rule
|
||||
err := tx.NewSelect().
|
||||
Model(&rules).
|
||||
Where("deleted = ?", 0).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil // No rules to migrate
|
||||
}
|
||||
return errors.NewInternalf(errors.CodeInternal, "failed to fetch rules")
|
||||
}
|
||||
|
||||
channelsByOrg, err := migration.getAllChannels(ctx, tx)
|
||||
if err != nil {
|
||||
return errors.NewInternalf(errors.CodeInternal, "fetching channels error: %v", err)
|
||||
}
|
||||
|
||||
var routesToInsert []*expressionRoute
|
||||
|
||||
routesToInsert, err = migration.convertRulesToRoutes(rules, channelsByOrg)
|
||||
if err != nil {
|
||||
return errors.NewInternalf(errors.CodeInternal, "converting rules to routes error: %v", err)
|
||||
}
|
||||
|
||||
// Insert all routes in a single batch operation
|
||||
if len(routesToInsert) > 0 {
|
||||
_, err = tx.NewInsert().
|
||||
Model(&routesToInsert).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return errors.NewInternalf(errors.CodeInternal, "failed to insert notification routes")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addRoutePolicies) convertRulesToRoutes(rules []*rule, channelsByOrg map[string][]string) ([]*expressionRoute, error) {
|
||||
var routes []*expressionRoute
|
||||
for _, r := range rules {
|
||||
var gettableRule ruletypes.GettableRule
|
||||
if err := json.Unmarshal([]byte(r.Data), &gettableRule); err != nil {
|
||||
return nil, errors.NewInternalf(errors.CodeInternal, "failed to unmarshal rule data for rule ID %s: %v", r.ID, err)
|
||||
}
|
||||
|
||||
if len(gettableRule.PreferredChannels) == 0 {
|
||||
channels, exists := channelsByOrg[r.OrgID]
|
||||
if !exists || len(channels) == 0 {
|
||||
continue
|
||||
}
|
||||
gettableRule.PreferredChannels = channels
|
||||
}
|
||||
severity := "critical"
|
||||
if v, ok := gettableRule.Labels["severity"]; ok {
|
||||
severity = v
|
||||
}
|
||||
expression := fmt.Sprintf(`%s == "%s" && %s == "%s"`, "threshold.name", severity, "ruleId", r.ID.String())
|
||||
route := &expressionRoute{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
},
|
||||
TimeAuditable: types.TimeAuditable{
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
},
|
||||
UserAuditable: types.UserAuditable{
|
||||
CreatedBy: r.CreatedBy,
|
||||
UpdatedBy: r.UpdatedBy,
|
||||
},
|
||||
Expression: expression,
|
||||
ExpressionKind: "rule",
|
||||
Channels: gettableRule.PreferredChannels,
|
||||
Name: r.ID.StringValue(),
|
||||
Enabled: true,
|
||||
OrgID: r.OrgID,
|
||||
}
|
||||
routes = append(routes, route)
|
||||
}
|
||||
return routes, nil
|
||||
}
|
||||
|
||||
func (migration *addRoutePolicies) getAllChannels(ctx context.Context, tx bun.Tx) (map[string][]string, error) {
|
||||
type channel struct {
|
||||
bun.BaseModel `bun:"table:notification_channel"`
|
||||
types.Identifiable
|
||||
types.TimeAuditable
|
||||
Name string `json:"name" bun:"name"`
|
||||
Type string `json:"type" bun:"type"`
|
||||
Data string `json:"data" bun:"data"`
|
||||
OrgID string `json:"org_id" bun:"org_id"`
|
||||
}
|
||||
|
||||
var channels []*channel
|
||||
err := tx.NewSelect().
|
||||
Model(&channels).
|
||||
Scan(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.NewInternalf(errors.CodeInternal, "failed to fetch all channels")
|
||||
}
|
||||
|
||||
// Group channels by org ID
|
||||
channelsByOrg := make(map[string][]string)
|
||||
for _, ch := range channels {
|
||||
channelsByOrg[ch.OrgID] = append(channelsByOrg[ch.OrgID], ch.Name)
|
||||
}
|
||||
|
||||
return channelsByOrg, nil
|
||||
}
|
||||
|
||||
func (migration *addRoutePolicies) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
package sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type addAuthToken struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
sqlschema sqlschema.SQLSchema
|
||||
}
|
||||
|
||||
func NewAddAuthTokenFactory(sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) factory.ProviderFactory[SQLMigration, Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("add_auth_token"), func(ctx context.Context, providerSettings factory.ProviderSettings, config Config) (SQLMigration, error) {
|
||||
return newAddAuthToken(ctx, providerSettings, config, sqlstore, sqlschema)
|
||||
})
|
||||
}
|
||||
|
||||
func newAddAuthToken(_ context.Context, _ factory.ProviderSettings, _ Config, sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) (SQLMigration, error) {
|
||||
return &addAuthToken{
|
||||
sqlstore: sqlstore,
|
||||
sqlschema: sqlschema,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (migration *addAuthToken) Register(migrations *migrate.Migrations) error {
|
||||
if err := migrations.Register(migration.Up, migration.Down); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addAuthToken) Up(ctx context.Context, db *bun.DB) error {
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
token := &sqlschema.Table{
|
||||
Name: "auth_token",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("meta"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("prev_access_token"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("access_token"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("prev_refresh_token"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("refresh_token"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("last_observed_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("rotated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("user_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("user_id"), ReferencedTableName: sqlschema.TableName("users"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
}
|
||||
|
||||
sqls := [][]byte{}
|
||||
createSQLs := migration.sqlschema.Operator().CreateTable(token)
|
||||
sqls = append(sqls, createSQLs...)
|
||||
|
||||
indexSQLs := migration.sqlschema.Operator().CreateIndex(&sqlschema.UniqueIndex{TableName: "auth_token", ColumnNames: []sqlschema.ColumnName{"access_token"}})
|
||||
sqls = append(sqls, indexSQLs...)
|
||||
|
||||
indexSQLs = migration.sqlschema.Operator().CreateIndex(&sqlschema.UniqueIndex{TableName: "auth_token", ColumnNames: []sqlschema.ColumnName{"refresh_token"}})
|
||||
sqls = append(sqls, indexSQLs...)
|
||||
|
||||
for _, sql := range sqls {
|
||||
if _, err := tx.ExecContext(ctx, string(sql)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *addAuthToken) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
742
pkg/sqlmigration/s100sqlmigration/100_v100.go
Normal file
742
pkg/sqlmigration/s100sqlmigration/100_v100.go
Normal file
@@ -0,0 +1,742 @@
|
||||
package s100sqlmigration
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/factory"
|
||||
"github.com/SigNoz/signoz/pkg/sqlmigration"
|
||||
"github.com/SigNoz/signoz/pkg/sqlschema"
|
||||
"github.com/SigNoz/signoz/pkg/sqlstore"
|
||||
"github.com/uptrace/bun"
|
||||
"github.com/uptrace/bun/migrate"
|
||||
)
|
||||
|
||||
type v100 struct {
|
||||
sqlstore sqlstore.SQLStore
|
||||
sqlschema sqlschema.SQLSchema
|
||||
}
|
||||
|
||||
func NewV100Factory(sqlstore sqlstore.SQLStore, sqlschema sqlschema.SQLSchema) factory.ProviderFactory[sqlmigration.SQLMigration, sqlmigration.Config] {
|
||||
return factory.NewProviderFactory(factory.MustNewName("v100"), func(_ context.Context, _ factory.ProviderSettings, _ sqlmigration.Config) (sqlmigration.SQLMigration, error) {
|
||||
return &v100{
|
||||
sqlstore: sqlstore,
|
||||
sqlschema: sqlschema,
|
||||
}, nil
|
||||
})
|
||||
}
|
||||
|
||||
func (migration *v100) Register(migrations *migrate.Migrations) error {
|
||||
return migrations.Register(migration.Up, migration.Down)
|
||||
}
|
||||
|
||||
func (migration *v100) Up(ctx context.Context, db *bun.DB) error {
|
||||
tables := []*sqlschema.Table{
|
||||
{
|
||||
Name: "organizations",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("name"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("display_name"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("alias"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("key"), DataType: sqlschema.DataTypeBigInt, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
},
|
||||
{
|
||||
Name: "users",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("display_name"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("email"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("role"), DataType: sqlschema.DataTypeText, Nullable: false, Default: "'VIEWER'"},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "saved_views",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("name"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("category"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("source_page"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("tags"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("data"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("extra_data"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""}, //Problematic
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "pipelines",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("order_id"), DataType: sqlschema.DataTypeInteger, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("enabled"), DataType: sqlschema.DataTypeBoolean, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("name"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("alias"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("description"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("filter"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("config_json"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "notification_channel",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("name"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("type"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("data"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "alertmanager_config",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("config"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("hash"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "alertmanager_state",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("silences"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("nflog"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "org_preference",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("preference_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("preference_value"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "user_preference",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("preference_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("preference_value"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("user_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("user_id"), ReferencedTableName: sqlschema.TableName("users"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "apdex_setting",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("service_name"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("threshold"), DataType: sqlschema.DataTypeNumeric, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("exclude_status_codes"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "ttl_setting",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("transaction_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("table_name"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("ttl"), DataType: sqlschema.DataTypeInteger, Nullable: false, Default: "0"},
|
||||
{Name: sqlschema.ColumnName("cold_storage_ttl"), DataType: sqlschema.DataTypeInteger, Nullable: false, Default: "0"},
|
||||
{Name: sqlschema.ColumnName("status"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("condition"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "virtual_field",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("name"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("expression"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("description"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("signal"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "installed_integration",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("type"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("config"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("installed_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: "CURRENT_TIMESTAMP"},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "cloud_integration",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("provider"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("config"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("account_id"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("last_agent_report"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("removed_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "cloud_integration_service",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("type"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("config"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("cloud_integration_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("cloud_integration_id"), ReferencedTableName: sqlschema.TableName("cloud_integration"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "rule",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("deleted"), DataType: sqlschema.DataTypeInteger, Nullable: false, Default: "0"},
|
||||
{Name: sqlschema.ColumnName("data"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "planned_maintenance",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("name"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("description"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("schedule"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "planned_maintenance_rule",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("planned_maintenance_id"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("rule_id"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("planned_maintenance_id"), ReferencedTableName: sqlschema.TableName("planned_maintenance"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
{ReferencingColumnName: sqlschema.ColumnName("rule_id"), ReferencedTableName: sqlschema.TableName("rule"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "quick_filter",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("filter"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("signal"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "factor_password",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("password"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("temporary"), DataType: sqlschema.DataTypeBoolean, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("user_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("user_id"), ReferencedTableName: sqlschema.TableName("users"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "reset_password_token",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("token"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("password_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("password_id"), ReferencedTableName: sqlschema.TableName("factor_password"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "factor_api_key",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_by"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_by"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("token"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("role"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("name"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("expires_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("last_used"), DataType: sqlschema.DataTypeTimestamp, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("revoked"), DataType: sqlschema.DataTypeBoolean, Nullable: false, Default: "false"},
|
||||
{Name: sqlschema.ColumnName("user_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("user_id"), ReferencedTableName: sqlschema.TableName("users"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "license",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("key"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("data"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("last_validated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "trace_funnel",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("name"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("description"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("steps"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("tags"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "dashboard",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("data"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("locked"), DataType: sqlschema.DataTypeBoolean, Nullable: false, Default: "false"},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "agent",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("agent_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("terminated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("status"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("config"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "agent_config_version",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_by"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("version"), DataType: sqlschema.DataTypeInteger, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("element_type"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("deploy_status"), DataType: sqlschema.DataTypeText, Nullable: false, Default: "'dirty'"},
|
||||
{Name: sqlschema.ColumnName("deploy_sequence"), DataType: sqlschema.DataTypeInteger, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("deploy_result"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("hash"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("config"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "agent_config_element",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("element_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("element_type"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("version_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("version_id"), ReferencedTableName: sqlschema.TableName("agent_config_version"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "user_invite",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("name"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("email"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("token"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("role"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "org_domains",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("org_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("name"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("data"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("org_id"), ReferencedTableName: sqlschema.TableName("organizations"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "route_policy",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: "id", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "created_at", DataType: sqlschema.DataTypeTimestamp, Nullable: false},
|
||||
{Name: "updated_at", DataType: sqlschema.DataTypeTimestamp, Nullable: false},
|
||||
{Name: "created_by", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "updated_by", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "expression", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "kind", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "channels", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "name", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
{Name: "description", DataType: sqlschema.DataTypeText, Nullable: true},
|
||||
{Name: "enabled", DataType: sqlschema.DataTypeBoolean, Nullable: false, Default: "true"},
|
||||
{Name: "tags", DataType: sqlschema.DataTypeText, Nullable: true},
|
||||
{Name: "org_id", DataType: sqlschema.DataTypeText, Nullable: false},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{
|
||||
ColumnNames: []sqlschema.ColumnName{"id"},
|
||||
},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{
|
||||
ReferencingColumnName: "org_id",
|
||||
ReferencedTableName: "organizations",
|
||||
ReferencedColumnName: "id",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "auth_token",
|
||||
Columns: []*sqlschema.Column{
|
||||
{Name: sqlschema.ColumnName("id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("meta"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("prev_access_token"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("access_token"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("prev_refresh_token"), DataType: sqlschema.DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("refresh_token"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("last_observed_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("rotated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: true, Default: ""},
|
||||
{Name: sqlschema.ColumnName("created_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("updated_at"), DataType: sqlschema.DataTypeTimestamp, Nullable: false, Default: ""},
|
||||
{Name: sqlschema.ColumnName("user_id"), DataType: sqlschema.DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &sqlschema.PrimaryKeyConstraint{ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("id")}},
|
||||
ForeignKeyConstraints: []*sqlschema.ForeignKeyConstraint{
|
||||
{ReferencingColumnName: sqlschema.ColumnName("user_id"), ReferencedTableName: sqlschema.TableName("users"), ReferencedColumnName: sqlschema.ColumnName("id")},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
indices := []sqlschema.Index{
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("organizations"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("name")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("organizations"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("alias")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("organizations"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("key")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("users"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("email"), sqlschema.ColumnName("org_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("alertmanager_config"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("org_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("alertmanager_state"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("org_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("org_preference"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("preference_id"), sqlschema.ColumnName("org_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("user_preference"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("preference_id"), sqlschema.ColumnName("user_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("installed_integration"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("type"), sqlschema.ColumnName("org_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("cloud_integration_service"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("type"), sqlschema.ColumnName("cloud_integration_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("quick_filter"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("org_id"), sqlschema.ColumnName("signal")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("factor_password"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("user_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("reset_password_token"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("password_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("reset_password_token"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("token")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("factor_api_key"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("token")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("license"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("key")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("agent"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("agent_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("agent_config_version"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("org_id"), sqlschema.ColumnName("version"), sqlschema.ColumnName("element_type")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("agent_config_element"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("element_id"), sqlschema.ColumnName("element_type"), sqlschema.ColumnName("version_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("user_invite"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("email"), sqlschema.ColumnName("org_id")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("user_invite"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("token")},
|
||||
},
|
||||
&sqlschema.UniqueIndex{
|
||||
TableName: sqlschema.TableName("org_domains"),
|
||||
ColumnNames: []sqlschema.ColumnName{sqlschema.ColumnName("name"), sqlschema.ColumnName("org_id")},
|
||||
},
|
||||
}
|
||||
|
||||
if err := migration.sqlschema.ToggleFKEnforcement(ctx, db, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
_ = tx.Rollback()
|
||||
}()
|
||||
|
||||
tableSQLs := [][]byte{}
|
||||
|
||||
// Alter or create tables.
|
||||
for _, table := range tables {
|
||||
existingTable, existingUniqueConstraints, err := migration.sqlschema.GetTable(ctx, table.Name)
|
||||
if err != nil {
|
||||
if errors.Ast(err, errors.TypeNotFound) {
|
||||
tableSQLs = append(tableSQLs, migration.sqlschema.Operator().CreateTable(table)...)
|
||||
continue
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
tableSQLs = append(tableSQLs, migration.sqlschema.Operator().AlterTable(existingTable, existingUniqueConstraints, table)...)
|
||||
}
|
||||
|
||||
// First, create/alter all tables. This is to ensure that the indices are created/altered after the tables are created/altered.
|
||||
for _, sql := range tableSQLs {
|
||||
if _, err := tx.ExecContext(ctx, string(sql)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var existingIndices []sqlschema.Index
|
||||
for _, table := range tables {
|
||||
indices, err := migration.sqlschema.GetIndices(ctx, table.Name)
|
||||
if err != nil {
|
||||
if errors.Ast(err, errors.TypeNotFound) {
|
||||
continue
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
existingIndices = append(existingIndices, indices...)
|
||||
}
|
||||
|
||||
indexSQLs := migration.sqlschema.Operator().DiffIndices(existingIndices, indices)
|
||||
|
||||
for _, sql := range indexSQLs {
|
||||
if _, err := tx.ExecContext(ctx, string(sql)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := migration.sqlschema.ToggleFKEnforcement(ctx, db, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (migration *v100) Down(ctx context.Context, db *bun.DB) error {
|
||||
return nil
|
||||
}
|
||||
@@ -21,15 +21,6 @@ type SQLMigration interface {
|
||||
Down(context.Context, *bun.DB) error
|
||||
}
|
||||
|
||||
var (
|
||||
OrgReference = "org"
|
||||
UserReference = "user"
|
||||
UserReferenceNoCascade = "user_no_cascade"
|
||||
FactorPasswordReference = "factor_password"
|
||||
CloudIntegrationReference = "cloud_integration"
|
||||
AgentConfigVersionReference = "agent_config_version"
|
||||
)
|
||||
|
||||
func New(
|
||||
ctx context.Context,
|
||||
settings factory.ProviderSettings,
|
||||
|
||||
@@ -54,6 +54,7 @@ func (migrator *migrator) Migrate(ctx context.Context) error {
|
||||
|
||||
group, err := migrator.migrator.Migrate(ctx)
|
||||
if err != nil {
|
||||
migrator.settings.Logger().ErrorContext(ctx, "failed to run sqlstore migrations", "error", err, "dialect", migrator.dialect, "group", group.String(), "applied", group.Migrations.Applied().String())
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -82,7 +83,7 @@ func (migrator *migrator) Rollback(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
migrator.settings.Logger().InfoContext(ctx, "rolled back", "group", group.String(), "dialect", migrator.dialect)
|
||||
migrator.settings.Logger().InfoContext(ctx, "rolled back", "group", group.String(), "dialect", migrator.dialect, "applied", group.Migrations.Applied().String())
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
type SQLMigrator interface {
|
||||
// Migrate migrates the database. Migrate acquires a lock on the database and runs the migrations.
|
||||
Migrate(context.Context) error
|
||||
|
||||
// Rollback rolls back the database. Rollback acquires a lock on the database and rolls back the migrations.
|
||||
Rollback(context.Context) error
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
|
||||
var (
|
||||
DataTypeText = DataType{s: valuer.NewString("TEXT"), z: ""}
|
||||
DataTypeVarchar = DataType{s: valuer.NewString("VARCHAR"), z: ""} // Do not use this data type. Use DataTypeText instead.
|
||||
DataTypeBigInt = DataType{s: valuer.NewString("BIGINT"), z: int64(0)}
|
||||
DataTypeInteger = DataType{s: valuer.NewString("INTEGER"), z: int64(0)}
|
||||
DataTypeNumeric = DataType{s: valuer.NewString("NUMERIC"), z: float64(0)}
|
||||
@@ -40,6 +41,13 @@ type Column struct {
|
||||
Default string
|
||||
}
|
||||
|
||||
func (column *Column) Equals(other *Column) bool {
|
||||
return column.Name == other.Name &&
|
||||
column.DataType == other.DataType &&
|
||||
column.Nullable == other.Nullable &&
|
||||
column.Default == other.Default
|
||||
}
|
||||
|
||||
func (column *Column) ToDefinitionSQL(fmter SQLFormatter) []byte {
|
||||
sql := []byte{}
|
||||
|
||||
@@ -128,3 +136,53 @@ func (column *Column) ToSetNotNullSQL(fmter SQLFormatter, tableName TableName) [
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
func (column *Column) ToDropNotNullSQL(fmter SQLFormatter, tableName TableName) []byte {
|
||||
sql := []byte{}
|
||||
|
||||
sql = append(sql, "ALTER TABLE "...)
|
||||
sql = fmter.AppendIdent(sql, string(tableName))
|
||||
sql = append(sql, " ALTER COLUMN "...)
|
||||
sql = fmter.AppendIdent(sql, string(column.Name))
|
||||
sql = append(sql, " DROP NOT NULL"...)
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
func (column *Column) ToSetDefaultSQL(fmter SQLFormatter, tableName TableName) []byte {
|
||||
sql := []byte{}
|
||||
|
||||
sql = append(sql, "ALTER TABLE "...)
|
||||
sql = fmter.AppendIdent(sql, string(tableName))
|
||||
sql = append(sql, " ALTER COLUMN "...)
|
||||
sql = fmter.AppendIdent(sql, string(column.Name))
|
||||
sql = append(sql, " SET DEFAULT "...)
|
||||
sql = append(sql, column.Default...)
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
func (column *Column) ToDropDefaultSQL(fmter SQLFormatter, tableName TableName) []byte {
|
||||
sql := []byte{}
|
||||
|
||||
sql = append(sql, "ALTER TABLE "...)
|
||||
sql = fmter.AppendIdent(sql, string(tableName))
|
||||
sql = append(sql, " ALTER COLUMN "...)
|
||||
sql = fmter.AppendIdent(sql, string(column.Name))
|
||||
sql = append(sql, " DROP DEFAULT"...)
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
func (column *Column) ToSetDataTypeSQL(fmter SQLFormatter, tableName TableName) []byte {
|
||||
sql := []byte{}
|
||||
|
||||
sql = append(sql, "ALTER TABLE "...)
|
||||
sql = fmter.AppendIdent(sql, string(tableName))
|
||||
sql = append(sql, " ALTER COLUMN "...)
|
||||
sql = fmter.AppendIdent(sql, string(column.Name))
|
||||
sql = append(sql, " SET DATA TYPE "...)
|
||||
sql = append(sql, fmter.SQLDataTypeOf(column.DataType)...)
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
@@ -49,6 +49,9 @@ type Constraint interface {
|
||||
|
||||
// The SQL representation of the constraint.
|
||||
ToDropSQL(fmter SQLFormatter, tableName TableName) []byte
|
||||
|
||||
// The SQL representation of the constraint.
|
||||
ToCreateSQL(fmter SQLFormatter, tableName TableName) []byte
|
||||
}
|
||||
|
||||
type PrimaryKeyConstraint struct {
|
||||
@@ -139,6 +142,27 @@ func (constraint *PrimaryKeyConstraint) ToDropSQL(fmter SQLFormatter, tableName
|
||||
return sql
|
||||
}
|
||||
|
||||
func (constraint *PrimaryKeyConstraint) ToCreateSQL(fmter SQLFormatter, tableName TableName) []byte {
|
||||
sql := []byte{}
|
||||
|
||||
sql = append(sql, "ALTER TABLE "...)
|
||||
sql = fmter.AppendIdent(sql, string(tableName))
|
||||
sql = append(sql, " ADD CONSTRAINT "...)
|
||||
sql = fmter.AppendIdent(sql, constraint.Name(tableName))
|
||||
sql = append(sql, " PRIMARY KEY ("...)
|
||||
|
||||
for i, column := range constraint.ColumnNames {
|
||||
if i > 0 {
|
||||
sql = append(sql, ", "...)
|
||||
}
|
||||
sql = fmter.AppendIdent(sql, string(column))
|
||||
}
|
||||
|
||||
sql = append(sql, ")"...)
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
type ForeignKeyConstraint struct {
|
||||
ReferencingColumnName ColumnName
|
||||
ReferencedTableName TableName
|
||||
@@ -220,6 +244,24 @@ func (constraint *ForeignKeyConstraint) ToDropSQL(fmter SQLFormatter, tableName
|
||||
return sql
|
||||
}
|
||||
|
||||
func (constraint *ForeignKeyConstraint) ToCreateSQL(fmter SQLFormatter, tableName TableName) []byte {
|
||||
sql := []byte{}
|
||||
|
||||
sql = append(sql, "ALTER TABLE "...)
|
||||
sql = fmter.AppendIdent(sql, string(tableName))
|
||||
sql = append(sql, " ADD CONSTRAINT "...)
|
||||
sql = fmter.AppendIdent(sql, constraint.Name(tableName))
|
||||
sql = append(sql, " FOREIGN KEY ("...)
|
||||
sql = fmter.AppendIdent(sql, string(constraint.ReferencingColumnName))
|
||||
sql = append(sql, ") REFERENCES "...)
|
||||
sql = fmter.AppendIdent(sql, string(constraint.ReferencedTableName))
|
||||
sql = append(sql, " ("...)
|
||||
sql = fmter.AppendIdent(sql, string(constraint.ReferencedColumnName))
|
||||
sql = append(sql, ")"...)
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
// Do not use this constraint type. Instead create an index with the `UniqueIndex` type.
|
||||
// The main difference between a Unique Index and a Unique Constraint is mostly semantic, with a constraint focusing more on data integrity, while an index focuses on performance.
|
||||
// We choose to create unique indices because of sqlite. Dropping a unique index is directly supported whilst dropping a unique constraint requires a recreation of the table with the constraint removed.
|
||||
@@ -323,3 +365,7 @@ func (constraint *UniqueConstraint) ToDropSQL(fmter SQLFormatter, tableName Tabl
|
||||
|
||||
return sql
|
||||
}
|
||||
|
||||
func (constraint *UniqueConstraint) ToCreateSQL(fmter SQLFormatter, tableName TableName) []byte {
|
||||
return []byte{}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ func (formatter Formatter) DataTypeOf(dataType string) DataType {
|
||||
switch strings.ToUpper(dataType) {
|
||||
case "TEXT":
|
||||
return DataTypeText
|
||||
case "VARCHAR":
|
||||
return DataTypeVarchar
|
||||
case "BIGINT":
|
||||
return DataTypeBigInt
|
||||
case "INTEGER":
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package sqlschema
|
||||
|
||||
import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
@@ -27,12 +28,18 @@ type Index interface {
|
||||
// Add name to the index. This is typically used to override the autogenerated name because the database might have a different name.
|
||||
Named(name string) Index
|
||||
|
||||
// Returns true if the index is named. A named index is not autogenerated
|
||||
IsNamed() bool
|
||||
|
||||
// The type of the index.
|
||||
Type() IndexType
|
||||
|
||||
// The columns that the index is applied to.
|
||||
Columns() []ColumnName
|
||||
|
||||
// Equals returns true if the index is equal to the other index.
|
||||
Equals(other Index) bool
|
||||
|
||||
// The SQL representation of the index.
|
||||
ToCreateSQL(fmter SQLFormatter) []byte
|
||||
|
||||
@@ -76,6 +83,10 @@ func (index *UniqueIndex) Named(name string) Index {
|
||||
}
|
||||
}
|
||||
|
||||
func (index *UniqueIndex) IsNamed() bool {
|
||||
return index.name != ""
|
||||
}
|
||||
|
||||
func (*UniqueIndex) Type() IndexType {
|
||||
return IndexTypeUnique
|
||||
}
|
||||
@@ -84,6 +95,14 @@ func (index *UniqueIndex) Columns() []ColumnName {
|
||||
return index.ColumnNames
|
||||
}
|
||||
|
||||
func (index *UniqueIndex) Equals(other Index) bool {
|
||||
if other.Type() != IndexTypeUnique {
|
||||
return false
|
||||
}
|
||||
|
||||
return index.Name() == other.Name() && slices.Equal(index.Columns(), other.Columns())
|
||||
}
|
||||
|
||||
func (index *UniqueIndex) ToCreateSQL(fmter SQLFormatter) []byte {
|
||||
sql := []byte{}
|
||||
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
package sqlschema
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
)
|
||||
|
||||
var _ SQLOperator = (*Operator)(nil)
|
||||
|
||||
type OperatorSupport struct {
|
||||
DropConstraint bool
|
||||
ColumnIfNotExistsExists bool
|
||||
AlterColumnSetNotNull bool
|
||||
// Support for creating and dropping constraints.
|
||||
SCreateAndDropConstraint bool
|
||||
|
||||
// Support for `IF EXISTS` and `IF NOT EXISTS` in `ALTER TABLE ADD COLUMN` and `ALTER TABLE DROP COLUMN`.
|
||||
SAlterTableAddAndDropColumnIfNotExistsAndExists bool
|
||||
|
||||
// Support for altering columns such as `ALTER TABLE ALTER COLUMN SET NOT NULL`.
|
||||
SAlterTableAlterColumnSetAndDrop bool
|
||||
}
|
||||
|
||||
type Operator struct {
|
||||
@@ -25,8 +35,115 @@ func (operator *Operator) CreateTable(table *Table) [][]byte {
|
||||
}
|
||||
|
||||
func (operator *Operator) RenameTable(table *Table, newName TableName) [][]byte {
|
||||
sql := table.ToRenameSQL(operator.fmter, newName)
|
||||
table.Name = newName
|
||||
return [][]byte{table.ToRenameSQL(operator.fmter, newName)}
|
||||
|
||||
return [][]byte{sql}
|
||||
}
|
||||
|
||||
func (operator *Operator) AlterTable(oldTable *Table, oldTableUniqueConstraints []*UniqueConstraint, newTable *Table) [][]byte {
|
||||
// The following has to be done in order:
|
||||
// - Drop constraints
|
||||
// - Drop columns (some columns might be part of constraints therefore this depends on Step 1)
|
||||
// - Add columns, then modify columns
|
||||
// - Rename table
|
||||
// - Add constraints (some constraints might be part of columns therefore this depends on Step 3, constraint names also depend on table name which is changed in Step 4)
|
||||
// - Create unique indices from unique constraints for the new table
|
||||
|
||||
sql := [][]byte{}
|
||||
|
||||
// Drop primary key constraint if it is in the old table but not in the new table.
|
||||
if oldTable.PrimaryKeyConstraint != nil && newTable.PrimaryKeyConstraint == nil {
|
||||
sql = append(sql, operator.DropConstraint(oldTable, oldTableUniqueConstraints, oldTable.PrimaryKeyConstraint)...)
|
||||
}
|
||||
|
||||
// Drop primary key constraint if it is in the old table and the new table but they are different.
|
||||
if oldTable.PrimaryKeyConstraint != nil && newTable.PrimaryKeyConstraint != nil && !oldTable.PrimaryKeyConstraint.Equals(newTable.PrimaryKeyConstraint) {
|
||||
sql = append(sql, operator.DropConstraint(oldTable, oldTableUniqueConstraints, oldTable.PrimaryKeyConstraint)...)
|
||||
}
|
||||
|
||||
// Drop foreign key constraints that are in the old table but not in the new table.
|
||||
for _, fkConstraint := range oldTable.ForeignKeyConstraints {
|
||||
if index := operator.findForeignKeyConstraint(newTable, fkConstraint); index == -1 {
|
||||
sql = append(sql, operator.DropConstraint(oldTable, oldTableUniqueConstraints, fkConstraint)...)
|
||||
}
|
||||
}
|
||||
|
||||
// Drop all unique constraints.
|
||||
for _, uniqueConstraint := range oldTableUniqueConstraints {
|
||||
sql = append(sql, operator.DropConstraint(oldTable, oldTableUniqueConstraints, uniqueConstraint)...)
|
||||
}
|
||||
|
||||
// Reduce number of drops for engines with no SCreateAndDropConstraint.
|
||||
if !operator.support.SCreateAndDropConstraint && len(sql) > 0 {
|
||||
// Do not send the unique constraints to recreate table. We will change them to indexes at the end.
|
||||
sql = operator.RecreateTable(oldTable, nil)
|
||||
}
|
||||
|
||||
// Drop columns that are in the old table but not in the new table.
|
||||
for _, column := range oldTable.Columns {
|
||||
if index := operator.findColumnByName(newTable, column.Name); index == -1 {
|
||||
sql = append(sql, operator.DropColumn(oldTable, column)...)
|
||||
}
|
||||
}
|
||||
|
||||
// Add columns that are in the new table but not in the old table.
|
||||
for _, column := range newTable.Columns {
|
||||
if index := operator.findColumnByName(oldTable, column.Name); index == -1 {
|
||||
sql = append(sql, operator.AddColumn(oldTable, oldTableUniqueConstraints, column, nil)...)
|
||||
}
|
||||
}
|
||||
|
||||
// Modify columns that are in the new table and in the old table
|
||||
alterColumnSQLs := [][]byte{}
|
||||
for _, column := range newTable.Columns {
|
||||
alterColumnSQLs = append(alterColumnSQLs, operator.AlterColumn(oldTable, oldTableUniqueConstraints, column)...)
|
||||
}
|
||||
|
||||
// Reduce number of drops for engines with no SAlterTableAlterColumnSetAndDrop.
|
||||
if !operator.support.SAlterTableAlterColumnSetAndDrop && len(alterColumnSQLs) > 0 {
|
||||
// Do not send the unique constraints to recreate table. We will change them to indexes at the end.
|
||||
sql = append(sql, operator.RecreateTable(oldTable, nil)...)
|
||||
}
|
||||
|
||||
if operator.support.SAlterTableAlterColumnSetAndDrop && len(alterColumnSQLs) > 0 {
|
||||
sql = append(sql, alterColumnSQLs...)
|
||||
}
|
||||
|
||||
// Check if the name has changed
|
||||
if oldTable.Name != newTable.Name {
|
||||
sql = append(sql, operator.RenameTable(oldTable, newTable.Name)...)
|
||||
}
|
||||
|
||||
// If the old table does not have a primary key constraint and the new table does, we need to create it.
|
||||
if oldTable.PrimaryKeyConstraint == nil {
|
||||
if newTable.PrimaryKeyConstraint != nil {
|
||||
sql = append(sql, operator.CreateConstraint(oldTable, oldTableUniqueConstraints, newTable.PrimaryKeyConstraint)...)
|
||||
}
|
||||
}
|
||||
|
||||
if oldTable.PrimaryKeyConstraint != nil {
|
||||
if !oldTable.PrimaryKeyConstraint.Equals(newTable.PrimaryKeyConstraint) {
|
||||
sql = append(sql, operator.CreateConstraint(oldTable, oldTableUniqueConstraints, newTable.PrimaryKeyConstraint)...)
|
||||
}
|
||||
}
|
||||
|
||||
// Create foreign key constraints that are in the new table but not in the old table.
|
||||
for _, fkConstraint := range newTable.ForeignKeyConstraints {
|
||||
if index := operator.findForeignKeyConstraint(oldTable, fkConstraint); index == -1 {
|
||||
sql = append(sql, operator.CreateConstraint(oldTable, oldTableUniqueConstraints, fkConstraint)...)
|
||||
}
|
||||
}
|
||||
|
||||
// Create indices for the new table.
|
||||
for _, uniqueConstraint := range oldTableUniqueConstraints {
|
||||
sql = append(sql, uniqueConstraint.ToIndex(oldTable.Name).ToCreateSQL(operator.fmter))
|
||||
}
|
||||
|
||||
// Remove duplicate SQLs.
|
||||
return slices.CompactFunc(sql, func(a, b []byte) bool {
|
||||
return string(a) == string(b)
|
||||
})
|
||||
}
|
||||
|
||||
func (operator *Operator) RecreateTable(table *Table, uniqueConstraints []*UniqueConstraint) [][]byte {
|
||||
@@ -63,16 +180,23 @@ func (operator *Operator) AddColumn(table *Table, uniqueConstraints []*UniqueCon
|
||||
table.Columns = append(table.Columns, column)
|
||||
|
||||
sqls := [][]byte{
|
||||
column.ToAddSQL(operator.fmter, table.Name, operator.support.ColumnIfNotExistsExists),
|
||||
column.ToAddSQL(operator.fmter, table.Name, operator.support.SAlterTableAddAndDropColumnIfNotExistsAndExists),
|
||||
}
|
||||
|
||||
if !column.Nullable {
|
||||
if val == nil {
|
||||
val = column.DataType.z
|
||||
}
|
||||
// If the value is not nil, always try to update the column.
|
||||
if val != nil {
|
||||
sqls = append(sqls, column.ToUpdateSQL(operator.fmter, table.Name, val))
|
||||
}
|
||||
|
||||
if operator.support.AlterColumnSetNotNull {
|
||||
// If the column is not nullable and does not have a default value and no value is provided, we need to set something.
|
||||
// So we set it to the zero value of the column's data type.
|
||||
if !column.Nullable && column.Default == "" && val == nil {
|
||||
sqls = append(sqls, column.ToUpdateSQL(operator.fmter, table.Name, column.DataType.z))
|
||||
}
|
||||
|
||||
// If the column is not nullable, we need to set it to not null.
|
||||
if !column.Nullable {
|
||||
if operator.support.SAlterTableAlterColumnSetAndDrop {
|
||||
sqls = append(sqls, column.ToSetNotNullSQL(operator.fmter, table.Name))
|
||||
} else {
|
||||
sqls = append(sqls, operator.RecreateTable(table, uniqueConstraints)...)
|
||||
@@ -82,6 +206,62 @@ func (operator *Operator) AddColumn(table *Table, uniqueConstraints []*UniqueCon
|
||||
return sqls
|
||||
}
|
||||
|
||||
func (operator *Operator) AlterColumn(table *Table, uniqueConstraints []*UniqueConstraint, column *Column) [][]byte {
|
||||
index := operator.findColumnByName(table, column.Name)
|
||||
// If the column does not exist, we do not need to alter it.
|
||||
if index == -1 {
|
||||
return [][]byte{}
|
||||
}
|
||||
|
||||
oldColumn := table.Columns[index]
|
||||
// If the column is the same, we do not need to alter it.
|
||||
if oldColumn.Equals(column) {
|
||||
return [][]byte{}
|
||||
}
|
||||
|
||||
sqls := [][]byte{}
|
||||
var recreateTable bool
|
||||
|
||||
if oldColumn.DataType != column.DataType {
|
||||
if operator.support.SAlterTableAlterColumnSetAndDrop {
|
||||
sqls = append(sqls, column.ToSetDataTypeSQL(operator.fmter, table.Name))
|
||||
} else {
|
||||
recreateTable = true
|
||||
}
|
||||
}
|
||||
|
||||
if oldColumn.Nullable != column.Nullable {
|
||||
if operator.support.SAlterTableAlterColumnSetAndDrop {
|
||||
if column.Nullable {
|
||||
sqls = append(sqls, column.ToDropNotNullSQL(operator.fmter, table.Name))
|
||||
} else {
|
||||
sqls = append(sqls, column.ToSetNotNullSQL(operator.fmter, table.Name))
|
||||
}
|
||||
} else {
|
||||
recreateTable = true
|
||||
}
|
||||
}
|
||||
|
||||
if oldColumn.Default != column.Default {
|
||||
if operator.support.SAlterTableAlterColumnSetAndDrop {
|
||||
if column.Default != "" {
|
||||
sqls = append(sqls, column.ToSetDefaultSQL(operator.fmter, table.Name))
|
||||
} else {
|
||||
sqls = append(sqls, column.ToDropDefaultSQL(operator.fmter, table.Name))
|
||||
}
|
||||
} else {
|
||||
recreateTable = true
|
||||
}
|
||||
}
|
||||
|
||||
table.Columns[index] = column
|
||||
if recreateTable {
|
||||
sqls = append(sqls, operator.RecreateTable(table, uniqueConstraints)...)
|
||||
}
|
||||
|
||||
return sqls
|
||||
}
|
||||
|
||||
func (operator *Operator) DropColumn(table *Table, column *Column) [][]byte {
|
||||
index := operator.findColumnByName(table, column.Name)
|
||||
// If the column does not exist, we do not need to drop it.
|
||||
@@ -91,7 +271,48 @@ func (operator *Operator) DropColumn(table *Table, column *Column) [][]byte {
|
||||
|
||||
table.Columns = append(table.Columns[:index], table.Columns[index+1:]...)
|
||||
|
||||
return [][]byte{column.ToDropSQL(operator.fmter, table.Name, operator.support.ColumnIfNotExistsExists)}
|
||||
return [][]byte{column.ToDropSQL(operator.fmter, table.Name, operator.support.SAlterTableAddAndDropColumnIfNotExistsAndExists)}
|
||||
}
|
||||
|
||||
func (operator *Operator) CreateConstraint(table *Table, uniqueConstraints []*UniqueConstraint, constraint Constraint) [][]byte {
|
||||
if constraint == nil {
|
||||
return [][]byte{}
|
||||
}
|
||||
|
||||
if reflect.ValueOf(constraint).IsNil() {
|
||||
return [][]byte{}
|
||||
}
|
||||
|
||||
if constraint.Type() == ConstraintTypeForeignKey {
|
||||
// Constraint already exists as foreign key constraint.
|
||||
if table.ForeignKeyConstraints != nil {
|
||||
for _, fkConstraint := range table.ForeignKeyConstraints {
|
||||
if constraint.Equals(fkConstraint) {
|
||||
return [][]byte{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
table.ForeignKeyConstraints = append(table.ForeignKeyConstraints, constraint.(*ForeignKeyConstraint))
|
||||
}
|
||||
|
||||
sqls := [][]byte{}
|
||||
if constraint.Type() == ConstraintTypePrimaryKey {
|
||||
if operator.support.SCreateAndDropConstraint {
|
||||
if table.PrimaryKeyConstraint != nil {
|
||||
// TODO(grandwizard28): this is a hack to drop the primary key constraint.
|
||||
// We need to find a better way to do this.
|
||||
sqls = append(sqls, table.PrimaryKeyConstraint.ToDropSQL(operator.fmter, table.Name))
|
||||
}
|
||||
}
|
||||
table.PrimaryKeyConstraint = constraint.(*PrimaryKeyConstraint)
|
||||
}
|
||||
|
||||
if operator.support.SCreateAndDropConstraint {
|
||||
return append(sqls, constraint.ToCreateSQL(operator.fmter, table.Name))
|
||||
}
|
||||
|
||||
return operator.RecreateTable(table, uniqueConstraints)
|
||||
}
|
||||
|
||||
func (operator *Operator) DropConstraint(table *Table, uniqueConstraints []*UniqueConstraint, constraint Constraint) [][]byte {
|
||||
@@ -104,20 +325,48 @@ func (operator *Operator) DropConstraint(table *Table, uniqueConstraints []*Uniq
|
||||
return [][]byte{}
|
||||
}
|
||||
|
||||
if operator.support.DropConstraint {
|
||||
if operator.support.SCreateAndDropConstraint {
|
||||
return [][]byte{uniqueConstraints[uniqueConstraintIndex].ToDropSQL(operator.fmter, table.Name)}
|
||||
}
|
||||
|
||||
return operator.RecreateTable(table, append(uniqueConstraints[:uniqueConstraintIndex], uniqueConstraints[uniqueConstraintIndex+1:]...))
|
||||
var copyOfUniqueConstraints []*UniqueConstraint
|
||||
copyOfUniqueConstraints = append(copyOfUniqueConstraints, uniqueConstraints[:uniqueConstraintIndex]...)
|
||||
copyOfUniqueConstraints = append(copyOfUniqueConstraints, uniqueConstraints[uniqueConstraintIndex+1:]...)
|
||||
|
||||
return operator.RecreateTable(table, copyOfUniqueConstraints)
|
||||
}
|
||||
|
||||
if operator.support.DropConstraint {
|
||||
if operator.support.SCreateAndDropConstraint {
|
||||
return [][]byte{toDropConstraint.ToDropSQL(operator.fmter, table.Name)}
|
||||
}
|
||||
|
||||
return operator.RecreateTable(table, uniqueConstraints)
|
||||
}
|
||||
|
||||
func (operator *Operator) DiffIndices(oldIndices []Index, newIndices []Index) [][]byte {
|
||||
sqls := [][]byte{}
|
||||
|
||||
for i, oldIndex := range oldIndices {
|
||||
if index := operator.findIndex(newIndices, oldIndex); index == -1 {
|
||||
sqls = append(sqls, oldIndex.ToDropSQL(operator.fmter))
|
||||
continue
|
||||
}
|
||||
|
||||
if oldIndex.IsNamed() {
|
||||
sqls = append(sqls, oldIndex.ToDropSQL(operator.fmter))
|
||||
sqls = append(sqls, newIndices[i].ToCreateSQL(operator.fmter))
|
||||
}
|
||||
}
|
||||
|
||||
for _, newIndex := range newIndices {
|
||||
if index := operator.findIndex(oldIndices, newIndex); index == -1 {
|
||||
sqls = append(sqls, newIndex.ToCreateSQL(operator.fmter))
|
||||
}
|
||||
}
|
||||
|
||||
return sqls
|
||||
}
|
||||
|
||||
func (*Operator) findColumnByName(table *Table, columnName ColumnName) int {
|
||||
for i, column := range table.Columns {
|
||||
if column.Name == columnName {
|
||||
@@ -141,3 +390,27 @@ func (*Operator) findUniqueConstraint(uniqueConstraints []*UniqueConstraint, con
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func (*Operator) findForeignKeyConstraint(table *Table, constraint Constraint) int {
|
||||
if constraint.Type() != ConstraintTypeForeignKey {
|
||||
return -1
|
||||
}
|
||||
|
||||
for i, fkConstraint := range table.ForeignKeyConstraints {
|
||||
if fkConstraint.Equals(constraint) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
func (*Operator) findIndex(indices []Index, index Index) int {
|
||||
for i, inputIndex := range indices {
|
||||
if index.Equals(inputIndex) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package sqlschema
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/uptrace/bun/schema"
|
||||
@@ -54,9 +56,8 @@ func TestOperatorAddColumn(t *testing.T) {
|
||||
column *Column
|
||||
val any
|
||||
uniqueConstraints []*UniqueConstraint
|
||||
support OperatorSupport
|
||||
expectedSQLs [][]byte
|
||||
expectedTable *Table
|
||||
expected map[OperatorSupport][][]byte
|
||||
}{
|
||||
{
|
||||
name: "NullableNoDefault_DoesNotExist",
|
||||
@@ -68,19 +69,21 @@ func TestOperatorAddColumn(t *testing.T) {
|
||||
},
|
||||
column: &Column{Name: "name", DataType: DataTypeText, Nullable: true, Default: ""},
|
||||
val: nil,
|
||||
support: OperatorSupport{
|
||||
ColumnIfNotExistsExists: true,
|
||||
AlterColumnSetNotNull: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "name" TEXT`),
|
||||
},
|
||||
expectedTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN "name" TEXT`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "name" TEXT`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -94,21 +97,21 @@ func TestOperatorAddColumn(t *testing.T) {
|
||||
},
|
||||
column: &Column{Name: "name", DataType: DataTypeBigInt, Nullable: true, Default: ""},
|
||||
val: nil,
|
||||
support: OperatorSupport{
|
||||
ColumnIfNotExistsExists: true,
|
||||
AlterColumnSetNotNull: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{},
|
||||
expectedTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NotNullableNoDefaultNoVal_DoesNotExist",
|
||||
name: "TextNotNullableNoDefaultNoVal_DoesNotExist",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -117,25 +120,32 @@ func TestOperatorAddColumn(t *testing.T) {
|
||||
},
|
||||
column: &Column{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
val: nil,
|
||||
support: OperatorSupport{
|
||||
ColumnIfNotExistsExists: true,
|
||||
AlterColumnSetNotNull: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "name" TEXT`),
|
||||
[]byte(`UPDATE "users" SET "name" = ''`),
|
||||
[]byte(`ALTER TABLE "users" ALTER COLUMN "name" SET NOT NULL`),
|
||||
},
|
||||
expectedTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN "name" TEXT`),
|
||||
[]byte(`UPDATE "users" SET "name" = ''`),
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "name" TEXT NOT NULL)`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id", "name") SELECT "id", "name" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "name" TEXT`),
|
||||
[]byte(`UPDATE "users" SET "name" = ''`),
|
||||
[]byte(`ALTER TABLE "users" ALTER COLUMN "name" SET NOT NULL`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NotNullableNoDefault_DoesNotExist",
|
||||
name: "IntegerNotNullableNoDefaultNoVal_DoesNotExist",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -143,81 +153,154 @@ func TestOperatorAddColumn(t *testing.T) {
|
||||
},
|
||||
},
|
||||
column: &Column{Name: "num", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
val: int64(100),
|
||||
support: OperatorSupport{
|
||||
ColumnIfNotExistsExists: true,
|
||||
AlterColumnSetNotNull: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "num" INTEGER`),
|
||||
[]byte(`UPDATE "users" SET "num" = 100`),
|
||||
[]byte(`ALTER TABLE "users" ALTER COLUMN "num" SET NOT NULL`),
|
||||
},
|
||||
expectedTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "num", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "NotNullableNoDefault_DoesNotExist_AlterColumnSetNotNullFalse",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
},
|
||||
column: &Column{Name: "num", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
val: int64(100),
|
||||
uniqueConstraints: []*UniqueConstraint{
|
||||
{ColumnNames: []ColumnName{"name"}},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
ColumnIfNotExistsExists: true,
|
||||
AlterColumnSetNotNull: false,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "num" INTEGER`),
|
||||
[]byte(`UPDATE "users" SET "num" = 100`),
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "name" TEXT NOT NULL, "num" INTEGER NOT NULL)`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id", "name", "num") SELECT "id", "name", "num" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
[]byte(`CREATE UNIQUE INDEX IF NOT EXISTS "uq_users_name" ON "users" ("name")`),
|
||||
},
|
||||
expectedTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: "num", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MismatchingDataType_DoesExist_AlterColumnSetNotNullFalse",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
},
|
||||
column: &Column{Name: "name", DataType: DataTypeBigInt, Nullable: false, Default: ""},
|
||||
val: nil,
|
||||
support: OperatorSupport{
|
||||
ColumnIfNotExistsExists: true,
|
||||
AlterColumnSetNotNull: false,
|
||||
},
|
||||
expectedSQLs: [][]byte{},
|
||||
expectedTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: "num", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN "num" INTEGER`),
|
||||
[]byte(`UPDATE "users" SET "num" = 0`),
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "num" INTEGER NOT NULL)`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id", "num") SELECT "id", "num" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "num" INTEGER`),
|
||||
[]byte(`UPDATE "users" SET "num" = 0`),
|
||||
[]byte(`ALTER TABLE "users" ALTER COLUMN "num" SET NOT NULL`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "IntegerNotNullableNoDefaultVal_DoesNotExist",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
},
|
||||
column: &Column{Name: "num", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
val: int64(100),
|
||||
expectedTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "num", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN "num" INTEGER`),
|
||||
[]byte(`UPDATE "users" SET "num" = 100`),
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "num" INTEGER NOT NULL)`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id", "num") SELECT "id", "num" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "num" INTEGER`),
|
||||
[]byte(`UPDATE "users" SET "num" = 100`),
|
||||
[]byte(`ALTER TABLE "users" ALTER COLUMN "num" SET NOT NULL`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "BooleanNotNullableNoDefaultValNoVal_DoesNotExist",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
},
|
||||
column: &Column{Name: "is_admin", DataType: DataTypeBoolean, Nullable: false, Default: ""},
|
||||
val: nil,
|
||||
expectedTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "is_admin", DataType: DataTypeBoolean, Nullable: false, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN "is_admin" BOOLEAN`),
|
||||
// Set to the zero value
|
||||
[]byte(`UPDATE "users" SET "is_admin" = FALSE`),
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "is_admin" BOOLEAN NOT NULL)`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id", "is_admin") SELECT "id", "is_admin" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "is_admin" BOOLEAN`),
|
||||
// Set to the zero value
|
||||
[]byte(`UPDATE "users" SET "is_admin" = FALSE`),
|
||||
[]byte(`ALTER TABLE "users" ALTER COLUMN "is_admin" SET NOT NULL`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "BooleanNullableDefaultVal_DoesNotExist",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
},
|
||||
column: &Column{Name: "is_admin", DataType: DataTypeBoolean, Nullable: true, Default: "TRUE"},
|
||||
val: nil,
|
||||
expectedTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "is_admin", DataType: DataTypeBoolean, Nullable: true, Default: "TRUE"},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN "is_admin" BOOLEAN DEFAULT TRUE`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "is_admin" BOOLEAN DEFAULT TRUE`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "TimestampNullableDefaultValAndVal_DoesNotExist",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
},
|
||||
column: &Column{Name: "created_at", DataType: DataTypeTimestamp, Nullable: true, Default: "CURRENT_TIMESTAMP"},
|
||||
val: time.Time{},
|
||||
expectedTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "created_at", DataType: DataTypeTimestamp, Nullable: true, Default: "CURRENT_TIMESTAMP"},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP`),
|
||||
[]byte(`UPDATE "users" SET "created_at" = '0001-01-01 00:00:00+00:00'`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "created_at" TIMESTAMP DEFAULT CURRENT_TIMESTAMP`),
|
||||
[]byte(`UPDATE "users" SET "created_at" = '0001-01-01 00:00:00+00:00'`),
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -226,11 +309,15 @@ func TestOperatorAddColumn(t *testing.T) {
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
fmter := NewFormatter(schema.NewNopFormatter().Dialect())
|
||||
operator := NewOperator(fmter, testCase.support)
|
||||
|
||||
actuals := operator.AddColumn(testCase.table, testCase.uniqueConstraints, testCase.column, testCase.val)
|
||||
assert.Equal(t, testCase.expectedSQLs, actuals)
|
||||
assert.Equal(t, testCase.expectedTable, testCase.table)
|
||||
for support, expectedSQLs := range testCase.expected {
|
||||
operator := NewOperator(fmter, support)
|
||||
clonedTable := testCase.table.Clone()
|
||||
|
||||
actuals := operator.AddColumn(clonedTable, testCase.uniqueConstraints, testCase.column, testCase.val)
|
||||
assert.Equal(t, expectedSQLs, actuals)
|
||||
assert.Equal(t, testCase.expectedTable, clonedTable)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -246,7 +333,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
expectedTable *Table
|
||||
}{
|
||||
{
|
||||
name: "PrimaryKeyConstraint_DoesExist_DropConstraintTrue",
|
||||
name: "PrimaryKeyConstraint_DoesExist_SCreateAndDropConstraintTrue",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -260,7 +347,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
ColumnNames: []ColumnName{"id"},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: true,
|
||||
SCreateAndDropConstraint: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "pk_users"`),
|
||||
@@ -273,7 +360,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PrimaryKeyConstraint_DoesNotExist_DropConstraintTrue",
|
||||
name: "PrimaryKeyConstraint_DoesNotExist_SCreateAndDropConstraintTrue",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -284,7 +371,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
ColumnNames: []ColumnName{"id"},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: true,
|
||||
SCreateAndDropConstraint: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{},
|
||||
expectedTable: &Table{
|
||||
@@ -295,7 +382,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PrimaryKeyConstraintDifferentName_DoesExist_DropConstraintTrue",
|
||||
name: "PrimaryKeyConstraintDifferentName_DoesExist_SCreateAndDropConstraintTrue",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -310,7 +397,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
ColumnNames: []ColumnName{"id"},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: true,
|
||||
SCreateAndDropConstraint: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "pk_users_different_name"`),
|
||||
@@ -323,7 +410,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PrimaryKeyConstraint_DoesExist_DropConstraintFalse",
|
||||
name: "PrimaryKeyConstraint_DoesExist_SCreateAndDropConstraintFalse",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -337,7 +424,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
ColumnNames: []ColumnName{"id"},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: false,
|
||||
SCreateAndDropConstraint: false,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL)`),
|
||||
@@ -353,7 +440,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "PrimaryKeyConstraint_DoesNotExist_DropConstraintFalse",
|
||||
name: "PrimaryKeyConstraint_DoesNotExist_SCreateAndDropConstraintFalse",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -364,7 +451,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
ColumnNames: []ColumnName{"id"},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: false,
|
||||
SCreateAndDropConstraint: false,
|
||||
},
|
||||
expectedSQLs: [][]byte{},
|
||||
expectedTable: &Table{
|
||||
@@ -375,7 +462,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "UniqueConstraint_DoesExist_DropConstraintTrue",
|
||||
name: "UniqueConstraint_DoesExist_SCreateAndDropConstraintTrue",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -390,7 +477,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
{ColumnNames: []ColumnName{"name"}},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: true,
|
||||
SCreateAndDropConstraint: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "uq_users_name"`),
|
||||
@@ -404,7 +491,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "UniqueConstraint_DoesNotExist_DropConstraintTrue",
|
||||
name: "UniqueConstraint_DoesNotExist_SCreateAndDropConstraintTrue",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -419,7 +506,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
{ColumnNames: []ColumnName{"id"}},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: true,
|
||||
SCreateAndDropConstraint: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{},
|
||||
expectedTable: &Table{
|
||||
@@ -431,7 +518,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "UniqueConstraint_DoesExist_DropConstraintFalse",
|
||||
name: "UniqueConstraint_DoesExist_SCreateAndDropConstraintFalse",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -446,7 +533,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
{ColumnNames: []ColumnName{"name"}},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: false,
|
||||
SCreateAndDropConstraint: false,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "name" TEXT NOT NULL)`),
|
||||
@@ -463,7 +550,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "UniqueConstraint_DoesNotExist_DropConstraintFalse",
|
||||
name: "UniqueConstraint_DoesNotExist_SCreateAndDropConstraintFalse",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -478,7 +565,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
{ColumnNames: []ColumnName{"id"}},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: false,
|
||||
SCreateAndDropConstraint: false,
|
||||
},
|
||||
expectedSQLs: [][]byte{},
|
||||
expectedTable: &Table{
|
||||
@@ -490,7 +577,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ForeignKeyConstraint_DoesExist_DropConstraintTrue",
|
||||
name: "ForeignKeyConstraint_DoesExist_SCreateAndDropConstraintTrue",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -506,7 +593,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
{ColumnNames: []ColumnName{"id"}},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: true,
|
||||
SCreateAndDropConstraint: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "fk_users_org_id"`),
|
||||
@@ -521,7 +608,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ForeignKeyConstraintDifferentName_DoesExist_DropConstraintTrue",
|
||||
name: "ForeignKeyConstraintDifferentName_DoesExist_SCreateAndDropConstraintTrue",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -537,7 +624,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
{ColumnNames: []ColumnName{"id"}},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: true,
|
||||
SCreateAndDropConstraint: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "my_fk"`),
|
||||
@@ -552,7 +639,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ForeignKeyConstraint_DoesNotExist_DropConstraintTrue",
|
||||
name: "ForeignKeyConstraint_DoesNotExist_SCreateAndDropConstraintTrue",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -569,7 +656,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
{ColumnNames: []ColumnName{"id"}},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: true,
|
||||
SCreateAndDropConstraint: true,
|
||||
},
|
||||
expectedSQLs: [][]byte{},
|
||||
expectedTable: &Table{
|
||||
@@ -584,7 +671,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ForeignKeyConstraint_DoesExist_DropConstraintFalse",
|
||||
name: "ForeignKeyConstraint_DoesExist_SCreateAndDropConstraintFalse",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -600,7 +687,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
{ColumnNames: []ColumnName{"id"}},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: false,
|
||||
SCreateAndDropConstraint: false,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "org_id" INTEGER NOT NULL)`),
|
||||
@@ -620,7 +707,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ForeignKeyConstraintDifferentName_DoesExist_DropConstraintFalse",
|
||||
name: "ForeignKeyConstraintDifferentName_DoesExist_SCreateAndDropConstraintFalse",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -636,7 +723,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
{ColumnNames: []ColumnName{"id"}},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: false,
|
||||
SCreateAndDropConstraint: false,
|
||||
},
|
||||
expectedSQLs: [][]byte{
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "org_id" INTEGER NOT NULL)`),
|
||||
@@ -656,7 +743,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ForeignKeyConstraint_DoesNotExist_DropConstraintFalse",
|
||||
name: "ForeignKeyConstraint_DoesNotExist_SCreateAndDropConstraintFalse",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
@@ -673,7 +760,7 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
{ColumnNames: []ColumnName{"id"}},
|
||||
},
|
||||
support: OperatorSupport{
|
||||
DropConstraint: false,
|
||||
SCreateAndDropConstraint: false,
|
||||
},
|
||||
expectedSQLs: [][]byte{},
|
||||
expectedTable: &Table{
|
||||
@@ -700,3 +787,366 @@ func TestOperatorDropConstraint(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestOperatorAlterTable(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
table *Table
|
||||
uniqueConstraints []*UniqueConstraint
|
||||
newTable *Table
|
||||
expected map[OperatorSupport][][]byte
|
||||
}{
|
||||
{
|
||||
name: "NoOperation",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
},
|
||||
newTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "RenameTable",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
},
|
||||
newTable: &Table{
|
||||
Name: "users_new",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
[]byte(`ALTER TABLE "users" RENAME TO "users_new"`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" RENAME TO "users_new"`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "AddColumn_NullableNoDefault_SAlterTableAddAndDropColumnIfNotExistsAndExistsTrue",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
},
|
||||
newTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: "age", DataType: DataTypeInteger, Nullable: true, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN "age" INTEGER`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "age" INTEGER`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CreatePrimaryKeyConstraint",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
},
|
||||
newTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &PrimaryKeyConstraint{
|
||||
ColumnNames: []ColumnName{"id"},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, CONSTRAINT "pk_users" PRIMARY KEY ("id"))`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id") SELECT "id" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" ADD CONSTRAINT "pk_users" PRIMARY KEY ("id")`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DropPrimaryKeyConstraint_AlterColumnNullable",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: true, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &PrimaryKeyConstraint{ColumnNames: []ColumnName{"id"}},
|
||||
},
|
||||
newTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
// first drop to remove the primary key constraint
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "name" TEXT)`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id", "name") SELECT "id", "name" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
// second drop to make the column nullable
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "name" TEXT NOT NULL)`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id", "name") SELECT "id", "name" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "pk_users"`),
|
||||
[]byte(`ALTER TABLE "users" ALTER COLUMN "name" SET NOT NULL`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DropForeignKeyConstraint_DropColumn",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "org_id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{
|
||||
{ReferencingColumnName: "org_id", ReferencedTableName: "orgs", ReferencedColumnName: "id"},
|
||||
},
|
||||
},
|
||||
newTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
// first drop to remove the foreign key constraint
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "org_id" INTEGER NOT NULL)`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id", "org_id") SELECT "id", "org_id" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
// second drop to remove the column
|
||||
[]byte(`ALTER TABLE "users" DROP COLUMN "org_id"`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
// first drop to remove the foreign key constraint
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "fk_users_org_id"`),
|
||||
// second drop to remove the column
|
||||
[]byte(`ALTER TABLE "users" DROP COLUMN IF EXISTS "org_id"`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DropMultipleConstraints",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: "age", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "org_id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "team_id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &PrimaryKeyConstraint{ColumnNames: []ColumnName{"id"}},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{
|
||||
{ReferencingColumnName: "org_id", ReferencedTableName: "orgs", ReferencedColumnName: "id"},
|
||||
{ReferencingColumnName: "team_id", ReferencedTableName: "teams", ReferencedColumnName: "id"},
|
||||
},
|
||||
},
|
||||
uniqueConstraints: []*UniqueConstraint{
|
||||
{ColumnNames: []ColumnName{"name", "age"}},
|
||||
},
|
||||
newTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: "age", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "org_id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "team_id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{
|
||||
{ReferencingColumnName: "team_id", ReferencedTableName: "teams", ReferencedColumnName: "id"},
|
||||
},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "name" TEXT NOT NULL, "age" INTEGER NOT NULL, "org_id" INTEGER NOT NULL, "team_id" INTEGER NOT NULL, CONSTRAINT "fk_users_team_id" FOREIGN KEY ("team_id") REFERENCES "teams" ("id"))`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id", "name", "age", "org_id", "team_id") SELECT "id", "name", "age", "org_id", "team_id" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
[]byte(`CREATE UNIQUE INDEX IF NOT EXISTS "uq_users_name_age" ON "users" ("name", "age")`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "pk_users"`),
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "fk_users_org_id"`),
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "uq_users_name_age"`),
|
||||
[]byte(`CREATE UNIQUE INDEX IF NOT EXISTS "uq_users_name_age" ON "users" ("name", "age")`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "DropUniqueConstraints_AlterMultipleColumns",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: true, Default: ""},
|
||||
{Name: "age", DataType: DataTypeInteger, Nullable: true, Default: ""},
|
||||
{Name: "email", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &PrimaryKeyConstraint{ColumnNames: []ColumnName{"id"}},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{
|
||||
{ReferencingColumnName: "org_id", ReferencedTableName: "orgs", ReferencedColumnName: "id"},
|
||||
},
|
||||
},
|
||||
uniqueConstraints: []*UniqueConstraint{
|
||||
{ColumnNames: []ColumnName{"email"}},
|
||||
{name: "my_name_constraint", ColumnNames: []ColumnName{"name"}},
|
||||
},
|
||||
newTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
{Name: "name", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
{Name: "age", DataType: DataTypeInteger, Nullable: false, Default: "0"},
|
||||
{Name: "email", DataType: DataTypeInteger, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &PrimaryKeyConstraint{ColumnNames: []ColumnName{"id"}},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{
|
||||
{ReferencingColumnName: "org_id", ReferencedTableName: "orgs", ReferencedColumnName: "id"},
|
||||
},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
// first drop to remove unique constraint
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "name" TEXT, "age" INTEGER, "email" INTEGER NOT NULL, CONSTRAINT "pk_users" PRIMARY KEY ("id"), CONSTRAINT "fk_users_org_id" FOREIGN KEY ("org_id") REFERENCES "orgs" ("id"))`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id", "name", "age", "email") SELECT "id", "name", "age", "email" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
// second drop to change all columns
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" INTEGER NOT NULL, "name" TEXT NOT NULL, "age" INTEGER NOT NULL DEFAULT 0, "email" INTEGER NOT NULL, CONSTRAINT "pk_users" PRIMARY KEY ("id"), CONSTRAINT "fk_users_org_id" FOREIGN KEY ("org_id") REFERENCES "orgs" ("id"))`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id", "name", "age", "email") SELECT "id", "name", "age", "email" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
// create unique index for the constraint
|
||||
[]byte(`CREATE UNIQUE INDEX IF NOT EXISTS "uq_users_email" ON "users" ("email")`),
|
||||
[]byte(`CREATE UNIQUE INDEX IF NOT EXISTS "uq_users_name" ON "users" ("name")`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "uq_users_email"`),
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "my_name_constraint"`),
|
||||
[]byte(`ALTER TABLE "users" ALTER COLUMN "name" SET NOT NULL`),
|
||||
[]byte(`ALTER TABLE "users" ALTER COLUMN "age" SET NOT NULL`),
|
||||
[]byte(`ALTER TABLE "users" ALTER COLUMN "age" SET DEFAULT 0`),
|
||||
[]byte(`CREATE UNIQUE INDEX IF NOT EXISTS "uq_users_email" ON "users" ("email")`),
|
||||
[]byte(`CREATE UNIQUE INDEX IF NOT EXISTS "uq_users_name" ON "users" ("name")`),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ChangePrimaryKeyConstraint",
|
||||
table: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "id", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &PrimaryKeyConstraint{ColumnNames: []ColumnName{"id"}},
|
||||
},
|
||||
newTable: &Table{
|
||||
Name: "users",
|
||||
Columns: []*Column{
|
||||
{Name: "uuid", DataType: DataTypeText, Nullable: false, Default: ""},
|
||||
},
|
||||
PrimaryKeyConstraint: &PrimaryKeyConstraint{ColumnNames: []ColumnName{"uuid"}},
|
||||
ForeignKeyConstraints: []*ForeignKeyConstraint{},
|
||||
},
|
||||
expected: map[OperatorSupport][][]byte{
|
||||
{SCreateAndDropConstraint: false, SAlterTableAddAndDropColumnIfNotExistsAndExists: false, SAlterTableAlterColumnSetAndDrop: false}: {
|
||||
// first drop to remove the primary key constraint
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("id" TEXT NOT NULL)`),
|
||||
[]byte(`INSERT INTO "users__temp" ("id") SELECT "id" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
// drop the column
|
||||
[]byte(`ALTER TABLE "users" DROP COLUMN "id"`),
|
||||
// add the column
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN "uuid" TEXT`),
|
||||
[]byte(`UPDATE "users" SET "uuid" = ''`),
|
||||
// second drop to make it non-nullable
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("uuid" TEXT NOT NULL)`),
|
||||
[]byte(`INSERT INTO "users__temp" ("uuid") SELECT "uuid" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
// third drop to add the primary key constraint
|
||||
[]byte(`CREATE TABLE IF NOT EXISTS "users__temp" ("uuid" TEXT NOT NULL, CONSTRAINT "pk_users" PRIMARY KEY ("uuid"))`),
|
||||
[]byte(`INSERT INTO "users__temp" ("uuid") SELECT "uuid" FROM "users"`),
|
||||
[]byte(`DROP TABLE IF EXISTS "users"`),
|
||||
[]byte(`ALTER TABLE "users__temp" RENAME TO "users"`),
|
||||
},
|
||||
{SCreateAndDropConstraint: true, SAlterTableAddAndDropColumnIfNotExistsAndExists: true, SAlterTableAlterColumnSetAndDrop: true}: {
|
||||
[]byte(`ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "pk_users"`),
|
||||
[]byte(`ALTER TABLE "users" DROP COLUMN IF EXISTS "id"`),
|
||||
[]byte(`ALTER TABLE "users" ADD COLUMN IF NOT EXISTS "uuid" TEXT`),
|
||||
[]byte(`UPDATE "users" SET "uuid" = ''`),
|
||||
[]byte(`ALTER TABLE "users" ALTER COLUMN "uuid" SET NOT NULL`),
|
||||
[]byte(`ALTER TABLE "users" ADD CONSTRAINT "pk_users" PRIMARY KEY ("uuid")`),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, testCase := range testCases {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
fmter := NewFormatter(schema.NewNopFormatter().Dialect())
|
||||
for support, sqls := range testCase.expected {
|
||||
operator := NewOperator(fmter, support)
|
||||
clonedTable := testCase.table.Clone()
|
||||
|
||||
actuals := operator.AlterTable(clonedTable, testCase.uniqueConstraints, testCase.newTable)
|
||||
for _, sql := range actuals {
|
||||
fmt.Println(string(sql))
|
||||
}
|
||||
assert.Equal(t, sqls, actuals)
|
||||
assert.EqualValues(t, testCase.newTable, clonedTable)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,9 +33,9 @@ func New(ctx context.Context, providerSettings factory.ProviderSettings, config
|
||||
settings: settings,
|
||||
sqlstore: sqlstore,
|
||||
operator: sqlschema.NewOperator(fmter, sqlschema.OperatorSupport{
|
||||
DropConstraint: false,
|
||||
ColumnIfNotExistsExists: false,
|
||||
AlterColumnSetNotNull: false,
|
||||
SCreateAndDropConstraint: false,
|
||||
SAlterTableAddAndDropColumnIfNotExistsAndExists: false,
|
||||
SAlterTableAlterColumnSetAndDrop: false,
|
||||
}),
|
||||
}, nil
|
||||
}
|
||||
@@ -56,7 +56,7 @@ func (provider *provider) GetTable(ctx context.Context, tableName sqlschema.Tabl
|
||||
BunDB().
|
||||
NewRaw("SELECT sql FROM sqlite_master WHERE type IN (?) AND tbl_name = ? AND sql IS NOT NULL", bun.In([]string{"table"}), string(tableName)).
|
||||
Scan(ctx, &sql); err != nil {
|
||||
return nil, nil, err
|
||||
return nil, nil, provider.sqlstore.WrapNotFoundErrf(err, errors.CodeNotFound, "table (%s) not found", tableName)
|
||||
}
|
||||
|
||||
table, uniqueConstraints, err := parseCreateTable(sql, provider.fmter)
|
||||
@@ -73,7 +73,7 @@ func (provider *provider) GetIndices(ctx context.Context, tableName sqlschema.Ta
|
||||
BunDB().
|
||||
QueryContext(ctx, "SELECT * FROM PRAGMA_index_list(?)", string(tableName))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, provider.sqlstore.WrapNotFoundErrf(err, errors.CodeNotFound, "no indices for table (%s) found", tableName)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
@@ -115,10 +115,16 @@ func (provider *provider) GetIndices(ctx context.Context, tableName sqlschema.Ta
|
||||
}
|
||||
|
||||
if unique {
|
||||
indices = append(indices, (&sqlschema.UniqueIndex{
|
||||
index := &sqlschema.UniqueIndex{
|
||||
TableName: tableName,
|
||||
ColumnNames: columns,
|
||||
}).Named(name).(*sqlschema.UniqueIndex))
|
||||
}
|
||||
|
||||
if index.Name() == name {
|
||||
indices = append(indices, index)
|
||||
} else {
|
||||
indices = append(indices, index.Named(name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,10 @@ type SQLOperator interface {
|
||||
// Returns a list of SQL statements to rename a table.
|
||||
RenameTable(*Table, TableName) [][]byte
|
||||
|
||||
// Returns a list of SQL statements to recreate a table.
|
||||
// Returns a list of SQL statements to alter the input table to the new table. It converts all unique constraints to unique indices and drops the unique constraints.
|
||||
AlterTable(*Table, []*UniqueConstraint, *Table) [][]byte
|
||||
|
||||
// Returns a list of SQL statements to recreate a table. In recreating the table, it converts all unqiue constraints to indices and copies data from the old table.
|
||||
RecreateTable(*Table, []*UniqueConstraint) [][]byte
|
||||
|
||||
// Returns a list of SQL statements to create an index.
|
||||
@@ -47,11 +50,21 @@ type SQLOperator interface {
|
||||
// If the column is not nullable, the column is added with the input value, then the column is made non-nullable.
|
||||
AddColumn(*Table, []*UniqueConstraint, *Column, any) [][]byte
|
||||
|
||||
// Returns a list of SQL statements to alter a column.
|
||||
AlterColumn(*Table, []*UniqueConstraint, *Column) [][]byte
|
||||
|
||||
// Returns a list of SQL statements to drop a column from a table.
|
||||
DropColumn(*Table, *Column) [][]byte
|
||||
|
||||
// Returns a list of SQL statements to create a constraint on a table.
|
||||
CreateConstraint(*Table, []*UniqueConstraint, Constraint) [][]byte
|
||||
|
||||
// Returns a list of SQL statements to drop a constraint from a table.
|
||||
DropConstraint(*Table, []*UniqueConstraint, Constraint) [][]byte
|
||||
|
||||
// Returns a list of SQL statements to get the difference between the input indices and the output indices. If the input indices are named,
|
||||
// they are dropped and recreated with autogenerated names.
|
||||
DiffIndices([]Index, []Index) [][]byte
|
||||
}
|
||||
|
||||
type SQLFormatter interface {
|
||||
|
||||
@@ -19,6 +19,7 @@ type BunDB struct {
|
||||
|
||||
func NewBunDB(settings factory.ScopedProviderSettings, sqldb *sql.DB, dialect schema.Dialect, hooks []SQLStoreHook, opts ...bun.DBOption) *BunDB {
|
||||
db := bun.NewDB(sqldb, dialect, opts...)
|
||||
bun.SetLogger(&bunLogger{settings.Logger()})
|
||||
|
||||
for _, hook := range hooks {
|
||||
db.AddQueryHook(hook)
|
||||
|
||||
12
pkg/sqlstore/logger.go
Normal file
12
pkg/sqlstore/logger.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package sqlstore
|
||||
|
||||
import "log/slog"
|
||||
|
||||
type bunLogger struct {
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (l *bunLogger) Printf(format string, v ...interface{}) {
|
||||
// the no lint directive is needed because the bun logger does not accept context
|
||||
l.logger.Info(format, v...) //nolint:sloglint
|
||||
}
|
||||
@@ -1,509 +0,0 @@
|
||||
package sqlitesqlstore
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
const (
|
||||
Identity string = "id"
|
||||
Integer string = "INTEGER"
|
||||
Text string = "TEXT"
|
||||
)
|
||||
|
||||
const (
|
||||
Org string = "org"
|
||||
User string = "user"
|
||||
UserNoCascade string = "user_no_cascade"
|
||||
FactorPassword string = "factor_password"
|
||||
CloudIntegration string = "cloud_integration"
|
||||
AgentConfigVersion string = "agent_config_version"
|
||||
)
|
||||
|
||||
const (
|
||||
OrgReference string = `("org_id") REFERENCES "organizations" ("id")`
|
||||
UserReference string = `("user_id") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE`
|
||||
UserNoCascadeReference string = `("user_id") REFERENCES "users" ("id")`
|
||||
FactorPasswordReference string = `("password_id") REFERENCES "factor_password" ("id")`
|
||||
CloudIntegrationReference string = `("cloud_integration_id") REFERENCES "cloud_integration" ("id") ON DELETE CASCADE`
|
||||
AgentConfigVersionReference string = `("version_id") REFERENCES "agent_config_version" ("id")`
|
||||
)
|
||||
|
||||
const (
|
||||
OrgField string = "org_id"
|
||||
)
|
||||
|
||||
type dialect struct{}
|
||||
|
||||
func (dialect *dialect) GetColumnType(ctx context.Context, bun bun.IDB, table string, column string) (string, error) {
|
||||
var columnType string
|
||||
|
||||
err := bun.
|
||||
NewSelect().
|
||||
ColumnExpr("type").
|
||||
TableExpr("pragma_table_info(?)", table).
|
||||
Where("name = ?", column).
|
||||
Scan(ctx, &columnType)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return columnType, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) IntToTimestamp(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if columnType != "INTEGER" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// if the columns is integer then do this
|
||||
if _, err := bun.ExecContext(ctx, `ALTER TABLE `+table+` RENAME COLUMN `+column+` TO `+column+`_old`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add new timestamp column
|
||||
if _, err := bun.
|
||||
NewAddColumn().
|
||||
Table(table).
|
||||
ColumnExpr(column + " TIMESTAMP").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// copy data from old column to new column, converting from int (unix timestamp) to timestamp
|
||||
if _, err := bun.
|
||||
NewUpdate().
|
||||
Table(table).
|
||||
Set(column + " = datetime(" + column + "_old, 'unixepoch')").
|
||||
Where("1=1").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// drop old column
|
||||
if _, err := bun.NewDropColumn().Table(table).Column(column + "_old").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) IntToBoolean(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
columnExists, err := dialect.ColumnExists(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !columnExists {
|
||||
return nil
|
||||
}
|
||||
|
||||
columnType, err := dialect.GetColumnType(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if columnType != "INTEGER" {
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err := bun.ExecContext(ctx, `ALTER TABLE `+table+` RENAME COLUMN `+column+` TO `+column+`_old`); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add new boolean column
|
||||
if _, err := bun.NewAddColumn().Table(table).ColumnExpr(column + " BOOLEAN").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// copy data from old column to new column, converting from int to boolean
|
||||
if _, err := bun.
|
||||
NewUpdate().
|
||||
Table(table).
|
||||
Set(column + " = CASE WHEN " + column + "_old = 1 THEN true ELSE false END").
|
||||
Where("1=1").
|
||||
Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// drop old column
|
||||
if _, err := bun.NewDropColumn().Table(table).Column(column + "_old").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) ColumnExists(ctx context.Context, bun bun.IDB, table string, column string) (bool, error) {
|
||||
var count int
|
||||
err := bun.NewSelect().
|
||||
ColumnExpr("COUNT(*)").
|
||||
TableExpr("pragma_table_info(?)", table).
|
||||
Where("name = ?", column).
|
||||
Scan(ctx, &count)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
return count > 0, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) AddColumn(ctx context.Context, bun bun.IDB, table string, column string, columnExpr string) error {
|
||||
exists, err := dialect.ColumnExists(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
_, err = bun.
|
||||
NewAddColumn().
|
||||
Table(table).
|
||||
ColumnExpr(column + " " + columnExpr).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) RenameColumn(ctx context.Context, bun bun.IDB, table string, oldColumnName string, newColumnName string) (bool, error) {
|
||||
oldColumnExists, err := dialect.ColumnExists(ctx, bun, table, oldColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
newColumnExists, err := dialect.ColumnExists(ctx, bun, table, newColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if newColumnExists {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
if !oldColumnExists {
|
||||
return false, errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "old column: %s doesn't exist", oldColumnName)
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
ExecContext(ctx, "ALTER TABLE "+table+" RENAME COLUMN "+oldColumnName+" TO "+newColumnName)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) DropColumn(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
exists, err := dialect.ColumnExists(ctx, bun, table, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
_, err = bun.
|
||||
NewDropColumn().
|
||||
Table(table).
|
||||
Column(column).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) TableExists(ctx context.Context, bun bun.IDB, table interface{}) (bool, error) {
|
||||
count := 0
|
||||
err := bun.
|
||||
NewSelect().
|
||||
ColumnExpr("count(*)").
|
||||
Table("sqlite_master").
|
||||
Where("type = ?", "table").
|
||||
Where("name = ?", bun.Dialect().Tables().Get(reflect.TypeOf(table)).Name).
|
||||
Scan(ctx, &count)
|
||||
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) RenameTableAndModifyModel(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, references []string, cb func(context.Context) error) error {
|
||||
if len(references) == 0 {
|
||||
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "cannot run migration without reference")
|
||||
}
|
||||
exists, err := dialect.TableExists(ctx, bun, newModel)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
var fkReferences []string
|
||||
for _, reference := range references {
|
||||
if reference == Org && !slices.Contains(fkReferences, OrgReference) {
|
||||
fkReferences = append(fkReferences, OrgReference)
|
||||
} else if reference == User && !slices.Contains(fkReferences, UserReference) {
|
||||
fkReferences = append(fkReferences, UserReference)
|
||||
} else if reference == UserNoCascade && !slices.Contains(fkReferences, UserNoCascadeReference) {
|
||||
fkReferences = append(fkReferences, UserNoCascadeReference)
|
||||
} else if reference == FactorPassword && !slices.Contains(fkReferences, FactorPasswordReference) {
|
||||
fkReferences = append(fkReferences, FactorPasswordReference)
|
||||
} else if reference == CloudIntegration && !slices.Contains(fkReferences, CloudIntegrationReference) {
|
||||
fkReferences = append(fkReferences, CloudIntegrationReference)
|
||||
} else if reference == AgentConfigVersion && !slices.Contains(fkReferences, AgentConfigVersionReference) {
|
||||
fkReferences = append(fkReferences, AgentConfigVersionReference)
|
||||
}
|
||||
}
|
||||
|
||||
createTable := bun.
|
||||
NewCreateTable().
|
||||
IfNotExists().
|
||||
Model(newModel)
|
||||
|
||||
for _, fk := range fkReferences {
|
||||
createTable = createTable.ForeignKey(fk)
|
||||
}
|
||||
|
||||
_, err = createTable.Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cb(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Model(oldModel).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) AddNotNullDefaultToColumn(ctx context.Context, bun bun.IDB, table string, column, columnType, defaultValue string) error {
|
||||
if _, err := bun.NewAddColumn().Table(table).ColumnExpr(fmt.Sprintf("%s_new %s NOT NULL DEFAULT %s ", column, columnType, defaultValue)).Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := bun.NewUpdate().Table(table).Set(fmt.Sprintf("%s_new = %s", column, column)).Where("1=1").Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := bun.NewDropColumn().Table(table).ColumnExpr(column).Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := bun.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s RENAME COLUMN %s_new TO %s", table, column, column)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) UpdatePrimaryKey(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, reference string, cb func(context.Context) error) error {
|
||||
if reference == "" {
|
||||
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "cannot run migration without reference")
|
||||
}
|
||||
oldTableName := bun.Dialect().Tables().Get(reflect.TypeOf(oldModel)).Name
|
||||
newTableName := bun.Dialect().Tables().Get(reflect.TypeOf(newModel)).Name
|
||||
|
||||
columnType, err := dialect.GetColumnType(ctx, bun, oldTableName, Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if columnType == Text {
|
||||
return nil
|
||||
}
|
||||
|
||||
fkReference := ""
|
||||
if reference == Org {
|
||||
fkReference = OrgReference
|
||||
} else if reference == User {
|
||||
fkReference = UserReference
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
NewCreateTable().
|
||||
IfNotExists().
|
||||
Model(newModel).
|
||||
ForeignKey(fkReference).
|
||||
Exec(ctx)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cb(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Model(oldModel).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s RENAME TO %s", newTableName, oldTableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) AddPrimaryKey(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, reference string, cb func(context.Context) error) error {
|
||||
if reference == "" {
|
||||
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "cannot run migration without reference")
|
||||
}
|
||||
oldTableName := bun.Dialect().Tables().Get(reflect.TypeOf(oldModel)).Name
|
||||
newTableName := bun.Dialect().Tables().Get(reflect.TypeOf(newModel)).Name
|
||||
|
||||
identityExists, err := dialect.ColumnExists(ctx, bun, oldTableName, Identity)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if identityExists {
|
||||
return nil
|
||||
}
|
||||
|
||||
fkReference := ""
|
||||
if reference == Org {
|
||||
fkReference = OrgReference
|
||||
} else if reference == User {
|
||||
fkReference = UserReference
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
NewCreateTable().
|
||||
IfNotExists().
|
||||
Model(newModel).
|
||||
ForeignKey(fkReference).
|
||||
Exec(ctx)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = cb(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
NewDropTable().
|
||||
IfExists().
|
||||
Model(oldModel).
|
||||
Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bun.
|
||||
ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s RENAME TO %s", newTableName, oldTableName))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) DropColumnWithForeignKeyConstraint(ctx context.Context, bunIDB bun.IDB, model interface{}, column string) error {
|
||||
var isForeignKeyEnabled bool
|
||||
if err := bunIDB.QueryRowContext(ctx, "PRAGMA foreign_keys").Scan(&isForeignKeyEnabled); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if isForeignKeyEnabled {
|
||||
return errors.Newf(errors.TypeInvalidInput, errors.CodeInvalidInput, "foreign keys are enabled, please disable them before running this migration")
|
||||
}
|
||||
|
||||
existingTable := bunIDB.Dialect().Tables().Get(reflect.TypeOf(model))
|
||||
columnExists, err := dialect.ColumnExists(ctx, bunIDB, existingTable.Name, column)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !columnExists {
|
||||
return nil
|
||||
}
|
||||
|
||||
newTableName := existingTable.Name + "_tmp"
|
||||
|
||||
// Create the newTmpTable query
|
||||
createTableQuery := bunIDB.NewCreateTable().Model(model).ModelTableExpr(newTableName)
|
||||
|
||||
var columnNames []string
|
||||
|
||||
for _, field := range existingTable.Fields {
|
||||
if field.Name != column {
|
||||
columnNames = append(columnNames, string(field.SQLName))
|
||||
}
|
||||
|
||||
if field.Name == OrgField {
|
||||
createTableQuery = createTableQuery.ForeignKey(OrgReference)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = createTableQuery.Exec(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Copy data from old table to new table
|
||||
if _, err := bunIDB.ExecContext(ctx, fmt.Sprintf("INSERT INTO %s SELECT %s FROM %s", newTableName, strings.Join(columnNames, ", "), existingTable.Name)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bunIDB.NewDropTable().Table(existingTable.Name).Exec(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = bunIDB.ExecContext(ctx, fmt.Sprintf("ALTER TABLE %s RENAME TO %s", newTableName, existingTable.Name))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) ToggleForeignKeyConstraint(ctx context.Context, bun *bun.DB, enable bool) error {
|
||||
if enable {
|
||||
_, err := bun.ExecContext(ctx, "PRAGMA foreign_keys = ON")
|
||||
return err
|
||||
}
|
||||
|
||||
_, err := bun.ExecContext(ctx, "PRAGMA foreign_keys = OFF")
|
||||
return err
|
||||
}
|
||||
@@ -16,7 +16,6 @@ type provider struct {
|
||||
settings factory.ScopedProviderSettings
|
||||
sqldb *sql.DB
|
||||
bundb *sqlstore.BunDB
|
||||
dialect *dialect
|
||||
}
|
||||
|
||||
func NewFactory(hookFactories ...factory.ProviderFactory[sqlstore.SQLStoreHook, sqlstore.Config]) factory.ProviderFactory[sqlstore.SQLStore, sqlstore.Config] {
|
||||
@@ -49,7 +48,6 @@ func New(ctx context.Context, providerSettings factory.ProviderSettings, config
|
||||
settings: settings,
|
||||
sqldb: sqldb,
|
||||
bundb: sqlstore.NewBunDB(settings, sqldb, sqlitedialect.New(), hooks),
|
||||
dialect: new(dialect),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -61,10 +59,6 @@ func (provider *provider) SQLDB() *sql.DB {
|
||||
return provider.sqldb
|
||||
}
|
||||
|
||||
func (provider *provider) Dialect() sqlstore.SQLDialect {
|
||||
return provider.dialect
|
||||
}
|
||||
|
||||
func (provider *provider) BunDBCtx(ctx context.Context) bun.IDB {
|
||||
return provider.bundb.BunDBCtx(ctx)
|
||||
}
|
||||
|
||||
@@ -17,9 +17,6 @@ type SQLStore interface {
|
||||
// BunDB returns an instance of bun.DB. This is the recommended way to interact with the database.
|
||||
BunDB() *bun.DB
|
||||
|
||||
// Returns the dialect of the database.
|
||||
Dialect() SQLDialect
|
||||
|
||||
// RunInTxCtx runs the given callback in a transaction. It creates and injects a new context with the transaction.
|
||||
// If a transaction is present in the context, it will be used.
|
||||
RunInTxCtx(ctx context.Context, opts *SQLStoreTxOptions, cb func(ctx context.Context) error) error
|
||||
@@ -38,51 +35,3 @@ type SQLStore interface {
|
||||
type SQLStoreHook interface {
|
||||
bun.QueryHook
|
||||
}
|
||||
|
||||
type SQLDialect interface {
|
||||
// Returns the type of the column for the given table and column.
|
||||
GetColumnType(context.Context, bun.IDB, string, string) (string, error)
|
||||
|
||||
// Migrates an integer column to a timestamp column for the given table and column.
|
||||
IntToTimestamp(context.Context, bun.IDB, string, string) error
|
||||
|
||||
// Migrates an integer column to a boolean column for the given table and column.
|
||||
IntToBoolean(context.Context, bun.IDB, string, string) error
|
||||
|
||||
// Adds a not null default to the given column for the given table, column, columnType and defaultValue.
|
||||
AddNotNullDefaultToColumn(context.Context, bun.IDB, string, string, string, string) error
|
||||
|
||||
// Checks if a column exists in a table for the given table and column.
|
||||
ColumnExists(context.Context, bun.IDB, string, string) (bool, error)
|
||||
|
||||
// Adds a column to a table for the given table, column and columnType.
|
||||
AddColumn(context.Context, bun.IDB, string, string, string) error
|
||||
|
||||
// Drops a column from a table for the given table and column.
|
||||
DropColumn(context.Context, bun.IDB, string, string) error
|
||||
|
||||
// Renames a column in a table for the given table, old column name and new column name.
|
||||
RenameColumn(context.Context, bun.IDB, string, string, string) (bool, error)
|
||||
|
||||
// Renames a table and modifies the given model for the given table, old model, new model, references and callback. The old model
|
||||
// and new model must inherit bun.BaseModel.
|
||||
RenameTableAndModifyModel(context.Context, bun.IDB, interface{}, interface{}, []string, func(context.Context) error) error
|
||||
|
||||
// Updates the primary key for the given table, old model, new model, reference and callback. The old model and new model
|
||||
// must inherit bun.BaseModel.
|
||||
UpdatePrimaryKey(context.Context, bun.IDB, interface{}, interface{}, string, func(context.Context) error) error
|
||||
|
||||
// Adds a primary key to the given table, old model, new model, reference and callback. The old model and new model
|
||||
// must inherit bun.BaseModel.
|
||||
AddPrimaryKey(context.Context, bun.IDB, interface{}, interface{}, string, func(context.Context) error) error
|
||||
|
||||
// Drops the column and the associated foreign key constraint for the given table and column.
|
||||
DropColumnWithForeignKeyConstraint(context.Context, bun.IDB, interface{}, string) error
|
||||
|
||||
// Checks if a table exists.
|
||||
TableExists(ctx context.Context, bun bun.IDB, table interface{}) (bool, error)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
package sqlstoretest
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/uptrace/bun"
|
||||
)
|
||||
|
||||
type dialect struct {
|
||||
}
|
||||
|
||||
func (dialect *dialect) IntToTimestamp(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) IntToBoolean(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) GetColumnType(ctx context.Context, bun bun.IDB, table string, column string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) ColumnExists(ctx context.Context, bun bun.IDB, table string, column string) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) AddColumn(ctx context.Context, bun bun.IDB, table string, column string, columnExpr string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) RenameColumn(ctx context.Context, bun bun.IDB, table string, oldColumnName string, newColumnName string) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) DropColumn(ctx context.Context, bun bun.IDB, table string, column string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) RenameTableAndModifyModel(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, references []string, cb func(context.Context) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) AddNotNullDefaultToColumn(ctx context.Context, bun bun.IDB, table string, column, columnType, defaultValue string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) UpdatePrimaryKey(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, reference string, cb func(context.Context) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) AddPrimaryKey(ctx context.Context, bun bun.IDB, oldModel interface{}, newModel interface{}, reference string, cb func(context.Context) error) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) DropColumnWithForeignKeyConstraint(ctx context.Context, bun bun.IDB, model interface{}, column string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) TableExists(ctx context.Context, bun bun.IDB, table interface{}) (bool, error) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (dialect *dialect) ToggleForeignKeyConstraint(ctx context.Context, bun *bun.DB, enable bool) error {
|
||||
return nil
|
||||
}
|
||||
@@ -16,10 +16,9 @@ import (
|
||||
var _ sqlstore.SQLStore = (*Provider)(nil)
|
||||
|
||||
type Provider struct {
|
||||
db *sql.DB
|
||||
mock sqlmock.Sqlmock
|
||||
bunDB *bun.DB
|
||||
dialect *dialect
|
||||
db *sql.DB
|
||||
mock sqlmock.Sqlmock
|
||||
bunDB *bun.DB
|
||||
}
|
||||
|
||||
func New(config sqlstore.Config, matcher sqlmock.QueryMatcher) *Provider {
|
||||
@@ -39,10 +38,9 @@ func New(config sqlstore.Config, matcher sqlmock.QueryMatcher) *Provider {
|
||||
}
|
||||
|
||||
return &Provider{
|
||||
db: db,
|
||||
mock: mock,
|
||||
bunDB: bunDB,
|
||||
dialect: new(dialect),
|
||||
db: db,
|
||||
mock: mock,
|
||||
bunDB: bunDB,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,10 +56,6 @@ func (provider *Provider) Mock() sqlmock.Sqlmock {
|
||||
return provider.mock
|
||||
}
|
||||
|
||||
func (provider *Provider) Dialect() sqlstore.SQLDialect {
|
||||
return provider.dialect
|
||||
}
|
||||
|
||||
func (provider *Provider) BunDBCtx(ctx context.Context) bun.IDB {
|
||||
return provider.bunDB
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
// nolint
|
||||
package transition
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type alertMigrateV5 struct {
|
||||
migrateCommon
|
||||
}
|
||||
|
||||
func NewAlertMigrateV5(logger *slog.Logger, logsDuplicateKeys []string, tracesDuplicateKeys []string) *alertMigrateV5 {
|
||||
ambiguity := map[string][]string{
|
||||
"logs": logsDuplicateKeys,
|
||||
"traces": tracesDuplicateKeys,
|
||||
}
|
||||
|
||||
return &alertMigrateV5{
|
||||
migrateCommon: migrateCommon{
|
||||
ambiguity: ambiguity,
|
||||
logger: logger,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *alertMigrateV5) Migrate(ctx context.Context, ruleData map[string]any) bool {
|
||||
|
||||
updated := false
|
||||
|
||||
var version string
|
||||
if _, ok := ruleData["version"].(string); ok {
|
||||
version = ruleData["version"].(string)
|
||||
}
|
||||
|
||||
if version == "v5" {
|
||||
m.logger.InfoContext(ctx, "alert is already migrated to v5, skipping", "alert_name", ruleData["alert"])
|
||||
return false
|
||||
}
|
||||
|
||||
m.logger.InfoContext(ctx, "migrating alert", "alert_name", ruleData["alert"])
|
||||
|
||||
ruleCondition, ok := ruleData["condition"].(map[string]any)
|
||||
if !ok {
|
||||
m.logger.WarnContext(ctx, "didn't find condition")
|
||||
return updated
|
||||
}
|
||||
|
||||
compositeQuery, ok := ruleCondition["compositeQuery"].(map[string]any)
|
||||
if !ok {
|
||||
m.logger.WarnContext(ctx, "didn't find composite query")
|
||||
return updated
|
||||
}
|
||||
|
||||
if compositeQuery["queries"] == nil {
|
||||
compositeQuery["queries"] = []any{}
|
||||
m.logger.InfoContext(ctx, "setup empty list")
|
||||
}
|
||||
|
||||
queryType := compositeQuery["queryType"]
|
||||
|
||||
// Migrate builder queries
|
||||
if builderQueries, ok := compositeQuery["builderQueries"].(map[string]any); ok && len(builderQueries) > 0 && queryType == "builder" {
|
||||
m.logger.InfoContext(ctx, "found builderQueries")
|
||||
queryType, _ := compositeQuery["queryType"].(string)
|
||||
if queryType == "builder" {
|
||||
for name, query := range builderQueries {
|
||||
if queryMap, ok := query.(map[string]any); ok {
|
||||
m.logger.InfoContext(ctx, "mapping builder query")
|
||||
var panelType string
|
||||
if pt, ok := compositeQuery["panelType"].(string); ok {
|
||||
panelType = pt
|
||||
}
|
||||
|
||||
if m.updateQueryData(ctx, queryMap, version, panelType) {
|
||||
updated = true
|
||||
}
|
||||
m.logger.InfoContext(ctx, "migrated querymap")
|
||||
|
||||
// wrap it in the v5 envelope
|
||||
envelope := m.wrapInV5Envelope(name, queryMap, "builder_query")
|
||||
m.logger.InfoContext(ctx, "envelope after wrap", "envelope", envelope)
|
||||
compositeQuery["queries"] = append(compositeQuery["queries"].([]any), envelope)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate prom queries
|
||||
if promQueries, ok := compositeQuery["promQueries"].(map[string]any); ok && len(promQueries) > 0 && queryType == "promql" {
|
||||
for name, query := range promQueries {
|
||||
if queryMap, ok := query.(map[string]any); ok {
|
||||
envelope := map[string]any{
|
||||
"type": "promql",
|
||||
"spec": map[string]any{
|
||||
"name": name,
|
||||
"query": queryMap["query"],
|
||||
"disabled": queryMap["disabled"],
|
||||
"legend": queryMap["legend"],
|
||||
},
|
||||
}
|
||||
compositeQuery["queries"] = append(compositeQuery["queries"].([]any), envelope)
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate clickhouse queries
|
||||
if chQueries, ok := compositeQuery["chQueries"].(map[string]any); ok && len(chQueries) > 0 && queryType == "clickhouse_sql" {
|
||||
for name, query := range chQueries {
|
||||
if queryMap, ok := query.(map[string]any); ok {
|
||||
envelope := map[string]any{
|
||||
"type": "clickhouse_sql",
|
||||
"spec": map[string]any{
|
||||
"name": name,
|
||||
"query": queryMap["query"],
|
||||
"disabled": queryMap["disabled"],
|
||||
"legend": queryMap["legend"],
|
||||
},
|
||||
}
|
||||
compositeQuery["queries"] = append(compositeQuery["queries"].([]any), envelope)
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
delete(compositeQuery, "builderQueries")
|
||||
delete(compositeQuery, "chQueries")
|
||||
delete(compositeQuery, "promQueries")
|
||||
|
||||
ruleData["version"] = "v5"
|
||||
|
||||
return updated
|
||||
}
|
||||
@@ -1,957 +0,0 @@
|
||||
// nolint
|
||||
package transition
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"regexp"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/telemetrytraces"
|
||||
)
|
||||
|
||||
type migrateCommon struct {
|
||||
ambiguity map[string][]string
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
func (migration *migrateCommon) wrapInV5Envelope(name string, queryMap map[string]any, queryType string) map[string]any {
|
||||
// Create a properly structured v5 query
|
||||
v5Query := map[string]any{
|
||||
"name": name,
|
||||
"disabled": queryMap["disabled"],
|
||||
"legend": queryMap["legend"],
|
||||
}
|
||||
|
||||
if name != queryMap["expression"] {
|
||||
// formula
|
||||
queryType = "builder_formula"
|
||||
v5Query["expression"] = queryMap["expression"]
|
||||
if functions, ok := queryMap["functions"]; ok {
|
||||
v5Query["functions"] = functions
|
||||
}
|
||||
return map[string]any{
|
||||
"type": queryType,
|
||||
"spec": v5Query,
|
||||
}
|
||||
}
|
||||
|
||||
// Add signal based on data source
|
||||
if dataSource, ok := queryMap["dataSource"].(string); ok {
|
||||
switch dataSource {
|
||||
case "traces":
|
||||
v5Query["signal"] = "traces"
|
||||
case "logs":
|
||||
v5Query["signal"] = "logs"
|
||||
case "metrics":
|
||||
v5Query["signal"] = "metrics"
|
||||
}
|
||||
}
|
||||
|
||||
if stepInterval, ok := queryMap["stepInterval"]; ok {
|
||||
v5Query["stepInterval"] = stepInterval
|
||||
}
|
||||
|
||||
if aggregations, ok := queryMap["aggregations"]; ok {
|
||||
v5Query["aggregations"] = aggregations
|
||||
}
|
||||
|
||||
if filter, ok := queryMap["filter"]; ok {
|
||||
v5Query["filter"] = filter
|
||||
}
|
||||
|
||||
// Copy groupBy with proper structure
|
||||
if groupBy, ok := queryMap["groupBy"].([]any); ok {
|
||||
v5GroupBy := make([]any, len(groupBy))
|
||||
for i, gb := range groupBy {
|
||||
if gbMap, ok := gb.(map[string]any); ok {
|
||||
v5GroupBy[i] = map[string]any{
|
||||
"name": gbMap["key"],
|
||||
"fieldDataType": gbMap["dataType"],
|
||||
"fieldContext": gbMap["type"],
|
||||
}
|
||||
}
|
||||
}
|
||||
v5Query["groupBy"] = v5GroupBy
|
||||
}
|
||||
|
||||
// Copy orderBy with proper structure
|
||||
if orderBy, ok := queryMap["orderBy"].([]any); ok {
|
||||
v5OrderBy := make([]any, len(orderBy))
|
||||
for i, ob := range orderBy {
|
||||
if obMap, ok := ob.(map[string]any); ok {
|
||||
v5OrderBy[i] = map[string]any{
|
||||
"key": map[string]any{
|
||||
"name": obMap["columnName"],
|
||||
"fieldDataType": obMap["dataType"],
|
||||
"fieldContext": obMap["type"],
|
||||
},
|
||||
"direction": obMap["order"],
|
||||
}
|
||||
}
|
||||
}
|
||||
v5Query["order"] = v5OrderBy
|
||||
}
|
||||
|
||||
// Copy selectColumns as selectFields
|
||||
if selectColumns, ok := queryMap["selectColumns"].([]any); ok {
|
||||
v5SelectFields := make([]any, len(selectColumns))
|
||||
for i, col := range selectColumns {
|
||||
if colMap, ok := col.(map[string]any); ok {
|
||||
v5SelectFields[i] = map[string]any{
|
||||
"name": colMap["key"],
|
||||
"fieldDataType": colMap["dataType"],
|
||||
"fieldContext": colMap["type"],
|
||||
}
|
||||
}
|
||||
}
|
||||
v5Query["selectFields"] = v5SelectFields
|
||||
}
|
||||
|
||||
// Copy limit and offset
|
||||
if limit, ok := queryMap["limit"]; ok {
|
||||
v5Query["limit"] = limit
|
||||
}
|
||||
if offset, ok := queryMap["offset"]; ok {
|
||||
v5Query["offset"] = offset
|
||||
}
|
||||
|
||||
if having, ok := queryMap["having"]; ok {
|
||||
v5Query["having"] = having
|
||||
}
|
||||
|
||||
if functions, ok := queryMap["functions"]; ok {
|
||||
v5Query["functions"] = functions
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"type": queryType,
|
||||
"spec": v5Query,
|
||||
}
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) updateQueryData(ctx context.Context, queryData map[string]any, version, widgetType string) bool {
|
||||
updated := false
|
||||
|
||||
aggregateOp, _ := queryData["aggregateOperator"].(string)
|
||||
hasAggregation := aggregateOp != "" && aggregateOp != "noop"
|
||||
|
||||
if mc.createAggregations(ctx, queryData, version, widgetType) {
|
||||
updated = true
|
||||
}
|
||||
|
||||
if mc.createFilterExpression(ctx, queryData) {
|
||||
updated = true
|
||||
}
|
||||
|
||||
if mc.fixGroupBy(queryData) {
|
||||
updated = true
|
||||
}
|
||||
|
||||
if mc.createHavingExpression(ctx, queryData) {
|
||||
updated = true
|
||||
}
|
||||
|
||||
if hasAggregation {
|
||||
if orderBy, ok := queryData["orderBy"].([]any); ok {
|
||||
newOrderBy := make([]any, 0)
|
||||
for _, order := range orderBy {
|
||||
if orderMap, ok := order.(map[string]any); ok {
|
||||
columnName, _ := orderMap["columnName"].(string)
|
||||
// skip timestamp, id (logs, traces), samples(metrics) ordering for aggregation queries
|
||||
if columnName != "timestamp" && columnName != "samples" && columnName != "id" {
|
||||
if columnName == "#SIGNOZ_VALUE" {
|
||||
if expr, has := mc.orderByExpr(queryData); has {
|
||||
orderMap["columnName"] = expr
|
||||
}
|
||||
} else {
|
||||
// if the order by key is not part of the group by keys, remove it
|
||||
present := false
|
||||
|
||||
groupBy, ok := queryData["groupBy"].([]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
for idx := range groupBy {
|
||||
item, ok := groupBy[idx].(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
key, ok := item["key"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if key == columnName {
|
||||
present = true
|
||||
}
|
||||
}
|
||||
|
||||
if !present {
|
||||
mc.logger.WarnContext(ctx, "found a order by without group by, skipping", "order_col_name", columnName)
|
||||
continue
|
||||
}
|
||||
}
|
||||
newOrderBy = append(newOrderBy, orderMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
queryData["orderBy"] = newOrderBy
|
||||
updated = true
|
||||
}
|
||||
} else {
|
||||
dataSource, _ := queryData["dataSource"].(string)
|
||||
|
||||
if orderBy, ok := queryData["orderBy"].([]any); ok {
|
||||
newOrderBy := make([]any, 0)
|
||||
for _, order := range orderBy {
|
||||
if orderMap, ok := order.(map[string]any); ok {
|
||||
columnName, _ := orderMap["columnName"].(string)
|
||||
// skip id and timestamp for (traces)
|
||||
if (columnName == "id" || columnName == "timestamp") && dataSource == "traces" {
|
||||
mc.logger.InfoContext(ctx, "skipping `id` order by for traces")
|
||||
continue
|
||||
}
|
||||
|
||||
// skip id for (logs)
|
||||
if (columnName == "id" || columnName == "timestamp") && dataSource == "logs" {
|
||||
mc.logger.InfoContext(ctx, "skipping `id`/`timestamp` order by for logs")
|
||||
continue
|
||||
}
|
||||
|
||||
newOrderBy = append(newOrderBy, orderMap)
|
||||
}
|
||||
}
|
||||
queryData["orderBy"] = newOrderBy
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
|
||||
if functions, ok := queryData["functions"].([]any); ok {
|
||||
v5Functions := make([]any, len(functions))
|
||||
for i, fn := range functions {
|
||||
if fnMap, ok := fn.(map[string]any); ok {
|
||||
v5Function := map[string]any{
|
||||
"name": fnMap["name"],
|
||||
}
|
||||
|
||||
// Convert args from v4 format to v5 FunctionArg format
|
||||
if args, ok := fnMap["args"].([]any); ok {
|
||||
v5Args := make([]any, len(args))
|
||||
for j, arg := range args {
|
||||
// In v4, args were just values. In v5, they are FunctionArg objects
|
||||
v5Args[j] = map[string]any{
|
||||
"name": "", // v4 didn't have named args
|
||||
"value": arg,
|
||||
}
|
||||
}
|
||||
v5Function["args"] = v5Args
|
||||
}
|
||||
|
||||
// Handle namedArgs if present (some functions might have used this)
|
||||
if namedArgs, ok := fnMap["namedArgs"].(map[string]any); ok {
|
||||
// Convert named args to the new format
|
||||
existingArgs, _ := v5Function["args"].([]any)
|
||||
if existingArgs == nil {
|
||||
existingArgs = []any{}
|
||||
}
|
||||
|
||||
for name, value := range namedArgs {
|
||||
existingArgs = append(existingArgs, map[string]any{
|
||||
"name": name,
|
||||
"value": value,
|
||||
})
|
||||
}
|
||||
v5Function["args"] = existingArgs
|
||||
}
|
||||
|
||||
v5Functions[i] = v5Function
|
||||
}
|
||||
}
|
||||
queryData["functions"] = v5Functions
|
||||
updated = true
|
||||
}
|
||||
|
||||
delete(queryData, "aggregateOperator")
|
||||
delete(queryData, "aggregateAttribute")
|
||||
delete(queryData, "temporality")
|
||||
delete(queryData, "timeAggregation")
|
||||
delete(queryData, "spaceAggregation")
|
||||
delete(queryData, "reduceTo")
|
||||
delete(queryData, "filters")
|
||||
delete(queryData, "ShiftBy")
|
||||
delete(queryData, "IsAnomaly")
|
||||
delete(queryData, "QueriesUsedInFormula")
|
||||
delete(queryData, "seriesAggregation")
|
||||
|
||||
return updated
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) orderByExpr(queryData map[string]any) (string, bool) {
|
||||
aggregateOp, hasOp := queryData["aggregateOperator"].(string)
|
||||
aggregateAttr, hasAttr := queryData["aggregateAttribute"].(map[string]any)
|
||||
dataSource, _ := queryData["dataSource"].(string)
|
||||
|
||||
if aggregateOp == "noop" {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if !hasOp || !hasAttr {
|
||||
return "", false
|
||||
}
|
||||
|
||||
var expr string
|
||||
var has bool
|
||||
|
||||
switch dataSource {
|
||||
case "metrics":
|
||||
|
||||
aggs, ok := queryData["aggregations"].([]any)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
if len(aggs) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
agg, ok := aggs[0].(map[string]any)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
spaceAgg, ok := agg["spaceAggregation"].(string)
|
||||
if !ok {
|
||||
return "", false
|
||||
}
|
||||
|
||||
expr = fmt.Sprintf("%s(%s)", spaceAgg, aggregateAttr["key"])
|
||||
has = true
|
||||
case "logs":
|
||||
expr = mc.buildAggregationExpression(aggregateOp, aggregateAttr)
|
||||
has = true
|
||||
case "traces":
|
||||
expr = mc.buildAggregationExpression(aggregateOp, aggregateAttr)
|
||||
has = true
|
||||
default:
|
||||
has = false
|
||||
}
|
||||
|
||||
return expr, has
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) createAggregations(ctx context.Context, queryData map[string]any, version, widgetType string) bool {
|
||||
aggregateOp, hasOp := queryData["aggregateOperator"].(string)
|
||||
aggregateAttr, hasAttr := queryData["aggregateAttribute"].(map[string]any)
|
||||
dataSource, _ := queryData["dataSource"].(string)
|
||||
|
||||
if aggregateOp == "noop" && dataSource != "metrics" {
|
||||
return false
|
||||
}
|
||||
|
||||
if !hasOp || !hasAttr {
|
||||
return false
|
||||
}
|
||||
|
||||
var aggregation map[string]any
|
||||
|
||||
switch dataSource {
|
||||
case "metrics":
|
||||
if version == "v4" {
|
||||
if _, ok := queryData["spaceAggregation"]; !ok {
|
||||
queryData["spaceAggregation"] = aggregateOp
|
||||
}
|
||||
aggregation = map[string]any{
|
||||
"metricName": aggregateAttr["key"],
|
||||
"temporality": queryData["temporality"],
|
||||
"timeAggregation": queryData["timeAggregation"],
|
||||
"spaceAggregation": queryData["spaceAggregation"],
|
||||
}
|
||||
if reduceTo, ok := queryData["reduceTo"].(string); ok {
|
||||
aggregation["reduceTo"] = reduceTo
|
||||
}
|
||||
} else {
|
||||
var timeAgg, spaceAgg, reduceTo string
|
||||
switch aggregateOp {
|
||||
case "sum_rate", "rate_sum":
|
||||
timeAgg = "rate"
|
||||
spaceAgg = "sum"
|
||||
reduceTo = "sum"
|
||||
case "avg_rate", "rate_avg":
|
||||
timeAgg = "rate"
|
||||
spaceAgg = "avg"
|
||||
reduceTo = "avg"
|
||||
case "min_rate", "rate_min":
|
||||
timeAgg = "rate"
|
||||
spaceAgg = "min"
|
||||
reduceTo = "min"
|
||||
case "max_rate", "rate_max":
|
||||
timeAgg = "rate"
|
||||
spaceAgg = "max"
|
||||
reduceTo = "max"
|
||||
case "hist_quantile_50":
|
||||
timeAgg = ""
|
||||
spaceAgg = "p50"
|
||||
reduceTo = "avg"
|
||||
case "hist_quantile_75":
|
||||
timeAgg = ""
|
||||
spaceAgg = "p75"
|
||||
reduceTo = "avg"
|
||||
case "hist_quantile_90":
|
||||
timeAgg = ""
|
||||
spaceAgg = "p90"
|
||||
reduceTo = "avg"
|
||||
case "hist_quantile_95":
|
||||
timeAgg = ""
|
||||
spaceAgg = "p95"
|
||||
reduceTo = "avg"
|
||||
case "hist_quantile_99":
|
||||
timeAgg = ""
|
||||
spaceAgg = "p99"
|
||||
reduceTo = "avg"
|
||||
case "rate":
|
||||
timeAgg = "rate"
|
||||
spaceAgg = "sum"
|
||||
reduceTo = "sum"
|
||||
case "p99", "p90", "p75", "p50", "p25", "p20", "p10", "p05":
|
||||
mc.logger.InfoContext(ctx, "found invalid config")
|
||||
timeAgg = "avg"
|
||||
spaceAgg = "avg"
|
||||
reduceTo = "avg"
|
||||
case "min":
|
||||
timeAgg = "min"
|
||||
spaceAgg = "min"
|
||||
reduceTo = "min"
|
||||
case "max":
|
||||
timeAgg = "max"
|
||||
spaceAgg = "max"
|
||||
reduceTo = "max"
|
||||
case "avg":
|
||||
timeAgg = "avg"
|
||||
spaceAgg = "avg"
|
||||
reduceTo = "avg"
|
||||
case "sum":
|
||||
timeAgg = "sum"
|
||||
spaceAgg = "sum"
|
||||
reduceTo = "sum"
|
||||
case "count":
|
||||
timeAgg = "count"
|
||||
spaceAgg = "sum"
|
||||
reduceTo = "sum"
|
||||
case "count_distinct":
|
||||
timeAgg = "count_distinct"
|
||||
spaceAgg = "sum"
|
||||
reduceTo = "sum"
|
||||
case "noop":
|
||||
mc.logger.WarnContext(ctx, "noop found in the aggregation data")
|
||||
timeAgg = "max"
|
||||
spaceAgg = "max"
|
||||
reduceTo = "max"
|
||||
}
|
||||
|
||||
aggregation = map[string]any{
|
||||
"metricName": aggregateAttr["key"],
|
||||
"temporality": queryData["temporality"],
|
||||
"timeAggregation": timeAgg,
|
||||
"spaceAggregation": spaceAgg,
|
||||
}
|
||||
if widgetType == "table" {
|
||||
aggregation["reduceTo"] = reduceTo
|
||||
} else {
|
||||
if reduceTo, ok := queryData["reduceTo"].(string); ok {
|
||||
aggregation["reduceTo"] = reduceTo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case "logs":
|
||||
expression := mc.buildAggregationExpression(aggregateOp, aggregateAttr)
|
||||
aggregation = map[string]any{
|
||||
"expression": expression,
|
||||
}
|
||||
case "traces":
|
||||
expression := mc.buildAggregationExpression(aggregateOp, aggregateAttr)
|
||||
aggregation = map[string]any{
|
||||
"expression": expression,
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
queryData["aggregations"] = []any{aggregation}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) createFilterExpression(ctx context.Context, queryData map[string]any) bool {
|
||||
filters, ok := queryData["filters"].(map[string]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
items, ok := filters["items"].([]any)
|
||||
if !ok || len(items) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
op, ok := filters["op"].(string)
|
||||
if !ok {
|
||||
op = "AND"
|
||||
}
|
||||
|
||||
dataSource, _ := queryData["dataSource"].(string)
|
||||
|
||||
expression := mc.buildExpression(ctx, items, op, dataSource)
|
||||
if expression != "" {
|
||||
if groupByExists := mc.groupByExistsExpr(queryData); groupByExists != "" && dataSource != "metrics" {
|
||||
mc.logger.InfoContext(ctx, "adding default exists for old qb", "group_by_exists", groupByExists)
|
||||
expression += " " + groupByExists
|
||||
}
|
||||
|
||||
queryData["filter"] = map[string]any{
|
||||
"expression": expression,
|
||||
}
|
||||
delete(queryData, "filters")
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) groupByExistsExpr(queryData map[string]any) string {
|
||||
expr := []string{}
|
||||
groupBy, ok := queryData["groupBy"].([]any)
|
||||
if !ok {
|
||||
return strings.Join(expr, " AND ")
|
||||
}
|
||||
|
||||
for idx := range groupBy {
|
||||
item, ok := groupBy[idx].(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
key, ok := item["key"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
expr = append(expr, fmt.Sprintf("%s EXISTS", key))
|
||||
|
||||
if _, ok := telemetrytraces.IntrinsicFields[key]; ok {
|
||||
delete(item, "type")
|
||||
}
|
||||
if _, ok := telemetrytraces.CalculatedFields[key]; ok {
|
||||
delete(item, "type")
|
||||
}
|
||||
if _, ok := telemetrytraces.IntrinsicFieldsDeprecated[key]; ok {
|
||||
delete(item, "type")
|
||||
}
|
||||
if _, ok := telemetrytraces.CalculatedFieldsDeprecated[key]; ok {
|
||||
delete(item, "type")
|
||||
}
|
||||
}
|
||||
|
||||
return strings.Join(expr, " AND ")
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) fixGroupBy(queryData map[string]any) bool {
|
||||
groupBy, ok := queryData["groupBy"].([]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
for idx := range groupBy {
|
||||
item, ok := groupBy[idx].(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
key, ok := item["key"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if _, ok := telemetrytraces.IntrinsicFields[key]; ok {
|
||||
delete(item, "type")
|
||||
}
|
||||
if _, ok := telemetrytraces.CalculatedFields[key]; ok {
|
||||
delete(item, "type")
|
||||
}
|
||||
if _, ok := telemetrytraces.IntrinsicFieldsDeprecated[key]; ok {
|
||||
delete(item, "type")
|
||||
}
|
||||
if _, ok := telemetrytraces.CalculatedFieldsDeprecated[key]; ok {
|
||||
delete(item, "type")
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) createHavingExpression(ctx context.Context, queryData map[string]any) bool {
|
||||
having, ok := queryData["having"].([]any)
|
||||
if !ok || len(having) == 0 {
|
||||
queryData["having"] = map[string]any{
|
||||
"expression": "",
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
dataSource, _ := queryData["dataSource"].(string)
|
||||
|
||||
for idx := range having {
|
||||
if havingItem, ok := having[idx].(map[string]any); ok {
|
||||
havingCol, has := mc.orderByExpr(queryData)
|
||||
if has {
|
||||
havingItem["columnName"] = havingCol
|
||||
havingItem["key"] = map[string]any{"key": havingCol}
|
||||
}
|
||||
having[idx] = havingItem
|
||||
}
|
||||
}
|
||||
|
||||
mc.logger.InfoContext(ctx, "having before expression", "having", having)
|
||||
|
||||
expression := mc.buildExpression(ctx, having, "AND", dataSource)
|
||||
mc.logger.InfoContext(ctx, "having expression after building", "expression", expression, "having", having)
|
||||
queryData["having"] = map[string]any{
|
||||
"expression": expression,
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) buildExpression(ctx context.Context, items []any, op, dataSource string) string {
|
||||
if len(items) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
var conditions []string
|
||||
|
||||
for _, item := range items {
|
||||
itemMap, ok := item.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
key, keyOk := itemMap["key"].(map[string]any)
|
||||
operator, opOk := itemMap["op"].(string)
|
||||
value, valueOk := itemMap["value"]
|
||||
|
||||
if !keyOk || !opOk || !valueOk {
|
||||
mc.logger.WarnContext(ctx, "didn't find either key, op, or value; continuing")
|
||||
continue
|
||||
}
|
||||
|
||||
keyStr, ok := key["key"].(string)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
|
||||
if slices.Contains(mc.ambiguity[dataSource], keyStr) {
|
||||
mc.logger.WarnContext(ctx, "ambiguity found for a key", "ambiguity_key", keyStr)
|
||||
typeStr, ok := key["type"].(string)
|
||||
if ok {
|
||||
if typeStr == "tag" {
|
||||
typeStr = "attribute"
|
||||
} else {
|
||||
typeStr = "resource"
|
||||
}
|
||||
keyStr = typeStr + "." + keyStr
|
||||
}
|
||||
}
|
||||
|
||||
condition := mc.buildCondition(ctx, keyStr, operator, value, key)
|
||||
if condition != "" {
|
||||
conditions = append(conditions, condition)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if len(conditions) == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
if len(conditions) == 1 {
|
||||
return conditions[0]
|
||||
}
|
||||
|
||||
return "(" + strings.Join(conditions, " "+op+" ") + ")"
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) buildCondition(ctx context.Context, key, operator string, value any, keyMetadata map[string]any) string {
|
||||
dataType, _ := keyMetadata["dataType"].(string)
|
||||
|
||||
formattedValue := mc.formatValue(ctx, value, dataType)
|
||||
|
||||
switch operator {
|
||||
case "=":
|
||||
return fmt.Sprintf("%s = %s", key, formattedValue)
|
||||
case "!=":
|
||||
return fmt.Sprintf("%s != %s", key, formattedValue)
|
||||
case ">":
|
||||
return fmt.Sprintf("%s > %s", key, formattedValue)
|
||||
case ">=":
|
||||
return fmt.Sprintf("%s >= %s", key, formattedValue)
|
||||
case "<":
|
||||
return fmt.Sprintf("%s < %s", key, formattedValue)
|
||||
case "<=":
|
||||
return fmt.Sprintf("%s <= %s", key, formattedValue)
|
||||
case "in", "IN":
|
||||
if !strings.HasPrefix(formattedValue, "[") && !mc.isVariable(formattedValue) {
|
||||
mc.logger.WarnContext(ctx, "multi-value operator in found with single value", "key", key, "formatted_value", formattedValue)
|
||||
return fmt.Sprintf("%s = %s", key, formattedValue)
|
||||
}
|
||||
return fmt.Sprintf("%s IN %s", key, formattedValue)
|
||||
case "nin", "NOT IN":
|
||||
if !strings.HasPrefix(formattedValue, "[") && !mc.isVariable(formattedValue) {
|
||||
mc.logger.WarnContext(ctx, "multi-value operator not in found with single value", "key", key, "formatted_value", formattedValue)
|
||||
return fmt.Sprintf("%s != %s", key, formattedValue)
|
||||
}
|
||||
return fmt.Sprintf("%s NOT IN %s", key, formattedValue)
|
||||
case "like", "LIKE":
|
||||
return fmt.Sprintf("%s LIKE %s", key, formattedValue)
|
||||
case "nlike", "NOT LIKE":
|
||||
return fmt.Sprintf("%s NOT LIKE %s", key, formattedValue)
|
||||
case "contains":
|
||||
return fmt.Sprintf("%s CONTAINS %s", key, formattedValue)
|
||||
case "ncontains":
|
||||
return fmt.Sprintf("%s NOT CONTAINS %s", key, formattedValue)
|
||||
case "regex":
|
||||
return fmt.Sprintf("%s REGEXP %s", key, formattedValue)
|
||||
case "nregex":
|
||||
return fmt.Sprintf("%s NOT REGEXP %s", key, formattedValue)
|
||||
case "exists":
|
||||
return fmt.Sprintf("%s EXISTS", key)
|
||||
case "nexists":
|
||||
return fmt.Sprintf("%s NOT EXISTS", key)
|
||||
case "has":
|
||||
return fmt.Sprintf("has(%s, %s)", key, formattedValue)
|
||||
case "nhas":
|
||||
return fmt.Sprintf("NOT has(%s, %s)", key, formattedValue)
|
||||
default:
|
||||
return fmt.Sprintf("%s %s %s", key, operator, formattedValue)
|
||||
}
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) buildAggregationExpression(operator string, attribute map[string]any) string {
|
||||
key, _ := attribute["key"].(string)
|
||||
|
||||
switch operator {
|
||||
case "count":
|
||||
return "count()"
|
||||
case "sum":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("sum(%s)", key)
|
||||
}
|
||||
return "sum()"
|
||||
case "avg":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("avg(%s)", key)
|
||||
}
|
||||
return "avg()"
|
||||
case "min":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("min(%s)", key)
|
||||
}
|
||||
return "min()"
|
||||
case "max":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("max(%s)", key)
|
||||
}
|
||||
return "max()"
|
||||
case "p05":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("p05(%s)", key)
|
||||
}
|
||||
return "p05()"
|
||||
case "p10":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("p10(%s)", key)
|
||||
}
|
||||
return "p10()"
|
||||
case "p20":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("p20(%s)", key)
|
||||
}
|
||||
return "p20()"
|
||||
case "p25":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("p25(%s)", key)
|
||||
}
|
||||
return "p25()"
|
||||
case "p50":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("p50(%s)", key)
|
||||
}
|
||||
return "p50()"
|
||||
case "p90":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("p90(%s)", key)
|
||||
}
|
||||
return "p90()"
|
||||
case "p95":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("p95(%s)", key)
|
||||
}
|
||||
return "p95()"
|
||||
case "p99":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("p99(%s)", key)
|
||||
}
|
||||
return "p99()"
|
||||
case "rate":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("rate(%s)", key)
|
||||
}
|
||||
return "rate()"
|
||||
case "rate_sum":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("rate_sum(%s)", key)
|
||||
}
|
||||
return "rate_sum()"
|
||||
case "rate_avg":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("rate_avg(%s)", key)
|
||||
}
|
||||
return "rate_avg()"
|
||||
case "rate_min":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("rate_min(%s)", key)
|
||||
}
|
||||
return "rate_min()"
|
||||
case "rate_max":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("rate_max(%s)", key)
|
||||
}
|
||||
return "rate_max()"
|
||||
case "sum_rate":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("sum(rate(%s))", key)
|
||||
}
|
||||
return "sum(rate())"
|
||||
case "count_distinct":
|
||||
if key != "" {
|
||||
return fmt.Sprintf("count_distinct(%s)", key)
|
||||
}
|
||||
return "count_distinct()"
|
||||
default:
|
||||
// For unknown operators, try to use them as-is
|
||||
if key != "" {
|
||||
return fmt.Sprintf("%s(%s)", operator, key)
|
||||
}
|
||||
return fmt.Sprintf("%s()", operator)
|
||||
}
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) formatValue(ctx context.Context, value any, dataType string) string {
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
if mc.isVariable(v) {
|
||||
mc.logger.InfoContext(ctx, "found a variable", "dashboard_variable", v)
|
||||
return mc.normalizeVariable(ctx, v)
|
||||
} else {
|
||||
// if we didn't recognize something as variable but looks like has variable like value, double check
|
||||
if strings.Contains(v, "{") || strings.Contains(v, "[") || strings.Contains(v, "$") {
|
||||
mc.logger.WarnContext(ctx, "variable like string found", "dashboard_variable", v)
|
||||
}
|
||||
}
|
||||
|
||||
if mc.isNumericType(dataType) {
|
||||
if _, err := fmt.Sscanf(v, "%f", new(float64)); err == nil {
|
||||
return v // Return the numeric string without quotes
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, it's a string literal - escape single quotes and wrap in quotes
|
||||
escaped := strings.ReplaceAll(v, "'", "\\'")
|
||||
return fmt.Sprintf("'%s'", escaped)
|
||||
case float64:
|
||||
return fmt.Sprintf("%v", v)
|
||||
case int:
|
||||
return fmt.Sprintf("%d", v)
|
||||
case bool:
|
||||
return fmt.Sprintf("%t", v)
|
||||
case []any:
|
||||
if len(v) == 1 {
|
||||
return mc.formatValue(ctx, v[0], dataType)
|
||||
}
|
||||
var values []string
|
||||
for _, item := range v {
|
||||
values = append(values, mc.formatValue(ctx, item, dataType))
|
||||
}
|
||||
return "[" + strings.Join(values, ", ") + "]"
|
||||
default:
|
||||
return fmt.Sprintf("%v", v)
|
||||
}
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) isNumericType(dataType string) bool {
|
||||
switch dataType {
|
||||
case "int", "int8", "int16", "int32", "int64",
|
||||
"uint", "uint8", "uint16", "uint32", "uint64",
|
||||
"float", "float32", "float64",
|
||||
"number", "numeric", "integer":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) isVariable(s string) bool {
|
||||
s = strings.TrimSpace(s)
|
||||
|
||||
patterns := []string{
|
||||
`^\{.*\}$`, // {var} or {.var}
|
||||
`^\{\{.*\}\}$`, // {{var}} or {{.var}}
|
||||
`^\$.*$`, // $var or $service.name
|
||||
`^\[\[.*\]\]$`, // [[var]] or [[.var]]
|
||||
`^\$\{\{.*\}\}$`, // ${{env}} or ${{.var}}
|
||||
}
|
||||
|
||||
for _, pattern := range patterns {
|
||||
matched, _ := regexp.MatchString(pattern, s)
|
||||
if matched {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (mc *migrateCommon) normalizeVariable(ctx context.Context, s string) string {
|
||||
s = strings.TrimSpace(s)
|
||||
|
||||
var varName string
|
||||
|
||||
// {{var}} or {{.var}}
|
||||
if strings.HasPrefix(s, "{{") && strings.HasSuffix(s, "}}") {
|
||||
varName = strings.TrimPrefix(strings.TrimSuffix(s, "}}"), "{{")
|
||||
varName = strings.TrimPrefix(varName, ".")
|
||||
// this is probably going to be problem if user has $ as start of key
|
||||
varName = strings.TrimPrefix(varName, "$")
|
||||
} else if strings.HasPrefix(s, "{") && strings.HasSuffix(s, "}") { // {var} or {.var}
|
||||
varName = strings.TrimPrefix(strings.TrimSuffix(s, "}"), "{")
|
||||
varName = strings.TrimPrefix(varName, ".")
|
||||
// this is probably going to be problem if user has $ as start of key
|
||||
varName = strings.TrimPrefix(varName, "$")
|
||||
} else if strings.HasPrefix(s, "[[") && strings.HasSuffix(s, "]]") {
|
||||
// [[var]] or [[.var]]
|
||||
varName = strings.TrimPrefix(strings.TrimSuffix(s, "]]"), "[[")
|
||||
varName = strings.TrimPrefix(varName, ".")
|
||||
} else if strings.HasPrefix(s, "${{") && strings.HasSuffix(s, "}}") {
|
||||
varName = strings.TrimPrefix(strings.TrimSuffix(s, "}}"), "${{")
|
||||
varName = strings.TrimPrefix(varName, ".")
|
||||
varName = strings.TrimPrefix(varName, "$")
|
||||
} else if strings.HasPrefix(s, "$") {
|
||||
// $var
|
||||
return s
|
||||
} else {
|
||||
return s
|
||||
}
|
||||
|
||||
if strings.Contains(varName, " ") {
|
||||
mc.logger.InfoContext(ctx, "found white space in var name, replacing it", "dashboard_var_name", varName)
|
||||
varName = strings.ReplaceAll(varName, " ", "")
|
||||
}
|
||||
|
||||
return "$" + varName
|
||||
}
|
||||
@@ -1,108 +0,0 @@
|
||||
// nolint
|
||||
package transition
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type dashboardMigrateV5 struct {
|
||||
migrateCommon
|
||||
}
|
||||
|
||||
func NewDashboardMigrateV5(logger *slog.Logger, logsDuplicateKeys []string, tracesDuplicateKeys []string) *dashboardMigrateV5 {
|
||||
ambiguity := map[string][]string{
|
||||
"logs": logsDuplicateKeys,
|
||||
"traces": tracesDuplicateKeys,
|
||||
}
|
||||
return &dashboardMigrateV5{
|
||||
migrateCommon: migrateCommon{
|
||||
ambiguity: ambiguity,
|
||||
logger: logger,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *dashboardMigrateV5) Migrate(ctx context.Context, dashboardData map[string]any) bool {
|
||||
updated := false
|
||||
|
||||
var version string
|
||||
if _, ok := dashboardData["version"].(string); ok {
|
||||
version = dashboardData["version"].(string)
|
||||
}
|
||||
|
||||
if version == "v5" {
|
||||
m.logger.InfoContext(ctx, "dashboard is already migrated to v5, skipping", "dashboard_name", dashboardData["title"])
|
||||
return false
|
||||
}
|
||||
|
||||
m.logger.InfoContext(ctx, "migrating dashboard", "dashboard_name", dashboardData["title"])
|
||||
|
||||
// if there is a white space in variable, replace it
|
||||
if variables, ok := dashboardData["variables"].(map[string]any); ok {
|
||||
for _, variable := range variables {
|
||||
if varMap, ok := variable.(map[string]any); ok {
|
||||
name, ok := varMap["name"].(string)
|
||||
if ok {
|
||||
if strings.Contains(name, " ") {
|
||||
m.logger.InfoContext(ctx, "found a variable with space in map, replacing it", "name", name)
|
||||
name = strings.ReplaceAll(name, " ", "")
|
||||
updated = true
|
||||
varMap["name"] = name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if widgets, ok := dashboardData["widgets"].([]any); ok {
|
||||
for _, widget := range widgets {
|
||||
if widgetMap, ok := widget.(map[string]any); ok {
|
||||
if m.updateWidget(ctx, widgetMap, version) {
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
dashboardData["version"] = "v5"
|
||||
|
||||
return updated
|
||||
}
|
||||
|
||||
func (migration *dashboardMigrateV5) updateWidget(ctx context.Context, widget map[string]any, version string) bool {
|
||||
query, ok := widget["query"].(map[string]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
if qType, ok := query["queryType"]; ok {
|
||||
if qType == "promql" || qType == "clickhouse_sql" {
|
||||
migration.logger.InfoContext(ctx, "nothing to migrate for query type", "query_type", qType)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
builder, ok := query["builder"].(map[string]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
queryData, ok := builder["queryData"].([]any)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
|
||||
widgetType := widget["panelTypes"].(string)
|
||||
|
||||
updated := false
|
||||
for _, qd := range queryData {
|
||||
if queryDataMap, ok := qd.(map[string]any); ok {
|
||||
if migration.updateQueryData(ctx, queryDataMap, version, widgetType) {
|
||||
updated = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return updated
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
// nolint
|
||||
package transition
|
||||
|
||||
import (
|
||||
"log/slog"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type savedViewMigrateV5 struct {
|
||||
migrateCommon
|
||||
}
|
||||
|
||||
func NewSavedViewMigrateV5(logger *slog.Logger, logsDuplicateKeys []string, tracesDuplicateKeys []string) *savedViewMigrateV5 {
|
||||
return &savedViewMigrateV5{
|
||||
migrateCommon: migrateCommon{ambiguity: make(map[string][]string), logger: logger},
|
||||
}
|
||||
}
|
||||
|
||||
func (m *savedViewMigrateV5) Migrate(ctx context.Context, data map[string]any) bool {
|
||||
updated := false
|
||||
|
||||
var version string
|
||||
if _, ok := data["version"].(string); ok {
|
||||
version = data["version"].(string)
|
||||
}
|
||||
|
||||
if version == "v5" {
|
||||
m.logger.InfoContext(ctx, "saved view is already migrated to v5, skipping")
|
||||
return false
|
||||
}
|
||||
|
||||
data["queries"] = make([]any, 0)
|
||||
|
||||
if builderQueries, ok := data["builderQueries"].(map[string]any); ok {
|
||||
for name, query := range builderQueries {
|
||||
if queryMap, ok := query.(map[string]any); ok {
|
||||
var panelType string
|
||||
if _, ok := data["panelType"].(string); ok {
|
||||
panelType = data["panelType"].(string)
|
||||
}
|
||||
if m.updateQueryData(ctx, queryMap, "v4", panelType) {
|
||||
updated = true
|
||||
}
|
||||
|
||||
m.logger.InfoContext(ctx, "migrated querymap")
|
||||
|
||||
// wrap it in the v5 envelope
|
||||
envelope := m.wrapInV5Envelope(name, queryMap, "builder_query")
|
||||
m.logger.InfoContext(ctx, "envelope after wrap", "envelope", envelope)
|
||||
data["queries"] = append(data["queries"].([]any), envelope)
|
||||
}
|
||||
}
|
||||
}
|
||||
delete(data, "builderQueries")
|
||||
|
||||
data["version"] = "v5"
|
||||
|
||||
return updated
|
||||
}
|
||||
Reference in New Issue
Block a user