git.sr.ht/api/graph/model/repository.go

151 lines
3.1 KiB
Go

package model
import (
"context"
"database/sql"
"strconv"
"time"
sq "github.com/Masterminds/squirrel"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing"
"git.sr.ht/~sircmpwn/core-go/database"
"git.sr.ht/~sircmpwn/core-go/model"
)
type Repository struct {
ID int `json:"id"`
Created time.Time `json:"created"`
Updated time.Time `json:"updated"`
Name string `json:"name"`
Description *string `json:"description"`
Readme *string `json:"readme"`
Path string
OwnerID int
Visibility Visibility
alias string
repo *RepoWrapper
fields *database.ModelFields
}
func (r *Repository) Repo() *RepoWrapper {
if r.repo != nil {
return r.repo
}
repo, err := git.PlainOpen(r.Path)
if err != nil {
panic(err)
}
r.repo = WrapRepo(repo)
return r.repo
}
func (r *Repository) Head() *Reference {
r.Repo().Lock()
ref, err := r.Repo().Head()
r.repo.Unlock()
if err != nil {
if err == plumbing.ErrReferenceNotFound {
return nil
}
panic(err)
}
return &Reference{Ref: ref, Repo: r}
}
func (r *Repository) As(alias string) *Repository {
r.alias = alias
return r
}
func (r *Repository) Alias() string {
return r.alias
}
func (r *Repository) Table() string {
return "repository"
}
func (r *Repository) Fields() *database.ModelFields {
if r.fields != nil {
return r.fields
}
r.fields = &database.ModelFields{
Fields: []*database.FieldMap{
{"id", "id", &r.ID},
{"created", "created", &r.Created},
{"updated", "updated", &r.Updated},
{"name", "name", &r.Name},
{"description", "description", &r.Description},
{"visibility", "visibility", &r.Visibility},
{"readme", "readme", &r.Readme},
// Always fetch:
{"id", "", &r.ID},
{"path", "", &r.Path},
{"owner_id", "", &r.OwnerID},
{"updated", "", &r.Updated},
},
}
return r.fields
}
func (r *Repository) QueryWithCursor(ctx context.Context,
runner sq.BaseRunner, q sq.SelectBuilder,
cur *model.Cursor) ([]*Repository, *model.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(runner).QueryContext(ctx); err != nil {
panic(err)
}
defer rows.Close()
var repos []*Repository
for rows.Next() {
var repo Repository
if err := rows.Scan(database.Scan(ctx, &repo)...); err != nil {
panic(err)
}
repos = append(repos, &repo)
}
if len(repos) > cur.Count {
cur = &model.Cursor{
Count: cur.Count,
Next: strconv.FormatInt(repos[len(repos)-1].Updated.Unix(), 10),
Search: cur.Search,
}
repos = repos[:cur.Count]
} else {
cur = nil
}
return repos, cur
}
func (r *Repository) DefaultSearch(query sq.SelectBuilder,
term string) (sq.SelectBuilder, error) {
name := database.WithAlias(r.alias, "name")
desc := database.WithAlias(r.alias, "description")
return query.
Where(sq.Or{
sq.Expr(name+` ILIKE '%' || ? || '%'`, term),
sq.Expr(desc+` ILIKE '%' || ? || '%'`, term),
}), nil
}