add space descendants data layer fn (#2511)

* add space descendants data layer fn
pull/3545/head
Marko Gaćeša 2024-08-14 16:49:30 +00:00 committed by Harness
parent 7e3253d366
commit d089d04025
7 changed files with 154 additions and 128 deletions

View File

@ -241,7 +241,7 @@ func (s *Service) ListPullReqLabels(
pullreqID int64,
filter *types.AssignableLabelFilter,
) (*types.ScopesLabels, int64, error) {
spaces, err := s.spaceStore.GetHierarchy(ctx, spaceID)
spaces, err := s.spaceStore.GetAncestors(ctx, spaceID)
if err != nil {
return nil, 0, fmt.Errorf("failed to get space hierarchy: %w", err)
}

View File

@ -169,10 +169,14 @@ type (
// GetAncestorIDs returns a list of all space IDs along the recursive path to the root space.
GetAncestorIDs(ctx context.Context, spaceID int64) ([]int64, error)
GetHierarchy(
ctx context.Context,
spaceID int64,
) ([]*types.Space, error)
// GetAncestors returns a list of all spaces along the recursive path to the root space.
GetAncestors(ctx context.Context, spaceID int64) ([]*types.Space, error)
// GetAncestorsData returns a list of space parent data for spaces that are ancestors of the space.
GetAncestorsData(ctx context.Context, spaceID int64) ([]types.SpaceParentData, error)
// GetDescendantsData returns a list of space parent data for spaces that are descendants of the space.
GetDescendantsData(ctx context.Context, spaceID int64) ([]types.SpaceParentData, error)
// Create creates a new space
Create(ctx context.Context, space *types.Space) error

View File

@ -433,45 +433,7 @@ func (s *PullReqStore) Count(ctx context.Context, opts *types.PullReqFilter) (in
}
stmt = stmt.From("pullreqs")
if len(opts.States) == 1 {
stmt = stmt.Where("pullreq_state = ?", opts.States[0])
} else if len(opts.States) > 1 {
stmt = stmt.Where(squirrel.Eq{"pullreq_state": opts.States})
}
if opts.SourceRepoID != 0 {
stmt = stmt.Where("pullreq_source_repo_id = ?", opts.SourceRepoID)
}
if opts.SourceBranch != "" {
stmt = stmt.Where("pullreq_source_branch = ?", opts.SourceBranch)
}
if opts.TargetRepoID != 0 {
stmt = stmt.Where("pullreq_target_repo_id = ?", opts.TargetRepoID)
}
if opts.TargetBranch != "" {
stmt = stmt.Where("pullreq_target_branch = ?", opts.TargetBranch)
}
if opts.Query != "" {
stmt = stmt.Where("LOWER(pullreq_title) LIKE ?", fmt.Sprintf("%%%s%%", strings.ToLower(opts.Query)))
}
if len(opts.CreatedBy) > 0 {
stmt = stmt.Where(squirrel.Eq{"pullreq_created_by": opts.CreatedBy})
}
if opts.CreatedLt > 0 {
stmt = stmt.Where("pullreq_created < ?", opts.CreatedLt)
}
if opts.CreatedGt > 0 {
stmt = stmt.Where("pullreq_created > ?", opts.CreatedGt)
}
setLabelKeyQuery(&stmt, opts)
s.applyFilter(&stmt, opts)
sql, args, err := stmt.ToSql()
if err != nil {
@ -500,45 +462,7 @@ func (s *PullReqStore) List(ctx context.Context, opts *types.PullReqFilter) ([]*
}
stmt = stmt.From("pullreqs")
if len(opts.States) == 1 {
stmt = stmt.Where("pullreq_state = ?", opts.States[0])
} else if len(opts.States) > 1 {
stmt = stmt.Where(squirrel.Eq{"pullreq_state": opts.States})
}
if opts.SourceRepoID != 0 {
stmt = stmt.Where("pullreq_source_repo_id = ?", opts.SourceRepoID)
}
if opts.SourceBranch != "" {
stmt = stmt.Where("pullreq_source_branch = ?", opts.SourceBranch)
}
if opts.TargetRepoID != 0 {
stmt = stmt.Where("pullreq_target_repo_id = ?", opts.TargetRepoID)
}
if opts.TargetBranch != "" {
stmt = stmt.Where("pullreq_target_branch = ?", opts.TargetBranch)
}
if opts.Query != "" {
stmt = stmt.Where("LOWER(pullreq_title) LIKE ?", fmt.Sprintf("%%%s%%", strings.ToLower(opts.Query)))
}
if len(opts.CreatedBy) > 0 {
stmt = stmt.Where(squirrel.Eq{"pullreq_created_by": opts.CreatedBy})
}
if opts.CreatedLt > 0 {
stmt = stmt.Where("pullreq_created < ?", opts.CreatedLt)
}
if opts.CreatedGt > 0 {
stmt = stmt.Where("pullreq_created > ?", opts.CreatedGt)
}
setLabelKeyQuery(&stmt, opts)
s.applyFilter(&stmt, opts)
stmt = stmt.Limit(database.Limit(opts.Size))
stmt = stmt.Offset(database.Offset(opts.Page, opts.Size))
@ -570,7 +494,47 @@ func (s *PullReqStore) List(ctx context.Context, opts *types.PullReqFilter) ([]*
return result, nil
}
func setLabelKeyQuery(stmt *squirrel.SelectBuilder, opts *types.PullReqFilter) {
func (*PullReqStore) applyFilter(stmt *squirrel.SelectBuilder, opts *types.PullReqFilter) {
if len(opts.States) == 1 {
*stmt = stmt.Where("pullreq_state = ?", opts.States[0])
} else if len(opts.States) > 1 {
*stmt = stmt.Where(squirrel.Eq{"pullreq_state": opts.States})
}
if opts.SourceRepoID != 0 {
*stmt = stmt.Where("pullreq_source_repo_id = ?", opts.SourceRepoID)
}
if opts.SourceBranch != "" {
*stmt = stmt.Where("pullreq_source_branch = ?", opts.SourceBranch)
}
if opts.TargetRepoID != 0 {
*stmt = stmt.Where("pullreq_target_repo_id = ?", opts.TargetRepoID)
}
if opts.TargetBranch != "" {
*stmt = stmt.Where("pullreq_target_branch = ?", opts.TargetBranch)
}
if opts.Query != "" {
*stmt = stmt.Where("LOWER(pullreq_title) LIKE ?", fmt.Sprintf("%%%s%%", strings.ToLower(opts.Query)))
}
if len(opts.CreatedBy) > 0 {
*stmt = stmt.Where(squirrel.Eq{"pullreq_created_by": opts.CreatedBy})
}
if opts.CreatedLt > 0 {
*stmt = stmt.Where("pullreq_created < ?", opts.CreatedLt)
}
if opts.CreatedGt > 0 {
*stmt = stmt.Where("pullreq_created > ?", opts.CreatedGt)
}
// labels
if len(opts.LabelID) == 0 && len(opts.ValueID) == 0 {
return
}

View File

@ -562,19 +562,9 @@ func (s *RepoStore) countAll(
parentID int64,
filter *types.RepoFilter,
) (int64, error) {
query := `WITH RECURSIVE SpaceHierarchy AS (
SELECT space_id, space_parent_id
FROM spaces
WHERE space_id = $1
UNION
SELECT s.space_id, s.space_parent_id
FROM spaces s
JOIN SpaceHierarchy h ON s.space_parent_id = h.space_id
)
SELECT space_id
FROM SpaceHierarchy h1;`
query := spaceDescendantsQuery + `
SELECT space_descendant_id
FROM space_descendants`
db := dbtx.GetAccessor(ctx, s.db)
@ -649,24 +639,14 @@ func (s *RepoStore) listAll(
parentID int64,
filter *types.RepoFilter,
) ([]*types.Repository, error) {
where := `WITH RECURSIVE SpaceHierarchy AS (
SELECT space_id, space_parent_id
FROM spaces
WHERE space_id = $1
UNION
SELECT s.space_id, s.space_parent_id
FROM spaces s
JOIN SpaceHierarchy h ON s.space_parent_id = h.space_id
)
SELECT space_id
FROM SpaceHierarchy h1;`
query := spaceDescendantsQuery + `
SELECT space_descendant_id
FROM space_descendants`
db := dbtx.GetAccessor(ctx, s.db)
var spaceIDs []int64
if err := db.SelectContext(ctx, &spaceIDs, where, parentID); err != nil {
if err := db.SelectContext(ctx, &spaceIDs, query, parentID); err != nil {
return nil, database.ProcessSQLErrorf(ctx, err, "failed to retrieve spaces")
}

View File

@ -192,26 +192,40 @@ func (s *SpaceStore) findByPathAndDeletedAt(
return s.find(ctx, spaceID, &deletedAt)
}
const spaceRecursiveQuery = `
WITH RECURSIVE SpaceHierarchy(space_hierarchy_id, space_hierarchy_parent_id) AS (
SELECT space_id, space_parent_id
const spaceAncestorsQuery = `
WITH RECURSIVE space_ancestors(space_ancestor_id, space_ancestor_uid, space_ancestor_parent_id) AS (
SELECT space_id, space_uid, space_parent_id
FROM spaces
WHERE space_id = $1
UNION
SELECT s.space_id, s.space_parent_id
FROM spaces s
JOIN SpaceHierarchy h ON s.space_id = h.space_hierarchy_parent_id
SELECT space_id, space_uid, space_parent_id
FROM spaces
JOIN space_ancestors ON space_id = space_ancestor_parent_id
)
`
const spaceDescendantsQuery = `
WITH RECURSIVE space_descendants(space_descendant_id, space_descendant_uid, space_descendant_parent_id) AS (
SELECT space_id, space_uid, space_parent_id
FROM spaces
WHERE space_id = $1
UNION
SELECT space_id, space_uid, space_parent_id
FROM spaces
JOIN space_descendants ON space_descendant_id = space_parent_id
)
`
// GetRootSpace returns a space where space_parent_id is NULL.
func (s *SpaceStore) GetRootSpace(ctx context.Context, spaceID int64) (*types.Space, error) {
query := spaceRecursiveQuery + `
SELECT space_hierarchy_id
FROM SpaceHierarchy
WHERE space_hierarchy_parent_id IS NULL;`
query := spaceAncestorsQuery + `
SELECT space_ancestor_id
FROM space_ancestors
WHERE space_ancestor_parent_id IS NULL`
db := dbtx.GetAccessor(ctx, s.db)
@ -225,37 +239,93 @@ func (s *SpaceStore) GetRootSpace(ctx context.Context, spaceID int64) (*types.Sp
// GetAncestorIDs returns a list of all space IDs along the recursive path to the root space.
func (s *SpaceStore) GetAncestorIDs(ctx context.Context, spaceID int64) ([]int64, error) {
query := spaceRecursiveQuery + `
SELECT space_hierarchy_id FROM SpaceHierarchy`
query := spaceAncestorsQuery + `
SELECT space_ancestor_id FROM space_ancestors`
db := dbtx.GetAccessor(ctx, s.db)
var spaceIDs []int64
if err := db.SelectContext(ctx, &spaceIDs, query, spaceID); err != nil {
return nil, database.ProcessSQLErrorf(ctx, err, "failed to get space hierarchy")
return nil, database.ProcessSQLErrorf(ctx, err, "failed to get space ancestors IDs")
}
return spaceIDs, nil
}
func (s *SpaceStore) GetHierarchy(
func (s *SpaceStore) GetAncestors(
ctx context.Context,
spaceID int64,
) ([]*types.Space, error) {
query := spaceRecursiveQuery + `
query := spaceAncestorsQuery + `
SELECT ` + spaceColumns + `
FROM spaces INNER JOIN SpaceHierarchy ON space_id = space_hierarchy_id`
FROM spaces INNER JOIN space_ancestors ON space_id = space_ancestor_id`
db := dbtx.GetAccessor(ctx, s.db)
var dst []*space
if err := db.SelectContext(ctx, &dst, query, spaceID); err != nil {
return nil, database.ProcessSQLErrorf(ctx, err, "Failed executing custom list query")
return nil, database.ProcessSQLErrorf(ctx, err, "Failed executing get space ancestors query")
}
return s.mapToSpaces(ctx, s.db, dst)
}
// GetAncestorsData returns a list of space parent data for spaces that are ancestors of the space.
func (s *SpaceStore) GetAncestorsData(ctx context.Context, spaceID int64) ([]types.SpaceParentData, error) {
query := spaceAncestorsQuery + `
SELECT space_ancestor_id, space_ancestor_uid, space_ancestor_parent_id FROM space_ancestors`
return s.readParentsData(ctx, query, spaceID)
}
// GetDescendantsData returns a list of space parent data for spaces that are descendants of the space.
func (s *SpaceStore) GetDescendantsData(ctx context.Context, spaceID int64) ([]types.SpaceParentData, error) {
query := spaceDescendantsQuery + `
SELECT space_descendant_id, space_descendant_uid, space_descendant_parent_id FROM space_descendants`
return s.readParentsData(ctx, query, spaceID)
}
func (s *SpaceStore) readParentsData(
ctx context.Context,
query string,
spaceID int64,
) ([]types.SpaceParentData, error) {
db := dbtx.GetAccessor(ctx, s.db)
rows, err := db.QueryContext(ctx, query, spaceID)
if err != nil {
return nil, database.ProcessSQLErrorf(ctx, err, "failed to run space parent data query")
}
defer func() { _ = rows.Close() }()
var result []types.SpaceParentData
for rows.Next() {
var id int64
var uid string
var parent null.Int
err = rows.Scan(&id, &uid, &parent)
if err != nil {
return nil, database.ProcessSQLErrorf(ctx, err, "failed to scan space parent data")
}
result = append(result, types.SpaceParentData{
ID: id,
Identifier: uid,
ParentID: parent.Int64,
})
}
if err := rows.Err(); err != nil {
return nil, database.ProcessSQLErrorf(ctx, err, "failed to read space parent data")
}
return result, nil
}
// Create a new space.
func (s *SpaceStore) Create(ctx context.Context, space *types.Space) error {
if space == nil {

View File

@ -100,6 +100,8 @@ type RepositoryGitInfo struct {
GitUID string
}
func (rgi *RepositoryGitInfo) GetGitUID() string { return rgi.GitUID }
type RepositoryPullReqSummary struct {
OpenCount int `json:"open_count"`
ClosedCount int `json:"closed_count"`

View File

@ -43,6 +43,12 @@ type Space struct {
Deleted *int64 `json:"deleted,omitempty"`
}
type SpaceParentData struct {
ID int64 `json:"id"`
Identifier string `json:"identifier"`
ParentID int64 `json:"parent_id"`
}
// Stores spaces query parameters.
type SpaceFilter struct {
Page int `json:"page"`