func (st *GormStore) BuildQuery(filter *usecases.Filter, ownerRelations []domain.DBRelation) (*gorm.DB, error) { query := st.db if ownerRelations != nil { for _, relation := range ownerRelations { relation.Ressource = utils.ToDBName(relation.Ressource) relation.Fk = utils.ToDBName(relation.Fk) relation.Related = utils.ToDBName(relation.Related) queryString := fmt.Sprintf("INNER JOIN %s ON %s.%s = %s.id", relation.Ressource, relation.Ressource, relation.Fk, relation.Related) query = query.Joins(queryString) query = query.Table(relation.Related) } } if filter != nil { gormFilter, err := processFilter(filter) if err != nil { return nil, err } if len(gormFilter.Fields) != 0 { query = query.Select(gormFilter.Fields) } if gormFilter.Offset != 0 { query = query.Offset(gormFilter.Offset) } if gormFilter.Limit != 0 { query = query.Limit(gormFilter.Limit) } if gormFilter.Order != "" { query = query.Order(gormFilter.Order) } if gormFilter.Where != "" { query = query.Where(gormFilter.Where) } for _, include := range gormFilter.Include { if include.Relation == "" { break } if include.Where == "" { query = query.Preload(include.Relation) } else { query = query.Preload(include.Relation, include.Where) } } } return query, nil }
func (r *RoleMappingRepo) UpdateByID(id int, roleMapping *domain.RoleMapping, context usecases.QueryContext) (*domain.RoleMapping, error) { query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return nil, internalerrors.DatabaseError } dbName := utils.ToDBName("roleMappings") oldRoleMapping := &domain.RoleMapping{} err = query.Where(dbName+".id = ?", id).First(oldRoleMapping).Error if err != nil { if strings.Contains(err.Error(), "record not found") { return nil, internalerrors.NotFound } return nil, internalerrors.DatabaseError } roleMapping.ID = oldRoleMapping.ID roleMapping.CreatedAt = oldRoleMapping.CreatedAt err = r.store.GetDB().Save(&roleMapping).Error if err != nil { if strings.Contains(err.Error(), "constraint") { return nil, internalerrors.NewViolatedConstraint(err.Error()) } return nil, internalerrors.DatabaseError } return roleMapping, nil }
func processSimpleOperationStr(buffer *bytes.Buffer, attribute, sign, condition string) { buffer.WriteString(utils.ToDBName(attribute)) buffer.WriteString(sign) buffer.WriteRune('\'') buffer.WriteString(condition) buffer.WriteRune('\'') }
func (r *AccountRepo) UpdateByID(id int, account *domain.Account, context usecases.QueryContext) (*domain.Account, error) { query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return nil, internalerrors.DatabaseError } dbName := utils.ToDBName("accounts") oldAccount := &domain.Account{} err = query.Where(dbName+".id = ?", id).First(oldAccount).Error if err != nil { if strings.Contains(err.Error(), "record not found") { return nil, internalerrors.NotFound } return nil, internalerrors.DatabaseError } account.ID = oldAccount.ID account.CreatedAt = oldAccount.CreatedAt err = r.store.GetDB().Save(&account).Error if err != nil { if strings.Contains(err.Error(), "constraint") { return nil, internalerrors.NewViolatedConstraint(err.Error()) } return nil, internalerrors.DatabaseError } return account, nil }
func (r *UserRepo) UpdateAttributesByID(id int, attributes map[string]interface{}, context usecases.QueryContext) (*domain.User, error) { query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return nil, internalerrors.DatabaseError } dbName := utils.ToDBName("users") user := &domain.User{} err = query.Where(dbName+".id = ?", id).First(user).Error if err != nil { if strings.Contains(err.Error(), "record not found") { return nil, internalerrors.NotFound } return nil, internalerrors.DatabaseError } err = r.store.GetDB().Model(&user).Updates(attributes).Error if err != nil { if strings.Contains(err.Error(), "constraint") { return nil, internalerrors.NewViolatedConstraint(err.Error()) } return nil, internalerrors.DatabaseError } return user, nil }
func (r *SessionRepo) UpdateByID(id int, session *domain.Session, context usecases.QueryContext) (*domain.Session, error) { query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return nil, internalerrors.DatabaseError } dbName := utils.ToDBName("sessions") err = query.Where(dbName+".id = ?", id).First(&domain.Session{}).Error if err != nil { if strings.Contains(err.Error(), "record not found") { return nil, internalerrors.NotFound } return nil, internalerrors.DatabaseError } err = r.store.GetDB().Where(dbName+".id = ?", id).Model(&domain.Session{}).Updates(&session).Error if err != nil { if strings.Contains(err.Error(), "constraint") { return nil, internalerrors.NewViolatedConstraint(err.Error()) } return nil, internalerrors.DatabaseError } return session, nil }
func processFilter(filter *usecases.Filter) (*interfaces.GormFilter, error) { fields := filter.Fields dbNamedFields := make([]string, len(fields)) for i, field := range fields { dbNamedFields[i] = utils.ToDBName(field) } if filter.Order != "" { order := strings.ToLower(filter.Order) matched, err := regexp.MatchString("\\A\\w+ (asc|desc)\\z", order) if err != nil || !matched { return nil, errors.New("invalid order filter") } split := strings.Split(filter.Order, " ") filter.Order = utils.ToDBName(split[0]) + " " + split[1] } processedFilter := &interfaces.GormFilter{Fields: dbNamedFields, Limit: filter.Limit, Offset: filter.Offset, Order: filter.Order} buffer := &bytes.Buffer{} err := processCondition(buffer, "", andSql, "", filter.Where) if err != nil { return nil, err } processedFilter.Where = buffer.String() gormIncludes, err := processInclude(filter.Include) if err != nil { return nil, err } processedFilter.Include = gormIncludes return processedFilter, nil }
func (r *AccountRepo) DeleteByID(id int, context usecases.QueryContext) error { query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return internalerrors.DatabaseError } account := &domain.Account{} err = query.Where(utils.ToDBName("accounts")+".id = ?", id).First(&account).Error if err != nil { if strings.Contains(err.Error(), "record not found") { return internalerrors.NotFound } return internalerrors.DatabaseError } err = r.store.GetDB().Where(utils.ToDBName("accounts")+".id = ?", account.ID).Delete(domain.Account{}).Error if err != nil { return internalerrors.DatabaseError } return nil }
func (r *AclRepo) FindByID(id int, context usecases.QueryContext) (*domain.Acl, error) { query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return nil, internalerrors.DatabaseError } acl := domain.Acl{} err = query.Where(utils.ToDBName("acls")+".id = ?", id).First(&acl).Error if err != nil { if strings.Contains(err.Error(), "record not found") { return nil, internalerrors.NotFound } return nil, internalerrors.DatabaseError } return &acl, nil }
func (r *AccountRepo) Update(accounts []domain.Account, context usecases.QueryContext) ([]domain.Account, error) { db := r.store.GetDB() transaction := db.Begin() query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return nil, internalerrors.DatabaseError } for _, account := range accounts { queryCopy := *query dbName := utils.ToDBName("accounts") oldAccount := &domain.Account{} err = queryCopy.Where(dbName+".id = ?", account.ID).First(oldAccount).Error if err != nil { if strings.Contains(err.Error(), "record not found") { return nil, internalerrors.NotFound } return nil, internalerrors.DatabaseError } account.ID = oldAccount.ID account.CreatedAt = oldAccount.CreatedAt err = r.store.GetDB().Save(&account).Error if err != nil { if strings.Contains(err.Error(), "constraint") { return nil, internalerrors.NewViolatedConstraint(err.Error()) } return nil, internalerrors.DatabaseError } } transaction.Commit() return accounts, nil }
func (r *RoleMappingRepo) Update(roleMappings []domain.RoleMapping, context usecases.QueryContext) ([]domain.RoleMapping, error) { db := r.store.GetDB() transaction := db.Begin() query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return nil, internalerrors.DatabaseError } for _, roleMapping := range roleMappings { queryCopy := *query dbName := utils.ToDBName("roleMappings") oldRoleMapping := &domain.RoleMapping{} err = queryCopy.Where(dbName+".id = ?", roleMapping.ID).First(oldRoleMapping).Error if err != nil { if strings.Contains(err.Error(), "record not found") { return nil, internalerrors.NotFound } return nil, internalerrors.DatabaseError } roleMapping.ID = oldRoleMapping.ID roleMapping.CreatedAt = oldRoleMapping.CreatedAt err = r.store.GetDB().Save(&roleMapping).Error if err != nil { if strings.Contains(err.Error(), "constraint") { return nil, internalerrors.NewViolatedConstraint(err.Error()) } return nil, internalerrors.DatabaseError } } transaction.Commit() return roleMappings, nil }
func (r *SessionRepo) Update(sessions []domain.Session, context usecases.QueryContext) ([]domain.Session, error) { db := r.store.GetDB() transaction := db.Begin() query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return nil, internalerrors.DatabaseError } for _, session := range sessions { queryCopy := *query dbName := utils.ToDBName("sessions") err = queryCopy.Where(dbName+".id = ?", session.ID).First(&domain.Session{}).Error if err != nil { if strings.Contains(err.Error(), "record not found") { return nil, internalerrors.NotFound } return nil, internalerrors.DatabaseError } err = r.store.GetDB().Where(dbName+".id = ?", session.ID).Model(&domain.Session{}).Updates(&session).Error if err != nil { if strings.Contains(err.Error(), "constraint") { return nil, internalerrors.NewViolatedConstraint(err.Error()) } return nil, internalerrors.DatabaseError } } transaction.Commit() return sessions, nil }
func (r *AccountRepo) DeleteAll(context usecases.QueryContext) error { query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return internalerrors.DatabaseError } accounts := []domain.Account{} err = query.Find(&accounts).Error if err != nil { return internalerrors.DatabaseError } accountIDs := []int{} for _, account := range accounts { accountIDs = append(accountIDs, account.ID) } err = r.store.GetDB().Delete(&accounts, utils.ToDBName("accounts")+".id IN (?)", accountIDs).Error if err != nil { return internalerrors.DatabaseError } return nil }
func (r *SessionRepo) DeleteAll(context usecases.QueryContext) error { query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return internalerrors.DatabaseError } sessions := []domain.Session{} err = query.Find(&sessions).Error if err != nil { return internalerrors.DatabaseError } sessionIDs := []int{} for _, session := range sessions { sessionIDs = append(sessionIDs, session.ID) } err = r.store.GetDB().Delete(&sessions, utils.ToDBName("sessions")+".id IN (?)", sessionIDs).Error if err != nil { return internalerrors.DatabaseError } return nil }
func (r *UserRepo) DeleteAll(context usecases.QueryContext) error { query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return internalerrors.DatabaseError } users := []domain.User{} err = query.Find(&users).Error if err != nil { return internalerrors.DatabaseError } userIDs := []int{} for _, user := range users { userIDs = append(userIDs, user.ID) } err = r.store.GetDB().Delete(&users, utils.ToDBName("users")+".id IN (?)", userIDs).Error if err != nil { return internalerrors.DatabaseError } return nil }
func (r *RoleRepo) DeleteAll(context usecases.QueryContext) error { query, err := r.store.BuildQuery(context.Filter, context.OwnerRelations) if err != nil { return internalerrors.DatabaseError } roles := []domain.Role{} err = query.Find(&roles).Error if err != nil { return internalerrors.DatabaseError } roleIDs := []int{} for _, role := range roles { roleIDs = append(roleIDs, role.ID) } err = r.store.GetDB().Delete(&roles, utils.ToDBName("roles")+".id IN (?)", roleIDs).Error if err != nil { return internalerrors.DatabaseError } return nil }
func processOperation(buffer *bytes.Buffer, attribute, operator, sign string, condition interface{}) error { switch condition.(type) { case bool: if condition.(bool) { processSimpleOperationStr(buffer, attribute, sign, "1") } else { processSimpleOperationStr(buffer, attribute, sign, "0") } case string: processSimpleOperationStr(buffer, attribute, sign, condition.(string)) case int: processSimpleOperation(buffer, attribute, sign, strconv.FormatInt(int64(condition.(int)), 10)) case float64: processSimpleOperation(buffer, attribute, sign, strconv.FormatFloat(condition.(float64), 'f', -1, 64)) case []int: intArray := condition.([]int) lenArray := len(intArray) buffer.WriteString(utils.ToDBName(attribute)) buffer.WriteString(" IN (") for i, value := range intArray { buffer.WriteString(strconv.FormatInt(int64(value), 10)) if i < lenArray-1 { buffer.WriteString(", ") } } buffer.WriteString(")") case []float64: floatArray := condition.([]float64) lenArray := len(floatArray) buffer.WriteString(utils.ToDBName(attribute)) buffer.WriteString(" IN (") for i, value := range floatArray { buffer.WriteString(strconv.FormatFloat(value, 'f', -1, 64)) if i < lenArray-1 { buffer.WriteString(", ") } } buffer.WriteString(")") case []interface{}: conditions := condition.([]interface{}) arrStr := []string{} strType := reflect.TypeOf("") for _, condition := range conditions { if reflect.TypeOf(condition) == strType { arrStr = append(arrStr, condition.(string)) } } if len(arrStr) == 0 { newBuffer := &bytes.Buffer{} buffer.WriteString("(") for _, condition := range conditions { processCondition(newBuffer, "", operator, sign, condition) } buffer.Write(newBuffer.Bytes()) buffer.WriteString(")") } else { lenArray := len(arrStr) buffer.WriteString(utils.ToDBName(attribute)) buffer.WriteString(" IN (") for i, value := range arrStr { buffer.WriteRune('\'') buffer.WriteString(value) buffer.WriteRune('\'') if i < lenArray-1 { buffer.WriteString(", ") } } buffer.WriteString(")") } } return nil }