** Required to address the impact of the following code block: const ( phoneNumberIndexName = "UQ_phone_number" phoneNumberColumnName = "phone_number" ) type indexInfo struct { IndexName string `json:"index_name"` ColumnName string `json:"column_name"` } **/ NewProvider returns a new SQL prov
( config *config.Config, deps *Dependencies, )
| 42 | |
| 43 | // NewProvider returns a new SQL provider |
| 44 | func NewProvider( |
| 45 | config *config.Config, |
| 46 | deps *Dependencies, |
| 47 | ) (*provider, error) { |
| 48 | var sqlDB *gorm.DB |
| 49 | var err error |
| 50 | |
| 51 | ormConfig := &gorm.Config{ |
| 52 | NamingStrategy: schema.NamingStrategy{ |
| 53 | TablePrefix: schemas.Prefix, |
| 54 | }, |
| 55 | AllowGlobalUpdate: false, |
| 56 | } |
| 57 | |
| 58 | dbType := config.DatabaseType |
| 59 | dbURL := config.DatabaseURL |
| 60 | |
| 61 | switch dbType { |
| 62 | case constants.DbTypePostgres, constants.DbTypeYugabyte, constants.DbTypeCockroachDB: |
| 63 | sqlDB, err = gorm.Open(postgres.Open(dbURL), ormConfig) |
| 64 | case constants.DbTypeSqlite: |
| 65 | sqlDB, err = gorm.Open(sqlite.Open(dbURL+"?_pragma=busy_timeout(5000)&_pragma=journal_mode(WAL)"), ormConfig) |
| 66 | case constants.DbTypeLibSQL: |
| 67 | sqlDB, err = gorm.Open(libsql.Open(dbURL), ormConfig) |
| 68 | case constants.DbTypeMysql, constants.DbTypeMariaDB, constants.DbTypePlanetScaleDB: |
| 69 | sqlDB, err = gorm.Open(mysql.Open(dbURL), ormConfig) |
| 70 | case constants.DbTypeSqlserver: |
| 71 | sqlDB, err = gorm.Open(sqlserver.Open(dbURL), ormConfig) |
| 72 | } |
| 73 | |
| 74 | if err != nil { |
| 75 | return nil, err |
| 76 | } |
| 77 | |
| 78 | // Older Authorizer releases (< 2.3.0) declared the email and phone_number |
| 79 | // columns of authorizer_users and authorizer_otps as UNIQUE. v2 keeps plain |
| 80 | // (non-unique) indexes and enforces uniqueness in the application layer (see |
| 81 | // AddUser/UpdateUser), so behaviour is identical across all supported |
| 82 | // databases and these fields can stay optional (email-only / phone-only |
| 83 | // signups). |
| 84 | // |
| 85 | // On an upgraded SQL database those columns are still unique, so GORM 1.25.x |
| 86 | // AutoMigrate reconciles them by issuing DROP CONSTRAINT "uni_<table>_<col>" |
| 87 | // — a fixed name (NamingStrategy.UniqueName) that rarely matches what the old |
| 88 | // DB actually created (authorizer_users_email_key, idx_authorizer_otps_phone_number, |
| 89 | // or any custom name) — failing with "constraint does not exist" (Postgres |
| 90 | // SQLSTATE 42704) and aborting startup. Clear the legacy uniqueness up front, |
| 91 | // name-agnostically, before AutoMigrate runs. |
| 92 | clearLegacyColumnUniqueness(sqlDB, deps.Log) |
| 93 | |
| 94 | err = sqlDB.AutoMigrate(&schemas.User{}, &schemas.VerificationRequest{}, &schemas.Session{}, &schemas.Env{}, &schemas.Webhook{}, &schemas.WebhookLog{}, &schemas.EmailTemplate{}, &schemas.OTP{}, &schemas.Authenticator{}, &schemas.SessionToken{}, &schemas.MFASession{}, &schemas.OAuthState{}, &schemas.AuditLog{}) |
| 95 | if err != nil { |
| 96 | return nil, err |
| 97 | } |
| 98 | |
| 99 | // IMPACT: Request user to manually delete: UQ_phone_number constraint |
| 100 | // unique constraint on phone number does not work with multiple null values for sqlserver |
| 101 | // for more information check https://stackoverflow.com/a/767702 |