From a894e83bc68ea5f5fb8db4b81e884b7aad8a9540 Mon Sep 17 00:00:00 2001 From: oppiliappan Date: Tue, 9 Dec 2025 09:04:29 +0000 Subject: [PATCH] orm: extract orm package from appview includes query and migration helpers Signed-off-by: oppiliappan --- appview/db/artifact.go | 5 +- appview/db/collaborators.go | 7 +- appview/db/db.go | 161 ++++--------------------- appview/db/follow.go | 7 +- appview/db/issues.go | 41 ++++--- appview/db/label.go | 15 +-- appview/db/language.go | 9 +- appview/db/notifications.go | 27 +++-- appview/db/pipeline.go | 11 +- appview/db/profile.go | 11 +- appview/db/pulls.go | 41 ++++--- appview/db/punchcard.go | 3 +- appview/db/reference.go | 7 +- appview/db/registration.go | 7 +- appview/db/repos.go | 11 +- appview/db/spindle.go | 11 +- appview/db/star.go | 9 +- appview/db/strings.go | 7 +- appview/db/timeline.go | 17 +-- appview/ingester.go | 49 ++++---- appview/issues/issues.go | 31 ++--- appview/knots/knots.go | 37 +++--- appview/labels/labels.go | 9 +- appview/middleware/middleware.go | 5 +- appview/notifications/notifications.go | 9 +- appview/notify/db/db.go | 21 ++-- appview/oauth/handler.go | 5 +- appview/pipelines/pipelines.go | 23 ++-- appview/pulls/opengraph.go | 3 +- appview/pulls/pulls.go | 37 +++--- appview/repo/artifact.go | 19 +-- appview/repo/feed.go | 5 +- appview/repo/index.go | 5 +- appview/repo/opengraph.go | 5 +- appview/repo/repo.go | 33 ++--- appview/repo/repo_util.go | 9 +- appview/repo/settings.go | 5 +- appview/repo/tags.go | 3 +- appview/serververify/verify.go | 9 +- appview/spindles/spindles.go | 49 ++++---- appview/state/gfi.go | 11 +- appview/state/knotstream.go | 11 +- appview/state/profile.go | 25 ++-- appview/state/spindlestream.go | 3 +- appview/state/state.go | 17 +-- appview/strings/strings.go | 13 +- appview/validator/issue.go | 3 +- orm/orm.go | 122 +++++++++++++++++++ 48 files changed, 519 insertions(+), 464 deletions(-) create mode 100644 orm/orm.go diff --git a/appview/db/artifact.go b/appview/db/artifact.go index 804dbe92..68042b78 100644 --- a/appview/db/artifact.go +++ b/appview/db/artifact.go @@ -8,6 +8,7 @@ import ( "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 { @@ -37,7 +38,7 @@ 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 @@ -109,7 +110,7 @@ func GetArtifact(e Execer, filters ...filter) ([]models.Artifact, error) { 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 { diff --git a/appview/db/collaborators.go b/appview/db/collaborators.go index c49b9d3e..8ac35b5f 100644 --- a/appview/db/collaborators.go +++ b/appview/db/collaborators.go @@ -6,6 +6,7 @@ import ( "time" "tangled.org/core/appview/models" + "tangled.org/core/orm" ) func AddCollaborator(e Execer, c models.Collaborator) error { @@ -16,7 +17,7 @@ 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 { @@ -58,10 +59,10 @@ func CollaboratingIn(e Execer, collaborator string) ([]models.Repo, error) { 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 diff --git a/appview/db/db.go b/appview/db/db.go index f11bd391..f4d5d93a 100644 --- a/appview/db/db.go +++ b/appview/db/db.go @@ -3,13 +3,12 @@ package db 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 { @@ -584,14 +583,14 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { } // 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 @@ -614,7 +613,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { 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; @@ -622,7 +621,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { 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 @@ -630,7 +629,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { 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; @@ -639,7 +638,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { 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; `) @@ -651,7 +650,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { // // [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 @@ -708,7 +707,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { }) 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; `) @@ -718,7 +717,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { // 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, @@ -741,7 +740,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { }) // 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 @@ -795,7 +794,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { 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 ''; @@ -807,7 +806,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { }) // 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; `) @@ -815,7 +814,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { }) // 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; `) @@ -823,7 +822,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { }) // 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; `) @@ -841,7 +840,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { // // 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 @@ -911,7 +910,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { // - 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 @@ -971,7 +970,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { // // 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 @@ -1052,7 +1051,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { // // 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 @@ -1106,21 +1105,21 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { // 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; @@ -1128,7 +1127,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { 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; `) @@ -1136,7 +1135,7 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { }) // 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, @@ -1180,118 +1179,6 @@ func Make(ctx context.Context, dbPath string) (*DB, error) { }, 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} -} diff --git a/appview/db/follow.go b/appview/db/follow.go index f69d4f56..d9b40332 100644 --- a/appview/db/follow.go +++ b/appview/db/follow.go @@ -7,6 +7,7 @@ import ( "time" "tangled.org/core/appview/models" + "tangled.org/core/orm" ) func AddFollow(e Execer, follow *models.Follow) error { @@ -134,7 +135,7 @@ func GetFollowerFollowingCounts(e Execer, dids []string) (map[string]models.Foll 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 @@ -191,11 +192,11 @@ func GetFollows(e Execer, limit int, filters ...filter) ([]models.Follow, error) } 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) { diff --git a/appview/db/issues.go b/appview/db/issues.go index e96f6ed3..b1fb5fe6 100644 --- a/appview/db/issues.go +++ b/appview/db/issues.go @@ -13,6 +13,7 @@ import ( "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 { @@ -27,8 +28,8 @@ 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: @@ -98,7 +99,7 @@ func updateIssue(tx *sql.Tx, issue *models.Issue) error { 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 @@ -114,8 +115,8 @@ func GetIssuesPaginated(e Execer, page pagination.Page, filters ...filter) ([]mo 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 { @@ -205,7 +206,7 @@ func GetIssuesPaginated(e Execer, page pagination.Page, filters ...filter) ([]mo 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) } @@ -228,7 +229,7 @@ func GetIssuesPaginated(e Execer, page pagination.Page, filters ...filter) ([]mo // 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) } @@ -240,7 +241,7 @@ func GetIssuesPaginated(e Execer, page pagination.Page, filters ...filter) ([]mo } // 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) } @@ -251,7 +252,7 @@ func GetIssuesPaginated(e Execer, page pagination.Page, filters ...filter) ([]mo } // 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) } @@ -277,8 +278,8 @@ func GetIssue(e Execer, repoAt syntax.ATURI, issueId int) (*models.Issue, error) 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 @@ -290,7 +291,7 @@ func GetIssue(e Execer, repoAt syntax.ATURI, issueId int) (*models.Issue, error) 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...) } @@ -298,14 +299,14 @@ func GetIssues(e Execer, filters ...filter) ([]models.Issue, error) { 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 @@ -397,7 +398,7 @@ func AddIssueComment(tx *sql.Tx, c models.IssueComment) (int64, error) { 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 { @@ -416,7 +417,7 @@ func DeleteIssueComments(e Execer, filters ...filter) error { 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 @@ -506,7 +507,7 @@ func GetIssueComments(e Execer, filters ...filter) ([]models.IssueComment, error // 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) } @@ -548,7 +549,7 @@ func DeleteIssues(tx *sql.Tx, did, rkey string) error { 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 { @@ -566,7 +567,7 @@ func CloseIssues(e Execer, filters ...filter) error { 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 { diff --git a/appview/db/label.go b/appview/db/label.go index e323ebb9..18d5780c 100644 --- a/appview/db/label.go +++ b/appview/db/label.go @@ -10,6 +10,7 @@ import ( "github.com/bluesky-social/indigo/atproto/syntax" "tangled.org/core/appview/models" + "tangled.org/core/orm" ) // no updating type for now @@ -59,7 +60,7 @@ func AddLabelDefinition(e Execer, l *models.LabelDefinition) (int64, error) { 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 { @@ -75,7 +76,7 @@ func DeleteLabelDefinition(e Execer, filters ...filter) error { 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 @@ -167,7 +168,7 @@ func GetLabelDefinitions(e Execer, filters ...filter) ([]models.LabelDefinition, } // 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 @@ -227,7 +228,7 @@ func AddLabelOp(e Execer, l *models.LabelOp) (int64, error) { 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 @@ -302,7 +303,7 @@ func GetLabelOps(e Execer, filters ...filter) ([]models.LabelOp, error) { } // 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 @@ -322,7 +323,7 @@ func GetLabels(e Execer, filters ...filter) (map[syntax.ATURI]models.LabelState, } 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 } @@ -338,7 +339,7 @@ func GetLabels(e Execer, filters ...filter) (map[syntax.ATURI]models.LabelState, 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 diff --git a/appview/db/language.go b/appview/db/language.go index 19adb648..7c80def9 100644 --- a/appview/db/language.go +++ b/appview/db/language.go @@ -7,9 +7,10 @@ import ( "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 { @@ -85,7 +86,7 @@ func InsertRepoLanguages(e Execer, langs []models.RepoLanguage) error { 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 { @@ -107,8 +108,8 @@ func DeleteRepoLanguages(e Execer, filters ...filter) error { 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) diff --git a/appview/db/notifications.go b/appview/db/notifications.go index ab6741f4..a244fb84 100644 --- a/appview/db/notifications.go +++ b/appview/db/notifications.go @@ -11,6 +11,7 @@ import ( "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 { @@ -44,7 +45,7 @@ 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 @@ -113,7 +114,7 @@ func GetNotificationsPaginated(e Execer, page pagination.Page, filters ...filter } // 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 @@ -256,11 +257,11 @@ func GetNotificationsWithEntities(e Execer, page pagination.Page, filters ...fil } // 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 { @@ -285,8 +286,8 @@ func CountNotifications(e Execer, filters ...filter) (int64, error) { } 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 @@ -314,8 +315,8 @@ func MarkNotificationRead(e Execer, notificationID int64, userDID string) error } 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 @@ -334,8 +335,8 @@ func MarkAllNotificationsRead(e Execer, userDID string) error { } 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 @@ -362,7 +363,7 @@ func DeleteNotification(e Execer, notificationID int64, userDID string) error { } 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 } @@ -375,7 +376,7 @@ func GetNotificationPreference(e Execer, userDid string) (*models.NotificationPr 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 @@ -483,7 +484,7 @@ func (d *DB) UpdateNotificationPreferences(ctx context.Context, prefs *models.No 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 diff --git a/appview/db/pipeline.go b/appview/db/pipeline.go index 49d24a48..5afa3c59 100644 --- a/appview/db/pipeline.go +++ b/appview/db/pipeline.go @@ -7,9 +7,10 @@ import ( "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 @@ -168,11 +169,11 @@ func AddPipelineStatus(e Execer, status models.PipelineStatus) error { // 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()...) } @@ -264,8 +265,8 @@ func GetPipelineStatuses(e Execer, limit int, filters ...filter) ([]models.Pipel 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) diff --git a/appview/db/profile.go b/appview/db/profile.go index 426e973a..a366a9e1 100644 --- a/appview/db/profile.go +++ b/appview/db/profile.go @@ -11,6 +11,7 @@ import ( "github.com/bluesky-social/indigo/atproto/syntax" "tangled.org/core/appview/models" + "tangled.org/core/orm" ) const TimeframeMonths = 7 @@ -44,8 +45,8 @@ func MakeProfileTimeline(e Execer, forDid string) (*models.ProfileTimeline, erro 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) @@ -65,7 +66,7 @@ func MakeProfileTimeline(e Execer, forDid string) (*models.ProfileTimeline, erro *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) } @@ -199,7 +200,7 @@ func UpsertProfile(tx *sql.Tx, profile *models.Profile) error { 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 { @@ -441,7 +442,7 @@ func ValidateProfile(e Execer, profile *models.Profile) error { } // 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) } diff --git a/appview/db/pulls.go b/appview/db/pulls.go index e765a340..dc5ed3ce 100644 --- a/appview/db/pulls.go +++ b/appview/db/pulls.go @@ -13,6 +13,7 @@ import ( "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 { @@ -118,7 +119,7 @@ func NextPullId(e Execer, repoAt syntax.ATURI) (int, 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 @@ -229,7 +230,7 @@ func GetPullsWithLimit(e Execer, limit int, filters ...filter) ([]*models.Pull, 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) } @@ -241,7 +242,7 @@ func GetPullsWithLimit(e Execer, limit int, filters ...filter) ([]*models.Pull, } // 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) } @@ -258,7 +259,7 @@ func GetPullsWithLimit(e Execer, limit int, filters ...filter) ([]*models.Pull, 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) } @@ -274,7 +275,7 @@ func GetPullsWithLimit(e Execer, limit int, filters ...filter) ([]*models.Pull, } } - 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) } @@ -295,17 +296,17 @@ func GetPullsWithLimit(e Execer, limit int, filters ...filter) ([]*models.Pull, 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 @@ -361,7 +362,7 @@ func GetPullIDs(e Execer, opts models.PullSearchOptions) ([]int64, error) { } 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 } @@ -373,7 +374,7 @@ func GetPull(e Execer, repoAt syntax.ATURI, pullId int) (*models.Pull, error) { } // 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 { @@ -448,7 +449,7 @@ func GetPullSubmissions(e Execer, filters ...filter) (map[syntax.ATURI][]*models // 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) } @@ -474,7 +475,7 @@ func GetPullSubmissions(e Execer, filters ...filter) (map[syntax.ATURI][]*models 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 { @@ -542,7 +543,7 @@ func GetPullComments(e Execer, filters ...filter) ([]models.PullComment, error) // 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) } @@ -708,7 +709,7 @@ func ResubmitPull(e Execer, pullAt syntax.ATURI, newRoundNumber int, newPatch st 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 @@ -732,7 +733,7 @@ func SetPullParentChangeId(e Execer, parentChangeId string, filters ...filter) e // 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 @@ -790,8 +791,8 @@ func GetPullCount(e Execer, repoAt syntax.ATURI) (models.PullCount, error) { 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 @@ -835,8 +836,8 @@ func GetStack(e Execer, stackId string) (models.Stack, error) { 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 diff --git a/appview/db/punchcard.go b/appview/db/punchcard.go index 0ab2925c..fa88821b 100644 --- a/appview/db/punchcard.go +++ b/appview/db/punchcard.go @@ -7,6 +7,7 @@ import ( "time" "tangled.org/core/appview/models" + "tangled.org/core/orm" ) // this adds to the existing count @@ -20,7 +21,7 @@ func AddPunch(e Execer, punch models.Punch) error { 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) diff --git a/appview/db/reference.go b/appview/db/reference.go index ca56d865..0cb1fe3f 100644 --- a/appview/db/reference.go +++ b/appview/db/reference.go @@ -8,6 +8,7 @@ import ( "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. @@ -205,7 +206,7 @@ func deleteReferences(tx *sql.Tx, fromAt syntax.ATURI) error { 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 @@ -347,7 +348,7 @@ func getIssueCommentBacklinks(e Execer, aturis []syntax.ATURI) ([]models.RichRef 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 @@ -427,7 +428,7 @@ func getPullCommentBacklinks(e Execer, aturis []syntax.ATURI) ([]models.RichRefe 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 diff --git a/appview/db/registration.go b/appview/db/registration.go index 69c5bcf4..74fa4812 100644 --- a/appview/db/registration.go +++ b/appview/db/registration.go @@ -7,9 +7,10 @@ import ( "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 @@ -69,7 +70,7 @@ func GetRegistrations(e Execer, filters ...filter) ([]models.Registration, error 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 { @@ -94,7 +95,7 @@ func AddKnot(e Execer, domain, did string) error { 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 { diff --git a/appview/db/repos.go b/appview/db/repos.go index 1dfe7129..c06697b3 100644 --- a/appview/db/repos.go +++ b/appview/db/repos.go @@ -11,9 +11,10 @@ import ( "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 @@ -294,7 +295,7 @@ func GetRepos(e Execer, limit int, filters ...filter) ([]models.Repo, error) { } // 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 @@ -311,7 +312,7 @@ func GetRepo(e Execer, filters ...filter) (*models.Repo, error) { 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 { @@ -542,7 +543,7 @@ func SubscribeLabel(e Execer, rl *models.RepoLabel) error { 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 { @@ -560,7 +561,7 @@ func UnsubscribeLabel(e Execer, filters ...filter) error { 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 { diff --git a/appview/db/spindle.go b/appview/db/spindle.go index 98fbfcea..cafab70c 100644 --- a/appview/db/spindle.go +++ b/appview/db/spindle.go @@ -7,9 +7,10 @@ import ( "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 @@ -91,7 +92,7 @@ func AddSpindle(e Execer, spindle models.Spindle) error { 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 { @@ -114,7 +115,7 @@ func VerifySpindle(e Execer, filters ...filter) (int64, error) { 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 { @@ -144,7 +145,7 @@ func AddSpindleMember(e Execer, member models.SpindleMember) error { 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 { @@ -163,7 +164,7 @@ func RemoveSpindleMember(e Execer, filters ...filter) error { 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 diff --git a/appview/db/star.go b/appview/db/star.go index b95fde65..e4581060 100644 --- a/appview/db/star.go +++ b/appview/db/star.go @@ -11,6 +11,7 @@ import ( "github.com/bluesky-social/indigo/atproto/syntax" "tangled.org/core/appview/models" + "tangled.org/core/orm" ) func AddStar(e Execer, star *models.Star) error { @@ -133,7 +134,7 @@ func GetStarStatuses(e Execer, userDid string, subjectAts []syntax.ATURI) (map[s // 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 { @@ -195,7 +196,7 @@ func GetRepoStars(e Execer, limit int, filters ...filter) ([]models.RepoStar, er 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 } @@ -225,7 +226,7 @@ func GetRepoStars(e Execer, limit int, filters ...filter) ([]models.RepoStar, er 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 { @@ -298,7 +299,7 @@ func GetTopStarredReposLastWeek(e Execer) ([]models.Repo, error) { } // 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 } diff --git a/appview/db/strings.go b/appview/db/strings.go index 7e87e111..dc20070d 100644 --- a/appview/db/strings.go +++ b/appview/db/strings.go @@ -8,6 +8,7 @@ import ( "time" "tangled.org/core/appview/models" + "tangled.org/core/orm" ) func AddString(e Execer, s models.String) error { @@ -44,7 +45,7 @@ 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 @@ -127,7 +128,7 @@ func GetStrings(e Execer, limit int, filters ...filter) ([]models.String, error) 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 { @@ -151,7 +152,7 @@ func CountStrings(e Execer, filters ...filter) (int64, error) { 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 { diff --git a/appview/db/timeline.go b/appview/db/timeline.go index 4b90f1bb..0d4b905a 100644 --- a/appview/db/timeline.go +++ b/appview/db/timeline.go @@ -5,6 +5,7 @@ import ( "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 @@ -84,9 +85,9 @@ func getRepoStarInfo(repo *models.Repo, starStatuses map[string]bool) (bool, int } 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...) @@ -104,7 +105,7 @@ func getTimelineRepos(e Execer, limit int, loggedInUserDid string, userIsFollowi 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 @@ -144,9 +145,9 @@ func getTimelineRepos(e Execer, limit int, loggedInUserDid string, userIsFollowi } 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...) @@ -180,9 +181,9 @@ func getTimelineStars(e Execer, limit int, loggedInUserDid string, userIsFollowi } 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...) @@ -199,7 +200,7 @@ func getTimelineFollows(e Execer, limit int, loggedInUserDid string, userIsFollo return nil, nil } - profiles, err := GetProfiles(e, FilterIn("did", subjects)) + profiles, err := GetProfiles(e, orm.FilterIn("did", subjects)) if err != nil { return nil, err } diff --git a/appview/ingester.go b/appview/ingester.go index ee48d9d1..af1300ae 100644 --- a/appview/ingester.go +++ b/appview/ingester.go @@ -21,6 +21,7 @@ import ( "tangled.org/core/appview/serververify" "tangled.org/core/appview/validator" "tangled.org/core/idresolver" + "tangled.org/core/orm" "tangled.org/core/rbac" ) @@ -253,7 +254,7 @@ func (i *Ingester) ingestArtifact(e *jmodels.Event) error { 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 { @@ -350,7 +351,7 @@ func (i *Ingester) ingestProfile(e *jmodels.Event) error { 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 { @@ -424,8 +425,8 @@ func (i *Ingester) ingestSpindleMember(ctx context.Context, e *jmodels.Event) er // 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)) @@ -440,8 +441,8 @@ func (i *Ingester) ingestSpindleMember(ctx context.Context, e *jmodels.Event) er // 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) } @@ -523,8 +524,8 @@ func (i *Ingester) ingestSpindle(ctx context.Context, e *jmodels.Event) error { // 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)) @@ -543,8 +544,8 @@ func (i *Ingester) ingestSpindle(ctx context.Context, e *jmodels.Event) error { // 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 @@ -552,8 +553,8 @@ func (i *Ingester) ingestSpindle(ctx context.Context, e *jmodels.Event) error { 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 @@ -621,8 +622,8 @@ func (i *Ingester) ingestString(e *jmodels.Event) error { 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) @@ -740,8 +741,8 @@ func (i *Ingester) ingestKnot(e *jmodels.Event) error { // 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) @@ -762,8 +763,8 @@ func (i *Ingester) ingestKnot(e *jmodels.Event) error { 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 @@ -915,8 +916,8 @@ func (i *Ingester) ingestIssueComment(e *jmodels.Event) error { 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) } @@ -969,8 +970,8 @@ func (i *Ingester) ingestLabelDefinition(e *jmodels.Event) error { 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) } @@ -1010,7 +1011,7 @@ func (i *Ingester) ingestLabelOp(e *jmodels.Event) error { 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)) } @@ -1019,7 +1020,7 @@ func (i *Ingester) ingestLabelOp(e *jmodels.Event) error { 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) } diff --git a/appview/issues/issues.go b/appview/issues/issues.go index 2dc809ae..bc761e32 100644 --- a/appview/issues/issues.go +++ b/appview/issues/issues.go @@ -29,6 +29,7 @@ import ( "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" ) @@ -113,8 +114,8 @@ func (rp *Issues) RepoSingleIssue(w http.ResponseWriter, r *http.Request) { 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) @@ -314,7 +315,7 @@ func (rp *Issues) CloseIssue(w http.ResponseWriter, r *http.Request) { 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) @@ -361,7 +362,7 @@ func (rp *Issues) ReopenIssue(w http.ResponseWriter, r *http.Request) { 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) @@ -506,7 +507,7 @@ func (rp *Issues) IssueComment(w http.ResponseWriter, r *http.Request) { 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) @@ -542,7 +543,7 @@ func (rp *Issues) EditIssueComment(w http.ResponseWriter, r *http.Request) { 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) @@ -652,7 +653,7 @@ func (rp *Issues) ReplyIssueCommentPlaceholder(w http.ResponseWriter, r *http.Re 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) @@ -688,7 +689,7 @@ func (rp *Issues) ReplyIssueComment(w http.ResponseWriter, r *http.Request) { 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) @@ -724,7 +725,7 @@ func (rp *Issues) DeleteIssueComment(w http.ResponseWriter, r *http.Request) { 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) @@ -751,7 +752,7 @@ func (rp *Issues) DeleteIssueComment(w http.ResponseWriter, r *http.Request) { // 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") @@ -840,7 +841,7 @@ func (rp *Issues) RepoIssues(w http.ResponseWriter, r *http.Request) { 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) @@ -856,8 +857,8 @@ func (rp *Issues) RepoIssues(w http.ResponseWriter, r *http.Request) { 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) @@ -868,8 +869,8 @@ func (rp *Issues) RepoIssues(w http.ResponseWriter, r *http.Request) { 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) diff --git a/appview/knots/knots.go b/appview/knots/knots.go index 5ed0a78c..8ee33389 100644 --- a/appview/knots/knots.go +++ b/appview/knots/knots.go @@ -21,6 +21,7 @@ import ( "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" @@ -72,7 +73,7 @@ func (k *Knots) knots(w http.ResponseWriter, r *http.Request) { 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) @@ -102,8 +103,8 @@ func (k *Knots) dashboard(w http.ResponseWriter, r *http.Request) { 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) @@ -127,7 +128,7 @@ func (k *Knots) dashboard(w http.ResponseWriter, r *http.Request) { 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) @@ -293,8 +294,8 @@ func (k *Knots) delete(w http.ResponseWriter, r *http.Request) { // 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) @@ -321,8 +322,8 @@ func (k *Knots) delete(w http.ResponseWriter, r *http.Request) { 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) @@ -402,8 +403,8 @@ func (k *Knots) retry(w http.ResponseWriter, r *http.Request) { // 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) @@ -493,8 +494,8 @@ func (k *Knots) retry(w http.ResponseWriter, r *http.Request) { // 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) @@ -529,9 +530,9 @@ func (k *Knots) addMember(w http.ResponseWriter, r *http.Request) { 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) @@ -637,9 +638,9 @@ func (k *Knots) removeMember(w http.ResponseWriter, r *http.Request) { 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) diff --git a/appview/labels/labels.go b/appview/labels/labels.go index ab9740ac..ce5432b7 100644 --- a/appview/labels/labels.go +++ b/appview/labels/labels.go @@ -16,6 +16,7 @@ import ( "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" @@ -88,14 +89,14 @@ func (l *Labels) PerformLabelOp(w http.ResponseWriter, r *http.Request) { 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 @@ -106,14 +107,14 @@ func (l *Labels) PerformLabelOp(w http.ResponseWriter, r *http.Request) { 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 diff --git a/appview/middleware/middleware.go b/appview/middleware/middleware.go index 41b6a05c..65c252ac 100644 --- a/appview/middleware/middleware.go +++ b/appview/middleware/middleware.go @@ -18,6 +18,7 @@ import ( "tangled.org/core/appview/pagination" "tangled.org/core/appview/reporesolver" "tangled.org/core/idresolver" + "tangled.org/core/orm" "tangled.org/core/rbac" ) @@ -217,8 +218,8 @@ func (mw Middleware) ResolveRepo() middlewareFunc { 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) diff --git a/appview/notifications/notifications.go b/appview/notifications/notifications.go index c0962e77..b4b643ab 100644 --- a/appview/notifications/notifications.go +++ b/appview/notifications/notifications.go @@ -11,6 +11,7 @@ import ( "tangled.org/core/appview/oauth" "tangled.org/core/appview/pages" "tangled.org/core/appview/pagination" + "tangled.org/core/orm" ) type Notifications struct { @@ -53,7 +54,7 @@ func (n *Notifications) notificationsPage(w http.ResponseWriter, r *http.Request 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) @@ -64,7 +65,7 @@ func (n *Notifications) notificationsPage(w http.ResponseWriter, r *http.Request 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) @@ -96,8 +97,8 @@ func (n *Notifications) getUnreadCount(w http.ResponseWriter, r *http.Request) { 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) diff --git a/appview/notify/db/db.go b/appview/notify/db/db.go index 0cd55892..209368a3 100644 --- a/appview/notify/db/db.go +++ b/appview/notify/db/db.go @@ -12,6 +12,7 @@ import ( "tangled.org/core/appview/models" "tangled.org/core/appview/notify" "tangled.org/core/idresolver" + "tangled.org/core/orm" ) const ( @@ -42,7 +43,7 @@ func (n *databaseNotifier) NewStar(ctx context.Context, star *models.Star) { 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 @@ -80,7 +81,7 @@ func (n *databaseNotifier) NewIssue(ctx context.Context, issue *models.Issue, me // - 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 @@ -119,7 +120,7 @@ func (n *databaseNotifier) NewIssue(ctx context.Context, issue *models.Issue, me } 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 @@ -207,7 +208,7 @@ func (n *databaseNotifier) DeleteFollow(ctx context.Context, follow *models.Foll } 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 @@ -218,7 +219,7 @@ func (n *databaseNotifier) NewPull(ctx context.Context, pull *models.Pull) { // - 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 @@ -258,7 +259,7 @@ func (n *databaseNotifier) NewPullComment(ctx context.Context, comment *models.P 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 @@ -327,7 +328,7 @@ func (n *databaseNotifier) NewIssueState(ctx context.Context, actor syntax.DID, // - 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 @@ -366,7 +367,7 @@ func (n *databaseNotifier) NewIssueState(ctx context.Context, actor syntax.DID, 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 @@ -377,7 +378,7 @@ func (n *databaseNotifier) NewPullState(ctx context.Context, actor syntax.DID, p // - 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 @@ -443,7 +444,7 @@ func (n *databaseNotifier) notifyEvent( 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 diff --git a/appview/oauth/handler.go b/appview/oauth/handler.go index a5a0e2ff..f95e2aa5 100644 --- a/appview/oauth/handler.go +++ b/appview/oauth/handler.go @@ -16,6 +16,7 @@ import ( "tangled.org/core/api/tangled" "tangled.org/core/appview/db" "tangled.org/core/consts" + "tangled.org/core/orm" "tangled.org/core/tid" ) @@ -97,8 +98,8 @@ func (o *OAuth) addToDefaultSpindle(did string) { // 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) diff --git a/appview/pipelines/pipelines.go b/appview/pipelines/pipelines.go index 4e6b3c6e..d28ca623 100644 --- a/appview/pipelines/pipelines.go +++ b/appview/pipelines/pipelines.go @@ -16,6 +16,7 @@ import ( "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" @@ -81,9 +82,9 @@ func (p *Pipelines) Index(w http.ResponseWriter, r *http.Request) { 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) @@ -122,10 +123,10 @@ func (p *Pipelines) Workflow(w http.ResponseWriter, r *http.Request) { 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) @@ -189,10 +190,10 @@ func (p *Pipelines) Logs(w http.ResponseWriter, r *http.Request) { 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)) diff --git a/appview/pulls/opengraph.go b/appview/pulls/opengraph.go index c0b4bdd2..b5c228db 100644 --- a/appview/pulls/opengraph.go +++ b/appview/pulls/opengraph.go @@ -13,6 +13,7 @@ import ( "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" ) @@ -276,7 +277,7 @@ func (s *Pulls) PullOpenGraphSummary(w http.ResponseWriter, r *http.Request) { } // 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) } diff --git a/appview/pulls/pulls.go b/appview/pulls/pulls.go index 1f9ef88b..d73aa78a 100644 --- a/appview/pulls/pulls.go +++ b/appview/pulls/pulls.go @@ -30,6 +30,7 @@ import ( "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" @@ -190,10 +191,10 @@ func (s *Pulls) RepoSinglePull(w http.ResponseWriter, r *http.Request) { 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) @@ -217,8 +218,8 @@ func (s *Pulls) RepoSinglePull(w http.ResponseWriter, r *http.Request) { 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) @@ -597,7 +598,7 @@ func (s *Pulls) RepoPulls(w http.ResponseWriter, r *http.Request) { pulls, err := db.GetPulls( s.db, - db.FilterIn("id", ids), + orm.FilterIn("id", ids), ) if err != nil { log.Println("failed to get pulls", err) @@ -648,10 +649,10 @@ func (s *Pulls) RepoPulls(w http.ResponseWriter, r *http.Request) { 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) @@ -664,8 +665,8 @@ func (s *Pulls) RepoPulls(w http.ResponseWriter, r *http.Request) { 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) @@ -1498,8 +1499,8 @@ func (s *Pulls) CompareForksBranchesFragment(w http.ResponseWriter, r *http.Requ // 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) @@ -2066,9 +2067,9 @@ func (s *Pulls) resubmitStackedPullHelper( 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 { diff --git a/appview/repo/artifact.go b/appview/repo/artifact.go index 00d2ca56..195976f4 100644 --- a/appview/repo/artifact.go +++ b/appview/repo/artifact.go @@ -15,6 +15,7 @@ import ( "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" @@ -155,9 +156,9 @@ func (rp *Repo) DownloadArtifact(w http.ResponseWriter, r *http.Request) { 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) @@ -234,9 +235,9 @@ func (rp *Repo) DeleteArtifact(w http.ResponseWriter, r *http.Request) { 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) @@ -276,9 +277,9 @@ func (rp *Repo) DeleteArtifact(w http.ResponseWriter, r *http.Request) { 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) diff --git a/appview/repo/feed.go b/appview/repo/feed.go index 5a6a124b..c2d55279 100644 --- a/appview/repo/feed.go +++ b/appview/repo/feed.go @@ -11,6 +11,7 @@ import ( "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" @@ -20,7 +21,7 @@ import ( 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 } @@ -28,7 +29,7 @@ func (rp *Repo) getRepoFeed(ctx context.Context, repo *models.Repo, ownerSlashRe 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 diff --git a/appview/repo/index.go b/appview/repo/index.go index 726e9dd0..3c56f586 100644 --- a/appview/repo/index.go +++ b/appview/repo/index.go @@ -23,6 +23,7 @@ import ( "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" @@ -171,8 +172,8 @@ func (rp *Repo) getLanguageInfo( // 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 { diff --git a/appview/repo/opengraph.go b/appview/repo/opengraph.go index 9e766208..3bb47a00 100644 --- a/appview/repo/opengraph.go +++ b/appview/repo/opengraph.go @@ -16,6 +16,7 @@ import ( "tangled.org/core/appview/db" "tangled.org/core/appview/models" "tangled.org/core/appview/ogcard" + "tangled.org/core/orm" "tangled.org/core/types" ) @@ -338,8 +339,8 @@ func (rp *Repo) Opengraph(w http.ResponseWriter, r *http.Request) { 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) diff --git a/appview/repo/repo.go b/appview/repo/repo.go index eb83fdbc..4f1fba6b 100644 --- a/appview/repo/repo.go +++ b/appview/repo/repo.go @@ -24,6 +24,7 @@ import ( 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" @@ -345,7 +346,7 @@ func (rp *Repo) DeleteLabelDef(w http.ResponseWriter, r *http.Request) { // 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 @@ -409,15 +410,15 @@ func (rp *Repo) DeleteLabelDef(w http.ResponseWriter, r *http.Request) { 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 @@ -456,7 +457,7 @@ func (rp *Repo) SubscribeLabel(w http.ResponseWriter, r *http.Request) { } 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 @@ -542,7 +543,7 @@ func (rp *Repo) UnsubscribeLabel(w http.ResponseWriter, r *http.Request) { } 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 @@ -582,8 +583,8 @@ func (rp *Repo) UnsubscribeLabel(w http.ResponseWriter, r *http.Request) { 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) @@ -612,8 +613,8 @@ func (rp *Repo) LabelPanel(w http.ResponseWriter, r *http.Request) { 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) @@ -625,7 +626,7 @@ func (rp *Repo) LabelPanel(w http.ResponseWriter, r *http.Request) { 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 @@ -660,8 +661,8 @@ func (rp *Repo) EditLabelPanel(w http.ResponseWriter, r *http.Request) { 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) @@ -673,7 +674,7 @@ func (rp *Repo) EditLabelPanel(w http.ResponseWriter, r *http.Request) { 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 @@ -1036,8 +1037,8 @@ func (rp *Repo) ForkRepo(w http.ResponseWriter, r *http.Request) { // 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) { diff --git a/appview/repo/repo_util.go b/appview/repo/repo_util.go index 0955e3fd..7d40fc67 100644 --- a/appview/repo/repo_util.go +++ b/appview/repo/repo_util.go @@ -8,6 +8,7 @@ import ( "tangled.org/core/appview/db" "tangled.org/core/appview/models" + "tangled.org/core/orm" "tangled.org/core/types" ) @@ -102,10 +103,10 @@ func getPipelineStatuses( 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 diff --git a/appview/repo/settings.go b/appview/repo/settings.go index 3d8dc410..b1dd0a89 100644 --- a/appview/repo/settings.go +++ b/appview/repo/settings.go @@ -14,6 +14,7 @@ import ( "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" @@ -210,14 +211,14 @@ func (rp *Repo) generalSettings(w http.ResponseWriter, r *http.Request) { 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) diff --git a/appview/repo/tags.go b/appview/repo/tags.go index 6319795d..783e02d2 100644 --- a/appview/repo/tags.go +++ b/appview/repo/tags.go @@ -10,6 +10,7 @@ import ( "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" @@ -44,7 +45,7 @@ func (rp *Repo) Tags(w http.ResponseWriter, r *http.Request) { 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 diff --git a/appview/serververify/verify.go b/appview/serververify/verify.go index dbe93420..2a5c5e58 100644 --- a/appview/serververify/verify.go +++ b/appview/serververify/verify.go @@ -9,6 +9,7 @@ import ( "tangled.org/core/api/tangled" "tangled.org/core/appview/db" "tangled.org/core/appview/xrpcclient" + "tangled.org/core/orm" "tangled.org/core/rbac" ) @@ -76,8 +77,8 @@ func MarkSpindleVerified(d *db.DB, e *rbac.Enforcer, instance, owner string) (in // 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) @@ -115,8 +116,8 @@ func MarkKnotVerified(d *db.DB, e *rbac.Enforcer, domain, owner string) error { // 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) diff --git a/appview/spindles/spindles.go b/appview/spindles/spindles.go index d362c091..0a89d729 100644 --- a/appview/spindles/spindles.go +++ b/appview/spindles/spindles.go @@ -20,6 +20,7 @@ import ( "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" @@ -71,7 +72,7 @@ func (s *Spindles) spindles(w http.ResponseWriter, r *http.Request) { 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) @@ -101,9 +102,9 @@ func (s *Spindles) dashboard(w http.ResponseWriter, r *http.Request) { 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)) @@ -123,7 +124,7 @@ func (s *Spindles) dashboard(w http.ResponseWriter, r *http.Request) { 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) @@ -290,8 +291,8 @@ func (s *Spindles) delete(w http.ResponseWriter, r *http.Request) { 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)) @@ -319,8 +320,8 @@ func (s *Spindles) delete(w http.ResponseWriter, r *http.Request) { // 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) @@ -330,8 +331,8 @@ func (s *Spindles) delete(w http.ResponseWriter, r *http.Request) { 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) @@ -410,8 +411,8 @@ func (s *Spindles) retry(w http.ResponseWriter, r *http.Request) { 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)) @@ -453,7 +454,7 @@ func (s *Spindles) retry(w http.ResponseWriter, r *http.Request) { 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) @@ -486,8 +487,8 @@ func (s *Spindles) addMember(w http.ResponseWriter, r *http.Request) { 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)) @@ -622,8 +623,8 @@ func (s *Spindles) removeMember(w http.ResponseWriter, r *http.Request) { 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)) @@ -672,9 +673,9 @@ func (s *Spindles) removeMember(w http.ResponseWriter, r *http.Request) { // 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) @@ -685,9 +686,9 @@ func (s *Spindles) removeMember(w http.ResponseWriter, r *http.Request) { // 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() diff --git a/appview/state/gfi.go b/appview/state/gfi.go index 1f6ff42d..63fa3bba 100644 --- a/appview/state/gfi.go +++ b/appview/state/gfi.go @@ -11,6 +11,7 @@ import ( "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) { @@ -20,14 +21,14 @@ 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) @@ -55,8 +56,8 @@ func (s *State) GoodFirstIssues(w http.ResponseWriter, r *http.Request) { 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) @@ -132,7 +133,7 @@ func (s *State) GoodFirstIssues(w http.ResponseWriter, r *http.Request) { } 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) } diff --git a/appview/state/knotstream.go b/appview/state/knotstream.go index 7a149184..2c7a6cfa 100644 --- a/appview/state/knotstream.go +++ b/appview/state/knotstream.go @@ -16,6 +16,7 @@ import ( 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" @@ -30,7 +31,7 @@ func Knotstream(ctx context.Context, c *config.Config, d *db.DB, enforcer *rbac. knots, err := db.GetRegistrations( d, - db.FilterIsNot("registered", "null"), + orm.FilterIsNot("registered", "null"), ) if err != nil { return nil, err @@ -143,8 +144,8 @@ func updateRepoLanguages(d *db.DB, record tangled.GitRefUpdate) error { 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) @@ -209,8 +210,8 @@ func ingestPipeline(d *db.DB, source ec.Source, msg ec.Message) error { 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) diff --git a/appview/state/profile.go b/appview/state/profile.go index 7b8353a0..400725ac 100644 --- a/appview/state/profile.go +++ b/appview/state/profile.go @@ -19,6 +19,7 @@ import ( "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) { @@ -56,17 +57,17 @@ func (s *State) profile(r *http.Request) (*pages.ProfileCard, error) { 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) } @@ -86,9 +87,9 @@ func (s *State) profile(r *http.Request) (*pages.ProfileCard, error) { 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) @@ -123,7 +124,7 @@ func (s *State) profileOverview(w http.ResponseWriter, r *http.Request) { 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) @@ -193,7 +194,7 @@ func (s *State) reposPage(w http.ResponseWriter, r *http.Request) { 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) @@ -219,7 +220,7 @@ func (s *State) starredPage(w http.ResponseWriter, r *http.Request) { } 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) @@ -248,7 +249,7 @@ func (s *State) stringsPage(w http.ResponseWriter, r *http.Request) { } 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) @@ -300,7 +301,7 @@ func (s *State) followPage( 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 ¶ms, err @@ -703,7 +704,7 @@ func (s *State) EditPinsFragment(w http.ResponseWriter, r *http.Request) { 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) } diff --git a/appview/state/spindlestream.go b/appview/state/spindlestream.go index 994e2298..a63d1305 100644 --- a/appview/state/spindlestream.go +++ b/appview/state/spindlestream.go @@ -17,6 +17,7 @@ import ( 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" ) @@ -27,7 +28,7 @@ func Spindlestream(ctx context.Context, c *config.Config, d *db.DB, enforcer *rb spindles, err := db.GetSpindles( d, - db.FilterIsNot("verified", "null"), + orm.FilterIsNot("verified", "null"), ) if err != nil { return nil, err diff --git a/appview/state/state.go b/appview/state/state.go index 2d0cf176..11d94a5d 100644 --- a/appview/state/state.go +++ b/appview/state/state.go @@ -30,6 +30,7 @@ import ( "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" @@ -299,7 +300,7 @@ func (s *State) Timeline(w http.ResponseWriter, r *http.Request) { 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 } @@ -323,8 +324,8 @@ func (s *State) UpgradeBanner(w http.ResponseWriter, r *http.Request) { 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) @@ -332,8 +333,8 @@ func (s *State) UpgradeBanner(w http.ResponseWriter, r *http.Request) { 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) @@ -504,8 +505,8 @@ func (s *State) NewRepo(w http.ResponseWriter, r *http.Request) { // 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") @@ -665,7 +666,7 @@ func rollbackRecord(ctx context.Context, aturi string, client *atpclient.APIClie } 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 } diff --git a/appview/strings/strings.go b/appview/strings/strings.go index f0029fa6..f12beb8c 100644 --- a/appview/strings/strings.go +++ b/appview/strings/strings.go @@ -17,6 +17,7 @@ import ( "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" @@ -108,8 +109,8 @@ func (s *Strings) contents(w http.ResponseWriter, r *http.Request) { 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) @@ -199,8 +200,8 @@ func (s *Strings) edit(w http.ResponseWriter, r *http.Request) { 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) @@ -408,8 +409,8 @@ func (s *Strings) delete(w http.ResponseWriter, r *http.Request) { 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 diff --git a/appview/validator/issue.go b/appview/validator/issue.go index 17aa6a73..b199f513 100644 --- a/appview/validator/issue.go +++ b/appview/validator/issue.go @@ -6,12 +6,13 @@ import ( "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) } diff --git a/orm/orm.go b/orm/orm.go new file mode 100644 index 00000000..c0f111da --- /dev/null +++ b/orm/orm.go @@ -0,0 +1,122 @@ +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} +} -- 2.43.0