~edwargix/git.sr.ht

a28f52924470dc783a8404d19c8bbc4cb4a3ca3c — Drew DeVault 5 years ago 895fa32
DRY up repository queries a bit
3 files changed, 48 insertions(+), 84 deletions(-)

M api/graph/model/cursor.go
M api/graph/model/repository.go
M api/graph/schema.resolvers.go
M api/graph/model/cursor.go => api/graph/model/cursor.go +3 -8
@@ 12,7 12,6 @@ import (
type Cursor struct {
	Count   int    `json:"count"`
	Next    string `json:"next"`
	OrderBy string `json:"order_by"`
	Search  string `json:"search"`
}



@@ 53,18 52,14 @@ func derefOrInt(i *int, d int) int {
func NewCursor(filter *Filter) *Cursor {
	if filter != nil {
		return &Cursor{
			Next: "",

			Count: derefOrInt(filter.Count, 25),
			// TODO:
			OrderBy: "",
			Search:  "",
			Next:   "",
			Count:  derefOrInt(filter.Count, 25),
			Search: "", // TODO
		}
	}
	return &Cursor{
		Count:   25,
		Next:    "",
		OrderBy: "",
		Search:  "",
	}
}

M api/graph/model/repository.go => api/graph/model/repository.go +43 -10
@@ 2,6 2,7 @@ package model

import (
	"context"
	"database/sql"
	"time"
	"strconv"



@@ 64,7 65,8 @@ func (r *Repository) Select(ctx context.Context) []string {
		"upstreamUrl": "upstream_uri",
	}),
		database.WithAlias(r.alias, "path"),
		database.WithAlias(r.alias, "owner_id"))
		database.WithAlias(r.alias, "owner_id"),
		database.WithAlias(r.alias, "updated"))
}

func (r *Repository) As(alias string) *Repository {


@@ 82,20 84,51 @@ func (r *Repository) Fields(ctx context.Context) []interface{} {
		"visibility":   &r.Visibility,
		"upstream_url": &r.UpstreamURL,
	})
	return append(fields, &r.Path, &r.OwnerID)
	return append(fields, &r.Path, &r.OwnerID, &r.Updated)
}

func (r *Repository) ApplyCursor(q sq.SelectBuilder, c *Cursor) sq.SelectBuilder {
	if c.Next != "" {
		id, _ := strconv.Atoi(c.Next)
		q = q.Where(r.alias + `.id <= ?`, id)
func (r *Repository) QueryWithCursor(ctx context.Context,
	db *sql.DB, q sq.SelectBuilder, cur *Cursor) ([]*Repository, *Cursor) {
	var (
		err  error
		rows *sql.Rows
	)

	if cur.Next != "" {
		ts, _ := strconv.ParseInt(cur.Next, 10, 64)
		updated := time.Unix(ts, 0)
		q = q.Where(database.WithAlias(r.alias, "updated") + "<= ?", updated)
	}
	q = q.
		OrderBy(database.WithAlias(r.alias, "updated") + " DESC").
		Limit(uint64(cur.Count + 1))

	if rows, err = q.RunWith(db).QueryContext(ctx); err != nil {
		panic(err)
	}
	if c.OrderBy != "" {
		q = q.OrderBy(c.OrderBy)
	defer rows.Close()

	var repos []*Repository
	for rows.Next() {
		var repo Repository
		if err := rows.Scan(repo.Fields(ctx)...); err != nil {
			panic(err)
		}
		repos = append(repos, &repo)
	}

	if len(repos) > cur.Count {
		cur = &Cursor{
			Count:  cur.Count,
			Next:   strconv.FormatInt(repos[len(repos)-1].Updated.Unix(), 10),
			Search: cur.Search,
		}
		repos = repos[:cur.Count]
	} else {
		q = q.OrderBy(r.alias + `.id DESC`)
		cur = nil
	}
	return q.Limit(uint64(c.Count + 1))

	return repos, cur
}

func (r *Repository) DefaultSearch(query sq.SelectBuilder,

M api/graph/schema.resolvers.go => api/graph/schema.resolvers.go +2 -66
@@ 5,10 5,8 @@ package graph

import (
	"context"
	"database/sql"
	"fmt"
	"sort"
	"strconv"
	"strings"

	"git.sr.ht/~sircmpwn/git.sr.ht/api/auth"


@@ 76,11 74,6 @@ func (r *queryResolver) User(ctx context.Context, username string) (*model.User,
}

func (r *queryResolver) Repositories(ctx context.Context, cursor *model.Cursor, filter *model.Filter) (*model.RepositoryCursor, error) {
	var (
		err  error
		rows *sql.Rows
	)

	if cursor == nil {
		cursor = model.NewCursor(filter)
	}


@@ 90,34 83,8 @@ func (r *queryResolver) Repositories(ctx context.Context, cursor *model.Cursor, 
		Select(ctx, repo).
		From(`repository repo`).
		Where(`repo.owner_id = ?`, auth.ForContext(ctx).ID)
	query = repo.ApplyCursor(query, cursor)

	if rows, err = query.RunWith(r.DB).QueryContext(ctx); err != nil {
		panic(err)
	}
	defer rows.Close()

	var repos []*model.Repository
	for rows.Next() {
		var repo model.Repository
		if err := rows.Scan(repo.Fields(ctx)...); err != nil {
			panic(err)
		}
		repos = append(repos, &repo)
	}

	if len(repos) > cursor.Count {
		cursor = &model.Cursor{
			Count:   cursor.Count,
			Next:    strconv.Itoa(repos[len(repos)-1].ID),
			OrderBy: `id DESC`,
			Search:  "",
		}
		repos = repos[:cursor.Count]
	} else {
		cursor = nil
	}

	repos, cursor := repo.QueryWithCursor(ctx, r.DB, query, cursor)
	return &model.RepositoryCursor{repos, cursor}, nil
}



@@ 173,11 140,6 @@ func (r *treeResolver) Entries(ctx context.Context, obj *model.Tree, cursor *mod
}

func (r *userResolver) Repositories(ctx context.Context, obj *model.User, cursor *model.Cursor, filter *model.Filter) (*model.RepositoryCursor, error) {
	var (
		err  error
		rows *sql.Rows
	)

	if cursor == nil {
		cursor = model.NewCursor(filter)
	}


@@ 187,34 149,8 @@ func (r *userResolver) Repositories(ctx context.Context, obj *model.User, cursor
		Select(ctx, repo).
		From(`repository repo`).
		Where(`repo.owner_id = ?`, obj.ID)
	query = repo.ApplyCursor(query, cursor)

	if rows, err = query.RunWith(r.DB).QueryContext(ctx); err != nil {
		panic(err)
	}
	defer rows.Close()

	var repos []*model.Repository
	for rows.Next() {
		var repo model.Repository
		if err := rows.Scan(repo.Fields(ctx)...); err != nil {
			panic(err)
		}
		repos = append(repos, &repo)
	}

	if len(repos) > cursor.Count {
		cursor = &model.Cursor{
			Count:   cursor.Count,
			Next:    strconv.Itoa(repos[len(repos)-1].ID),
			OrderBy: `id DESC`,
			Search:  "",
		}
		repos = repos[:cursor.Count]
	} else {
		cursor = nil
	}

	repos, cursor := repo.QueryWithCursor(ctx, r.DB, query, cursor)
	return &model.RepositoryCursor{repos, cursor}, nil
}