github.com/abolfazlbeh/zhycan@v0.0.0-20230819144214-24cf38237387/internal/db/manager.go (about) 1 package db 2 3 import ( 4 "fmt" 5 "github.com/abolfazlbeh/zhycan/internal/config" 6 "github.com/abolfazlbeh/zhycan/internal/utils" 7 "go.mongodb.org/mongo-driver/mongo" 8 "gorm.io/gorm" 9 "log" 10 "reflect" 11 "strings" 12 "sync" 13 ) 14 15 // Mark: manager 16 17 // manager object 18 type manager struct { 19 name string 20 lock sync.Mutex 21 sqliteDbInstances map[string]*SqlWrapper[Sqlite] 22 mysqlDbInstances map[string]*SqlWrapper[Mysql] 23 postgresDbInstances map[string]*SqlWrapper[Postgresql] 24 mongoDbInstances map[string]*MongoWrapper 25 supportedDBs []string 26 27 isManagerInitialized bool 28 } 29 30 // MARK: Module variables 31 var managerInstance *manager = nil 32 var once sync.Once 33 34 // Module init function 35 func init() { 36 log.Println("DB Manager Package Initialized...") 37 } 38 39 // init - Manager Constructor - It initializes the manager configuration params 40 func (m *manager) init() { 41 m.name = "db" 42 m.isManagerInitialized = false 43 44 m.lock.Lock() 45 defer m.lock.Unlock() 46 47 m.supportedDBs = []string{"sqlite", "mysql", "postgresql", "mongodb"} 48 49 // read configs 50 connectionsObj, err := config.GetManager().Get(m.name, "connections") 51 if err != nil { 52 return 53 } 54 55 m.sqliteDbInstances = make(map[string]*SqlWrapper[Sqlite]) 56 m.mysqlDbInstances = make(map[string]*SqlWrapper[Mysql]) 57 m.postgresDbInstances = make(map[string]*SqlWrapper[Postgresql]) 58 m.mongoDbInstances = make(map[string]*MongoWrapper) 59 60 for _, item := range connectionsObj.([]interface{}) { 61 dbInstanceName := item.(string) 62 63 dbTypeKey := fmt.Sprintf("%s.%s", dbInstanceName, "type") 64 dbTypeInf, err := config.GetManager().Get(m.name, dbTypeKey) 65 if err != nil { 66 continue 67 } 68 69 // create a new instance based on type 70 dbType := strings.ToLower(dbTypeInf.(string)) 71 if utils.ArrayContains(&m.supportedDBs, dbType) { 72 switch dbType { 73 case "sqlite": 74 obj, err := NewSqlWrapper[Sqlite](fmt.Sprintf("db/%s", dbInstanceName), dbType) 75 if err != nil { 76 // TODO: log error here 77 continue 78 } 79 80 m.sqliteDbInstances[dbInstanceName] = reflect.ValueOf(obj).Interface().(*SqlWrapper[Sqlite]) 81 break 82 case "mysql": 83 obj, err := NewSqlWrapper[Mysql](fmt.Sprintf("db/%s", dbInstanceName), dbType) 84 if err != nil { 85 // TODO: log error here 86 continue 87 } 88 89 m.mysqlDbInstances[dbInstanceName] = reflect.ValueOf(obj).Interface().(*SqlWrapper[Mysql]) 90 break 91 case "postgresql": 92 obj, err := NewSqlWrapper[Postgresql](fmt.Sprintf("db/%s", dbInstanceName), dbType) 93 if err != nil { 94 // TODO: log error here 95 continue 96 } 97 98 m.postgresDbInstances[dbInstanceName] = reflect.ValueOf(obj).Interface().(*SqlWrapper[Postgresql]) 99 break 100 case "mongodb": 101 obj, err := NewMongoWrapper(fmt.Sprintf("db/%s", dbInstanceName)) 102 if err != nil { 103 // TODO: log error here 104 continue 105 } 106 m.mongoDbInstances[dbInstanceName] = obj 107 } 108 } 109 } 110 111 m.isManagerInitialized = true 112 } 113 114 // restartOnChangeConfig - subscribe a function for when the config is changed 115 func (m *manager) restartOnChangeConfig() { 116 // Config config server to reload 117 wrapper, err := config.GetManager().GetConfigWrapper(m.name) 118 if err == nil { 119 wrapper.RegisterChangeCallback(func() interface{} { 120 if m.isManagerInitialized { 121 m.init() 122 } 123 return nil 124 }) 125 } else { 126 // TODO: make some logs 127 } 128 } 129 130 // MARK: Public Functions 131 132 // GetManager - This function returns singleton instance of Db Manager 133 func GetManager() *manager { 134 // once used for prevent race condition and manage critical section. 135 once.Do(func() { 136 managerInstance = &manager{} 137 managerInstance.init() 138 managerInstance.restartOnChangeConfig() 139 }) 140 return managerInstance 141 } 142 143 // GetDb - Get *gorm.DB instance from the underlying interfaces 144 func (m *manager) GetDb(instanceName string) (*gorm.DB, error) { 145 if m.isManagerInitialized { 146 if v, ok := m.sqliteDbInstances[instanceName]; ok { 147 return v.GetDb() 148 } else if v, ok := m.mysqlDbInstances[instanceName]; ok { 149 return v.GetDb() 150 } else if v, ok := m.postgresDbInstances[instanceName]; ok { 151 return v.GetDb() 152 } 153 } 154 return nil, NewNotExistServiceNameErr(instanceName) 155 } 156 157 // GetMongoDb - Get *mongo.Client instance from the underlying interfaces 158 func (m *manager) GetMongoDb(instanceName string) (*mongo.Client, error) { 159 if m.isManagerInitialized { 160 if v, ok := m.mongoDbInstances[instanceName]; ok { 161 return v.GetDb() 162 } 163 } 164 return nil, NewNotExistServiceNameErr(instanceName) 165 } 166 167 // Migrate - migrate models on specific database 168 func (m *manager) Migrate(instanceName string, models ...interface{}) error { 169 if m.isManagerInitialized { 170 if v, ok := m.sqliteDbInstances[instanceName]; ok { 171 return v.Migrate(models) 172 } else if v, ok := m.mysqlDbInstances[instanceName]; ok { 173 return v.Migrate(models) 174 } else if v, ok := m.postgresDbInstances[instanceName]; ok { 175 return v.Migrate(models) 176 } 177 } 178 return NewNotExistServiceNameErr(instanceName) 179 } 180 181 // AttachMigrationFunc - attach migration function to be called by end user 182 func (m *manager) AttachMigrationFunc(instanceName string, f func(migrator gorm.Migrator) error) error { 183 if m.isManagerInitialized { 184 if v, ok := m.sqliteDbInstances[instanceName]; ok { 185 return v.AttachMigrationFunc(f) 186 } else if v, ok := m.mysqlDbInstances[instanceName]; ok { 187 return v.AttachMigrationFunc(f) 188 } else if v, ok := m.postgresDbInstances[instanceName]; ok { 189 return v.AttachMigrationFunc(f) 190 } 191 } 192 return NewNotExistServiceNameErr(instanceName) 193 }