package mysql import ( "context" "database/sql" "encoding/json" "git.aiterp.net/stufflog3/stufflog3/entities" "git.aiterp.net/stufflog3/stufflog3/models" "git.aiterp.net/stufflog3/stufflog3/ports/mysql/mysqlcore" ) type scopeRepository struct { db *sql.DB q *mysqlcore.Queries } func (r *scopeRepository) Find(ctx context.Context, id int) (*entities.Scope, error) { row, err := r.q.GetScope(ctx, id) if err != nil { if err == sql.ErrNoRows { return nil, models.NotFoundError("Scope") } return nil, err } customLabels := make(map[string]string, 0) if row.CustomLabels.Valid { _ = json.Unmarshal(row.CustomLabels.RawMessage, &customLabels) } return &entities.Scope{ ID: row.ID, Name: row.Name, Abbreviation: row.Abbreviation, CustomLabels: customLabels, }, nil } func (r *scopeRepository) List(ctx context.Context) ([]entities.Scope, error) { rows, err := r.q.ListScopes(ctx) if err != nil { if err == sql.ErrNoRows { return []entities.Scope{}, nil } return nil, err } res := make([]entities.Scope, 0, len(rows)) for _, row := range rows { customLabels := make(map[string]string, 0) if row.CustomLabels.Valid { _ = json.Unmarshal(row.CustomLabels.RawMessage, &customLabels) } res = append(res, entities.Scope{ ID: row.ID, Name: row.Name, Abbreviation: row.Abbreviation, CustomLabels: customLabels, }) } return nil, err } func (r *scopeRepository) ListUser(ctx context.Context, userID string) ([]entities.Scope, error) { rows, err := r.q.ListScopesByUser(ctx, userID) if err != nil { if err == sql.ErrNoRows { return []entities.Scope{}, nil } return nil, err } res := make([]entities.Scope, 0, len(rows)) for _, row := range rows { customLabels := make(map[string]string, 0) if row.CustomLabels.Valid { _ = json.Unmarshal(row.CustomLabels.RawMessage, &customLabels) } res = append(res, entities.Scope{ ID: row.ID, Name: row.Name, Abbreviation: row.Abbreviation, CustomLabels: customLabels, }) } return res, nil } func (r *scopeRepository) Create(ctx context.Context, scope entities.Scope, owner entities.ScopeMember) (*entities.Scope, error) { tx, err := r.db.BeginTx(ctx, nil) if err != nil { return nil, err } defer tx.Rollback() q := r.q.WithTx(tx) if len(scope.CustomLabels) == 0 { scope.CustomLabels = nil } res, err := q.InsertScope(ctx, mysqlcore.InsertScopeParams{ Name: scope.Name, Abbreviation: scope.Abbreviation, CustomLabels: sqlJsonPtr(scope.CustomLabels), }) if err != nil { return nil, err } id, err := res.LastInsertId() if err != nil { return nil, err } err = q.ReplaceScopeMember(ctx, mysqlcore.ReplaceScopeMemberParams{ ScopeID: int(id), UserID: owner.UserID, Name: owner.Name, Owner: true, }) if err != nil { return nil, err } err = tx.Commit() if err != nil { return nil, err } scope.ID = int(id) return &scope, nil } func (r *scopeRepository) Update(ctx context.Context, scope entities.Scope, update models.ScopeUpdate) error { scope.ApplyUpdate(update) return r.q.UpdateScope(ctx, mysqlcore.UpdateScopeParams{ Name: scope.Name, Abbreviation: scope.Abbreviation, CustomLabels: sqlJsonPtr(scope.CustomLabels), ID: scope.ID, }) } func (r *scopeRepository) Delete(ctx context.Context, scope entities.Scope) error { tx, err := r.db.BeginTx(ctx, nil) if err != nil { return err } defer tx.Rollback() q := r.q.WithTx(tx) // Wipe all progress stats, err := q.ListStats(ctx, scope.ID) if err != nil { return err } for _, stat := range stats { err = q.ClearProjectRequirementStatsByStat(ctx, stat.ID) if err != nil { return err } err = q.ClearItemStatProgressByStat(ctx, stat.ID) if err != nil { return err } } // Clean up scoped data err = q.DeleteAllScopeMembers(ctx, scope.ID) if err != nil { return err } err = q.DeleteAllScopeItems(ctx, scope.ID) if err != nil { return err } err = q.DeleteAllScopeProjectRequirements(ctx, scope.ID) if err != nil { return err } err = q.DeleteAllScopeProjects(ctx, scope.ID) if err != nil { return err } err = q.DeleteAllScopeSprints(ctx, scope.ID) if err != nil { return err } err = q.DeleteAllScopeStats(ctx, scope.ID) if err != nil { return err } err = q.DeleteScope(ctx, scope.ID) if err != nil { return err } return tx.Commit() } func (r *scopeRepository) ListMembers(ctx context.Context, scopeIDs ...int) ([]entities.ScopeMember, error) { res := make([]entities.ScopeMember, 0, 8) if len(scopeIDs) == 1 { rows, err := r.q.ListScopeMembers(ctx, scopeIDs[0]) if err != nil { if err == sql.ErrNoRows { return []entities.ScopeMember{}, nil } return nil, err } for _, row := range rows { res = append(res, entities.ScopeMember{ ScopeID: row.ScopeID, UserID: row.UserID, Name: row.Name, Owner: row.Owner, }) } } else { for i := 0; i < len(scopeIDs); i += 6 { ids := []int{-1, -2, -3, -4, -5, -6} copy(ids, scopeIDs[i:]) rows, err := r.q.ListScopeMembersMulti(ctx, mysqlcore.ListScopeMembersMultiParams{ ScopeID: ids[0], ScopeID_2: ids[1], ScopeID_3: ids[2], ScopeID_4: ids[3], ScopeID_5: ids[4], ScopeID_6: ids[5], }) if err != nil { if err == sql.ErrNoRows { return []entities.ScopeMember{}, nil } return nil, err } for _, row := range rows { res = append(res, entities.ScopeMember{ ScopeID: row.ScopeID, UserID: row.UserID, Name: row.Name, Owner: row.Owner, }) } } } return res, nil } func (r *scopeRepository) SaveMember(ctx context.Context, member entities.ScopeMember) error { return r.q.ReplaceScopeMember(ctx, mysqlcore.ReplaceScopeMemberParams{ ScopeID: member.ScopeID, UserID: member.UserID, Name: member.Name, Owner: member.Owner, }) } func (r *scopeRepository) DeleteMember(ctx context.Context, member entities.ScopeMember) error { return r.q.DeleteScopeMember(ctx, mysqlcore.DeleteScopeMemberParams{ ScopeID: member.ScopeID, UserID: member.UserID, }) }