forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

orm: extract orm package from appview

includes query and migration helpers

Signed-off-by: oppiliappan <me@oppi.li>

+3 -2
appview/db/artifact.go
···
"github.com/go-git/go-git/v5/plumbing"
"github.com/ipfs/go-cid"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
func AddArtifact(e Execer, artifact models.Artifact) error {
···
return err
}
-
func GetArtifact(e Execer, filters ...filter) ([]models.Artifact, error) {
+
func GetArtifact(e Execer, filters ...orm.Filter) ([]models.Artifact, error) {
var artifacts []models.Artifact
var conditions []string
···
return artifacts, nil
}
-
func DeleteArtifact(e Execer, filters ...filter) error {
+
func DeleteArtifact(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
+4 -3
appview/db/collaborators.go
···
"time"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
func AddCollaborator(e Execer, c models.Collaborator) error {
···
return err
}
-
func DeleteCollaborator(e Execer, filters ...filter) error {
+
func DeleteCollaborator(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
···
return nil, nil
}
-
return GetRepos(e, 0, FilterIn("at_uri", repoAts))
+
return GetRepos(e, 0, orm.FilterIn("at_uri", repoAts))
}
-
func GetCollaborators(e Execer, filters ...filter) ([]models.Collaborator, error) {
+
func GetCollaborators(e Execer, filters ...orm.Filter) ([]models.Collaborator, error) {
var collaborators []models.Collaborator
var conditions []string
var args []any
+24 -137
appview/db/db.go
···
import (
"context"
"database/sql"
-
"fmt"
"log/slog"
-
"reflect"
"strings"
_ "github.com/mattn/go-sqlite3"
"tangled.org/core/log"
+
"tangled.org/core/orm"
)
type DB struct {
···
}
// run migrations
-
runMigration(conn, logger, "add-description-to-repos", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-description-to-repos", func(tx *sql.Tx) error {
tx.Exec(`
alter table repos add column description text check (length(description) <= 200);
`)
return nil
})
-
runMigration(conn, logger, "add-rkey-to-pubkeys", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-rkey-to-pubkeys", func(tx *sql.Tx) error {
// add unconstrained column
_, err := tx.Exec(`
alter table public_keys
···
return nil
})
-
runMigration(conn, logger, "add-rkey-to-comments", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-rkey-to-comments", func(tx *sql.Tx) error {
_, err := tx.Exec(`
alter table comments drop column comment_at;
alter table comments add column rkey text;
···
return err
})
-
runMigration(conn, logger, "add-deleted-and-edited-to-issue-comments", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-deleted-and-edited-to-issue-comments", func(tx *sql.Tx) error {
_, err := tx.Exec(`
alter table comments add column deleted text; -- timestamp
alter table comments add column edited text; -- timestamp
···
return err
})
-
runMigration(conn, logger, "add-source-info-to-pulls-and-submissions", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-source-info-to-pulls-and-submissions", func(tx *sql.Tx) error {
_, err := tx.Exec(`
alter table pulls add column source_branch text;
alter table pulls add column source_repo_at text;
···
return err
})
-
runMigration(conn, logger, "add-source-to-repos", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-source-to-repos", func(tx *sql.Tx) error {
_, err := tx.Exec(`
alter table repos add column source text;
`)
···
//
// [0]: https://sqlite.org/pragma.html#pragma_foreign_keys
conn.ExecContext(ctx, "pragma foreign_keys = off;")
-
runMigration(conn, logger, "recreate-pulls-column-for-stacking-support", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "recreate-pulls-column-for-stacking-support", func(tx *sql.Tx) error {
_, err := tx.Exec(`
create table pulls_new (
-- identifiers
···
})
conn.ExecContext(ctx, "pragma foreign_keys = on;")
-
runMigration(conn, logger, "add-spindle-to-repos", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-spindle-to-repos", func(tx *sql.Tx) error {
tx.Exec(`
alter table repos add column spindle text;
`)
···
// drop all knot secrets, add unique constraint to knots
//
// knots will henceforth use service auth for signed requests
-
runMigration(conn, logger, "no-more-secrets", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "no-more-secrets", func(tx *sql.Tx) error {
_, err := tx.Exec(`
create table registrations_new (
id integer primary key autoincrement,
···
})
// recreate and add rkey + created columns with default constraint
-
runMigration(conn, logger, "rework-collaborators-table", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "rework-collaborators-table", func(tx *sql.Tx) error {
// create new table
// - repo_at instead of repo integer
// - rkey field
···
return err
})
-
runMigration(conn, logger, "add-rkey-to-issues", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-rkey-to-issues", func(tx *sql.Tx) error {
_, err := tx.Exec(`
alter table issues add column rkey text not null default '';
···
})
// repurpose the read-only column to "needs-upgrade"
-
runMigration(conn, logger, "rename-registrations-read-only-to-needs-upgrade", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "rename-registrations-read-only-to-needs-upgrade", func(tx *sql.Tx) error {
_, err := tx.Exec(`
alter table registrations rename column read_only to needs_upgrade;
`)
···
})
// require all knots to upgrade after the release of total xrpc
-
runMigration(conn, logger, "migrate-knots-to-total-xrpc", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "migrate-knots-to-total-xrpc", func(tx *sql.Tx) error {
_, err := tx.Exec(`
update registrations set needs_upgrade = 1;
`)
···
})
// require all knots to upgrade after the release of total xrpc
-
runMigration(conn, logger, "migrate-spindles-to-xrpc-owner", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "migrate-spindles-to-xrpc-owner", func(tx *sql.Tx) error {
_, err := tx.Exec(`
alter table spindles add column needs_upgrade integer not null default 0;
`)
···
//
// disable foreign-keys for the next migration
conn.ExecContext(ctx, "pragma foreign_keys = off;")
-
runMigration(conn, logger, "remove-issue-at-from-issues", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "remove-issue-at-from-issues", func(tx *sql.Tx) error {
_, err := tx.Exec(`
create table if not exists issues_new (
-- identifiers
···
// - new columns
// * column "reply_to" which can be any other comment
// * column "at-uri" which is a generated column
-
runMigration(conn, logger, "rework-issue-comments", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "rework-issue-comments", func(tx *sql.Tx) error {
_, err := tx.Exec(`
create table if not exists issue_comments (
-- identifiers
···
//
// disable foreign-keys for the next migration
conn.ExecContext(ctx, "pragma foreign_keys = off;")
-
runMigration(conn, logger, "add-at-uri-to-pulls", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-at-uri-to-pulls", func(tx *sql.Tx) error {
_, err := tx.Exec(`
create table if not exists pulls_new (
-- identifiers
···
//
// disable foreign-keys for the next migration
conn.ExecContext(ctx, "pragma foreign_keys = off;")
-
runMigration(conn, logger, "remove-repo-at-pull-id-from-pull-submissions", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "remove-repo-at-pull-id-from-pull-submissions", func(tx *sql.Tx) error {
_, err := tx.Exec(`
create table if not exists pull_submissions_new (
-- identifiers
···
// knots may report the combined patch for a comparison, we can store that on the appview side
// (but not on the pds record), because calculating the combined patch requires a git index
-
runMigration(conn, logger, "add-combined-column-submissions", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-combined-column-submissions", func(tx *sql.Tx) error {
_, err := tx.Exec(`
alter table pull_submissions add column combined text;
`)
return err
})
-
runMigration(conn, logger, "add-pronouns-profile", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-pronouns-profile", func(tx *sql.Tx) error {
_, err := tx.Exec(`
alter table profile add column pronouns text;
`)
return err
})
-
runMigration(conn, logger, "add-meta-column-repos", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-meta-column-repos", func(tx *sql.Tx) error {
_, err := tx.Exec(`
alter table repos add column website text;
alter table repos add column topics text;
···
return err
})
-
runMigration(conn, logger, "add-usermentioned-preference", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "add-usermentioned-preference", func(tx *sql.Tx) error {
_, err := tx.Exec(`
alter table notification_preferences add column user_mentioned integer not null default 1;
`)
···
})
// remove the foreign key constraints from stars.
-
runMigration(conn, logger, "generalize-stars-subject", func(tx *sql.Tx) error {
+
orm.RunMigration(conn, logger, "generalize-stars-subject", func(tx *sql.Tx) error {
_, err := tx.Exec(`
create table stars_new (
id integer primary key autoincrement,
···
}, nil
-
type migrationFn = func(*sql.Tx) error
-
-
func runMigration(c *sql.Conn, logger *slog.Logger, name string, migrationFn migrationFn) error {
-
logger = logger.With("migration", name)
-
-
tx, err := c.BeginTx(context.Background(), nil)
-
if err != nil {
-
return err
-
}
-
defer tx.Rollback()
-
-
var exists bool
-
err = tx.QueryRow("select exists (select 1 from migrations where name = ?)", name).Scan(&exists)
-
if err != nil {
-
return err
-
}
-
-
if !exists {
-
// run migration
-
err = migrationFn(tx)
-
if err != nil {
-
logger.Error("failed to run migration", "err", err)
-
return err
-
}
-
-
// mark migration as complete
-
_, err = tx.Exec("insert into migrations (name) values (?)", name)
-
if err != nil {
-
logger.Error("failed to mark migration as complete", "err", err)
-
return err
-
}
-
-
// commit the transaction
-
if err := tx.Commit(); err != nil {
-
return err
-
}
-
-
logger.Info("migration applied successfully")
-
} else {
-
logger.Warn("skipped migration, already applied")
-
}
-
-
return nil
-
}
-
func (d *DB) Close() error {
return d.DB.Close()
-
-
type filter struct {
-
key string
-
arg any
-
cmp string
-
}
-
-
func newFilter(key, cmp string, arg any) filter {
-
return filter{
-
key: key,
-
arg: arg,
-
cmp: cmp,
-
}
-
}
-
-
func FilterEq(key string, arg any) filter { return newFilter(key, "=", arg) }
-
func FilterNotEq(key string, arg any) filter { return newFilter(key, "<>", arg) }
-
func FilterGte(key string, arg any) filter { return newFilter(key, ">=", arg) }
-
func FilterLte(key string, arg any) filter { return newFilter(key, "<=", arg) }
-
func FilterIs(key string, arg any) filter { return newFilter(key, "is", arg) }
-
func FilterIsNot(key string, arg any) filter { return newFilter(key, "is not", arg) }
-
func FilterIn(key string, arg any) filter { return newFilter(key, "in", arg) }
-
func FilterLike(key string, arg any) filter { return newFilter(key, "like", arg) }
-
func FilterNotLike(key string, arg any) filter { return newFilter(key, "not like", arg) }
-
func FilterContains(key string, arg any) filter {
-
return newFilter(key, "like", fmt.Sprintf("%%%v%%", arg))
-
}
-
-
func (f filter) Condition() string {
-
rv := reflect.ValueOf(f.arg)
-
kind := rv.Kind()
-
-
// if we have `FilterIn(k, [1, 2, 3])`, compile it down to `k in (?, ?, ?)`
-
if (kind == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8) || kind == reflect.Array {
-
if rv.Len() == 0 {
-
// always false
-
return "1 = 0"
-
}
-
-
placeholders := make([]string, rv.Len())
-
for i := range placeholders {
-
placeholders[i] = "?"
-
}
-
-
return fmt.Sprintf("%s %s (%s)", f.key, f.cmp, strings.Join(placeholders, ", "))
-
}
-
-
return fmt.Sprintf("%s %s ?", f.key, f.cmp)
-
}
-
-
func (f filter) Arg() []any {
-
rv := reflect.ValueOf(f.arg)
-
kind := rv.Kind()
-
if (kind == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8) || kind == reflect.Array {
-
if rv.Len() == 0 {
-
return nil
-
}
-
-
out := make([]any, rv.Len())
-
for i := range rv.Len() {
-
out[i] = rv.Index(i).Interface()
-
}
-
return out
-
}
-
-
return []any{f.arg}
-
}
+4 -3
appview/db/follow.go
···
"time"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
func AddFollow(e Execer, follow *models.Follow) error {
···
return result, nil
}
-
func GetFollows(e Execer, limit int, filters ...filter) ([]models.Follow, error) {
+
func GetFollows(e Execer, limit int, filters ...orm.Filter) ([]models.Follow, error) {
var follows []models.Follow
var conditions []string
···
}
func GetFollowers(e Execer, did string) ([]models.Follow, error) {
-
return GetFollows(e, 0, FilterEq("subject_did", did))
+
return GetFollows(e, 0, orm.FilterEq("subject_did", did))
}
func GetFollowing(e Execer, did string) ([]models.Follow, error) {
-
return GetFollows(e, 0, FilterEq("user_did", did))
+
return GetFollows(e, 0, orm.FilterEq("user_did", did))
}
func getFollowStatuses(e Execer, userDid string, subjectDids []string) (map[string]models.FollowStatus, error) {
+21 -20
appview/db/issues.go
···
"tangled.org/core/api/tangled"
"tangled.org/core/appview/models"
"tangled.org/core/appview/pagination"
+
"tangled.org/core/orm"
)
func PutIssue(tx *sql.Tx, issue *models.Issue) error {
···
issues, err := GetIssues(
tx,
-
FilterEq("did", issue.Did),
-
FilterEq("rkey", issue.Rkey),
+
orm.FilterEq("did", issue.Did),
+
orm.FilterEq("rkey", issue.Rkey),
)
switch {
case err != nil:
···
return nil
}
-
func GetIssuesPaginated(e Execer, page pagination.Page, filters ...filter) ([]models.Issue, error) {
+
func GetIssuesPaginated(e Execer, page pagination.Page, filters ...orm.Filter) ([]models.Issue, error) {
issueMap := make(map[string]*models.Issue) // at-uri -> issue
var conditions []string
···
whereClause = " where " + strings.Join(conditions, " and ")
}
-
pLower := FilterGte("row_num", page.Offset+1)
-
pUpper := FilterLte("row_num", page.Offset+page.Limit)
+
pLower := orm.FilterGte("row_num", page.Offset+1)
+
pUpper := orm.FilterLte("row_num", page.Offset+page.Limit)
pageClause := ""
if page.Limit > 0 {
···
repoAts = append(repoAts, string(issue.RepoAt))
}
-
repos, err := GetRepos(e, 0, FilterIn("at_uri", repoAts))
+
repos, err := GetRepos(e, 0, orm.FilterIn("at_uri", repoAts))
if err != nil {
return nil, fmt.Errorf("failed to build repo mappings: %w", err)
}
···
// collect comments
issueAts := slices.Collect(maps.Keys(issueMap))
-
comments, err := GetIssueComments(e, FilterIn("issue_at", issueAts))
+
comments, err := GetIssueComments(e, orm.FilterIn("issue_at", issueAts))
if err != nil {
return nil, fmt.Errorf("failed to query comments: %w", err)
}
···
}
// collect allLabels for each issue
-
allLabels, err := GetLabels(e, FilterIn("subject", issueAts))
+
allLabels, err := GetLabels(e, orm.FilterIn("subject", issueAts))
if err != nil {
return nil, fmt.Errorf("failed to query labels: %w", err)
}
···
}
// collect references for each issue
-
allReferencs, err := GetReferencesAll(e, FilterIn("from_at", issueAts))
+
allReferencs, err := GetReferencesAll(e, orm.FilterIn("from_at", issueAts))
if err != nil {
return nil, fmt.Errorf("failed to query reference_links: %w", err)
}
···
issues, err := GetIssuesPaginated(
e,
pagination.Page{},
-
FilterEq("repo_at", repoAt),
-
FilterEq("issue_id", issueId),
+
orm.FilterEq("repo_at", repoAt),
+
orm.FilterEq("issue_id", issueId),
)
if err != nil {
return nil, err
···
return &issues[0], nil
}
-
func GetIssues(e Execer, filters ...filter) ([]models.Issue, error) {
+
func GetIssues(e Execer, filters ...orm.Filter) ([]models.Issue, error) {
return GetIssuesPaginated(e, pagination.Page{}, filters...)
}
···
func GetIssueIDs(e Execer, opts models.IssueSearchOptions) ([]int64, error) {
var ids []int64
-
var filters []filter
+
var filters []orm.Filter
openValue := 0
if opts.IsOpen {
openValue = 1
}
-
filters = append(filters, FilterEq("open", openValue))
+
filters = append(filters, orm.FilterEq("open", openValue))
if opts.RepoAt != "" {
-
filters = append(filters, FilterEq("repo_at", opts.RepoAt))
+
filters = append(filters, orm.FilterEq("repo_at", opts.RepoAt))
}
var conditions []string
···
return id, nil
}
-
func DeleteIssueComments(e Execer, filters ...filter) error {
+
func DeleteIssueComments(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
···
return err
}
-
func GetIssueComments(e Execer, filters ...filter) ([]models.IssueComment, error) {
+
func GetIssueComments(e Execer, filters ...orm.Filter) ([]models.IssueComment, error) {
commentMap := make(map[string]*models.IssueComment)
var conditions []string
···
// collect references for each comments
commentAts := slices.Collect(maps.Keys(commentMap))
-
allReferencs, err := GetReferencesAll(e, FilterIn("from_at", commentAts))
+
allReferencs, err := GetReferencesAll(e, orm.FilterIn("from_at", commentAts))
if err != nil {
return nil, fmt.Errorf("failed to query reference_links: %w", err)
}
···
return nil
}
-
func CloseIssues(e Execer, filters ...filter) error {
+
func CloseIssues(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
···
return err
}
-
func ReopenIssues(e Execer, filters ...filter) error {
+
func ReopenIssues(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
+8 -7
appview/db/label.go
···
"github.com/bluesky-social/indigo/atproto/syntax"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
// no updating type for now
···
return id, nil
}
-
func DeleteLabelDefinition(e Execer, filters ...filter) error {
+
func DeleteLabelDefinition(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
···
return err
}
-
func GetLabelDefinitions(e Execer, filters ...filter) ([]models.LabelDefinition, error) {
+
func GetLabelDefinitions(e Execer, filters ...orm.Filter) ([]models.LabelDefinition, error) {
var labelDefinitions []models.LabelDefinition
var conditions []string
var args []any
···
}
// helper to get exactly one label def
-
func GetLabelDefinition(e Execer, filters ...filter) (*models.LabelDefinition, error) {
+
func GetLabelDefinition(e Execer, filters ...orm.Filter) (*models.LabelDefinition, error) {
labels, err := GetLabelDefinitions(e, filters...)
if err != nil {
return nil, err
···
return id, nil
}
-
func GetLabelOps(e Execer, filters ...filter) ([]models.LabelOp, error) {
+
func GetLabelOps(e Execer, filters ...orm.Filter) ([]models.LabelOp, error) {
var labelOps []models.LabelOp
var conditions []string
var args []any
···
}
// get labels for a given list of subject URIs
-
func GetLabels(e Execer, filters ...filter) (map[syntax.ATURI]models.LabelState, error) {
+
func GetLabels(e Execer, filters ...orm.Filter) (map[syntax.ATURI]models.LabelState, error) {
ops, err := GetLabelOps(e, filters...)
if err != nil {
return nil, err
···
}
labelAts := slices.Collect(maps.Keys(labelAtSet))
-
actx, err := NewLabelApplicationCtx(e, FilterIn("at_uri", labelAts))
+
actx, err := NewLabelApplicationCtx(e, orm.FilterIn("at_uri", labelAts))
if err != nil {
return nil, err
}
···
return results, nil
}
-
func NewLabelApplicationCtx(e Execer, filters ...filter) (*models.LabelApplicationCtx, error) {
+
func NewLabelApplicationCtx(e Execer, filters ...orm.Filter) (*models.LabelApplicationCtx, error) {
labels, err := GetLabelDefinitions(e, filters...)
if err != nil {
return nil, err
+5 -4
appview/db/language.go
···
"github.com/bluesky-social/indigo/atproto/syntax"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
-
func GetRepoLanguages(e Execer, filters ...filter) ([]models.RepoLanguage, error) {
+
func GetRepoLanguages(e Execer, filters ...orm.Filter) ([]models.RepoLanguage, error) {
var conditions []string
var args []any
for _, filter := range filters {
···
return nil
}
-
func DeleteRepoLanguages(e Execer, filters ...filter) error {
+
func DeleteRepoLanguages(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
···
func UpdateRepoLanguages(tx *sql.Tx, repoAt syntax.ATURI, ref string, langs []models.RepoLanguage) error {
err := DeleteRepoLanguages(
tx,
-
FilterEq("repo_at", repoAt),
-
FilterEq("ref", ref),
+
orm.FilterEq("repo_at", repoAt),
+
orm.FilterEq("ref", ref),
)
if err != nil {
return fmt.Errorf("failed to delete existing languages: %w", err)
+14 -13
appview/db/notifications.go
···
"github.com/bluesky-social/indigo/atproto/syntax"
"tangled.org/core/appview/models"
"tangled.org/core/appview/pagination"
+
"tangled.org/core/orm"
)
func CreateNotification(e Execer, notification *models.Notification) error {
···
}
// GetNotificationsPaginated retrieves notifications with filters and pagination
-
func GetNotificationsPaginated(e Execer, page pagination.Page, filters ...filter) ([]*models.Notification, error) {
+
func GetNotificationsPaginated(e Execer, page pagination.Page, filters ...orm.Filter) ([]*models.Notification, error) {
var conditions []string
var args []any
···
}
// GetNotificationsWithEntities retrieves notifications with their related entities
-
func GetNotificationsWithEntities(e Execer, page pagination.Page, filters ...filter) ([]*models.NotificationWithEntity, error) {
+
func GetNotificationsWithEntities(e Execer, page pagination.Page, filters ...orm.Filter) ([]*models.NotificationWithEntity, error) {
var conditions []string
var args []any
···
}
// GetNotifications retrieves notifications with filters
-
func GetNotifications(e Execer, filters ...filter) ([]*models.Notification, error) {
+
func GetNotifications(e Execer, filters ...orm.Filter) ([]*models.Notification, error) {
return GetNotificationsPaginated(e, pagination.FirstPage(), filters...)
}
-
func CountNotifications(e Execer, filters ...filter) (int64, error) {
+
func CountNotifications(e Execer, filters ...orm.Filter) (int64, error) {
var conditions []string
var args []any
for _, filter := range filters {
···
}
func MarkNotificationRead(e Execer, notificationID int64, userDID string) error {
-
idFilter := FilterEq("id", notificationID)
-
recipientFilter := FilterEq("recipient_did", userDID)
+
idFilter := orm.FilterEq("id", notificationID)
+
recipientFilter := orm.FilterEq("recipient_did", userDID)
query := fmt.Sprintf(`
UPDATE notifications
···
}
func MarkAllNotificationsRead(e Execer, userDID string) error {
-
recipientFilter := FilterEq("recipient_did", userDID)
-
readFilter := FilterEq("read", 0)
+
recipientFilter := orm.FilterEq("recipient_did", userDID)
+
readFilter := orm.FilterEq("read", 0)
query := fmt.Sprintf(`
UPDATE notifications
···
}
func DeleteNotification(e Execer, notificationID int64, userDID string) error {
-
idFilter := FilterEq("id", notificationID)
-
recipientFilter := FilterEq("recipient_did", userDID)
+
idFilter := orm.FilterEq("id", notificationID)
+
recipientFilter := orm.FilterEq("recipient_did", userDID)
query := fmt.Sprintf(`
DELETE FROM notifications
···
}
func GetNotificationPreference(e Execer, userDid string) (*models.NotificationPreferences, error) {
-
prefs, err := GetNotificationPreferences(e, FilterEq("user_did", userDid))
+
prefs, err := GetNotificationPreferences(e, orm.FilterEq("user_did", userDid))
if err != nil {
return nil, err
}
···
return p, nil
}
-
func GetNotificationPreferences(e Execer, filters ...filter) (map[syntax.DID]*models.NotificationPreferences, error) {
+
func GetNotificationPreferences(e Execer, filters ...orm.Filter) (map[syntax.DID]*models.NotificationPreferences, error) {
prefsMap := make(map[syntax.DID]*models.NotificationPreferences)
var conditions []string
···
func (d *DB) ClearOldNotifications(ctx context.Context, olderThan time.Duration) error {
cutoff := time.Now().Add(-olderThan)
-
createdFilter := FilterLte("created", cutoff)
+
createdFilter := orm.FilterLte("created", cutoff)
query := fmt.Sprintf(`
DELETE FROM notifications
+6 -5
appview/db/pipeline.go
···
"time"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
-
func GetPipelines(e Execer, filters ...filter) ([]models.Pipeline, error) {
+
func GetPipelines(e Execer, filters ...orm.Filter) ([]models.Pipeline, error) {
var pipelines []models.Pipeline
var conditions []string
···
// this is a mega query, but the most useful one:
// get N pipelines, for each one get the latest status of its N workflows
-
func GetPipelineStatuses(e Execer, limit int, filters ...filter) ([]models.Pipeline, error) {
+
func GetPipelineStatuses(e Execer, limit int, filters ...orm.Filter) ([]models.Pipeline, error) {
var conditions []string
var args []any
for _, filter := range filters {
-
filter.key = "p." + filter.key // the table is aliased in the query to `p`
+
filter.Key = "p." + filter.Key // the table is aliased in the query to `p`
conditions = append(conditions, filter.Condition())
args = append(args, filter.Arg()...)
}
···
conditions = nil
args = nil
for _, p := range pipelines {
-
knotFilter := FilterEq("pipeline_knot", p.Knot)
-
rkeyFilter := FilterEq("pipeline_rkey", p.Rkey)
+
knotFilter := orm.FilterEq("pipeline_knot", p.Knot)
+
rkeyFilter := orm.FilterEq("pipeline_rkey", p.Rkey)
conditions = append(conditions, fmt.Sprintf("(%s and %s)", knotFilter.Condition(), rkeyFilter.Condition()))
args = append(args, p.Knot)
args = append(args, p.Rkey)
+6 -5
appview/db/profile.go
···
"github.com/bluesky-social/indigo/atproto/syntax"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
const TimeframeMonths = 7
···
issues, err := GetIssues(
e,
-
FilterEq("did", forDid),
-
FilterGte("created", time.Now().AddDate(0, -TimeframeMonths, 0)),
+
orm.FilterEq("did", forDid),
+
orm.FilterGte("created", time.Now().AddDate(0, -TimeframeMonths, 0)),
)
if err != nil {
return nil, fmt.Errorf("error getting issues by owner did: %w", err)
···
*items = append(*items, &issue)
}
-
repos, err := GetRepos(e, 0, FilterEq("did", forDid))
+
repos, err := GetRepos(e, 0, orm.FilterEq("did", forDid))
if err != nil {
return nil, fmt.Errorf("error getting all repos by did: %w", err)
}
···
return tx.Commit()
}
-
func GetProfiles(e Execer, filters ...filter) (map[string]*models.Profile, error) {
+
func GetProfiles(e Execer, filters ...orm.Filter) (map[string]*models.Profile, error) {
var conditions []string
var args []any
for _, filter := range filters {
···
}
// ensure all pinned repos are either own repos or collaborating repos
-
repos, err := GetRepos(e, 0, FilterEq("did", profile.Did))
+
repos, err := GetRepos(e, 0, orm.FilterEq("did", profile.Did))
if err != nil {
log.Printf("getting repos for %s: %s", profile.Did, err)
}
+21 -20
appview/db/pulls.go
···
"github.com/bluesky-social/indigo/atproto/syntax"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
func NewPull(tx *sql.Tx, pull *models.Pull) error {
···
return pullId - 1, err
}
-
func GetPullsWithLimit(e Execer, limit int, filters ...filter) ([]*models.Pull, error) {
+
func GetPullsWithLimit(e Execer, limit int, filters ...orm.Filter) ([]*models.Pull, error) {
pulls := make(map[syntax.ATURI]*models.Pull)
var conditions []string
···
for _, p := range pulls {
pullAts = append(pullAts, p.AtUri())
}
-
submissionsMap, err := GetPullSubmissions(e, FilterIn("pull_at", pullAts))
+
submissionsMap, err := GetPullSubmissions(e, orm.FilterIn("pull_at", pullAts))
if err != nil {
return nil, fmt.Errorf("failed to get submissions: %w", err)
}
···
}
// collect allLabels for each issue
-
allLabels, err := GetLabels(e, FilterIn("subject", pullAts))
+
allLabels, err := GetLabels(e, orm.FilterIn("subject", pullAts))
if err != nil {
return nil, fmt.Errorf("failed to query labels: %w", err)
}
···
sourceAts = append(sourceAts, *p.PullSource.RepoAt)
}
}
-
sourceRepos, err := GetRepos(e, 0, FilterIn("at_uri", sourceAts))
+
sourceRepos, err := GetRepos(e, 0, orm.FilterIn("at_uri", sourceAts))
if err != nil && !errors.Is(err, sql.ErrNoRows) {
return nil, fmt.Errorf("failed to get source repos: %w", err)
}
···
}
}
-
allReferences, err := GetReferencesAll(e, FilterIn("from_at", pullAts))
+
allReferences, err := GetReferencesAll(e, orm.FilterIn("from_at", pullAts))
if err != nil {
return nil, fmt.Errorf("failed to query reference_links: %w", err)
}
···
return orderedByPullId, nil
}
-
func GetPulls(e Execer, filters ...filter) ([]*models.Pull, error) {
+
func GetPulls(e Execer, filters ...orm.Filter) ([]*models.Pull, error) {
return GetPullsWithLimit(e, 0, filters...)
}
func GetPullIDs(e Execer, opts models.PullSearchOptions) ([]int64, error) {
var ids []int64
-
var filters []filter
-
filters = append(filters, FilterEq("state", opts.State))
+
var filters []orm.Filter
+
filters = append(filters, orm.FilterEq("state", opts.State))
if opts.RepoAt != "" {
-
filters = append(filters, FilterEq("repo_at", opts.RepoAt))
+
filters = append(filters, orm.FilterEq("repo_at", opts.RepoAt))
}
var conditions []string
···
}
func GetPull(e Execer, repoAt syntax.ATURI, pullId int) (*models.Pull, error) {
-
pulls, err := GetPullsWithLimit(e, 1, FilterEq("repo_at", repoAt), FilterEq("pull_id", pullId))
+
pulls, err := GetPullsWithLimit(e, 1, orm.FilterEq("repo_at", repoAt), orm.FilterEq("pull_id", pullId))
if err != nil {
return nil, err
}
···
}
// mapping from pull -> pull submissions
-
func GetPullSubmissions(e Execer, filters ...filter) (map[syntax.ATURI][]*models.PullSubmission, error) {
+
func GetPullSubmissions(e Execer, filters ...orm.Filter) (map[syntax.ATURI][]*models.PullSubmission, error) {
var conditions []string
var args []any
for _, filter := range filters {
···
// Get comments for all submissions using GetPullComments
submissionIds := slices.Collect(maps.Keys(submissionMap))
-
comments, err := GetPullComments(e, FilterIn("submission_id", submissionIds))
+
comments, err := GetPullComments(e, orm.FilterIn("submission_id", submissionIds))
if err != nil {
return nil, fmt.Errorf("failed to get pull comments: %w", err)
}
···
return m, nil
}
-
func GetPullComments(e Execer, filters ...filter) ([]models.PullComment, error) {
+
func GetPullComments(e Execer, filters ...orm.Filter) ([]models.PullComment, error) {
var conditions []string
var args []any
for _, filter := range filters {
···
// collect references for each comments
commentAts := slices.Collect(maps.Keys(commentMap))
-
allReferencs, err := GetReferencesAll(e, FilterIn("from_at", commentAts))
+
allReferencs, err := GetReferencesAll(e, orm.FilterIn("from_at", commentAts))
if err != nil {
return nil, fmt.Errorf("failed to query reference_links: %w", err)
}
···
return err
}
-
func SetPullParentChangeId(e Execer, parentChangeId string, filters ...filter) error {
+
func SetPullParentChangeId(e Execer, parentChangeId string, filters ...orm.Filter) error {
var conditions []string
var args []any
···
// Only used when stacking to update contents in the event of a rebase (the interdiff should be empty).
// otherwise submissions are immutable
-
func UpdatePull(e Execer, newPatch, sourceRev string, filters ...filter) error {
+
func UpdatePull(e Execer, newPatch, sourceRev string, filters ...orm.Filter) error {
var conditions []string
var args []any
···
func GetStack(e Execer, stackId string) (models.Stack, error) {
unorderedPulls, err := GetPulls(
e,
-
FilterEq("stack_id", stackId),
-
FilterNotEq("state", models.PullDeleted),
+
orm.FilterEq("stack_id", stackId),
+
orm.FilterNotEq("state", models.PullDeleted),
)
if err != nil {
return nil, err
···
func GetAbandonedPulls(e Execer, stackId string) ([]*models.Pull, error) {
pulls, err := GetPulls(
e,
-
FilterEq("stack_id", stackId),
-
FilterEq("state", models.PullDeleted),
+
orm.FilterEq("stack_id", stackId),
+
orm.FilterEq("state", models.PullDeleted),
)
if err != nil {
return nil, err
+2 -1
appview/db/punchcard.go
···
"time"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
// this adds to the existing count
···
return err
}
-
func MakePunchcard(e Execer, filters ...filter) (*models.Punchcard, error) {
+
func MakePunchcard(e Execer, filters ...orm.Filter) (*models.Punchcard, error) {
punchcard := &models.Punchcard{}
now := time.Now()
startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC)
+4 -3
appview/db/reference.go
···
"github.com/bluesky-social/indigo/atproto/syntax"
"tangled.org/core/api/tangled"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
// ValidateReferenceLinks resolves refLinks to Issue/PR/IssueComment/PullComment ATURIs.
···
return err
}
-
func GetReferencesAll(e Execer, filters ...filter) (map[syntax.ATURI][]syntax.ATURI, error) {
+
func GetReferencesAll(e Execer, filters ...orm.Filter) (map[syntax.ATURI][]syntax.ATURI, error) {
var (
conditions []string
args []any
···
if len(aturis) == 0 {
return nil, nil
}
-
filter := FilterIn("c.at_uri", aturis)
+
filter := orm.FilterIn("c.at_uri", aturis)
rows, err := e.Query(
fmt.Sprintf(
`select r.did, r.name, i.issue_id, c.id, i.title, i.open
···
if len(aturis) == 0 {
return nil, nil
}
-
filter := FilterIn("c.comment_at", aturis)
+
filter := orm.FilterIn("c.comment_at", aturis)
rows, err := e.Query(
fmt.Sprintf(
`select r.did, r.name, p.pull_id, c.id, p.title, p.state
+4 -3
appview/db/registration.go
···
"time"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
-
func GetRegistrations(e Execer, filters ...filter) ([]models.Registration, error) {
+
func GetRegistrations(e Execer, filters ...orm.Filter) ([]models.Registration, error) {
var registrations []models.Registration
var conditions []string
···
return registrations, nil
}
-
func MarkRegistered(e Execer, filters ...filter) error {
+
func MarkRegistered(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
···
return err
}
-
func DeleteKnot(e Execer, filters ...filter) error {
+
func DeleteKnot(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
+6 -5
appview/db/repos.go
···
"github.com/bluesky-social/indigo/atproto/syntax"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
-
func GetRepos(e Execer, limit int, filters ...filter) ([]models.Repo, error) {
+
func GetRepos(e Execer, limit int, filters ...orm.Filter) ([]models.Repo, error) {
repoMap := make(map[syntax.ATURI]*models.Repo)
var conditions []string
···
}
// helper to get exactly one repo
-
func GetRepo(e Execer, filters ...filter) (*models.Repo, error) {
+
func GetRepo(e Execer, filters ...orm.Filter) (*models.Repo, error) {
repos, err := GetRepos(e, 0, filters...)
if err != nil {
return nil, err
···
return &repos[0], nil
}
-
func CountRepos(e Execer, filters ...filter) (int64, error) {
+
func CountRepos(e Execer, filters ...orm.Filter) (int64, error) {
var conditions []string
var args []any
for _, filter := range filters {
···
return err
}
-
func UnsubscribeLabel(e Execer, filters ...filter) error {
+
func UnsubscribeLabel(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
···
return err
}
-
func GetRepoLabels(e Execer, filters ...filter) ([]models.RepoLabel, error) {
+
func GetRepoLabels(e Execer, filters ...orm.Filter) ([]models.RepoLabel, error) {
var conditions []string
var args []any
for _, filter := range filters {
+6 -5
appview/db/spindle.go
···
"time"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
-
func GetSpindles(e Execer, filters ...filter) ([]models.Spindle, error) {
+
func GetSpindles(e Execer, filters ...orm.Filter) ([]models.Spindle, error) {
var spindles []models.Spindle
var conditions []string
···
return err
}
-
func VerifySpindle(e Execer, filters ...filter) (int64, error) {
+
func VerifySpindle(e Execer, filters ...orm.Filter) (int64, error) {
var conditions []string
var args []any
for _, filter := range filters {
···
return res.RowsAffected()
}
-
func DeleteSpindle(e Execer, filters ...filter) error {
+
func DeleteSpindle(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
···
return err
}
-
func RemoveSpindleMember(e Execer, filters ...filter) error {
+
func RemoveSpindleMember(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
···
return err
}
-
func GetSpindleMembers(e Execer, filters ...filter) ([]models.SpindleMember, error) {
+
func GetSpindleMembers(e Execer, filters ...orm.Filter) ([]models.SpindleMember, error) {
var members []models.SpindleMember
var conditions []string
+5 -4
appview/db/star.go
···
"github.com/bluesky-social/indigo/atproto/syntax"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
func AddStar(e Execer, star *models.Star) error {
···
// GetRepoStars return a list of stars each holding target repository.
// If there isn't known repo with starred at-uri, those stars will be ignored.
-
func GetRepoStars(e Execer, limit int, filters ...filter) ([]models.RepoStar, error) {
+
func GetRepoStars(e Execer, limit int, filters ...orm.Filter) ([]models.RepoStar, error) {
var conditions []string
var args []any
for _, filter := range filters {
···
return nil, nil
}
-
repos, err := GetRepos(e, 0, FilterIn("at_uri", args))
+
repos, err := GetRepos(e, 0, orm.FilterIn("at_uri", args))
if err != nil {
return nil, err
}
···
return repoStars, nil
}
-
func CountStars(e Execer, filters ...filter) (int64, error) {
+
func CountStars(e Execer, filters ...orm.Filter) (int64, error) {
var conditions []string
var args []any
for _, filter := range filters {
···
}
// get full repo data
-
repos, err := GetRepos(e, 0, FilterIn("at_uri", repoUris))
+
repos, err := GetRepos(e, 0, orm.FilterIn("at_uri", repoUris))
if err != nil {
return nil, err
}
+4 -3
appview/db/strings.go
···
"time"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
func AddString(e Execer, s models.String) error {
···
return err
}
-
func GetStrings(e Execer, limit int, filters ...filter) ([]models.String, error) {
+
func GetStrings(e Execer, limit int, filters ...orm.Filter) ([]models.String, error) {
var all []models.String
var conditions []string
···
return all, nil
}
-
func CountStrings(e Execer, filters ...filter) (int64, error) {
+
func CountStrings(e Execer, filters ...orm.Filter) (int64, error) {
var conditions []string
var args []any
for _, filter := range filters {
···
return count, nil
}
-
func DeleteString(e Execer, filters ...filter) error {
+
func DeleteString(e Execer, filters ...orm.Filter) error {
var conditions []string
var args []any
for _, filter := range filters {
+9 -8
appview/db/timeline.go
···
"github.com/bluesky-social/indigo/atproto/syntax"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
// TODO: this gathers heterogenous events from different sources and aggregates
···
}
func getTimelineRepos(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) {
-
filters := make([]filter, 0)
+
filters := make([]orm.Filter, 0)
if userIsFollowing != nil {
-
filters = append(filters, FilterIn("did", userIsFollowing))
+
filters = append(filters, orm.FilterIn("did", userIsFollowing))
}
repos, err := GetRepos(e, limit, filters...)
···
var origRepos []models.Repo
if args != nil {
-
origRepos, err = GetRepos(e, 0, FilterIn("at_uri", args))
+
origRepos, err = GetRepos(e, 0, orm.FilterIn("at_uri", args))
}
if err != nil {
return nil, err
···
}
func getTimelineStars(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) {
-
filters := make([]filter, 0)
+
filters := make([]orm.Filter, 0)
if userIsFollowing != nil {
-
filters = append(filters, FilterIn("did", userIsFollowing))
+
filters = append(filters, orm.FilterIn("did", userIsFollowing))
}
stars, err := GetRepoStars(e, limit, filters...)
···
}
func getTimelineFollows(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) {
-
filters := make([]filter, 0)
+
filters := make([]orm.Filter, 0)
if userIsFollowing != nil {
-
filters = append(filters, FilterIn("user_did", userIsFollowing))
+
filters = append(filters, orm.FilterIn("user_did", userIsFollowing))
}
follows, err := GetFollows(e, limit, filters...)
···
return nil, nil
}
-
profiles, err := GetProfiles(e, FilterIn("did", subjects))
+
profiles, err := GetProfiles(e, orm.FilterIn("did", subjects))
if err != nil {
return nil, err
}
+25 -24
appview/ingester.go
···
"tangled.org/core/appview/serververify"
"tangled.org/core/appview/validator"
"tangled.org/core/idresolver"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
)
···
err = db.AddArtifact(i.Db, artifact)
case jmodels.CommitOperationDelete:
-
err = db.DeleteArtifact(i.Db, db.FilterEq("did", did), db.FilterEq("rkey", e.Commit.RKey))
+
err = db.DeleteArtifact(i.Db, orm.FilterEq("did", did), orm.FilterEq("rkey", e.Commit.RKey))
}
if err != nil {
···
err = db.UpsertProfile(tx, &profile)
case jmodels.CommitOperationDelete:
-
err = db.DeleteArtifact(i.Db, db.FilterEq("did", did), db.FilterEq("rkey", e.Commit.RKey))
+
err = db.DeleteArtifact(i.Db, orm.FilterEq("did", did), orm.FilterEq("rkey", e.Commit.RKey))
}
if err != nil {
···
// get record from db first
members, err := db.GetSpindleMembers(
ddb,
-
db.FilterEq("did", did),
-
db.FilterEq("rkey", rkey),
+
orm.FilterEq("did", did),
+
orm.FilterEq("rkey", rkey),
)
if err != nil || len(members) != 1 {
return fmt.Errorf("failed to get member: %w, len(members) = %d", err, len(members))
···
// remove record by rkey && update enforcer
if err = db.RemoveSpindleMember(
tx,
-
db.FilterEq("did", did),
-
db.FilterEq("rkey", rkey),
+
orm.FilterEq("did", did),
+
orm.FilterEq("rkey", rkey),
); err != nil {
return fmt.Errorf("failed to remove from db: %w", err)
}
···
// get record from db first
spindles, err := db.GetSpindles(
ddb,
-
db.FilterEq("owner", did),
-
db.FilterEq("instance", instance),
+
orm.FilterEq("owner", did),
+
orm.FilterEq("instance", instance),
)
if err != nil || len(spindles) != 1 {
return fmt.Errorf("failed to get spindles: %w, len(spindles) = %d", err, len(spindles))
···
// remove spindle members first
err = db.RemoveSpindleMember(
tx,
-
db.FilterEq("owner", did),
-
db.FilterEq("instance", instance),
+
orm.FilterEq("owner", did),
+
orm.FilterEq("instance", instance),
)
if err != nil {
return err
···
err = db.DeleteSpindle(
tx,
-
db.FilterEq("owner", did),
-
db.FilterEq("instance", instance),
+
orm.FilterEq("owner", did),
+
orm.FilterEq("instance", instance),
)
if err != nil {
return err
···
case jmodels.CommitOperationDelete:
if err := db.DeleteString(
ddb,
-
db.FilterEq("did", did),
-
db.FilterEq("rkey", rkey),
+
orm.FilterEq("did", did),
+
orm.FilterEq("rkey", rkey),
); err != nil {
l.Error("failed to delete", "err", err)
return fmt.Errorf("failed to delete string record: %w", err)
···
// get record from db first
registrations, err := db.GetRegistrations(
ddb,
-
db.FilterEq("domain", domain),
-
db.FilterEq("did", did),
+
orm.FilterEq("domain", domain),
+
orm.FilterEq("did", did),
)
if err != nil {
return fmt.Errorf("failed to get registration: %w", err)
···
err = db.DeleteKnot(
tx,
-
db.FilterEq("did", did),
-
db.FilterEq("domain", domain),
+
orm.FilterEq("did", did),
+
orm.FilterEq("domain", domain),
)
if err != nil {
return err
···
case jmodels.CommitOperationDelete:
if err := db.DeleteIssueComments(
ddb,
-
db.FilterEq("did", did),
-
db.FilterEq("rkey", rkey),
+
orm.FilterEq("did", did),
+
orm.FilterEq("rkey", rkey),
); err != nil {
return fmt.Errorf("failed to delete issue comment record: %w", err)
}
···
case jmodels.CommitOperationDelete:
if err := db.DeleteLabelDefinition(
ddb,
-
db.FilterEq("did", did),
-
db.FilterEq("rkey", rkey),
+
orm.FilterEq("did", did),
+
orm.FilterEq("rkey", rkey),
); err != nil {
return fmt.Errorf("failed to delete labeldef record: %w", err)
}
···
var repo *models.Repo
switch collection {
case tangled.RepoIssueNSID:
-
i, err := db.GetIssues(ddb, db.FilterEq("at_uri", subject))
+
i, err := db.GetIssues(ddb, orm.FilterEq("at_uri", subject))
if err != nil || len(i) != 1 {
return fmt.Errorf("failed to find subject: %w || subject count %d", err, len(i))
···
return fmt.Errorf("unsupport label subject: %s", collection)
-
actx, err := db.NewLabelApplicationCtx(ddb, db.FilterIn("at_uri", repo.Labels))
+
actx, err := db.NewLabelApplicationCtx(ddb, orm.FilterIn("at_uri", repo.Labels))
if err != nil {
return fmt.Errorf("failed to build label application ctx: %w", err)
+16 -15
appview/issues/issues.go
···
"tangled.org/core/appview/reporesolver"
"tangled.org/core/appview/validator"
"tangled.org/core/idresolver"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
"tangled.org/core/tid"
)
···
labelDefs, err := db.GetLabelDefinitions(
rp.db,
-
db.FilterIn("at_uri", f.Labels),
-
db.FilterContains("scope", tangled.RepoIssueNSID),
+
orm.FilterIn("at_uri", f.Labels),
+
orm.FilterContains("scope", tangled.RepoIssueNSID),
)
if err != nil {
l.Error("failed to fetch labels", "err", err)
···
if isIssueOwner || isRepoOwner || isCollaborator {
err = db.CloseIssues(
rp.db,
-
db.FilterEq("id", issue.Id),
+
orm.FilterEq("id", issue.Id),
)
if err != nil {
l.Error("failed to close issue", "err", err)
···
if isCollaborator || isRepoOwner || isIssueOwner {
err := db.ReopenIssues(
rp.db,
-
db.FilterEq("id", issue.Id),
+
orm.FilterEq("id", issue.Id),
)
if err != nil {
l.Error("failed to reopen issue", "err", err)
···
commentId := chi.URLParam(r, "commentId")
comments, err := db.GetIssueComments(
rp.db,
-
db.FilterEq("id", commentId),
+
orm.FilterEq("id", commentId),
)
if err != nil {
l.Error("failed to fetch comment", "id", commentId)
···
commentId := chi.URLParam(r, "commentId")
comments, err := db.GetIssueComments(
rp.db,
-
db.FilterEq("id", commentId),
+
orm.FilterEq("id", commentId),
)
if err != nil {
l.Error("failed to fetch comment", "id", commentId)
···
commentId := chi.URLParam(r, "commentId")
comments, err := db.GetIssueComments(
rp.db,
-
db.FilterEq("id", commentId),
+
orm.FilterEq("id", commentId),
)
if err != nil {
l.Error("failed to fetch comment", "id", commentId)
···
commentId := chi.URLParam(r, "commentId")
comments, err := db.GetIssueComments(
rp.db,
-
db.FilterEq("id", commentId),
+
orm.FilterEq("id", commentId),
)
if err != nil {
l.Error("failed to fetch comment", "id", commentId)
···
commentId := chi.URLParam(r, "commentId")
comments, err := db.GetIssueComments(
rp.db,
-
db.FilterEq("id", commentId),
+
orm.FilterEq("id", commentId),
)
if err != nil {
l.Error("failed to fetch comment", "id", commentId)
···
// optimistic deletion
deleted := time.Now()
-
err = db.DeleteIssueComments(rp.db, db.FilterEq("id", comment.Id))
+
err = db.DeleteIssueComments(rp.db, orm.FilterEq("id", comment.Id))
if err != nil {
l.Error("failed to delete comment", "err", err)
rp.pages.Notice(w, fmt.Sprintf("comment-%s-status", commentId), "failed to delete comment")
···
issues, err = db.GetIssues(
rp.db,
-
db.FilterIn("id", res.Hits),
+
orm.FilterIn("id", res.Hits),
)
if err != nil {
l.Error("failed to get issues", "err", err)
···
issues, err = db.GetIssuesPaginated(
rp.db,
page,
-
db.FilterEq("repo_at", f.RepoAt()),
-
db.FilterEq("open", openInt),
+
orm.FilterEq("repo_at", f.RepoAt()),
+
orm.FilterEq("open", openInt),
)
if err != nil {
l.Error("failed to get issues", "err", err)
···
labelDefs, err := db.GetLabelDefinitions(
rp.db,
-
db.FilterIn("at_uri", f.Labels),
-
db.FilterContains("scope", tangled.RepoIssueNSID),
+
orm.FilterIn("at_uri", f.Labels),
+
orm.FilterContains("scope", tangled.RepoIssueNSID),
)
if err != nil {
l.Error("failed to fetch labels", "err", err)
+19 -18
appview/knots/knots.go
···
"tangled.org/core/appview/xrpcclient"
"tangled.org/core/eventconsumer"
"tangled.org/core/idresolver"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
"tangled.org/core/tid"
···
user := k.OAuth.GetUser(r)
registrations, err := db.GetRegistrations(
k.Db,
-
db.FilterEq("did", user.Did),
+
orm.FilterEq("did", user.Did),
)
if err != nil {
k.Logger.Error("failed to fetch knot registrations", "err", err)
···
registrations, err := db.GetRegistrations(
k.Db,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("domain", domain),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("domain", domain),
)
if err != nil {
l.Error("failed to get registrations", "err", err)
···
repos, err := db.GetRepos(
k.Db,
0,
-
db.FilterEq("knot", domain),
+
orm.FilterEq("knot", domain),
)
if err != nil {
l.Error("failed to get knot repos", "err", err)
···
// get record from db first
registrations, err := db.GetRegistrations(
k.Db,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("domain", domain),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("domain", domain),
)
if err != nil {
l.Error("failed to get registration", "err", err)
···
err = db.DeleteKnot(
tx,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("domain", domain),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("domain", domain),
)
if err != nil {
l.Error("failed to delete registration", "err", err)
···
// get record from db first
registrations, err := db.GetRegistrations(
k.Db,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("domain", domain),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("domain", domain),
)
if err != nil {
l.Error("failed to get registration", "err", err)
···
// Get updated registration to show
registrations, err = db.GetRegistrations(
k.Db,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("domain", domain),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("domain", domain),
)
if err != nil {
l.Error("failed to get registration", "err", err)
···
registrations, err := db.GetRegistrations(
k.Db,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("domain", domain),
-
db.FilterIsNot("registered", "null"),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("domain", domain),
+
orm.FilterIsNot("registered", "null"),
)
if err != nil {
l.Error("failed to get registration", "err", err)
···
registrations, err := db.GetRegistrations(
k.Db,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("domain", domain),
-
db.FilterIsNot("registered", "null"),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("domain", domain),
+
orm.FilterIsNot("registered", "null"),
)
if err != nil {
l.Error("failed to get registration", "err", err)
+5 -4
appview/labels/labels.go
···
"tangled.org/core/appview/oauth"
"tangled.org/core/appview/pages"
"tangled.org/core/appview/validator"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
"tangled.org/core/tid"
···
repoAt := r.Form.Get("repo")
subjectUri := r.Form.Get("subject")
-
repo, err := db.GetRepo(l.db, db.FilterEq("at_uri", repoAt))
+
repo, err := db.GetRepo(l.db, orm.FilterEq("at_uri", repoAt))
if err != nil {
fail("Failed to get repository.", err)
return
}
// find all the labels that this repo subscribes to
-
repoLabels, err := db.GetRepoLabels(l.db, db.FilterEq("repo_at", repoAt))
+
repoLabels, err := db.GetRepoLabels(l.db, orm.FilterEq("repo_at", repoAt))
if err != nil {
fail("Failed to get labels for this repository.", err)
return
···
labelAts = append(labelAts, rl.LabelAt.String())
}
-
actx, err := db.NewLabelApplicationCtx(l.db, db.FilterIn("at_uri", labelAts))
+
actx, err := db.NewLabelApplicationCtx(l.db, orm.FilterIn("at_uri", labelAts))
if err != nil {
fail("Invalid form data.", err)
return
}
// calculate the start state by applying already known labels
-
existingOps, err := db.GetLabelOps(l.db, db.FilterEq("subject", subjectUri))
+
existingOps, err := db.GetLabelOps(l.db, orm.FilterEq("subject", subjectUri))
if err != nil {
fail("Invalid form data.", err)
return
+3 -2
appview/middleware/middleware.go
···
"tangled.org/core/appview/pagination"
"tangled.org/core/appview/reporesolver"
"tangled.org/core/idresolver"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
)
···
repo, err := db.GetRepo(
mw.db,
-
db.FilterEq("did", id.DID.String()),
-
db.FilterEq("name", repoName),
+
orm.FilterEq("did", id.DID.String()),
+
orm.FilterEq("name", repoName),
)
if err != nil {
log.Println("failed to resolve repo", "err", err)
+5 -4
appview/notifications/notifications.go
···
"tangled.org/core/appview/oauth"
"tangled.org/core/appview/pages"
"tangled.org/core/appview/pagination"
+
"tangled.org/core/orm"
)
type Notifications struct {
···
total, err := db.CountNotifications(
n.db,
-
db.FilterEq("recipient_did", user.Did),
+
orm.FilterEq("recipient_did", user.Did),
)
if err != nil {
l.Error("failed to get total notifications", "err", err)
···
notifications, err := db.GetNotificationsWithEntities(
n.db,
page,
-
db.FilterEq("recipient_did", user.Did),
+
orm.FilterEq("recipient_did", user.Did),
)
if err != nil {
l.Error("failed to get notifications", "err", err)
···
count, err := db.CountNotifications(
n.db,
-
db.FilterEq("recipient_did", user.Did),
-
db.FilterEq("read", 0),
+
orm.FilterEq("recipient_did", user.Did),
+
orm.FilterEq("read", 0),
)
if err != nil {
http.Error(w, "Failed to get unread count", http.StatusInternalServerError)
+11 -10
appview/notify/db/db.go
···
"tangled.org/core/appview/models"
"tangled.org/core/appview/notify"
"tangled.org/core/idresolver"
+
"tangled.org/core/orm"
)
const (
···
return
}
var err error
-
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(star.RepoAt)))
+
repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", string(star.RepoAt)))
if err != nil {
log.Printf("NewStar: failed to get repos: %v", err)
return
···
// - collaborators in the repo
var recipients []syntax.DID
recipients = append(recipients, syntax.DID(issue.Repo.Did))
-
collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", issue.Repo.RepoAt()))
+
collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", issue.Repo.RepoAt()))
if err != nil {
log.Printf("failed to fetch collaborators: %v", err)
return
···
}
func (n *databaseNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment, mentions []syntax.DID) {
-
issues, err := db.GetIssues(n.db, db.FilterEq("at_uri", comment.IssueAt))
+
issues, err := db.GetIssues(n.db, orm.FilterEq("at_uri", comment.IssueAt))
if err != nil {
log.Printf("NewIssueComment: failed to get issues: %v", err)
return
···
}
func (n *databaseNotifier) NewPull(ctx context.Context, pull *models.Pull) {
-
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(pull.RepoAt)))
+
repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", string(pull.RepoAt)))
if err != nil {
log.Printf("NewPull: failed to get repos: %v", err)
return
···
// - collaborators in the repo
var recipients []syntax.DID
recipients = append(recipients, syntax.DID(repo.Did))
-
collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", repo.RepoAt()))
+
collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", repo.RepoAt()))
if err != nil {
log.Printf("failed to fetch collaborators: %v", err)
return
···
return
}
-
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", comment.RepoAt))
+
repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", comment.RepoAt))
if err != nil {
log.Printf("NewPullComment: failed to get repos: %v", err)
return
···
// - all issue participants
var recipients []syntax.DID
recipients = append(recipients, syntax.DID(issue.Repo.Did))
-
collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", issue.Repo.RepoAt()))
+
collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", issue.Repo.RepoAt()))
if err != nil {
log.Printf("failed to fetch collaborators: %v", err)
return
···
func (n *databaseNotifier) NewPullState(ctx context.Context, actor syntax.DID, pull *models.Pull) {
// Get repo details
-
repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(pull.RepoAt)))
+
repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", string(pull.RepoAt)))
if err != nil {
log.Printf("NewPullState: failed to get repos: %v", err)
return
···
// - all pull participants
var recipients []syntax.DID
recipients = append(recipients, syntax.DID(repo.Did))
-
collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", repo.RepoAt()))
+
collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", repo.RepoAt()))
if err != nil {
log.Printf("failed to fetch collaborators: %v", err)
return
···
prefMap, err := db.GetNotificationPreferences(
n.db,
-
db.FilterIn("user_did", slices.Collect(maps.Keys(recipientSet))),
+
orm.FilterIn("user_did", slices.Collect(maps.Keys(recipientSet))),
)
if err != nil {
// failed to get prefs for users
+3 -2
appview/oauth/handler.go
···
"tangled.org/core/api/tangled"
"tangled.org/core/appview/db"
"tangled.org/core/consts"
+
"tangled.org/core/orm"
"tangled.org/core/tid"
)
···
// and create an sh.tangled.spindle.member record with that
spindleMembers, err := db.GetSpindleMembers(
o.Db,
-
db.FilterEq("instance", "spindle.tangled.sh"),
-
db.FilterEq("subject", did),
+
orm.FilterEq("instance", "spindle.tangled.sh"),
+
orm.FilterEq("subject", did),
)
if err != nil {
l.Error("failed to get spindle members", "err", err)
+12 -11
appview/pipelines/pipelines.go
···
"tangled.org/core/appview/reporesolver"
"tangled.org/core/eventconsumer"
"tangled.org/core/idresolver"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
spindlemodel "tangled.org/core/spindle/models"
···
ps, err := db.GetPipelineStatuses(
p.db,
30,
-
db.FilterEq("repo_owner", f.Did),
-
db.FilterEq("repo_name", f.Name),
-
db.FilterEq("knot", f.Knot),
+
orm.FilterEq("repo_owner", f.Did),
+
orm.FilterEq("repo_name", f.Name),
+
orm.FilterEq("knot", f.Knot),
)
if err != nil {
l.Error("failed to query db", "err", err)
···
ps, err := db.GetPipelineStatuses(
p.db,
1,
-
db.FilterEq("repo_owner", f.Did),
-
db.FilterEq("repo_name", f.Name),
-
db.FilterEq("knot", f.Knot),
-
db.FilterEq("id", pipelineId),
+
orm.FilterEq("repo_owner", f.Did),
+
orm.FilterEq("repo_name", f.Name),
+
orm.FilterEq("knot", f.Knot),
+
orm.FilterEq("id", pipelineId),
)
if err != nil {
l.Error("failed to query db", "err", err)
···
ps, err := db.GetPipelineStatuses(
p.db,
1,
-
db.FilterEq("repo_owner", f.Did),
-
db.FilterEq("repo_name", f.Name),
-
db.FilterEq("knot", f.Knot),
-
db.FilterEq("id", pipelineId),
+
orm.FilterEq("repo_owner", f.Did),
+
orm.FilterEq("repo_name", f.Name),
+
orm.FilterEq("knot", f.Knot),
+
orm.FilterEq("id", pipelineId),
)
if err != nil || len(ps) != 1 {
l.Error("pipeline query failed", "err", err, "count", len(ps))
+2 -1
appview/pulls/opengraph.go
···
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
"tangled.org/core/appview/ogcard"
+
"tangled.org/core/orm"
"tangled.org/core/patchutil"
"tangled.org/core/types"
)
···
}
// Get comment count from database
-
comments, err := db.GetPullComments(s.db, db.FilterEq("pull_id", pull.ID))
+
comments, err := db.GetPullComments(s.db, orm.FilterEq("pull_id", pull.ID))
if err != nil {
log.Printf("failed to get pull comments: %v", err)
}
+19 -18
appview/pulls/pulls.go
···
"tangled.org/core/appview/validator"
"tangled.org/core/appview/xrpcclient"
"tangled.org/core/idresolver"
+
"tangled.org/core/orm"
"tangled.org/core/patchutil"
"tangled.org/core/rbac"
"tangled.org/core/tid"
···
ps, err := db.GetPipelineStatuses(
s.db,
len(shas),
-
db.FilterEq("repo_owner", f.Did),
-
db.FilterEq("repo_name", f.Name),
-
db.FilterEq("knot", f.Knot),
-
db.FilterIn("sha", shas),
+
orm.FilterEq("repo_owner", f.Did),
+
orm.FilterEq("repo_name", f.Name),
+
orm.FilterEq("knot", f.Knot),
+
orm.FilterIn("sha", shas),
)
if err != nil {
log.Printf("failed to fetch pipeline statuses: %s", err)
···
labelDefs, err := db.GetLabelDefinitions(
s.db,
-
db.FilterIn("at_uri", f.Labels),
-
db.FilterContains("scope", tangled.RepoPullNSID),
+
orm.FilterIn("at_uri", f.Labels),
+
orm.FilterContains("scope", tangled.RepoPullNSID),
)
if err != nil {
log.Println("failed to fetch labels", err)
···
pulls, err := db.GetPulls(
s.db,
-
db.FilterIn("id", ids),
+
orm.FilterIn("id", ids),
)
if err != nil {
log.Println("failed to get pulls", err)
···
ps, err := db.GetPipelineStatuses(
s.db,
len(shas),
-
db.FilterEq("repo_owner", f.Did),
-
db.FilterEq("repo_name", f.Name),
-
db.FilterEq("knot", f.Knot),
-
db.FilterIn("sha", shas),
+
orm.FilterEq("repo_owner", f.Did),
+
orm.FilterEq("repo_name", f.Name),
+
orm.FilterEq("knot", f.Knot),
+
orm.FilterIn("sha", shas),
)
if err != nil {
log.Printf("failed to fetch pipeline statuses: %s", err)
···
labelDefs, err := db.GetLabelDefinitions(
s.db,
-
db.FilterIn("at_uri", f.Labels),
-
db.FilterContains("scope", tangled.RepoPullNSID),
+
orm.FilterIn("at_uri", f.Labels),
+
orm.FilterContains("scope", tangled.RepoPullNSID),
)
if err != nil {
log.Println("failed to fetch labels", err)
···
// fork repo
repo, err := db.GetRepo(
s.db,
-
db.FilterEq("did", forkOwnerDid),
-
db.FilterEq("name", forkName),
+
orm.FilterEq("did", forkOwnerDid),
+
orm.FilterEq("name", forkName),
if err != nil {
log.Println("failed to get repo", "did", forkOwnerDid, "name", forkName, "err", err)
···
tx,
p.ParentChangeId,
// these should be enough filters to be unique per-stack
-
db.FilterEq("repo_at", p.RepoAt.String()),
-
db.FilterEq("owner_did", p.OwnerDid),
-
db.FilterEq("change_id", p.ChangeId),
+
orm.FilterEq("repo_at", p.RepoAt.String()),
+
orm.FilterEq("owner_did", p.OwnerDid),
+
orm.FilterEq("change_id", p.ChangeId),
if err != nil {
+10 -9
appview/repo/artifact.go
···
"tangled.org/core/appview/models"
"tangled.org/core/appview/pages"
"tangled.org/core/appview/xrpcclient"
+
"tangled.org/core/orm"
"tangled.org/core/tid"
"tangled.org/core/types"
···
artifacts, err := db.GetArtifact(
rp.db,
-
db.FilterEq("repo_at", f.RepoAt()),
-
db.FilterEq("tag", tag.Tag.Hash[:]),
-
db.FilterEq("name", filename),
+
orm.FilterEq("repo_at", f.RepoAt()),
+
orm.FilterEq("tag", tag.Tag.Hash[:]),
+
orm.FilterEq("name", filename),
)
if err != nil {
log.Println("failed to get artifacts", err)
···
artifacts, err := db.GetArtifact(
rp.db,
-
db.FilterEq("repo_at", f.RepoAt()),
-
db.FilterEq("tag", tag[:]),
-
db.FilterEq("name", filename),
+
orm.FilterEq("repo_at", f.RepoAt()),
+
orm.FilterEq("tag", tag[:]),
+
orm.FilterEq("name", filename),
)
if err != nil {
log.Println("failed to get artifacts", err)
···
defer tx.Rollback()
err = db.DeleteArtifact(tx,
-
db.FilterEq("repo_at", f.RepoAt()),
-
db.FilterEq("tag", artifact.Tag[:]),
-
db.FilterEq("name", filename),
+
orm.FilterEq("repo_at", f.RepoAt()),
+
orm.FilterEq("tag", artifact.Tag[:]),
+
orm.FilterEq("name", filename),
)
if err != nil {
log.Println("failed to remove artifact record from db", err)
+3 -2
appview/repo/feed.go
···
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
"tangled.org/core/appview/pagination"
+
"tangled.org/core/orm"
"github.com/bluesky-social/indigo/atproto/identity"
"github.com/bluesky-social/indigo/atproto/syntax"
···
func (rp *Repo) getRepoFeed(ctx context.Context, repo *models.Repo, ownerSlashRepo string) (*feeds.Feed, error) {
const feedLimitPerType = 100
-
pulls, err := db.GetPullsWithLimit(rp.db, feedLimitPerType, db.FilterEq("repo_at", repo.RepoAt()))
+
pulls, err := db.GetPullsWithLimit(rp.db, feedLimitPerType, orm.FilterEq("repo_at", repo.RepoAt()))
if err != nil {
return nil, err
}
···
issues, err := db.GetIssuesPaginated(
rp.db,
pagination.Page{Limit: feedLimitPerType},
-
db.FilterEq("repo_at", repo.RepoAt()),
+
orm.FilterEq("repo_at", repo.RepoAt()),
)
if err != nil {
return nil, err
+3 -2
appview/repo/index.go
···
"tangled.org/core/appview/models"
"tangled.org/core/appview/pages"
"tangled.org/core/appview/xrpcclient"
+
"tangled.org/core/orm"
"tangled.org/core/types"
"github.com/go-chi/chi/v5"
···
// first attempt to fetch from db
langs, err := db.GetRepoLanguages(
rp.db,
-
db.FilterEq("repo_at", repo.RepoAt()),
-
db.FilterEq("ref", currentRef),
+
orm.FilterEq("repo_at", repo.RepoAt()),
+
orm.FilterEq("ref", currentRef),
)
if err != nil || langs == nil {
+3 -2
appview/repo/opengraph.go
···
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
"tangled.org/core/appview/ogcard"
+
"tangled.org/core/orm"
"tangled.org/core/types"
)
···
var languageStats []types.RepoLanguageDetails
langs, err := db.GetRepoLanguages(
rp.db,
-
db.FilterEq("repo_at", f.RepoAt()),
-
db.FilterEq("is_default_ref", 1),
+
orm.FilterEq("repo_at", f.RepoAt()),
+
orm.FilterEq("is_default_ref", 1),
)
if err != nil {
log.Printf("failed to get language stats from db: %v", err)
+17 -16
appview/repo/repo.go
···
xrpcclient "tangled.org/core/appview/xrpcclient"
"tangled.org/core/eventconsumer"
"tangled.org/core/idresolver"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
"tangled.org/core/tid"
"tangled.org/core/xrpc/serviceauth"
···
// get form values
labelId := r.FormValue("label-id")
-
label, err := db.GetLabelDefinition(rp.db, db.FilterEq("id", labelId))
+
label, err := db.GetLabelDefinition(rp.db, orm.FilterEq("id", labelId))
if err != nil {
fail("Failed to find label definition.", err)
return
···
err = db.UnsubscribeLabel(
tx,
-
db.FilterEq("repo_at", f.RepoAt()),
-
db.FilterEq("label_at", removedAt),
+
orm.FilterEq("repo_at", f.RepoAt()),
+
orm.FilterEq("label_at", removedAt),
)
if err != nil {
fail("Failed to unsubscribe label.", err)
return
}
-
err = db.DeleteLabelDefinition(tx, db.FilterEq("id", label.Id))
+
err = db.DeleteLabelDefinition(tx, orm.FilterEq("id", label.Id))
if err != nil {
fail("Failed to delete label definition.", err)
return
···
}
labelAts := r.Form["label"]
-
_, err = db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", labelAts))
+
_, err = db.GetLabelDefinitions(rp.db, orm.FilterIn("at_uri", labelAts))
if err != nil {
fail("Failed to subscribe to label.", err)
return
···
}
labelAts := r.Form["label"]
-
_, err = db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", labelAts))
+
_, err = db.GetLabelDefinitions(rp.db, orm.FilterIn("at_uri", labelAts))
if err != nil {
fail("Failed to unsubscribe to label.", err)
return
···
err = db.UnsubscribeLabel(
rp.db,
-
db.FilterEq("repo_at", f.RepoAt()),
-
db.FilterIn("label_at", labelAts),
+
orm.FilterEq("repo_at", f.RepoAt()),
+
orm.FilterIn("label_at", labelAts),
)
if err != nil {
fail("Failed to unsubscribe label.", err)
···
labelDefs, err := db.GetLabelDefinitions(
rp.db,
-
db.FilterIn("at_uri", f.Labels),
-
db.FilterContains("scope", subject.Collection().String()),
+
orm.FilterIn("at_uri", f.Labels),
+
orm.FilterContains("scope", subject.Collection().String()),
)
if err != nil {
l.Error("failed to fetch label defs", "err", err)
···
defs[l.AtUri().String()] = &l
}
-
states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject))
+
states, err := db.GetLabels(rp.db, orm.FilterEq("subject", subject))
if err != nil {
l.Error("failed to build label state", "err", err)
return
···
labelDefs, err := db.GetLabelDefinitions(
rp.db,
-
db.FilterIn("at_uri", f.Labels),
-
db.FilterContains("scope", subject.Collection().String()),
+
orm.FilterIn("at_uri", f.Labels),
+
orm.FilterContains("scope", subject.Collection().String()),
)
if err != nil {
l.Error("failed to fetch labels", "err", err)
···
defs[l.AtUri().String()] = &l
}
-
states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject))
+
states, err := db.GetLabels(rp.db, orm.FilterEq("subject", subject))
if err != nil {
l.Error("failed to build label state", "err", err)
return
···
// in the user's account.
existingRepo, err := db.GetRepo(
rp.db,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("name", forkName),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("name", forkName),
if err != nil {
if !errors.Is(err, sql.ErrNoRows) {
+5 -4
appview/repo/repo_util.go
···
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
"tangled.org/core/types"
)
···
ps, err := db.GetPipelineStatuses(
d,
len(shas),
-
db.FilterEq("repo_owner", repo.Did),
-
db.FilterEq("repo_name", repo.Name),
-
db.FilterEq("knot", repo.Knot),
-
db.FilterIn("sha", shas),
+
orm.FilterEq("repo_owner", repo.Did),
+
orm.FilterEq("repo_name", repo.Name),
+
orm.FilterEq("knot", repo.Knot),
+
orm.FilterIn("sha", shas),
)
if err != nil {
return nil, err
+3 -2
appview/repo/settings.go
···
"tangled.org/core/appview/oauth"
"tangled.org/core/appview/pages"
xrpcclient "tangled.org/core/appview/xrpcclient"
+
"tangled.org/core/orm"
"tangled.org/core/types"
comatproto "github.com/bluesky-social/indigo/api/atproto"
···
return
}
-
defaultLabels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", rp.config.Label.DefaultLabelDefs))
+
defaultLabels, err := db.GetLabelDefinitions(rp.db, orm.FilterIn("at_uri", rp.config.Label.DefaultLabelDefs))
if err != nil {
l.Error("failed to fetch labels", "err", err)
rp.pages.Error503(w)
return
}
-
labels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", f.Labels))
+
labels, err := db.GetLabelDefinitions(rp.db, orm.FilterIn("at_uri", f.Labels))
if err != nil {
l.Error("failed to fetch labels", "err", err)
rp.pages.Error503(w)
+2 -1
appview/repo/tags.go
···
"tangled.org/core/appview/models"
"tangled.org/core/appview/pages"
xrpcclient "tangled.org/core/appview/xrpcclient"
+
"tangled.org/core/orm"
"tangled.org/core/types"
indigoxrpc "github.com/bluesky-social/indigo/xrpc"
···
rp.pages.Error503(w)
return
}
-
artifacts, err := db.GetArtifact(rp.db, db.FilterEq("repo_at", f.RepoAt()))
+
artifacts, err := db.GetArtifact(rp.db, orm.FilterEq("repo_at", f.RepoAt()))
if err != nil {
l.Error("failed grab artifacts", "err", err)
return
+5 -4
appview/serververify/verify.go
···
"tangled.org/core/api/tangled"
"tangled.org/core/appview/db"
"tangled.org/core/appview/xrpcclient"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
)
···
// mark this spindle as verified in the db
rowId, err := db.VerifySpindle(
tx,
-
db.FilterEq("owner", owner),
-
db.FilterEq("instance", instance),
+
orm.FilterEq("owner", owner),
+
orm.FilterEq("instance", instance),
)
if err != nil {
return 0, fmt.Errorf("failed to write to DB: %w", err)
···
// mark as registered
err = db.MarkRegistered(
tx,
-
db.FilterEq("did", owner),
-
db.FilterEq("domain", domain),
+
orm.FilterEq("did", owner),
+
orm.FilterEq("domain", domain),
)
if err != nil {
return fmt.Errorf("failed to register domain: %w", err)
+25 -24
appview/spindles/spindles.go
···
"tangled.org/core/appview/serververify"
"tangled.org/core/appview/xrpcclient"
"tangled.org/core/idresolver"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
"tangled.org/core/tid"
···
user := s.OAuth.GetUser(r)
all, err := db.GetSpindles(
s.Db,
-
db.FilterEq("owner", user.Did),
+
orm.FilterEq("owner", user.Did),
)
if err != nil {
s.Logger.Error("failed to fetch spindles", "err", err)
···
spindles, err := db.GetSpindles(
s.Db,
-
db.FilterEq("instance", instance),
-
db.FilterEq("owner", user.Did),
-
db.FilterIsNot("verified", "null"),
+
orm.FilterEq("instance", instance),
+
orm.FilterEq("owner", user.Did),
+
orm.FilterIsNot("verified", "null"),
)
if err != nil || len(spindles) != 1 {
l.Error("failed to get spindle", "err", err, "len(spindles)", len(spindles))
···
repos, err := db.GetRepos(
s.Db,
0,
-
db.FilterEq("spindle", instance),
+
orm.FilterEq("spindle", instance),
)
if err != nil {
l.Error("failed to get spindle repos", "err", err)
···
spindles, err := db.GetSpindles(
s.Db,
-
db.FilterEq("owner", user.Did),
-
db.FilterEq("instance", instance),
+
orm.FilterEq("owner", user.Did),
+
orm.FilterEq("instance", instance),
)
if err != nil || len(spindles) != 1 {
l.Error("failed to retrieve instance", "err", err, "len(spindles)", len(spindles))
···
// remove spindle members first
err = db.RemoveSpindleMember(
tx,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("instance", instance),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("instance", instance),
)
if err != nil {
l.Error("failed to remove spindle members", "err", err)
···
err = db.DeleteSpindle(
tx,
-
db.FilterEq("owner", user.Did),
-
db.FilterEq("instance", instance),
+
orm.FilterEq("owner", user.Did),
+
orm.FilterEq("instance", instance),
)
if err != nil {
l.Error("failed to delete spindle", "err", err)
···
spindles, err := db.GetSpindles(
s.Db,
-
db.FilterEq("owner", user.Did),
-
db.FilterEq("instance", instance),
+
orm.FilterEq("owner", user.Did),
+
orm.FilterEq("instance", instance),
)
if err != nil || len(spindles) != 1 {
l.Error("failed to retrieve instance", "err", err, "len(spindles)", len(spindles))
···
verifiedSpindle, err := db.GetSpindles(
s.Db,
-
db.FilterEq("id", rowId),
+
orm.FilterEq("id", rowId),
)
if err != nil || len(verifiedSpindle) != 1 {
l.Error("failed get new spindle", "err", err)
···
spindles, err := db.GetSpindles(
s.Db,
-
db.FilterEq("owner", user.Did),
-
db.FilterEq("instance", instance),
+
orm.FilterEq("owner", user.Did),
+
orm.FilterEq("instance", instance),
)
if err != nil || len(spindles) != 1 {
l.Error("failed to retrieve instance", "err", err, "len(spindles)", len(spindles))
···
spindles, err := db.GetSpindles(
s.Db,
-
db.FilterEq("owner", user.Did),
-
db.FilterEq("instance", instance),
+
orm.FilterEq("owner", user.Did),
+
orm.FilterEq("instance", instance),
)
if err != nil || len(spindles) != 1 {
l.Error("failed to retrieve instance", "err", err, "len(spindles)", len(spindles))
···
// get the record from the DB first:
members, err := db.GetSpindleMembers(
s.Db,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("instance", instance),
-
db.FilterEq("subject", memberId.DID),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("instance", instance),
+
orm.FilterEq("subject", memberId.DID),
)
if err != nil || len(members) != 1 {
l.Error("failed to get member", "err", err)
···
// remove from db
if err = db.RemoveSpindleMember(
tx,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("instance", instance),
-
db.FilterEq("subject", memberId.DID),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("instance", instance),
+
orm.FilterEq("subject", memberId.DID),
); err != nil {
l.Error("failed to remove spindle member", "err", err)
fail()
+6 -5
appview/state/gfi.go
···
"tangled.org/core/appview/pages"
"tangled.org/core/appview/pagination"
"tangled.org/core/consts"
+
"tangled.org/core/orm"
)
func (s *State) GoodFirstIssues(w http.ResponseWriter, r *http.Request) {
···
goodFirstIssueLabel := s.config.Label.GoodFirstIssue
-
gfiLabelDef, err := db.GetLabelDefinition(s.db, db.FilterEq("at_uri", goodFirstIssueLabel))
+
gfiLabelDef, err := db.GetLabelDefinition(s.db, orm.FilterEq("at_uri", goodFirstIssueLabel))
if err != nil {
log.Println("failed to get gfi label def", err)
s.pages.Error500(w)
return
}
-
repoLabels, err := db.GetRepoLabels(s.db, db.FilterEq("label_at", goodFirstIssueLabel))
+
repoLabels, err := db.GetRepoLabels(s.db, orm.FilterEq("label_at", goodFirstIssueLabel))
if err != nil {
log.Println("failed to get repo labels", err)
s.pages.Error503(w)
···
pagination.Page{
Limit: 500,
},
-
db.FilterIn("repo_at", repoUris),
-
db.FilterEq("open", 1),
+
orm.FilterIn("repo_at", repoUris),
+
orm.FilterEq("open", 1),
)
if err != nil {
log.Println("failed to get issues", err)
···
}
if len(uriList) > 0 {
-
allLabelDefs, err = db.GetLabelDefinitions(s.db, db.FilterIn("at_uri", uriList))
+
allLabelDefs, err = db.GetLabelDefinitions(s.db, orm.FilterIn("at_uri", uriList))
if err != nil {
log.Println("failed to fetch labels", err)
}
+6 -5
appview/state/knotstream.go
···
ec "tangled.org/core/eventconsumer"
"tangled.org/core/eventconsumer/cursor"
"tangled.org/core/log"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
"tangled.org/core/workflow"
···
knots, err := db.GetRegistrations(
d,
-
db.FilterIsNot("registered", "null"),
+
orm.FilterIsNot("registered", "null"),
)
if err != nil {
return nil, err
···
repos, err := db.GetRepos(
d,
0,
-
db.FilterEq("did", record.RepoDid),
-
db.FilterEq("name", record.RepoName),
+
orm.FilterEq("did", record.RepoDid),
+
orm.FilterEq("name", record.RepoName),
)
if err != nil {
return fmt.Errorf("failed to look for repo in DB (%s/%s): %w", record.RepoDid, record.RepoName, err)
···
repos, err := db.GetRepos(
d,
0,
-
db.FilterEq("did", record.TriggerMetadata.Repo.Did),
-
db.FilterEq("name", record.TriggerMetadata.Repo.Repo),
+
orm.FilterEq("did", record.TriggerMetadata.Repo.Did),
+
orm.FilterEq("name", record.TriggerMetadata.Repo.Repo),
)
if err != nil {
return fmt.Errorf("failed to look for repo in DB: nsid %s, rkey %s, %w", msg.Nsid, msg.Rkey, err)
+13 -12
appview/state/profile.go
···
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
"tangled.org/core/appview/pages"
+
"tangled.org/core/orm"
)
func (s *State) Profile(w http.ResponseWriter, r *http.Request) {
···
return nil, fmt.Errorf("failed to get profile: %w", err)
}
-
repoCount, err := db.CountRepos(s.db, db.FilterEq("did", did))
+
repoCount, err := db.CountRepos(s.db, orm.FilterEq("did", did))
if err != nil {
return nil, fmt.Errorf("failed to get repo count: %w", err)
}
-
stringCount, err := db.CountStrings(s.db, db.FilterEq("did", did))
+
stringCount, err := db.CountStrings(s.db, orm.FilterEq("did", did))
if err != nil {
return nil, fmt.Errorf("failed to get string count: %w", err)
}
-
starredCount, err := db.CountStars(s.db, db.FilterEq("did", did))
+
starredCount, err := db.CountStars(s.db, orm.FilterEq("did", did))
if err != nil {
return nil, fmt.Errorf("failed to get starred repo count: %w", err)
}
···
startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC)
punchcard, err := db.MakePunchcard(
s.db,
-
db.FilterEq("did", did),
-
db.FilterGte("date", startOfYear.Format(time.DateOnly)),
-
db.FilterLte("date", now.Format(time.DateOnly)),
+
orm.FilterEq("did", did),
+
orm.FilterGte("date", startOfYear.Format(time.DateOnly)),
+
orm.FilterLte("date", now.Format(time.DateOnly)),
)
if err != nil {
return nil, fmt.Errorf("failed to get punchcard for %s: %w", did, err)
···
repos, err := db.GetRepos(
s.db,
0,
-
db.FilterEq("did", profile.UserDid),
+
orm.FilterEq("did", profile.UserDid),
)
if err != nil {
l.Error("failed to fetch repos", "err", err)
···
repos, err := db.GetRepos(
s.db,
0,
-
db.FilterEq("did", profile.UserDid),
+
orm.FilterEq("did", profile.UserDid),
)
if err != nil {
l.Error("failed to get repos", "err", err)
···
}
l = l.With("profileDid", profile.UserDid)
-
stars, err := db.GetRepoStars(s.db, 0, db.FilterEq("did", profile.UserDid))
+
stars, err := db.GetRepoStars(s.db, 0, orm.FilterEq("did", profile.UserDid))
if err != nil {
l.Error("failed to get stars", "err", err)
s.pages.Error500(w)
···
}
l = l.With("profileDid", profile.UserDid)
-
strings, err := db.GetStrings(s.db, 0, db.FilterEq("did", profile.UserDid))
+
strings, err := db.GetStrings(s.db, 0, orm.FilterEq("did", profile.UserDid))
if err != nil {
l.Error("failed to get strings", "err", err)
s.pages.Error500(w)
···
followDids = append(followDids, extractDid(follow))
}
-
profiles, err := db.GetProfiles(s.db, db.FilterIn("did", followDids))
+
profiles, err := db.GetProfiles(s.db, orm.FilterIn("did", followDids))
if err != nil {
l.Error("failed to get profiles", "followDids", followDids, "err", err)
return &params, err
···
log.Printf("getting profile data for %s: %s", user.Did, err)
}
-
repos, err := db.GetRepos(s.db, 0, db.FilterEq("did", user.Did))
+
repos, err := db.GetRepos(s.db, 0, orm.FilterEq("did", user.Did))
if err != nil {
log.Printf("getting repos for %s: %s", user.Did, err)
}
+2 -1
appview/state/spindlestream.go
···
ec "tangled.org/core/eventconsumer"
"tangled.org/core/eventconsumer/cursor"
"tangled.org/core/log"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
spindle "tangled.org/core/spindle/models"
)
···
spindles, err := db.GetSpindles(
d,
-
db.FilterIsNot("verified", "null"),
+
orm.FilterIsNot("verified", "null"),
)
if err != nil {
return nil, err
+9 -8
appview/state/state.go
···
"tangled.org/core/jetstream"
"tangled.org/core/log"
tlog "tangled.org/core/log"
+
"tangled.org/core/orm"
"tangled.org/core/rbac"
"tangled.org/core/tid"
···
return
}
-
gfiLabel, err := db.GetLabelDefinition(s.db, db.FilterEq("at_uri", s.config.Label.GoodFirstIssue))
+
gfiLabel, err := db.GetLabelDefinition(s.db, orm.FilterEq("at_uri", s.config.Label.GoodFirstIssue))
if err != nil {
// non-fatal
}
···
regs, err := db.GetRegistrations(
s.db,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("needs_upgrade", 1),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("needs_upgrade", 1),
)
if err != nil {
l.Error("non-fatal: failed to get registrations", "err", err)
···
spindles, err := db.GetSpindles(
s.db,
-
db.FilterEq("owner", user.Did),
-
db.FilterEq("needs_upgrade", 1),
+
orm.FilterEq("owner", user.Did),
+
orm.FilterEq("needs_upgrade", 1),
)
if err != nil {
l.Error("non-fatal: failed to get spindles", "err", err)
···
// Check for existing repos
existingRepo, err := db.GetRepo(
s.db,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("name", repoName),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("name", repoName),
)
if err == nil && existingRepo != nil {
l.Info("repo exists")
···
}
func BackfillDefaultDefs(e db.Execer, r *idresolver.Resolver, defaults []string) error {
-
defaultLabels, err := db.GetLabelDefinitions(e, db.FilterIn("at_uri", defaults))
+
defaultLabels, err := db.GetLabelDefinitions(e, orm.FilterIn("at_uri", defaults))
if err != nil {
return err
}
+7 -6
appview/strings/strings.go
···
"tangled.org/core/appview/pages"
"tangled.org/core/appview/pages/markup"
"tangled.org/core/idresolver"
+
"tangled.org/core/orm"
"tangled.org/core/tid"
"github.com/bluesky-social/indigo/api/atproto"
···
strings, err := db.GetStrings(
s.Db,
0,
-
db.FilterEq("did", id.DID),
-
db.FilterEq("rkey", rkey),
+
orm.FilterEq("did", id.DID),
+
orm.FilterEq("rkey", rkey),
)
if err != nil {
l.Error("failed to fetch string", "err", err)
···
all, err := db.GetStrings(
s.Db,
0,
-
db.FilterEq("did", id.DID),
-
db.FilterEq("rkey", rkey),
+
orm.FilterEq("did", id.DID),
+
orm.FilterEq("rkey", rkey),
)
if err != nil {
l.Error("failed to fetch string", "err", err)
···
if err := db.DeleteString(
s.Db,
-
db.FilterEq("did", user.Did),
-
db.FilterEq("rkey", rkey),
+
orm.FilterEq("did", user.Did),
+
orm.FilterEq("rkey", rkey),
); err != nil {
fail("Failed to delete string.", err)
return
+2 -1
appview/validator/issue.go
···
"tangled.org/core/appview/db"
"tangled.org/core/appview/models"
+
"tangled.org/core/orm"
)
func (v *Validator) ValidateIssueComment(comment *models.IssueComment) error {
// if comments have parents, only ingest ones that are 1 level deep
if comment.ReplyTo != nil {
-
parents, err := db.GetIssueComments(v.db, db.FilterEq("at_uri", *comment.ReplyTo))
+
parents, err := db.GetIssueComments(v.db, orm.FilterEq("at_uri", *comment.ReplyTo))
if err != nil {
return fmt.Errorf("failed to fetch parent comment: %w", err)
}
+122
orm/orm.go
···
+
package orm
+
+
import (
+
"context"
+
"database/sql"
+
"fmt"
+
"log/slog"
+
"reflect"
+
"strings"
+
)
+
+
type migrationFn = func(*sql.Tx) error
+
+
func RunMigration(c *sql.Conn, logger *slog.Logger, name string, migrationFn migrationFn) error {
+
logger = logger.With("migration", name)
+
+
tx, err := c.BeginTx(context.Background(), nil)
+
if err != nil {
+
return err
+
}
+
defer tx.Rollback()
+
+
var exists bool
+
err = tx.QueryRow("select exists (select 1 from migrations where name = ?)", name).Scan(&exists)
+
if err != nil {
+
return err
+
}
+
+
if !exists {
+
// run migration
+
err = migrationFn(tx)
+
if err != nil {
+
logger.Error("failed to run migration", "err", err)
+
return err
+
}
+
+
// mark migration as complete
+
_, err = tx.Exec("insert into migrations (name) values (?)", name)
+
if err != nil {
+
logger.Error("failed to mark migration as complete", "err", err)
+
return err
+
}
+
+
// commit the transaction
+
if err := tx.Commit(); err != nil {
+
return err
+
}
+
+
logger.Info("migration applied successfully")
+
} else {
+
logger.Warn("skipped migration, already applied")
+
}
+
+
return nil
+
}
+
+
type Filter struct {
+
Key string
+
arg any
+
Cmp string
+
}
+
+
func newFilter(key, cmp string, arg any) Filter {
+
return Filter{
+
Key: key,
+
arg: arg,
+
Cmp: cmp,
+
}
+
}
+
+
func FilterEq(key string, arg any) Filter { return newFilter(key, "=", arg) }
+
func FilterNotEq(key string, arg any) Filter { return newFilter(key, "<>", arg) }
+
func FilterGte(key string, arg any) Filter { return newFilter(key, ">=", arg) }
+
func FilterLte(key string, arg any) Filter { return newFilter(key, "<=", arg) }
+
func FilterIs(key string, arg any) Filter { return newFilter(key, "is", arg) }
+
func FilterIsNot(key string, arg any) Filter { return newFilter(key, "is not", arg) }
+
func FilterIn(key string, arg any) Filter { return newFilter(key, "in", arg) }
+
func FilterLike(key string, arg any) Filter { return newFilter(key, "like", arg) }
+
func FilterNotLike(key string, arg any) Filter { return newFilter(key, "not like", arg) }
+
func FilterContains(key string, arg any) Filter {
+
return newFilter(key, "like", fmt.Sprintf("%%%v%%", arg))
+
}
+
+
func (f Filter) Condition() string {
+
rv := reflect.ValueOf(f.arg)
+
kind := rv.Kind()
+
+
// if we have `FilterIn(k, [1, 2, 3])`, compile it down to `k in (?, ?, ?)`
+
if (kind == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8) || kind == reflect.Array {
+
if rv.Len() == 0 {
+
// always false
+
return "1 = 0"
+
}
+
+
placeholders := make([]string, rv.Len())
+
for i := range placeholders {
+
placeholders[i] = "?"
+
}
+
+
return fmt.Sprintf("%s %s (%s)", f.Key, f.Cmp, strings.Join(placeholders, ", "))
+
}
+
+
return fmt.Sprintf("%s %s ?", f.Key, f.Cmp)
+
}
+
+
func (f Filter) Arg() []any {
+
rv := reflect.ValueOf(f.arg)
+
kind := rv.Kind()
+
if (kind == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8) || kind == reflect.Array {
+
if rv.Len() == 0 {
+
return nil
+
}
+
+
out := make([]any, rv.Len())
+
for i := range rv.Len() {
+
out[i] = rv.Index(i).Interface()
+
}
+
return out
+
}
+
+
return []any{f.arg}
+
}