github.com/angryronald/go-kit@v0.0.0-20240505173814-ff2bd9c79dbf/generic/repository/sql/generic.repository.mutable.go (about) 1 package sql 2 3 import ( 4 "context" 5 "fmt" 6 7 "gorm.io/gorm" 8 9 "github.com/google/uuid" 10 11 "github.com/angryronald/go-kit/appcontext" 12 "github.com/angryronald/go-kit/cast" 13 "github.com/angryronald/go-kit/generic/repository" 14 ) 15 16 type GenericRepository struct { 17 db *gorm.DB 18 } 19 20 func (r *GenericRepository) FindAll(ctx context.Context, params map[string]interface{}, conditionalOperations []repository.ConditionalOperation, relationalOperations []repository.RelationalOperation, page int, limit int, result interface{}) (interface{}, error) { 21 if !repository.IsValidOperations(conditionalOperations, relationalOperations, params) { 22 return nil, repository.ErrBadParameters 23 } 24 25 where := fmt.Sprintf(`"deleted_at" %s %s`, repository.IS, "NULL") 26 i := 0 27 args := []interface{}{} 28 if len(params) > 0 { 29 where = fmt.Sprintf(`%s %s`, where, repository.AND) 30 } 31 for k, v := range params { 32 switch conditionalOperations[i] { 33 case repository.IN: 34 encapsulation := "" 35 if !repository.AreAllNumbers(v.([]interface{})) { 36 encapsulation = "'" 37 } 38 where = fmt.Sprintf(`%s %s %s (%s)`, where, k, conditionalOperations[i], repository.StringJoin(v.([]interface{}), encapsulation)) 39 40 break 41 42 case repository.ILIKE, repository.LIKE: 43 where = fmt.Sprintf(`%s %s %s ?`, where, k, conditionalOperations[i]) 44 args = append(args, fmt.Sprintf("%%%s%%", v)) 45 break 46 47 default: 48 where = fmt.Sprintf(`%s %s %s ?`, where, k, conditionalOperations[i]) 49 args = append(args, v) 50 } 51 52 if i < len(relationalOperations) { 53 where = fmt.Sprintf(`%s %s`, where, relationalOperations[i]) 54 } 55 i++ 56 } 57 order := fmt.Sprintf(`"created_at" %s`, repository.DESC) 58 59 if page == 0 && limit == 0 { 60 if err := r.db.Where( 61 where, 62 args..., 63 ).Order(order).Find(&result).Error; err != nil { 64 if err == gorm.ErrRecordNotFound { 65 return nil, repository.ErrNotFound 66 } 67 return nil, err 68 } 69 70 return result, nil 71 } 72 73 if err := r.db.Where( 74 where, 75 args..., 76 ).Order(order). 77 Offset((page - 1) * limit). 78 Limit(limit). 79 Find(&result).Error; err != nil { 80 return nil, err 81 } 82 83 return result, nil 84 } 85 86 func (r *GenericRepository) FindOne(ctx context.Context, key string, value interface{}, result interface{}) (interface{}, error) { 87 where := fmt.Sprintf(`"deleted_at" %s NULL %s %s %s ?`, repository.IS, repository.AND, key, repository.EQUAL_WITH) 88 args := []interface{}{ 89 value, 90 } 91 if err := r.db.Where( 92 where, 93 args, 94 ).First(&result).Error; err != nil { 95 if err == gorm.ErrRecordNotFound { 96 return nil, repository.ErrNotFound 97 } 98 return nil, err 99 } 100 101 return result, nil 102 } 103 104 func (r *GenericRepository) FindByID(ctx context.Context, id uuid.UUID, result interface{}) (interface{}, error) { 105 where := fmt.Sprintf(`"deleted_at" %s NULL %s "id" %s ?`, repository.IS, repository.AND, repository.EQUAL_WITH) 106 args := []interface{}{ 107 id, 108 } 109 if err := r.db.Where( 110 where, 111 args, 112 ).First(&result).Error; err != nil { 113 if err == gorm.ErrRecordNotFound { 114 return nil, repository.ErrNotFound 115 } 116 return nil, err 117 } 118 119 return result, nil 120 } 121 122 func (r *GenericRepository) Insert(ctx context.Context, data interface{}) (interface{}, error) { 123 newID, err := uuid.NewRandom() 124 if err != nil { 125 return nil, err 126 } 127 if err = repository.UpdatePropertyValue(data, "ID", newID); err != nil { 128 return nil, err 129 } 130 if err = repository.UpdatePropertyValue(data, "CreatedBy", appcontext.UserID(ctx)); err != nil { 131 return nil, err 132 } 133 if err = repository.UpdatePropertyValue(data, "UpdatedBy", appcontext.UserID(ctx)); err != nil && err != repository.ErrPropertyNotFound { 134 return nil, err 135 } 136 137 if err := r.db.Create(data).Error; err != nil { 138 if err == gorm.ErrDuplicatedKey { 139 return nil, repository.ErrConflict 140 } 141 return nil, err 142 } 143 return data, nil 144 } 145 146 func (r *GenericRepository) Update(ctx context.Context, data interface{}) (interface{}, error) { 147 var err error 148 149 newData, _ := repository.CopyObject(data) 150 ID, _ := repository.GetStructPropertyAsString(newData, "ID") 151 152 if _, err = r.FindByID(ctx, uuid.MustParse(ID), newData); err != nil { 153 return nil, repository.ErrNotFound 154 } 155 156 if err = repository.UpdatePropertyValue(data, "UpdatedBy", appcontext.UserID(ctx)); err != nil && err != repository.ErrPropertyNotFound { 157 return nil, err 158 } 159 160 if err = r.db.Save(data).Error; err != nil { 161 return nil, err 162 } 163 return data, nil 164 } 165 166 func (r *GenericRepository) Delete(ctx context.Context, data interface{}) (interface{}, error) { 167 userID := appcontext.UserID(ctx) 168 if err := repository.UpdatePropertyValue(data, "DeletedBy", &userID); err != nil && err != repository.ErrPropertyNotFound { 169 return nil, err 170 } 171 172 if err := r.db.Delete(data).Error; err != nil { 173 return nil, err 174 } 175 return data, nil 176 } 177 178 func (r *GenericRepository) Upsert(ctx context.Context, data interface{}) (interface{}, error) { 179 var currentID string 180 var err error 181 currentID, _ = repository.GetStructPropertyAsString(data, "ID") 182 if currentID == "" { 183 newID, err := uuid.NewRandom() 184 if err != nil { 185 return nil, err 186 } 187 188 if err = repository.UpdatePropertyValue(data, "ID", newID); err != nil { 189 return nil, err 190 } 191 if err = repository.UpdatePropertyValue(data, "CreatedBy", appcontext.UserID(ctx)); err != nil { 192 return nil, err 193 } 194 } 195 196 if err = repository.UpdatePropertyValue(data, "UpdatedBy", appcontext.UserID(ctx)); err != nil && err != repository.ErrPropertyNotFound { 197 return nil, err 198 } 199 200 if err := r.db.Save(data).Error; err != nil { 201 if err == gorm.ErrDuplicatedKey { 202 return nil, repository.ErrConflict 203 } 204 return nil, err 205 } 206 return data, nil 207 } 208 209 func (r *GenericRepository) BulkInsert(ctx context.Context, data interface{}) (interface{}, error) { 210 tx := r.db.Begin() 211 defer func() { 212 if r := recover(); r != nil { 213 tx.Rollback() 214 } 215 }() 216 217 copyOfData, err := repository.CopySliceOfPointers(data) 218 if err != nil { 219 return nil, err 220 } 221 222 dataInArray := cast.StructPointerArrayToInterfacePointerArray(copyOfData) 223 for i := 0; i < len(dataInArray); i++ { 224 newID, err := uuid.NewRandom() 225 if err != nil { 226 return nil, err 227 } 228 229 if err = repository.UpdatePropertyValue(dataInArray[i], "ID", newID); err != nil { 230 return nil, err 231 } 232 if err = repository.UpdatePropertyValue(dataInArray[i], "CreatedBy", appcontext.UserID(ctx)); err != nil { 233 return nil, err 234 } 235 if err = repository.UpdatePropertyValue(dataInArray[i], "UpdatedBy", appcontext.UserID(ctx)); err != nil { 236 return nil, err 237 } 238 } 239 240 dataInArrayWithIdentity, err := repository.CopySliceOfPointersWithIdentitySeparated(copyOfData, dataInArray) 241 if err != nil { 242 return nil, err 243 } 244 245 if err := r.db.Create(dataInArrayWithIdentity).Error; err != nil { 246 tx.Rollback() 247 if err == gorm.ErrDuplicatedKey { 248 return nil, repository.ErrConflict 249 } 250 return nil, err 251 } 252 return dataInArrayWithIdentity, tx.Commit().Error 253 } 254 255 func (r *GenericRepository) BulkUpsert(ctx context.Context, data interface{}) (interface{}, error) { 256 tx := r.db.Begin() 257 defer func() { 258 if r := recover(); r != nil { 259 tx.Rollback() 260 } 261 }() 262 263 copyOfData, err := repository.CopySliceOfPointers(data) 264 if err != nil { 265 return nil, err 266 } 267 268 dataInArray := cast.StructPointerArrayToInterfacePointerArray(copyOfData) 269 for i := 0; i < len(dataInArray); i++ { 270 var currentID string 271 var err error 272 currentID, _ = repository.GetStructPropertyAsString(data, "ID") 273 if currentID == "" { 274 newID, err := uuid.NewRandom() 275 if err != nil { 276 return nil, err 277 } 278 279 if err = repository.UpdatePropertyValue(dataInArray[i], "ID", newID); err != nil { 280 return nil, err 281 } 282 if err = repository.UpdatePropertyValue(dataInArray[i], "CreatedBy", appcontext.UserID(ctx)); err != nil { 283 return nil, err 284 } 285 } 286 if err = repository.UpdatePropertyValue(dataInArray[i], "UpdatedBy", appcontext.UserID(ctx)); err != nil { 287 return nil, err 288 } 289 } 290 291 dataInArrayWithIdentity, err := repository.CopySliceOfPointersWithIdentitySeparated(copyOfData, dataInArray) 292 if err != nil { 293 return nil, err 294 } 295 296 if err := tx.Save(dataInArrayWithIdentity).Error; err != nil { 297 tx.Rollback() 298 if err == gorm.ErrDuplicatedKey { 299 return nil, repository.ErrConflict 300 } 301 return nil, err 302 } 303 304 return dataInArrayWithIdentity, tx.Commit().Error 305 } 306 307 func (r *GenericRepository) Query(ctx context.Context, query string, params []interface{}, result interface{}) (interface{}, error) { 308 if err := r.db.Raw(query, params...).Find(&result).Error; err != nil { 309 if err == gorm.ErrRecordNotFound { 310 return nil, repository.ErrNotFound 311 } 312 return nil, err 313 } 314 315 return result, nil 316 } 317 318 func NewRepository(db *gorm.DB) repository.GenericRepositoryInterface { 319 return &GenericRepository{ 320 db: db, 321 } 322 } 323 324 func NewMutableRepository(db *gorm.DB) repository.MutableGenericRepositoryInterface { 325 return &GenericRepository{ 326 db: db, 327 } 328 }