From 15163f3daa349b2a5159ee9c34ab037ea5a17d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ga=C4=87e=C5=A1a?= Date: Thu, 8 Dec 2022 12:52:31 +0100 Subject: [PATCH] pullreq: dedicated struct for pulling data from DB (#116) --- internal/api/controller/pullreq/create.go | 18 ++-- internal/api/controller/pullreq/find.go | 2 +- internal/api/controller/pullreq/list.go | 2 +- internal/api/handler/pullreq/create.go | 4 +- internal/api/handler/pullreq/find.go | 4 +- internal/api/handler/pullreq/list.go | 9 +- internal/api/handler/pullreq/pullreq.go | 31 ------ internal/api/openapi/pullreq.go | 8 +- internal/store/database/null/bool.go | 118 ++++++++++++++++++++++ internal/store/database/null/int64.go | 116 +++++++++++++++++++++ internal/store/database/null/null.go | 7 ++ internal/store/database/null/string.go | 109 ++++++++++++++++++++ internal/store/database/pullreq.go | 106 ++++++++++++++++--- internal/store/database/pullreq_sync.go | 6 +- internal/store/store.go | 6 +- types/pullreq.go | 45 ++++----- types/user.go | 13 ++- 17 files changed, 495 insertions(+), 109 deletions(-) delete mode 100644 internal/api/handler/pullreq/pullreq.go create mode 100644 internal/store/database/null/bool.go create mode 100644 internal/store/database/null/int64.go create mode 100644 internal/store/database/null/null.go create mode 100644 internal/store/database/null/string.go diff --git a/internal/api/controller/pullreq/create.go b/internal/api/controller/pullreq/create.go index da48fabdf..bfbe1f7e5 100644 --- a/internal/api/controller/pullreq/create.go +++ b/internal/api/controller/pullreq/create.go @@ -30,7 +30,7 @@ func (c *Controller) Create( session *auth.Session, repoRef string, in *CreateInput, -) (*types.PullReqInfo, error) { +) (*types.PullReq, error) { now := time.Now().UnixMilli() targetRepo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoEdit) @@ -84,6 +84,13 @@ func (c *Controller) Create( MergedBy: nil, Merged: nil, MergeStrategy: nil, + Author: types.PrincipalInfo{ + ID: session.Principal.ID, + UID: session.Principal.UID, + Name: session.Principal.DisplayName, + Email: session.Principal.Email, + }, + Merger: nil, } return c.pullreqStore.Create(ctx, pr) @@ -92,12 +99,5 @@ func (c *Controller) Create( return nil, err } - pri := &types.PullReqInfo{ - PullReq: *pr, - AuthorID: session.Principal.ID, - AuthorName: session.Principal.DisplayName, - AuthorEmail: session.Principal.Email, - } - - return pri, nil + return pr, nil } diff --git a/internal/api/controller/pullreq/find.go b/internal/api/controller/pullreq/find.go index a068e27c8..039cd369c 100644 --- a/internal/api/controller/pullreq/find.go +++ b/internal/api/controller/pullreq/find.go @@ -19,7 +19,7 @@ func (c *Controller) Find( session *auth.Session, repoRef string, pullreqNum int64, -) (*types.PullReqInfo, error) { +) (*types.PullReq, error) { if pullreqNum <= 0 { return nil, usererror.BadRequest("A valid pull request number must be provided.") } diff --git a/internal/api/controller/pullreq/list.go b/internal/api/controller/pullreq/list.go index 86c450d03..f14726c80 100644 --- a/internal/api/controller/pullreq/list.go +++ b/internal/api/controller/pullreq/list.go @@ -18,7 +18,7 @@ func (c *Controller) List( session *auth.Session, repoRef string, filter *types.PullReqFilter, -) ([]*types.PullReqInfo, error) { +) ([]*types.PullReq, error) { repo, err := c.getRepoCheckAccess(ctx, session, repoRef, enum.PermissionRepoView) if err != nil { return nil, err diff --git a/internal/api/handler/pullreq/create.go b/internal/api/handler/pullreq/create.go index 349c6e6db..a1ed8598a 100644 --- a/internal/api/handler/pullreq/create.go +++ b/internal/api/handler/pullreq/create.go @@ -32,14 +32,12 @@ func HandleCreate(pullreqCtrl *pullreq.Controller) http.HandlerFunc { return } - result, err := pullreqCtrl.Create(ctx, session, repoRef, in) + pr, err := pullreqCtrl.Create(ctx, session, repoRef, in) if err != nil { render.TranslatedUserError(w, err) return } - pr := mapPullReqInfo(result) - render.JSON(w, http.StatusOK, pr) } } diff --git a/internal/api/handler/pullreq/find.go b/internal/api/handler/pullreq/find.go index 2763e908d..18040f032 100644 --- a/internal/api/handler/pullreq/find.go +++ b/internal/api/handler/pullreq/find.go @@ -30,14 +30,12 @@ func HandleFind(pullreqCtrl *pullreq.Controller) http.HandlerFunc { return } - result, err := pullreqCtrl.Find(ctx, session, repoRef, pullreqNumber) + pr, err := pullreqCtrl.Find(ctx, session, repoRef, pullreqNumber) if err != nil { render.TranslatedUserError(w, err) return } - pr := mapPullReqInfo(result) - render.JSON(w, http.StatusOK, pr) } } diff --git a/internal/api/handler/pullreq/list.go b/internal/api/handler/pullreq/list.go index b54b70402..4de028ceb 100644 --- a/internal/api/handler/pullreq/list.go +++ b/internal/api/handler/pullreq/list.go @@ -35,17 +35,12 @@ func HandleList(pullreqCtrl *pullreq.Controller) http.HandlerFunc { filter.Order = enum.OrderDesc } - result, err := pullreqCtrl.List(ctx, session, repoRef, filter) + prs, err := pullreqCtrl.List(ctx, session, repoRef, filter) if err != nil { render.TranslatedUserError(w, err) return } - list := make([]*PullReq, len(result)) - for i, pri := range result { - list[i] = mapPullReqInfo(pri) - } - - render.JSON(w, http.StatusOK, list) + render.JSON(w, http.StatusOK, prs) } } diff --git a/internal/api/handler/pullreq/pullreq.go b/internal/api/handler/pullreq/pullreq.go deleted file mode 100644 index d319b7fcf..000000000 --- a/internal/api/handler/pullreq/pullreq.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2022 Harness Inc. All rights reserved. -// Use of this source code is governed by the Polyform Free Trial License -// that can be found in the LICENSE.md file for this repository. - -package pullreq - -import "github.com/harness/gitness/types" - -type PullReq struct { - types.PullReq - Author types.Identity `json:"author"` - Merger *types.Identity `json:"merger"` -} - -func mapPullReqInfo(pri *types.PullReqInfo) *PullReq { - pr := &PullReq{} - pr.PullReq = pri.PullReq - pr.Author = types.Identity{ - ID: pri.AuthorID, - Name: pri.AuthorName, - Email: pri.AuthorEmail, - } - if pr.MergedBy != nil { - pr.Merger = &types.Identity{ - ID: *pri.MergerID, - Name: *pri.MergerName, - Email: *pri.MergerEmail, - } - } - return pr -} diff --git a/internal/api/openapi/pullreq.go b/internal/api/openapi/pullreq.go index 0c2d81e17..f788fa384 100644 --- a/internal/api/openapi/pullreq.go +++ b/internal/api/openapi/pullreq.go @@ -8,9 +8,9 @@ import ( "net/http" "github.com/harness/gitness/internal/api/controller/pullreq" - handler "github.com/harness/gitness/internal/api/handler/pullreq" "github.com/harness/gitness/internal/api/request" "github.com/harness/gitness/internal/api/usererror" + "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" "github.com/gotidy/ptr" @@ -114,7 +114,7 @@ func pullReqOperations(reflector *openapi3.Reflector) { createPullReq.WithTags("pullreq") createPullReq.WithMapOfAnything(map[string]interface{}{"operationId": "createPullReq"}) _ = reflector.SetRequest(&createPullReq, new(createPullReqRequest), http.MethodPost) - _ = reflector.SetJSONResponse(&createPullReq, new(handler.PullReq), http.StatusCreated) + _ = reflector.SetJSONResponse(&createPullReq, new(types.PullReq), http.StatusCreated) _ = reflector.SetJSONResponse(&createPullReq, new(usererror.Error), http.StatusBadRequest) _ = reflector.SetJSONResponse(&createPullReq, new(usererror.Error), http.StatusInternalServerError) _ = reflector.SetJSONResponse(&createPullReq, new(usererror.Error), http.StatusUnauthorized) @@ -130,7 +130,7 @@ func pullReqOperations(reflector *openapi3.Reflector) { queryParameterDirection, queryParameterSortPullRequest, queryParameterPage, queryParameterPerPage) _ = reflector.SetRequest(&listPullReq, new(listPullReqRequest), http.MethodGet) - _ = reflector.SetJSONResponse(&listPullReq, new([]handler.PullReq), http.StatusOK) + _ = reflector.SetJSONResponse(&listPullReq, new([]types.PullReq), http.StatusOK) _ = reflector.SetJSONResponse(&listPullReq, new(usererror.Error), http.StatusBadRequest) _ = reflector.SetJSONResponse(&listPullReq, new(usererror.Error), http.StatusInternalServerError) _ = reflector.SetJSONResponse(&listPullReq, new(usererror.Error), http.StatusUnauthorized) @@ -141,7 +141,7 @@ func pullReqOperations(reflector *openapi3.Reflector) { getPullReq.WithTags("pullreq") getPullReq.WithMapOfAnything(map[string]interface{}{"operationId": "getPullReq"}) _ = reflector.SetRequest(&getPullReq, new(getPullReqRequest), http.MethodGet) - _ = reflector.SetJSONResponse(&getPullReq, new(handler.PullReq), http.StatusOK) + _ = reflector.SetJSONResponse(&getPullReq, new(types.PullReq), http.StatusOK) _ = reflector.SetJSONResponse(&getPullReq, new(usererror.Error), http.StatusBadRequest) _ = reflector.SetJSONResponse(&getPullReq, new(usererror.Error), http.StatusInternalServerError) _ = reflector.SetJSONResponse(&getPullReq, new(usererror.Error), http.StatusUnauthorized) diff --git a/internal/store/database/null/bool.go b/internal/store/database/null/bool.go new file mode 100644 index 000000000..39b3030a0 --- /dev/null +++ b/internal/store/database/null/bool.go @@ -0,0 +1,118 @@ +// Copyright 2022 Harness Inc. All rights reserved. +// Use of this source code is governed by the Polyform Free Trial License +// that can be found in the LICENSE.md file for this repository. + +package null + +import ( + "database/sql" + "database/sql/driver" + "encoding/json" + "fmt" + "strconv" +) + +// Bool represents a bool that may be null. +type Bool struct { + sql.NullBool +} + +func NewBool(b bool) Bool { + return Bool{ + sql.NullBool{ + Bool: b, + Valid: true, + }, + } +} + +// FromBool returns a null Bool if the parameter is false or a true Bool. +func FromBool(b bool) Bool { + if !b { + return Bool{} + } + return NewBool(b) +} + +// FromPtrBool returns a null Bool if the parameter is nil, a valid Bool otherwise. +func FromPtrBool(b bool) Bool { + if !b { + return Bool{} + } + return NewBool(b) +} + +// ToBool converts null.Bool to a bool. +func (b *Bool) ToBool() bool { + if !b.Valid { + return false + } + return b.Bool +} + +// ToPtrBool converts null.Bool to a *bool. +func (b *Bool) ToPtrBool() *bool { + if !b.Valid { + return nil + } + return &b.Bool +} + +// UnmarshalJSON implements json.Unmarshaler. +func (b *Bool) UnmarshalJSON(input []byte) error { + var i interface{} + if err := json.Unmarshal(input, &i); err != nil { + return err + } + + switch val := i.(type) { + case bool: + b.Bool = val + b.Valid = true + default: + b.Bool = false + b.Valid = false + } + + return nil +} + +// MarshalJSON implements json.Marshaler. +func (b *Bool) MarshalJSON() ([]byte, error) { + if !b.Valid { + return []byte(null), nil + } + return json.Marshal(b.Bool) +} + +// Scan implements sql.Scanner interface +func (b *Bool) Scan(input interface{}) error { + switch val := input.(type) { + case nil: + b.Bool, b.Valid = false, false + case bool: + b.Bool, b.Valid = val, true + case int64: + b.Bool, b.Valid = val != 0, true + case float64: + b.Bool, b.Valid = val != 0.0, true + case []byte: + bb, err := strconv.ParseBool(string(val)) + b.Bool, b.Valid = bb, err == nil + case string: + bb, err := strconv.ParseBool(val) + b.Bool, b.Valid = bb, err == nil + default: + return fmt.Errorf("failed to convert %v (%T) to null.Bool", input, input) + } + + return nil +} + +// Value implements driver.Valuer interface +func (b *Bool) Value() (driver.Value, error) { + if !b.Valid { + return nil, nil + } + return b.Bool, nil +} diff --git a/internal/store/database/null/int64.go b/internal/store/database/null/int64.go new file mode 100644 index 000000000..ed58b2a38 --- /dev/null +++ b/internal/store/database/null/int64.go @@ -0,0 +1,116 @@ +// Copyright 2022 Harness Inc. All rights reserved. +// Use of this source code is governed by the Polyform Free Trial License +// that can be found in the LICENSE.md file for this repository. + +package null + +import ( + "database/sql" + "database/sql/driver" + "encoding/json" + "fmt" + "strconv" +) + +// Int64 represents an int64 that may be null. +type Int64 struct { + sql.NullInt64 +} + +func NewInt64(i int64) Int64 { + return Int64{ + sql.NullInt64{ + Int64: i, + Valid: true, + }, + } +} + +// FromInt64 returns a null Int64 if the parameter is zero, a valid Int64 otherwise. +func FromInt64(i int64) Int64 { + if i == 0 { + return Int64{} + } + return NewInt64(i) +} + +// FromPtrInt64 returns a null Int64 if the parameter is nil, a valid Int64 otherwise. +func FromPtrInt64(i *int64) Int64 { + if i == nil { + return Int64{} + } + return NewInt64(*i) +} + +// ToInt64 converts the null.Int64 to an int64. +func (i *Int64) ToInt64() int64 { + if !i.Valid { + return 0 + } + return i.Int64 +} + +// ToPtrInt64 converts the null.Int64 to an *int64. +func (i *Int64) ToPtrInt64() *int64 { + if !i.Valid { + return nil + } + return &i.Int64 +} + +// UnmarshalJSON implements json.Unmarshaler. +func (i *Int64) UnmarshalJSON(input []byte) error { + var value interface{} + if err := json.Unmarshal(input, &value); err != nil { + return err + } + + switch z := value.(type) { + case float64: // in JSON a number is float64 + i.Int64 = int64(z) + i.Valid = true + default: + i.Int64 = 0 + i.Valid = false + } + + return nil +} + +// MarshalJSON implements json.Marshaler. +func (i *Int64) MarshalJSON() ([]byte, error) { + if !i.Valid { + return []byte(null), nil + } + return json.Marshal(i.Int64) +} + +// Scan implements sql.Scanner interface +func (i *Int64) Scan(input interface{}) error { + switch val := input.(type) { + case nil: + i.Int64, i.Valid = 0, false + case int64: + i.Int64, i.Valid = val, true + case float64: + i.Int64, i.Valid = int64(val), true + case []byte: + ii, err := strconv.ParseInt(string(val), 10, 64) + i.Int64, i.Valid = ii, err == nil + case string: + ii, err := strconv.ParseInt(val, 10, 64) + i.Int64, i.Valid = ii, err == nil + default: + return fmt.Errorf("failed to convert %v (%T) to null.Int64", input, input) + } + + return nil +} + +// Value implements driver.Valuer interface +func (i *Int64) Value() (driver.Value, error) { + if !i.Valid { + return nil, nil + } + return i.Int64, nil +} diff --git a/internal/store/database/null/null.go b/internal/store/database/null/null.go new file mode 100644 index 000000000..a97ae2870 --- /dev/null +++ b/internal/store/database/null/null.go @@ -0,0 +1,7 @@ +// Copyright 2022 Harness Inc. All rights reserved. +// Use of this source code is governed by the Polyform Free Trial License +// that can be found in the LICENSE.md file for this repository. + +package null + +const null = "null" diff --git a/internal/store/database/null/string.go b/internal/store/database/null/string.go new file mode 100644 index 000000000..6532e21ba --- /dev/null +++ b/internal/store/database/null/string.go @@ -0,0 +1,109 @@ +// Copyright 2022 Harness Inc. All rights reserved. +// Use of this source code is governed by the Polyform Free Trial License +// that can be found in the LICENSE.md file for this repository. + +package null + +import ( + "database/sql" + "database/sql/driver" + "encoding/json" + "fmt" +) + +// String represents a string that may be null. +type String struct { + sql.NullString +} + +func NewString(s string) String { + return String{ + sql.NullString{ + String: s, + Valid: true, + }, + } +} + +// FromNullableString returns a null String if the parameter is empty, a valid String otherwise. +func FromNullableString(s string) String { + if s == "" { + return String{} + } + return NewString(s) +} + +// FromPtrString returns a null String if the parameter is nil, a valid String otherwise. +func FromPtrString(s *string) String { + if s == nil { + return String{} + } + return NewString(*s) +} + +// ToString converts the null.String to a string. +func (s *String) ToString() string { + if !s.Valid { + return "" + } + return s.String +} + +// ToPtrString converts the null.String to a *string. +func (s *String) ToPtrString() *string { + if !s.Valid { + return nil + } + return &s.String +} + +// UnmarshalJSON implements json.Unmarshaler. +func (s *String) UnmarshalJSON(input []byte) error { + var val interface{} + if err := json.Unmarshal(input, &val); err != nil { + return err + } + + switch z := val.(type) { + case string: + s.String = z + s.Valid = true + default: + s.String = "" + s.Valid = false + } + + return nil +} + +// MarshalJSON implements json.Marshaler. +func (s *String) MarshalJSON() ([]byte, error) { + if !s.Valid { + return []byte(null), nil + } + return json.Marshal(s.String) +} + +// Scan implements sql.Scanner interface +func (s *String) Scan(input interface{}) error { + switch val := input.(type) { + case nil: + s.String, s.Valid = "", false + case []byte: + s.String, s.Valid = string(val), true + case string: + s.String, s.Valid = val, true + default: + return fmt.Errorf("failed to convert %v (%T) to null.String", input, input) + } + + return nil +} + +// Value implements driver.Valuer interface +func (s *String) Value() (driver.Value, error) { + if !s.Valid { + return nil, nil + } + return s.String, nil +} diff --git a/internal/store/database/pullreq.go b/internal/store/database/pullreq.go index 87e01aef0..0f06d0bf2 100644 --- a/internal/store/database/pullreq.go +++ b/internal/store/database/pullreq.go @@ -9,6 +9,7 @@ import ( "github.com/harness/gitness/internal/store" "github.com/harness/gitness/internal/store/database/dbtx" + "github.com/harness/gitness/internal/store/database/null" "github.com/harness/gitness/types" "github.com/harness/gitness/types/enum" @@ -31,14 +32,44 @@ type PullReqStore struct { db *sqlx.DB } +// pullReq is used to fetch pull request data from the database. +// The object should be later re-packed into a different struct to return it as an API response. +type pullReq struct { + ID int64 `db:"pullreq_id"` + CreatedBy int64 `db:"pullreq_created_by"` + Created int64 `db:"pullreq_created"` + Updated int64 `db:"pullreq_updated"` + Number int64 `db:"pullreq_number"` + State enum.PullReqState `db:"pullreq_state"` + + Title string `db:"pullreq_title"` + Description string `db:"pullreq_description"` + + SourceRepoID int64 `db:"pullreq_source_repo_id"` + SourceBranch string `db:"pullreq_source_branch"` + TargetRepoID int64 `db:"pullreq_target_repo_id"` + TargetBranch string `db:"pullreq_target_branch"` + + MergedBy null.Int64 `db:"pullreq_merged_by"` + Merged null.Int64 `db:"pullreq_merged"` + MergeStrategy null.String `db:"pullreq_merge_strategy"` + + AuthorUID string `db:"author_uid"` + AuthorName string `db:"author_name"` + AuthorEmail string `db:"author_email"` + MergerUID null.String `db:"merger_uid"` + MergerName null.String `db:"merger_name"` + MergerEmail null.String `db:"merger_email"` +} + const ( pullReqColumns = ` pullreq_id ,pullreq_created_by ,pullreq_created ,pullreq_updated + ,pullreq_number ,pullreq_state - ,pullreq_number ,pullreq_title ,pullreq_description ,pullreq_source_repo_id @@ -48,10 +79,10 @@ const ( ,pullreq_merged_by ,pullreq_merged ,pullreq_merge_strategy - ,author.principal_id as "author_id" + ,author.principal_uid as "author_uid" ,author.principal_displayName as "author_name" ,author.principal_email as "author_email" - ,merger.principal_id as "merger_id" + ,merger.principal_uid as "merger_uid" ,merger.principal_displayName as "merger_name" ,merger.principal_email as "merger_email"` @@ -63,31 +94,33 @@ const ( ) // Find finds the pull request by id. -func (s *PullReqStore) Find(ctx context.Context, id int64) (*types.PullReqInfo, error) { +func (s *PullReqStore) Find(ctx context.Context, id int64) (*types.PullReq, error) { const sqlQuery = pullReqSelectBase + ` WHERE pullreq_id = $1` db := dbtx.GetAccessor(ctx, s.db) - dst := new(types.PullReqInfo) + dst := &pullReq{} if err := db.GetContext(ctx, dst, sqlQuery, id); err != nil { return nil, processSQLErrorf(err, "Select query failed") } - return dst, nil + + return mapPullReq(dst), nil } // FindByNumber finds the pull request by repo ID and pull request number. -func (s *PullReqStore) FindByNumber(ctx context.Context, repoID, number int64) (*types.PullReqInfo, error) { +func (s *PullReqStore) FindByNumber(ctx context.Context, repoID, number int64) (*types.PullReq, error) { const sqlQuery = pullReqSelectBase + ` WHERE pullreq_target_repo_id = $1 AND pullreq_number = $2` db := dbtx.GetAccessor(ctx, s.db) - dst := new(types.PullReqInfo) + dst := &pullReq{} if err := db.GetContext(ctx, dst, sqlQuery, repoID, number); err != nil { return nil, processSQLErrorf(err, "Select query failed") } - return dst, nil + + return mapPullReq(dst), nil } // Create creates a new pull request. @@ -123,8 +156,7 @@ func (s *PullReqStore) Create(ctx context.Context, pullReq *types.PullReq) error ,:pullreq_merged_by ,:pullreq_merged ,:pullreq_merge_strategy - ) RETURNING pullreq_id -` + ) RETURNING pullreq_id` db := dbtx.GetAccessor(ctx, s.db) @@ -234,7 +266,7 @@ func (s *PullReqStore) Count(ctx context.Context, repoID int64, opts *types.Pull } // List returns a list of pull requests for a repo. -func (s *PullReqStore) List(ctx context.Context, repoID int64, opts *types.PullReqFilter) ([]*types.PullReqInfo, error) { +func (s *PullReqStore) List(ctx context.Context, repoID int64, opts *types.PullReqFilter) ([]*types.PullReq, error) { stmt := builder. Select(pullReqColumns). From("pullreq"). @@ -276,7 +308,7 @@ func (s *PullReqStore) List(ctx context.Context, repoID int64, opts *types.PullR return nil, errors.Wrap(err, "Failed to convert query to sql") } - dst := make([]*types.PullReqInfo, 0) + dst := make([]*pullReq, 0) db := dbtx.GetAccessor(ctx, s.db) @@ -284,5 +316,51 @@ func (s *PullReqStore) List(ctx context.Context, repoID int64, opts *types.PullR return nil, processSQLErrorf(err, "Failed executing custom list query") } - return dst, nil + return mapSlicePullReq(dst), nil +} + +func mapPullReq(pr *pullReq) *types.PullReq { + m := &types.PullReq{ + ID: pr.ID, + CreatedBy: pr.CreatedBy, + Created: pr.Created, + Updated: pr.Updated, + Number: pr.Number, + State: pr.State, + Title: pr.Title, + Description: pr.Description, + SourceRepoID: pr.SourceRepoID, + SourceBranch: pr.SourceBranch, + TargetRepoID: pr.TargetRepoID, + TargetBranch: pr.TargetBranch, + MergedBy: pr.MergedBy.ToPtrInt64(), + Merged: pr.Merged.ToPtrInt64(), + MergeStrategy: pr.MergeStrategy.ToPtrString(), + Author: types.PrincipalInfo{}, + Merger: nil, + } + m.Author = types.PrincipalInfo{ + ID: pr.CreatedBy, + UID: pr.AuthorUID, + Name: pr.AuthorName, + Email: pr.AuthorEmail, + } + if pr.MergedBy.Valid { + m.Merger = &types.PrincipalInfo{ + ID: pr.MergedBy.Int64, + UID: pr.MergerUID.String, + Name: pr.MergerName.String, + Email: pr.MergerEmail.String, + } + } + + return m +} + +func mapSlicePullReq(prs []*pullReq) []*types.PullReq { + m := make([]*types.PullReq, len(prs)) + for i, pr := range prs { + m[i] = mapPullReq(pr) + } + return m } diff --git a/internal/store/database/pullreq_sync.go b/internal/store/database/pullreq_sync.go index 916cac164..307643693 100644 --- a/internal/store/database/pullreq_sync.go +++ b/internal/store/database/pullreq_sync.go @@ -29,14 +29,14 @@ type PullReqStoreSync struct { } // Find finds the pull request by id. -func (s *PullReqStoreSync) Find(ctx context.Context, id int64) (*types.PullReqInfo, error) { +func (s *PullReqStoreSync) Find(ctx context.Context, id int64) (*types.PullReq, error) { mutex.RLock() defer mutex.RUnlock() return s.base.Find(ctx, id) } // FindByNumber finds the pull request by repo ID and pull request number. -func (s *PullReqStoreSync) FindByNumber(ctx context.Context, repoID, number int64) (*types.PullReqInfo, error) { +func (s *PullReqStoreSync) FindByNumber(ctx context.Context, repoID, number int64) (*types.PullReq, error) { mutex.RLock() defer mutex.RUnlock() return s.base.FindByNumber(ctx, repoID, number) @@ -82,7 +82,7 @@ func (s *PullReqStoreSync) List( ctx context.Context, repoID int64, opts *types.PullReqFilter, -) ([]*types.PullReqInfo, error) { +) ([]*types.PullReq, error) { mutex.RLock() defer mutex.RUnlock() return s.base.List(ctx, repoID, opts) diff --git a/internal/store/store.go b/internal/store/store.go index d02daf0b4..28fa82116 100644 --- a/internal/store/store.go +++ b/internal/store/store.go @@ -201,10 +201,10 @@ type ( // PullReqStore defines the pull request data storage. PullReqStore interface { // Find the pull request by id. - Find(ctx context.Context, id int64) (*types.PullReqInfo, error) + Find(ctx context.Context, id int64) (*types.PullReq, error) // FindByNumber finds the pull request by repo ID and the pull request number. - FindByNumber(ctx context.Context, repoID, number int64) (*types.PullReqInfo, error) + FindByNumber(ctx context.Context, repoID, number int64) (*types.PullReq, error) // Create a new pull request. Create(ctx context.Context, pullreq *types.PullReq) error @@ -222,7 +222,7 @@ type ( Count(ctx context.Context, repoID int64, opts *types.PullReqFilter) (int64, error) // List returns a list of pull requests in a space. - List(ctx context.Context, repoID int64, opts *types.PullReqFilter) ([]*types.PullReqInfo, error) + List(ctx context.Context, repoID int64, opts *types.PullReqFilter) ([]*types.PullReq, error) } // SystemStore defines internal system metadata storage. diff --git a/types/pullreq.go b/types/pullreq.go index 99f33a677..c63a28fa6 100644 --- a/types/pullreq.go +++ b/types/pullreq.go @@ -10,25 +10,28 @@ import ( // PullReq represents a pull request. type PullReq struct { - ID int64 `db:"pullreq_id" json:"id"` - CreatedBy int64 `db:"pullreq_created_by" json:"-"` - Created int64 `db:"pullreq_created" json:"created"` - Updated int64 `db:"pullreq_updated" json:"updated"` - Number int64 `db:"pullreq_number" json:"number"` + ID int64 `json:"id"` + CreatedBy int64 `json:"-"` + Created int64 `json:"created"` + Updated int64 `json:"updated"` + Number int64 `json:"number"` - State enum.PullReqState `db:"pullreq_state" json:"state"` + State enum.PullReqState `json:"state"` - Title string `db:"pullreq_title" json:"title"` - Description string `db:"pullreq_description" json:"description"` + Title string `json:"title"` + Description string `json:"description"` - SourceRepoID int64 `db:"pullreq_source_repo_id" json:"source_repo_id"` - SourceBranch string `db:"pullreq_source_branch" json:"source_branch"` - TargetRepoID int64 `db:"pullreq_target_repo_id" json:"target_repo_id"` - TargetBranch string `db:"pullreq_target_branch" json:"target_branch"` + SourceRepoID int64 `json:"source_repo_id"` + SourceBranch string `json:"source_branch"` + TargetRepoID int64 `json:"target_repo_id"` + TargetBranch string `json:"target_branch"` - MergedBy *int64 `db:"pullreq_merged_by" json:"-"` - Merged *int64 `db:"pullreq_merged" json:"merged"` - MergeStrategy *string `db:"pullreq_merge_strategy" json:"merge_strategy"` + MergedBy *int64 `json:"-"` + Merged *int64 `json:"merged"` + MergeStrategy *string `json:"merge_strategy"` + + Author PrincipalInfo `json:"author"` + Merger *PrincipalInfo `json:"merger"` } // PullReqFilter stores pull request query parameters. @@ -41,15 +44,3 @@ type PullReqFilter struct { Sort enum.PullReqSort `json:"sort"` Order enum.Order `json:"direction"` } - -// PullReqInfo is used to fetch pull request data from the database. -// The object should be later re-packed into a different struct to return it as an API response. -type PullReqInfo struct { - PullReq - AuthorID int64 `db:"author_id"` - AuthorName string `db:"author_name"` - AuthorEmail string `db:"author_email"` - MergerID *int64 `db:"merger_id"` - MergerName *string `db:"merger_name"` - MergerEmail *string `db:"merger_email"` -} diff --git a/types/user.go b/types/user.go index 4f62fb29c..634e41344 100644 --- a/types/user.go +++ b/types/user.go @@ -45,8 +45,15 @@ type ( } Identity struct { - ID int64 `db:"id" json:"id"` - Name string `db:"name" json:"name"` - Email string `db:"email" json:"email"` + ID int64 `json:"id"` + Name string `json:"name"` + Email string `json:"email"` + } + + PrincipalInfo struct { + ID int64 `json:"id"` + UID string `json:"uid"` + Name string `json:"name"` + Email string `json:"email"` } )