Monorepo for Tangled tangled.org

orm: extract orm package from appview #875

merged opened by oppi.li targeting master from op/zxpquyouulmx

includes query and migration helpers

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

Labels

None yet.

assignee

None yet.

Participants 2
AT URI
at://did:plc:qfpnj4og54vl56wngdriaxug/sh.tangled.repo.pull/3m7mtqstsqz22
+519 -464
Diff #0
+3 -2
appview/db/artifact.go
··· 8 8 "github.com/go-git/go-git/v5/plumbing" 9 9 "github.com/ipfs/go-cid" 10 10 "tangled.org/core/appview/models" 11 + "tangled.org/core/orm" 11 12 ) 12 13 13 14 func AddArtifact(e Execer, artifact models.Artifact) error { ··· 37 38 return err 38 39 } 39 40 40 - func GetArtifact(e Execer, filters ...filter) ([]models.Artifact, error) { 41 + func GetArtifact(e Execer, filters ...orm.Filter) ([]models.Artifact, error) { 41 42 var artifacts []models.Artifact 42 43 43 44 var conditions []string ··· 109 110 return artifacts, nil 110 111 } 111 112 112 - func DeleteArtifact(e Execer, filters ...filter) error { 113 + func DeleteArtifact(e Execer, filters ...orm.Filter) error { 113 114 var conditions []string 114 115 var args []any 115 116 for _, filter := range filters {
+4 -3
appview/db/collaborators.go
··· 6 6 "time" 7 7 8 8 "tangled.org/core/appview/models" 9 + "tangled.org/core/orm" 9 10 ) 10 11 11 12 func AddCollaborator(e Execer, c models.Collaborator) error { ··· 16 17 return err 17 18 } 18 19 19 - func DeleteCollaborator(e Execer, filters ...filter) error { 20 + func DeleteCollaborator(e Execer, filters ...orm.Filter) error { 20 21 var conditions []string 21 22 var args []any 22 23 for _, filter := range filters { ··· 58 59 return nil, nil 59 60 } 60 61 61 - return GetRepos(e, 0, FilterIn("at_uri", repoAts)) 62 + return GetRepos(e, 0, orm.FilterIn("at_uri", repoAts)) 62 63 } 63 64 64 - func GetCollaborators(e Execer, filters ...filter) ([]models.Collaborator, error) { 65 + func GetCollaborators(e Execer, filters ...orm.Filter) ([]models.Collaborator, error) { 65 66 var collaborators []models.Collaborator 66 67 var conditions []string 67 68 var args []any
+24 -137
appview/db/db.go
··· 3 3 import ( 4 4 "context" 5 5 "database/sql" 6 - "fmt" 7 6 "log/slog" 8 - "reflect" 9 7 "strings" 10 8 11 9 _ "github.com/mattn/go-sqlite3" 12 10 "tangled.org/core/log" 11 + "tangled.org/core/orm" 13 12 ) 14 13 15 14 type DB struct { ··· 584 583 } 585 584 586 585 // run migrations 587 - runMigration(conn, logger, "add-description-to-repos", func(tx *sql.Tx) error { 586 + orm.RunMigration(conn, logger, "add-description-to-repos", func(tx *sql.Tx) error { 588 587 tx.Exec(` 589 588 alter table repos add column description text check (length(description) <= 200); 590 589 `) 591 590 return nil 592 591 }) 593 592 594 - runMigration(conn, logger, "add-rkey-to-pubkeys", func(tx *sql.Tx) error { 593 + orm.RunMigration(conn, logger, "add-rkey-to-pubkeys", func(tx *sql.Tx) error { 595 594 // add unconstrained column 596 595 _, err := tx.Exec(` 597 596 alter table public_keys ··· 614 613 return nil 615 614 }) 616 615 617 - runMigration(conn, logger, "add-rkey-to-comments", func(tx *sql.Tx) error { 616 + orm.RunMigration(conn, logger, "add-rkey-to-comments", func(tx *sql.Tx) error { 618 617 _, err := tx.Exec(` 619 618 alter table comments drop column comment_at; 620 619 alter table comments add column rkey text; ··· 622 621 return err 623 622 }) 624 623 625 - runMigration(conn, logger, "add-deleted-and-edited-to-issue-comments", func(tx *sql.Tx) error { 624 + orm.RunMigration(conn, logger, "add-deleted-and-edited-to-issue-comments", func(tx *sql.Tx) error { 626 625 _, err := tx.Exec(` 627 626 alter table comments add column deleted text; -- timestamp 628 627 alter table comments add column edited text; -- timestamp ··· 630 629 return err 631 630 }) 632 631 633 - runMigration(conn, logger, "add-source-info-to-pulls-and-submissions", func(tx *sql.Tx) error { 632 + orm.RunMigration(conn, logger, "add-source-info-to-pulls-and-submissions", func(tx *sql.Tx) error { 634 633 _, err := tx.Exec(` 635 634 alter table pulls add column source_branch text; 636 635 alter table pulls add column source_repo_at text; ··· 639 638 return err 640 639 }) 641 640 642 - runMigration(conn, logger, "add-source-to-repos", func(tx *sql.Tx) error { 641 + orm.RunMigration(conn, logger, "add-source-to-repos", func(tx *sql.Tx) error { 643 642 _, err := tx.Exec(` 644 643 alter table repos add column source text; 645 644 `) ··· 651 650 // 652 651 // [0]: https://sqlite.org/pragma.html#pragma_foreign_keys 653 652 conn.ExecContext(ctx, "pragma foreign_keys = off;") 654 - runMigration(conn, logger, "recreate-pulls-column-for-stacking-support", func(tx *sql.Tx) error { 653 + orm.RunMigration(conn, logger, "recreate-pulls-column-for-stacking-support", func(tx *sql.Tx) error { 655 654 _, err := tx.Exec(` 656 655 create table pulls_new ( 657 656 -- identifiers ··· 708 707 }) 709 708 conn.ExecContext(ctx, "pragma foreign_keys = on;") 710 709 711 - runMigration(conn, logger, "add-spindle-to-repos", func(tx *sql.Tx) error { 710 + orm.RunMigration(conn, logger, "add-spindle-to-repos", func(tx *sql.Tx) error { 712 711 tx.Exec(` 713 712 alter table repos add column spindle text; 714 713 `) ··· 718 717 // drop all knot secrets, add unique constraint to knots 719 718 // 720 719 // knots will henceforth use service auth for signed requests 721 - runMigration(conn, logger, "no-more-secrets", func(tx *sql.Tx) error { 720 + orm.RunMigration(conn, logger, "no-more-secrets", func(tx *sql.Tx) error { 722 721 _, err := tx.Exec(` 723 722 create table registrations_new ( 724 723 id integer primary key autoincrement, ··· 741 740 }) 742 741 743 742 // recreate and add rkey + created columns with default constraint 744 - runMigration(conn, logger, "rework-collaborators-table", func(tx *sql.Tx) error { 743 + orm.RunMigration(conn, logger, "rework-collaborators-table", func(tx *sql.Tx) error { 745 744 // create new table 746 745 // - repo_at instead of repo integer 747 746 // - rkey field ··· 795 794 return err 796 795 }) 797 796 798 - runMigration(conn, logger, "add-rkey-to-issues", func(tx *sql.Tx) error { 797 + orm.RunMigration(conn, logger, "add-rkey-to-issues", func(tx *sql.Tx) error { 799 798 _, err := tx.Exec(` 800 799 alter table issues add column rkey text not null default ''; 801 800 ··· 807 806 }) 808 807 809 808 // repurpose the read-only column to "needs-upgrade" 810 - runMigration(conn, logger, "rename-registrations-read-only-to-needs-upgrade", func(tx *sql.Tx) error { 809 + orm.RunMigration(conn, logger, "rename-registrations-read-only-to-needs-upgrade", func(tx *sql.Tx) error { 811 810 _, err := tx.Exec(` 812 811 alter table registrations rename column read_only to needs_upgrade; 813 812 `) ··· 815 814 }) 816 815 817 816 // require all knots to upgrade after the release of total xrpc 818 - runMigration(conn, logger, "migrate-knots-to-total-xrpc", func(tx *sql.Tx) error { 817 + orm.RunMigration(conn, logger, "migrate-knots-to-total-xrpc", func(tx *sql.Tx) error { 819 818 _, err := tx.Exec(` 820 819 update registrations set needs_upgrade = 1; 821 820 `) ··· 823 822 }) 824 823 825 824 // require all knots to upgrade after the release of total xrpc 826 - runMigration(conn, logger, "migrate-spindles-to-xrpc-owner", func(tx *sql.Tx) error { 825 + orm.RunMigration(conn, logger, "migrate-spindles-to-xrpc-owner", func(tx *sql.Tx) error { 827 826 _, err := tx.Exec(` 828 827 alter table spindles add column needs_upgrade integer not null default 0; 829 828 `) ··· 841 840 // 842 841 // disable foreign-keys for the next migration 843 842 conn.ExecContext(ctx, "pragma foreign_keys = off;") 844 - runMigration(conn, logger, "remove-issue-at-from-issues", func(tx *sql.Tx) error { 843 + orm.RunMigration(conn, logger, "remove-issue-at-from-issues", func(tx *sql.Tx) error { 845 844 _, err := tx.Exec(` 846 845 create table if not exists issues_new ( 847 846 -- identifiers ··· 911 910 // - new columns 912 911 // * column "reply_to" which can be any other comment 913 912 // * column "at-uri" which is a generated column 914 - runMigration(conn, logger, "rework-issue-comments", func(tx *sql.Tx) error { 913 + orm.RunMigration(conn, logger, "rework-issue-comments", func(tx *sql.Tx) error { 915 914 _, err := tx.Exec(` 916 915 create table if not exists issue_comments ( 917 916 -- identifiers ··· 971 970 // 972 971 // disable foreign-keys for the next migration 973 972 conn.ExecContext(ctx, "pragma foreign_keys = off;") 974 - runMigration(conn, logger, "add-at-uri-to-pulls", func(tx *sql.Tx) error { 973 + orm.RunMigration(conn, logger, "add-at-uri-to-pulls", func(tx *sql.Tx) error { 975 974 _, err := tx.Exec(` 976 975 create table if not exists pulls_new ( 977 976 -- identifiers ··· 1052 1051 // 1053 1052 // disable foreign-keys for the next migration 1054 1053 conn.ExecContext(ctx, "pragma foreign_keys = off;") 1055 - runMigration(conn, logger, "remove-repo-at-pull-id-from-pull-submissions", func(tx *sql.Tx) error { 1054 + orm.RunMigration(conn, logger, "remove-repo-at-pull-id-from-pull-submissions", func(tx *sql.Tx) error { 1056 1055 _, err := tx.Exec(` 1057 1056 create table if not exists pull_submissions_new ( 1058 1057 -- identifiers ··· 1106 1105 1107 1106 // knots may report the combined patch for a comparison, we can store that on the appview side 1108 1107 // (but not on the pds record), because calculating the combined patch requires a git index 1109 - runMigration(conn, logger, "add-combined-column-submissions", func(tx *sql.Tx) error { 1108 + orm.RunMigration(conn, logger, "add-combined-column-submissions", func(tx *sql.Tx) error { 1110 1109 _, err := tx.Exec(` 1111 1110 alter table pull_submissions add column combined text; 1112 1111 `) 1113 1112 return err 1114 1113 }) 1115 1114 1116 - runMigration(conn, logger, "add-pronouns-profile", func(tx *sql.Tx) error { 1115 + orm.RunMigration(conn, logger, "add-pronouns-profile", func(tx *sql.Tx) error { 1117 1116 _, err := tx.Exec(` 1118 1117 alter table profile add column pronouns text; 1119 1118 `) 1120 1119 return err 1121 1120 }) 1122 1121 1123 - runMigration(conn, logger, "add-meta-column-repos", func(tx *sql.Tx) error { 1122 + orm.RunMigration(conn, logger, "add-meta-column-repos", func(tx *sql.Tx) error { 1124 1123 _, err := tx.Exec(` 1125 1124 alter table repos add column website text; 1126 1125 alter table repos add column topics text; ··· 1128 1127 return err 1129 1128 }) 1130 1129 1131 - runMigration(conn, logger, "add-usermentioned-preference", func(tx *sql.Tx) error { 1130 + orm.RunMigration(conn, logger, "add-usermentioned-preference", func(tx *sql.Tx) error { 1132 1131 _, err := tx.Exec(` 1133 1132 alter table notification_preferences add column user_mentioned integer not null default 1; 1134 1133 `) ··· 1136 1135 }) 1137 1136 1138 1137 // remove the foreign key constraints from stars. 1139 - runMigration(conn, logger, "generalize-stars-subject", func(tx *sql.Tx) error { 1138 + orm.RunMigration(conn, logger, "generalize-stars-subject", func(tx *sql.Tx) error { 1140 1139 _, err := tx.Exec(` 1141 1140 create table stars_new ( 1142 1141 id integer primary key autoincrement, ··· 1180 1179 }, nil 1181 1180 } 1182 1181 1183 - type migrationFn = func(*sql.Tx) error 1184 - 1185 - func runMigration(c *sql.Conn, logger *slog.Logger, name string, migrationFn migrationFn) error { 1186 - logger = logger.With("migration", name) 1187 - 1188 - tx, err := c.BeginTx(context.Background(), nil) 1189 - if err != nil { 1190 - return err 1191 - } 1192 - defer tx.Rollback() 1193 - 1194 - var exists bool 1195 - err = tx.QueryRow("select exists (select 1 from migrations where name = ?)", name).Scan(&exists) 1196 - if err != nil { 1197 - return err 1198 - } 1199 - 1200 - if !exists { 1201 - // run migration 1202 - err = migrationFn(tx) 1203 - if err != nil { 1204 - logger.Error("failed to run migration", "err", err) 1205 - return err 1206 - } 1207 - 1208 - // mark migration as complete 1209 - _, err = tx.Exec("insert into migrations (name) values (?)", name) 1210 - if err != nil { 1211 - logger.Error("failed to mark migration as complete", "err", err) 1212 - return err 1213 - } 1214 - 1215 - // commit the transaction 1216 - if err := tx.Commit(); err != nil { 1217 - return err 1218 - } 1219 - 1220 - logger.Info("migration applied successfully") 1221 - } else { 1222 - logger.Warn("skipped migration, already applied") 1223 - } 1224 - 1225 - return nil 1226 - } 1227 - 1228 1182 func (d *DB) Close() error { 1229 1183 return d.DB.Close() 1230 1184 } 1231 - 1232 - type filter struct { 1233 - key string 1234 - arg any 1235 - cmp string 1236 - } 1237 - 1238 - func newFilter(key, cmp string, arg any) filter { 1239 - return filter{ 1240 - key: key, 1241 - arg: arg, 1242 - cmp: cmp, 1243 - } 1244 - } 1245 - 1246 - func FilterEq(key string, arg any) filter { return newFilter(key, "=", arg) } 1247 - func FilterNotEq(key string, arg any) filter { return newFilter(key, "<>", arg) } 1248 - func FilterGte(key string, arg any) filter { return newFilter(key, ">=", arg) } 1249 - func FilterLte(key string, arg any) filter { return newFilter(key, "<=", arg) } 1250 - func FilterIs(key string, arg any) filter { return newFilter(key, "is", arg) } 1251 - func FilterIsNot(key string, arg any) filter { return newFilter(key, "is not", arg) } 1252 - func FilterIn(key string, arg any) filter { return newFilter(key, "in", arg) } 1253 - func FilterLike(key string, arg any) filter { return newFilter(key, "like", arg) } 1254 - func FilterNotLike(key string, arg any) filter { return newFilter(key, "not like", arg) } 1255 - func FilterContains(key string, arg any) filter { 1256 - return newFilter(key, "like", fmt.Sprintf("%%%v%%", arg)) 1257 - } 1258 - 1259 - func (f filter) Condition() string { 1260 - rv := reflect.ValueOf(f.arg) 1261 - kind := rv.Kind() 1262 - 1263 - // if we have `FilterIn(k, [1, 2, 3])`, compile it down to `k in (?, ?, ?)` 1264 - if (kind == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8) || kind == reflect.Array { 1265 - if rv.Len() == 0 { 1266 - // always false 1267 - return "1 = 0" 1268 - } 1269 - 1270 - placeholders := make([]string, rv.Len()) 1271 - for i := range placeholders { 1272 - placeholders[i] = "?" 1273 - } 1274 - 1275 - return fmt.Sprintf("%s %s (%s)", f.key, f.cmp, strings.Join(placeholders, ", ")) 1276 - } 1277 - 1278 - return fmt.Sprintf("%s %s ?", f.key, f.cmp) 1279 - } 1280 - 1281 - func (f filter) Arg() []any { 1282 - rv := reflect.ValueOf(f.arg) 1283 - kind := rv.Kind() 1284 - if (kind == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8) || kind == reflect.Array { 1285 - if rv.Len() == 0 { 1286 - return nil 1287 - } 1288 - 1289 - out := make([]any, rv.Len()) 1290 - for i := range rv.Len() { 1291 - out[i] = rv.Index(i).Interface() 1292 - } 1293 - return out 1294 - } 1295 - 1296 - return []any{f.arg} 1297 - }
+4 -3
appview/db/follow.go
··· 7 7 "time" 8 8 9 9 "tangled.org/core/appview/models" 10 + "tangled.org/core/orm" 10 11 ) 11 12 12 13 func AddFollow(e Execer, follow *models.Follow) error { ··· 134 135 return result, nil 135 136 } 136 137 137 - func GetFollows(e Execer, limit int, filters ...filter) ([]models.Follow, error) { 138 + func GetFollows(e Execer, limit int, filters ...orm.Filter) ([]models.Follow, error) { 138 139 var follows []models.Follow 139 140 140 141 var conditions []string ··· 191 192 } 192 193 193 194 func GetFollowers(e Execer, did string) ([]models.Follow, error) { 194 - return GetFollows(e, 0, FilterEq("subject_did", did)) 195 + return GetFollows(e, 0, orm.FilterEq("subject_did", did)) 195 196 } 196 197 197 198 func GetFollowing(e Execer, did string) ([]models.Follow, error) { 198 - return GetFollows(e, 0, FilterEq("user_did", did)) 199 + return GetFollows(e, 0, orm.FilterEq("user_did", did)) 199 200 } 200 201 201 202 func getFollowStatuses(e Execer, userDid string, subjectDids []string) (map[string]models.FollowStatus, error) {
+21 -20
appview/db/issues.go
··· 13 13 "tangled.org/core/api/tangled" 14 14 "tangled.org/core/appview/models" 15 15 "tangled.org/core/appview/pagination" 16 + "tangled.org/core/orm" 16 17 ) 17 18 18 19 func PutIssue(tx *sql.Tx, issue *models.Issue) error { ··· 27 28 28 29 issues, err := GetIssues( 29 30 tx, 30 - FilterEq("did", issue.Did), 31 - FilterEq("rkey", issue.Rkey), 31 + orm.FilterEq("did", issue.Did), 32 + orm.FilterEq("rkey", issue.Rkey), 32 33 ) 33 34 switch { 34 35 case err != nil: ··· 98 99 return nil 99 100 } 100 101 101 - func GetIssuesPaginated(e Execer, page pagination.Page, filters ...filter) ([]models.Issue, error) { 102 + func GetIssuesPaginated(e Execer, page pagination.Page, filters ...orm.Filter) ([]models.Issue, error) { 102 103 issueMap := make(map[string]*models.Issue) // at-uri -> issue 103 104 104 105 var conditions []string ··· 114 115 whereClause = " where " + strings.Join(conditions, " and ") 115 116 } 116 117 117 - pLower := FilterGte("row_num", page.Offset+1) 118 - pUpper := FilterLte("row_num", page.Offset+page.Limit) 118 + pLower := orm.FilterGte("row_num", page.Offset+1) 119 + pUpper := orm.FilterLte("row_num", page.Offset+page.Limit) 119 120 120 121 pageClause := "" 121 122 if page.Limit > 0 { ··· 205 206 repoAts = append(repoAts, string(issue.RepoAt)) 206 207 } 207 208 208 - repos, err := GetRepos(e, 0, FilterIn("at_uri", repoAts)) 209 + repos, err := GetRepos(e, 0, orm.FilterIn("at_uri", repoAts)) 209 210 if err != nil { 210 211 return nil, fmt.Errorf("failed to build repo mappings: %w", err) 211 212 } ··· 228 229 // collect comments 229 230 issueAts := slices.Collect(maps.Keys(issueMap)) 230 231 231 - comments, err := GetIssueComments(e, FilterIn("issue_at", issueAts)) 232 + comments, err := GetIssueComments(e, orm.FilterIn("issue_at", issueAts)) 232 233 if err != nil { 233 234 return nil, fmt.Errorf("failed to query comments: %w", err) 234 235 } ··· 240 241 } 241 242 242 243 // collect allLabels for each issue 243 - allLabels, err := GetLabels(e, FilterIn("subject", issueAts)) 244 + allLabels, err := GetLabels(e, orm.FilterIn("subject", issueAts)) 244 245 if err != nil { 245 246 return nil, fmt.Errorf("failed to query labels: %w", err) 246 247 } ··· 251 252 } 252 253 253 254 // collect references for each issue 254 - allReferencs, err := GetReferencesAll(e, FilterIn("from_at", issueAts)) 255 + allReferencs, err := GetReferencesAll(e, orm.FilterIn("from_at", issueAts)) 255 256 if err != nil { 256 257 return nil, fmt.Errorf("failed to query reference_links: %w", err) 257 258 } ··· 277 278 issues, err := GetIssuesPaginated( 278 279 e, 279 280 pagination.Page{}, 280 - FilterEq("repo_at", repoAt), 281 - FilterEq("issue_id", issueId), 281 + orm.FilterEq("repo_at", repoAt), 282 + orm.FilterEq("issue_id", issueId), 282 283 ) 283 284 if err != nil { 284 285 return nil, err ··· 290 291 return &issues[0], nil 291 292 } 292 293 293 - func GetIssues(e Execer, filters ...filter) ([]models.Issue, error) { 294 + func GetIssues(e Execer, filters ...orm.Filter) ([]models.Issue, error) { 294 295 return GetIssuesPaginated(e, pagination.Page{}, filters...) 295 296 } 296 297 ··· 298 299 func GetIssueIDs(e Execer, opts models.IssueSearchOptions) ([]int64, error) { 299 300 var ids []int64 300 301 301 - var filters []filter 302 + var filters []orm.Filter 302 303 openValue := 0 303 304 if opts.IsOpen { 304 305 openValue = 1 305 306 } 306 - filters = append(filters, FilterEq("open", openValue)) 307 + filters = append(filters, orm.FilterEq("open", openValue)) 307 308 if opts.RepoAt != "" { 308 - filters = append(filters, FilterEq("repo_at", opts.RepoAt)) 309 + filters = append(filters, orm.FilterEq("repo_at", opts.RepoAt)) 309 310 } 310 311 311 312 var conditions []string ··· 397 398 return id, nil 398 399 } 399 400 400 - func DeleteIssueComments(e Execer, filters ...filter) error { 401 + func DeleteIssueComments(e Execer, filters ...orm.Filter) error { 401 402 var conditions []string 402 403 var args []any 403 404 for _, filter := range filters { ··· 416 417 return err 417 418 } 418 419 419 - func GetIssueComments(e Execer, filters ...filter) ([]models.IssueComment, error) { 420 + func GetIssueComments(e Execer, filters ...orm.Filter) ([]models.IssueComment, error) { 420 421 commentMap := make(map[string]*models.IssueComment) 421 422 422 423 var conditions []string ··· 506 507 507 508 // collect references for each comments 508 509 commentAts := slices.Collect(maps.Keys(commentMap)) 509 - allReferencs, err := GetReferencesAll(e, FilterIn("from_at", commentAts)) 510 + allReferencs, err := GetReferencesAll(e, orm.FilterIn("from_at", commentAts)) 510 511 if err != nil { 511 512 return nil, fmt.Errorf("failed to query reference_links: %w", err) 512 513 } ··· 548 549 return nil 549 550 } 550 551 551 - func CloseIssues(e Execer, filters ...filter) error { 552 + func CloseIssues(e Execer, filters ...orm.Filter) error { 552 553 var conditions []string 553 554 var args []any 554 555 for _, filter := range filters { ··· 566 567 return err 567 568 } 568 569 569 - func ReopenIssues(e Execer, filters ...filter) error { 570 + func ReopenIssues(e Execer, filters ...orm.Filter) error { 570 571 var conditions []string 571 572 var args []any 572 573 for _, filter := range filters {
+8 -7
appview/db/label.go
··· 10 10 11 11 "github.com/bluesky-social/indigo/atproto/syntax" 12 12 "tangled.org/core/appview/models" 13 + "tangled.org/core/orm" 13 14 ) 14 15 15 16 // no updating type for now ··· 59 60 return id, nil 60 61 } 61 62 62 - func DeleteLabelDefinition(e Execer, filters ...filter) error { 63 + func DeleteLabelDefinition(e Execer, filters ...orm.Filter) error { 63 64 var conditions []string 64 65 var args []any 65 66 for _, filter := range filters { ··· 75 76 return err 76 77 } 77 78 78 - func GetLabelDefinitions(e Execer, filters ...filter) ([]models.LabelDefinition, error) { 79 + func GetLabelDefinitions(e Execer, filters ...orm.Filter) ([]models.LabelDefinition, error) { 79 80 var labelDefinitions []models.LabelDefinition 80 81 var conditions []string 81 82 var args []any ··· 167 168 } 168 169 169 170 // helper to get exactly one label def 170 - func GetLabelDefinition(e Execer, filters ...filter) (*models.LabelDefinition, error) { 171 + func GetLabelDefinition(e Execer, filters ...orm.Filter) (*models.LabelDefinition, error) { 171 172 labels, err := GetLabelDefinitions(e, filters...) 172 173 if err != nil { 173 174 return nil, err ··· 227 228 return id, nil 228 229 } 229 230 230 - func GetLabelOps(e Execer, filters ...filter) ([]models.LabelOp, error) { 231 + func GetLabelOps(e Execer, filters ...orm.Filter) ([]models.LabelOp, error) { 231 232 var labelOps []models.LabelOp 232 233 var conditions []string 233 234 var args []any ··· 302 303 } 303 304 304 305 // get labels for a given list of subject URIs 305 - func GetLabels(e Execer, filters ...filter) (map[syntax.ATURI]models.LabelState, error) { 306 + func GetLabels(e Execer, filters ...orm.Filter) (map[syntax.ATURI]models.LabelState, error) { 306 307 ops, err := GetLabelOps(e, filters...) 307 308 if err != nil { 308 309 return nil, err ··· 322 323 } 323 324 labelAts := slices.Collect(maps.Keys(labelAtSet)) 324 325 325 - actx, err := NewLabelApplicationCtx(e, FilterIn("at_uri", labelAts)) 326 + actx, err := NewLabelApplicationCtx(e, orm.FilterIn("at_uri", labelAts)) 326 327 if err != nil { 327 328 return nil, err 328 329 } ··· 338 339 return results, nil 339 340 } 340 341 341 - func NewLabelApplicationCtx(e Execer, filters ...filter) (*models.LabelApplicationCtx, error) { 342 + func NewLabelApplicationCtx(e Execer, filters ...orm.Filter) (*models.LabelApplicationCtx, error) { 342 343 labels, err := GetLabelDefinitions(e, filters...) 343 344 if err != nil { 344 345 return nil, err
+5 -4
appview/db/language.go
··· 7 7 8 8 "github.com/bluesky-social/indigo/atproto/syntax" 9 9 "tangled.org/core/appview/models" 10 + "tangled.org/core/orm" 10 11 ) 11 12 12 - func GetRepoLanguages(e Execer, filters ...filter) ([]models.RepoLanguage, error) { 13 + func GetRepoLanguages(e Execer, filters ...orm.Filter) ([]models.RepoLanguage, error) { 13 14 var conditions []string 14 15 var args []any 15 16 for _, filter := range filters { ··· 85 86 return nil 86 87 } 87 88 88 - func DeleteRepoLanguages(e Execer, filters ...filter) error { 89 + func DeleteRepoLanguages(e Execer, filters ...orm.Filter) error { 89 90 var conditions []string 90 91 var args []any 91 92 for _, filter := range filters { ··· 107 108 func UpdateRepoLanguages(tx *sql.Tx, repoAt syntax.ATURI, ref string, langs []models.RepoLanguage) error { 108 109 err := DeleteRepoLanguages( 109 110 tx, 110 - FilterEq("repo_at", repoAt), 111 - FilterEq("ref", ref), 111 + orm.FilterEq("repo_at", repoAt), 112 + orm.FilterEq("ref", ref), 112 113 ) 113 114 if err != nil { 114 115 return fmt.Errorf("failed to delete existing languages: %w", err)
+14 -13
appview/db/notifications.go
··· 11 11 "github.com/bluesky-social/indigo/atproto/syntax" 12 12 "tangled.org/core/appview/models" 13 13 "tangled.org/core/appview/pagination" 14 + "tangled.org/core/orm" 14 15 ) 15 16 16 17 func CreateNotification(e Execer, notification *models.Notification) error { ··· 44 45 } 45 46 46 47 // GetNotificationsPaginated retrieves notifications with filters and pagination 47 - func GetNotificationsPaginated(e Execer, page pagination.Page, filters ...filter) ([]*models.Notification, error) { 48 + func GetNotificationsPaginated(e Execer, page pagination.Page, filters ...orm.Filter) ([]*models.Notification, error) { 48 49 var conditions []string 49 50 var args []any 50 51 ··· 113 114 } 114 115 115 116 // GetNotificationsWithEntities retrieves notifications with their related entities 116 - func GetNotificationsWithEntities(e Execer, page pagination.Page, filters ...filter) ([]*models.NotificationWithEntity, error) { 117 + func GetNotificationsWithEntities(e Execer, page pagination.Page, filters ...orm.Filter) ([]*models.NotificationWithEntity, error) { 117 118 var conditions []string 118 119 var args []any 119 120 ··· 256 257 } 257 258 258 259 // GetNotifications retrieves notifications with filters 259 - func GetNotifications(e Execer, filters ...filter) ([]*models.Notification, error) { 260 + func GetNotifications(e Execer, filters ...orm.Filter) ([]*models.Notification, error) { 260 261 return GetNotificationsPaginated(e, pagination.FirstPage(), filters...) 261 262 } 262 263 263 - func CountNotifications(e Execer, filters ...filter) (int64, error) { 264 + func CountNotifications(e Execer, filters ...orm.Filter) (int64, error) { 264 265 var conditions []string 265 266 var args []any 266 267 for _, filter := range filters { ··· 285 286 } 286 287 287 288 func MarkNotificationRead(e Execer, notificationID int64, userDID string) error { 288 - idFilter := FilterEq("id", notificationID) 289 - recipientFilter := FilterEq("recipient_did", userDID) 289 + idFilter := orm.FilterEq("id", notificationID) 290 + recipientFilter := orm.FilterEq("recipient_did", userDID) 290 291 291 292 query := fmt.Sprintf(` 292 293 UPDATE notifications ··· 314 315 } 315 316 316 317 func MarkAllNotificationsRead(e Execer, userDID string) error { 317 - recipientFilter := FilterEq("recipient_did", userDID) 318 - readFilter := FilterEq("read", 0) 318 + recipientFilter := orm.FilterEq("recipient_did", userDID) 319 + readFilter := orm.FilterEq("read", 0) 319 320 320 321 query := fmt.Sprintf(` 321 322 UPDATE notifications ··· 334 335 } 335 336 336 337 func DeleteNotification(e Execer, notificationID int64, userDID string) error { 337 - idFilter := FilterEq("id", notificationID) 338 - recipientFilter := FilterEq("recipient_did", userDID) 338 + idFilter := orm.FilterEq("id", notificationID) 339 + recipientFilter := orm.FilterEq("recipient_did", userDID) 339 340 340 341 query := fmt.Sprintf(` 341 342 DELETE FROM notifications ··· 362 363 } 363 364 364 365 func GetNotificationPreference(e Execer, userDid string) (*models.NotificationPreferences, error) { 365 - prefs, err := GetNotificationPreferences(e, FilterEq("user_did", userDid)) 366 + prefs, err := GetNotificationPreferences(e, orm.FilterEq("user_did", userDid)) 366 367 if err != nil { 367 368 return nil, err 368 369 } ··· 375 376 return p, nil 376 377 } 377 378 378 - func GetNotificationPreferences(e Execer, filters ...filter) (map[syntax.DID]*models.NotificationPreferences, error) { 379 + func GetNotificationPreferences(e Execer, filters ...orm.Filter) (map[syntax.DID]*models.NotificationPreferences, error) { 379 380 prefsMap := make(map[syntax.DID]*models.NotificationPreferences) 380 381 381 382 var conditions []string ··· 483 484 484 485 func (d *DB) ClearOldNotifications(ctx context.Context, olderThan time.Duration) error { 485 486 cutoff := time.Now().Add(-olderThan) 486 - createdFilter := FilterLte("created", cutoff) 487 + createdFilter := orm.FilterLte("created", cutoff) 487 488 488 489 query := fmt.Sprintf(` 489 490 DELETE FROM notifications
+6 -5
appview/db/pipeline.go
··· 7 7 "time" 8 8 9 9 "tangled.org/core/appview/models" 10 + "tangled.org/core/orm" 10 11 ) 11 12 12 - func GetPipelines(e Execer, filters ...filter) ([]models.Pipeline, error) { 13 + func GetPipelines(e Execer, filters ...orm.Filter) ([]models.Pipeline, error) { 13 14 var pipelines []models.Pipeline 14 15 15 16 var conditions []string ··· 168 169 169 170 // this is a mega query, but the most useful one: 170 171 // get N pipelines, for each one get the latest status of its N workflows 171 - func GetPipelineStatuses(e Execer, limit int, filters ...filter) ([]models.Pipeline, error) { 172 + func GetPipelineStatuses(e Execer, limit int, filters ...orm.Filter) ([]models.Pipeline, error) { 172 173 var conditions []string 173 174 var args []any 174 175 for _, filter := range filters { 175 - filter.key = "p." + filter.key // the table is aliased in the query to `p` 176 + filter.Key = "p." + filter.Key // the table is aliased in the query to `p` 176 177 conditions = append(conditions, filter.Condition()) 177 178 args = append(args, filter.Arg()...) 178 179 } ··· 264 265 conditions = nil 265 266 args = nil 266 267 for _, p := range pipelines { 267 - knotFilter := FilterEq("pipeline_knot", p.Knot) 268 - rkeyFilter := FilterEq("pipeline_rkey", p.Rkey) 268 + knotFilter := orm.FilterEq("pipeline_knot", p.Knot) 269 + rkeyFilter := orm.FilterEq("pipeline_rkey", p.Rkey) 269 270 conditions = append(conditions, fmt.Sprintf("(%s and %s)", knotFilter.Condition(), rkeyFilter.Condition())) 270 271 args = append(args, p.Knot) 271 272 args = append(args, p.Rkey)
+6 -5
appview/db/profile.go
··· 11 11 12 12 "github.com/bluesky-social/indigo/atproto/syntax" 13 13 "tangled.org/core/appview/models" 14 + "tangled.org/core/orm" 14 15 ) 15 16 16 17 const TimeframeMonths = 7 ··· 44 45 45 46 issues, err := GetIssues( 46 47 e, 47 - FilterEq("did", forDid), 48 - FilterGte("created", time.Now().AddDate(0, -TimeframeMonths, 0)), 48 + orm.FilterEq("did", forDid), 49 + orm.FilterGte("created", time.Now().AddDate(0, -TimeframeMonths, 0)), 49 50 ) 50 51 if err != nil { 51 52 return nil, fmt.Errorf("error getting issues by owner did: %w", err) ··· 65 66 *items = append(*items, &issue) 66 67 } 67 68 68 - repos, err := GetRepos(e, 0, FilterEq("did", forDid)) 69 + repos, err := GetRepos(e, 0, orm.FilterEq("did", forDid)) 69 70 if err != nil { 70 71 return nil, fmt.Errorf("error getting all repos by did: %w", err) 71 72 } ··· 199 200 return tx.Commit() 200 201 } 201 202 202 - func GetProfiles(e Execer, filters ...filter) (map[string]*models.Profile, error) { 203 + func GetProfiles(e Execer, filters ...orm.Filter) (map[string]*models.Profile, error) { 203 204 var conditions []string 204 205 var args []any 205 206 for _, filter := range filters { ··· 441 442 } 442 443 443 444 // ensure all pinned repos are either own repos or collaborating repos 444 - repos, err := GetRepos(e, 0, FilterEq("did", profile.Did)) 445 + repos, err := GetRepos(e, 0, orm.FilterEq("did", profile.Did)) 445 446 if err != nil { 446 447 log.Printf("getting repos for %s: %s", profile.Did, err) 447 448 }
+21 -20
appview/db/pulls.go
··· 13 13 14 14 "github.com/bluesky-social/indigo/atproto/syntax" 15 15 "tangled.org/core/appview/models" 16 + "tangled.org/core/orm" 16 17 ) 17 18 18 19 func NewPull(tx *sql.Tx, pull *models.Pull) error { ··· 118 119 return pullId - 1, err 119 120 } 120 121 121 - func GetPullsWithLimit(e Execer, limit int, filters ...filter) ([]*models.Pull, error) { 122 + func GetPullsWithLimit(e Execer, limit int, filters ...orm.Filter) ([]*models.Pull, error) { 122 123 pulls := make(map[syntax.ATURI]*models.Pull) 123 124 124 125 var conditions []string ··· 229 230 for _, p := range pulls { 230 231 pullAts = append(pullAts, p.AtUri()) 231 232 } 232 - submissionsMap, err := GetPullSubmissions(e, FilterIn("pull_at", pullAts)) 233 + submissionsMap, err := GetPullSubmissions(e, orm.FilterIn("pull_at", pullAts)) 233 234 if err != nil { 234 235 return nil, fmt.Errorf("failed to get submissions: %w", err) 235 236 } ··· 241 242 } 242 243 243 244 // collect allLabels for each issue 244 - allLabels, err := GetLabels(e, FilterIn("subject", pullAts)) 245 + allLabels, err := GetLabels(e, orm.FilterIn("subject", pullAts)) 245 246 if err != nil { 246 247 return nil, fmt.Errorf("failed to query labels: %w", err) 247 248 } ··· 258 259 sourceAts = append(sourceAts, *p.PullSource.RepoAt) 259 260 } 260 261 } 261 - sourceRepos, err := GetRepos(e, 0, FilterIn("at_uri", sourceAts)) 262 + sourceRepos, err := GetRepos(e, 0, orm.FilterIn("at_uri", sourceAts)) 262 263 if err != nil && !errors.Is(err, sql.ErrNoRows) { 263 264 return nil, fmt.Errorf("failed to get source repos: %w", err) 264 265 } ··· 274 275 } 275 276 } 276 277 277 - allReferences, err := GetReferencesAll(e, FilterIn("from_at", pullAts)) 278 + allReferences, err := GetReferencesAll(e, orm.FilterIn("from_at", pullAts)) 278 279 if err != nil { 279 280 return nil, fmt.Errorf("failed to query reference_links: %w", err) 280 281 } ··· 295 296 return orderedByPullId, nil 296 297 } 297 298 298 - func GetPulls(e Execer, filters ...filter) ([]*models.Pull, error) { 299 + func GetPulls(e Execer, filters ...orm.Filter) ([]*models.Pull, error) { 299 300 return GetPullsWithLimit(e, 0, filters...) 300 301 } 301 302 302 303 func GetPullIDs(e Execer, opts models.PullSearchOptions) ([]int64, error) { 303 304 var ids []int64 304 305 305 - var filters []filter 306 - filters = append(filters, FilterEq("state", opts.State)) 306 + var filters []orm.Filter 307 + filters = append(filters, orm.FilterEq("state", opts.State)) 307 308 if opts.RepoAt != "" { 308 - filters = append(filters, FilterEq("repo_at", opts.RepoAt)) 309 + filters = append(filters, orm.FilterEq("repo_at", opts.RepoAt)) 309 310 } 310 311 311 312 var conditions []string ··· 361 362 } 362 363 363 364 func GetPull(e Execer, repoAt syntax.ATURI, pullId int) (*models.Pull, error) { 364 - pulls, err := GetPullsWithLimit(e, 1, FilterEq("repo_at", repoAt), FilterEq("pull_id", pullId)) 365 + pulls, err := GetPullsWithLimit(e, 1, orm.FilterEq("repo_at", repoAt), orm.FilterEq("pull_id", pullId)) 365 366 if err != nil { 366 367 return nil, err 367 368 } ··· 373 374 } 374 375 375 376 // mapping from pull -> pull submissions 376 - func GetPullSubmissions(e Execer, filters ...filter) (map[syntax.ATURI][]*models.PullSubmission, error) { 377 + func GetPullSubmissions(e Execer, filters ...orm.Filter) (map[syntax.ATURI][]*models.PullSubmission, error) { 377 378 var conditions []string 378 379 var args []any 379 380 for _, filter := range filters { ··· 448 449 449 450 // Get comments for all submissions using GetPullComments 450 451 submissionIds := slices.Collect(maps.Keys(submissionMap)) 451 - comments, err := GetPullComments(e, FilterIn("submission_id", submissionIds)) 452 + comments, err := GetPullComments(e, orm.FilterIn("submission_id", submissionIds)) 452 453 if err != nil { 453 454 return nil, fmt.Errorf("failed to get pull comments: %w", err) 454 455 } ··· 474 475 return m, nil 475 476 } 476 477 477 - func GetPullComments(e Execer, filters ...filter) ([]models.PullComment, error) { 478 + func GetPullComments(e Execer, filters ...orm.Filter) ([]models.PullComment, error) { 478 479 var conditions []string 479 480 var args []any 480 481 for _, filter := range filters { ··· 542 543 543 544 // collect references for each comments 544 545 commentAts := slices.Collect(maps.Keys(commentMap)) 545 - allReferencs, err := GetReferencesAll(e, FilterIn("from_at", commentAts)) 546 + allReferencs, err := GetReferencesAll(e, orm.FilterIn("from_at", commentAts)) 546 547 if err != nil { 547 548 return nil, fmt.Errorf("failed to query reference_links: %w", err) 548 549 } ··· 708 709 return err 709 710 } 710 711 711 - func SetPullParentChangeId(e Execer, parentChangeId string, filters ...filter) error { 712 + func SetPullParentChangeId(e Execer, parentChangeId string, filters ...orm.Filter) error { 712 713 var conditions []string 713 714 var args []any 714 715 ··· 732 733 733 734 // Only used when stacking to update contents in the event of a rebase (the interdiff should be empty). 734 735 // otherwise submissions are immutable 735 - func UpdatePull(e Execer, newPatch, sourceRev string, filters ...filter) error { 736 + func UpdatePull(e Execer, newPatch, sourceRev string, filters ...orm.Filter) error { 736 737 var conditions []string 737 738 var args []any 738 739 ··· 790 791 func GetStack(e Execer, stackId string) (models.Stack, error) { 791 792 unorderedPulls, err := GetPulls( 792 793 e, 793 - FilterEq("stack_id", stackId), 794 - FilterNotEq("state", models.PullDeleted), 794 + orm.FilterEq("stack_id", stackId), 795 + orm.FilterNotEq("state", models.PullDeleted), 795 796 ) 796 797 if err != nil { 797 798 return nil, err ··· 835 836 func GetAbandonedPulls(e Execer, stackId string) ([]*models.Pull, error) { 836 837 pulls, err := GetPulls( 837 838 e, 838 - FilterEq("stack_id", stackId), 839 - FilterEq("state", models.PullDeleted), 839 + orm.FilterEq("stack_id", stackId), 840 + orm.FilterEq("state", models.PullDeleted), 840 841 ) 841 842 if err != nil { 842 843 return nil, err
+2 -1
appview/db/punchcard.go
··· 7 7 "time" 8 8 9 9 "tangled.org/core/appview/models" 10 + "tangled.org/core/orm" 10 11 ) 11 12 12 13 // this adds to the existing count ··· 20 21 return err 21 22 } 22 23 23 - func MakePunchcard(e Execer, filters ...filter) (*models.Punchcard, error) { 24 + func MakePunchcard(e Execer, filters ...orm.Filter) (*models.Punchcard, error) { 24 25 punchcard := &models.Punchcard{} 25 26 now := time.Now() 26 27 startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC)
+4 -3
appview/db/reference.go
··· 8 8 "github.com/bluesky-social/indigo/atproto/syntax" 9 9 "tangled.org/core/api/tangled" 10 10 "tangled.org/core/appview/models" 11 + "tangled.org/core/orm" 11 12 ) 12 13 13 14 // ValidateReferenceLinks resolves refLinks to Issue/PR/IssueComment/PullComment ATURIs. ··· 205 206 return err 206 207 } 207 208 208 - func GetReferencesAll(e Execer, filters ...filter) (map[syntax.ATURI][]syntax.ATURI, error) { 209 + func GetReferencesAll(e Execer, filters ...orm.Filter) (map[syntax.ATURI][]syntax.ATURI, error) { 209 210 var ( 210 211 conditions []string 211 212 args []any ··· 347 348 if len(aturis) == 0 { 348 349 return nil, nil 349 350 } 350 - filter := FilterIn("c.at_uri", aturis) 351 + filter := orm.FilterIn("c.at_uri", aturis) 351 352 rows, err := e.Query( 352 353 fmt.Sprintf( 353 354 `select r.did, r.name, i.issue_id, c.id, i.title, i.open ··· 427 428 if len(aturis) == 0 { 428 429 return nil, nil 429 430 } 430 - filter := FilterIn("c.comment_at", aturis) 431 + filter := orm.FilterIn("c.comment_at", aturis) 431 432 rows, err := e.Query( 432 433 fmt.Sprintf( 433 434 `select r.did, r.name, p.pull_id, c.id, p.title, p.state
+4 -3
appview/db/registration.go
··· 7 7 "time" 8 8 9 9 "tangled.org/core/appview/models" 10 + "tangled.org/core/orm" 10 11 ) 11 12 12 - func GetRegistrations(e Execer, filters ...filter) ([]models.Registration, error) { 13 + func GetRegistrations(e Execer, filters ...orm.Filter) ([]models.Registration, error) { 13 14 var registrations []models.Registration 14 15 15 16 var conditions []string ··· 69 70 return registrations, nil 70 71 } 71 72 72 - func MarkRegistered(e Execer, filters ...filter) error { 73 + func MarkRegistered(e Execer, filters ...orm.Filter) error { 73 74 var conditions []string 74 75 var args []any 75 76 for _, filter := range filters { ··· 94 95 return err 95 96 } 96 97 97 - func DeleteKnot(e Execer, filters ...filter) error { 98 + func DeleteKnot(e Execer, filters ...orm.Filter) error { 98 99 var conditions []string 99 100 var args []any 100 101 for _, filter := range filters {
+6 -5
appview/db/repos.go
··· 11 11 12 12 "github.com/bluesky-social/indigo/atproto/syntax" 13 13 "tangled.org/core/appview/models" 14 + "tangled.org/core/orm" 14 15 ) 15 16 16 - func GetRepos(e Execer, limit int, filters ...filter) ([]models.Repo, error) { 17 + func GetRepos(e Execer, limit int, filters ...orm.Filter) ([]models.Repo, error) { 17 18 repoMap := make(map[syntax.ATURI]*models.Repo) 18 19 19 20 var conditions []string ··· 294 295 } 295 296 296 297 // helper to get exactly one repo 297 - func GetRepo(e Execer, filters ...filter) (*models.Repo, error) { 298 + func GetRepo(e Execer, filters ...orm.Filter) (*models.Repo, error) { 298 299 repos, err := GetRepos(e, 0, filters...) 299 300 if err != nil { 300 301 return nil, err ··· 311 312 return &repos[0], nil 312 313 } 313 314 314 - func CountRepos(e Execer, filters ...filter) (int64, error) { 315 + func CountRepos(e Execer, filters ...orm.Filter) (int64, error) { 315 316 var conditions []string 316 317 var args []any 317 318 for _, filter := range filters { ··· 542 543 return err 543 544 } 544 545 545 - func UnsubscribeLabel(e Execer, filters ...filter) error { 546 + func UnsubscribeLabel(e Execer, filters ...orm.Filter) error { 546 547 var conditions []string 547 548 var args []any 548 549 for _, filter := range filters { ··· 560 561 return err 561 562 } 562 563 563 - func GetRepoLabels(e Execer, filters ...filter) ([]models.RepoLabel, error) { 564 + func GetRepoLabels(e Execer, filters ...orm.Filter) ([]models.RepoLabel, error) { 564 565 var conditions []string 565 566 var args []any 566 567 for _, filter := range filters {
+6 -5
appview/db/spindle.go
··· 7 7 "time" 8 8 9 9 "tangled.org/core/appview/models" 10 + "tangled.org/core/orm" 10 11 ) 11 12 12 - func GetSpindles(e Execer, filters ...filter) ([]models.Spindle, error) { 13 + func GetSpindles(e Execer, filters ...orm.Filter) ([]models.Spindle, error) { 13 14 var spindles []models.Spindle 14 15 15 16 var conditions []string ··· 91 92 return err 92 93 } 93 94 94 - func VerifySpindle(e Execer, filters ...filter) (int64, error) { 95 + func VerifySpindle(e Execer, filters ...orm.Filter) (int64, error) { 95 96 var conditions []string 96 97 var args []any 97 98 for _, filter := range filters { ··· 114 115 return res.RowsAffected() 115 116 } 116 117 117 - func DeleteSpindle(e Execer, filters ...filter) error { 118 + func DeleteSpindle(e Execer, filters ...orm.Filter) error { 118 119 var conditions []string 119 120 var args []any 120 121 for _, filter := range filters { ··· 144 145 return err 145 146 } 146 147 147 - func RemoveSpindleMember(e Execer, filters ...filter) error { 148 + func RemoveSpindleMember(e Execer, filters ...orm.Filter) error { 148 149 var conditions []string 149 150 var args []any 150 151 for _, filter := range filters { ··· 163 164 return err 164 165 } 165 166 166 - func GetSpindleMembers(e Execer, filters ...filter) ([]models.SpindleMember, error) { 167 + func GetSpindleMembers(e Execer, filters ...orm.Filter) ([]models.SpindleMember, error) { 167 168 var members []models.SpindleMember 168 169 169 170 var conditions []string
+5 -4
appview/db/star.go
··· 11 11 12 12 "github.com/bluesky-social/indigo/atproto/syntax" 13 13 "tangled.org/core/appview/models" 14 + "tangled.org/core/orm" 14 15 ) 15 16 16 17 func AddStar(e Execer, star *models.Star) error { ··· 133 134 134 135 // GetRepoStars return a list of stars each holding target repository. 135 136 // If there isn't known repo with starred at-uri, those stars will be ignored. 136 - func GetRepoStars(e Execer, limit int, filters ...filter) ([]models.RepoStar, error) { 137 + func GetRepoStars(e Execer, limit int, filters ...orm.Filter) ([]models.RepoStar, error) { 137 138 var conditions []string 138 139 var args []any 139 140 for _, filter := range filters { ··· 195 196 return nil, nil 196 197 } 197 198 198 - repos, err := GetRepos(e, 0, FilterIn("at_uri", args)) 199 + repos, err := GetRepos(e, 0, orm.FilterIn("at_uri", args)) 199 200 if err != nil { 200 201 return nil, err 201 202 } ··· 225 226 return repoStars, nil 226 227 } 227 228 228 - func CountStars(e Execer, filters ...filter) (int64, error) { 229 + func CountStars(e Execer, filters ...orm.Filter) (int64, error) { 229 230 var conditions []string 230 231 var args []any 231 232 for _, filter := range filters { ··· 298 299 } 299 300 300 301 // get full repo data 301 - repos, err := GetRepos(e, 0, FilterIn("at_uri", repoUris)) 302 + repos, err := GetRepos(e, 0, orm.FilterIn("at_uri", repoUris)) 302 303 if err != nil { 303 304 return nil, err 304 305 }
+4 -3
appview/db/strings.go
··· 8 8 "time" 9 9 10 10 "tangled.org/core/appview/models" 11 + "tangled.org/core/orm" 11 12 ) 12 13 13 14 func AddString(e Execer, s models.String) error { ··· 44 45 return err 45 46 } 46 47 47 - func GetStrings(e Execer, limit int, filters ...filter) ([]models.String, error) { 48 + func GetStrings(e Execer, limit int, filters ...orm.Filter) ([]models.String, error) { 48 49 var all []models.String 49 50 50 51 var conditions []string ··· 127 128 return all, nil 128 129 } 129 130 130 - func CountStrings(e Execer, filters ...filter) (int64, error) { 131 + func CountStrings(e Execer, filters ...orm.Filter) (int64, error) { 131 132 var conditions []string 132 133 var args []any 133 134 for _, filter := range filters { ··· 151 152 return count, nil 152 153 } 153 154 154 - func DeleteString(e Execer, filters ...filter) error { 155 + func DeleteString(e Execer, filters ...orm.Filter) error { 155 156 var conditions []string 156 157 var args []any 157 158 for _, filter := range filters {
+9 -8
appview/db/timeline.go
··· 5 5 6 6 "github.com/bluesky-social/indigo/atproto/syntax" 7 7 "tangled.org/core/appview/models" 8 + "tangled.org/core/orm" 8 9 ) 9 10 10 11 // TODO: this gathers heterogenous events from different sources and aggregates ··· 84 85 } 85 86 86 87 func getTimelineRepos(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { 87 - filters := make([]filter, 0) 88 + filters := make([]orm.Filter, 0) 88 89 if userIsFollowing != nil { 89 - filters = append(filters, FilterIn("did", userIsFollowing)) 90 + filters = append(filters, orm.FilterIn("did", userIsFollowing)) 90 91 } 91 92 92 93 repos, err := GetRepos(e, limit, filters...) ··· 104 105 105 106 var origRepos []models.Repo 106 107 if args != nil { 107 - origRepos, err = GetRepos(e, 0, FilterIn("at_uri", args)) 108 + origRepos, err = GetRepos(e, 0, orm.FilterIn("at_uri", args)) 108 109 } 109 110 if err != nil { 110 111 return nil, err ··· 144 145 } 145 146 146 147 func getTimelineStars(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { 147 - filters := make([]filter, 0) 148 + filters := make([]orm.Filter, 0) 148 149 if userIsFollowing != nil { 149 - filters = append(filters, FilterIn("did", userIsFollowing)) 150 + filters = append(filters, orm.FilterIn("did", userIsFollowing)) 150 151 } 151 152 152 153 stars, err := GetRepoStars(e, limit, filters...) ··· 180 181 } 181 182 182 183 func getTimelineFollows(e Execer, limit int, loggedInUserDid string, userIsFollowing []string) ([]models.TimelineEvent, error) { 183 - filters := make([]filter, 0) 184 + filters := make([]orm.Filter, 0) 184 185 if userIsFollowing != nil { 185 - filters = append(filters, FilterIn("user_did", userIsFollowing)) 186 + filters = append(filters, orm.FilterIn("user_did", userIsFollowing)) 186 187 } 187 188 188 189 follows, err := GetFollows(e, limit, filters...) ··· 199 200 return nil, nil 200 201 } 201 202 202 - profiles, err := GetProfiles(e, FilterIn("did", subjects)) 203 + profiles, err := GetProfiles(e, orm.FilterIn("did", subjects)) 203 204 if err != nil { 204 205 return nil, err 205 206 }
+25 -24
appview/ingester.go
··· 21 21 "tangled.org/core/appview/serververify" 22 22 "tangled.org/core/appview/validator" 23 23 "tangled.org/core/idresolver" 24 + "tangled.org/core/orm" 24 25 "tangled.org/core/rbac" 25 26 ) 26 27 ··· 253 254 254 255 err = db.AddArtifact(i.Db, artifact) 255 256 case jmodels.CommitOperationDelete: 256 - err = db.DeleteArtifact(i.Db, db.FilterEq("did", did), db.FilterEq("rkey", e.Commit.RKey)) 257 + err = db.DeleteArtifact(i.Db, orm.FilterEq("did", did), orm.FilterEq("rkey", e.Commit.RKey)) 257 258 } 258 259 259 260 if err != nil { ··· 350 351 351 352 err = db.UpsertProfile(tx, &profile) 352 353 case jmodels.CommitOperationDelete: 353 - err = db.DeleteArtifact(i.Db, db.FilterEq("did", did), db.FilterEq("rkey", e.Commit.RKey)) 354 + err = db.DeleteArtifact(i.Db, orm.FilterEq("did", did), orm.FilterEq("rkey", e.Commit.RKey)) 354 355 } 355 356 356 357 if err != nil { ··· 424 425 // get record from db first 425 426 members, err := db.GetSpindleMembers( 426 427 ddb, 427 - db.FilterEq("did", did), 428 - db.FilterEq("rkey", rkey), 428 + orm.FilterEq("did", did), 429 + orm.FilterEq("rkey", rkey), 429 430 ) 430 431 if err != nil || len(members) != 1 { 431 432 return fmt.Errorf("failed to get member: %w, len(members) = %d", err, len(members)) ··· 440 441 // remove record by rkey && update enforcer 441 442 if err = db.RemoveSpindleMember( 442 443 tx, 443 - db.FilterEq("did", did), 444 - db.FilterEq("rkey", rkey), 444 + orm.FilterEq("did", did), 445 + orm.FilterEq("rkey", rkey), 445 446 ); err != nil { 446 447 return fmt.Errorf("failed to remove from db: %w", err) 447 448 } ··· 523 524 // get record from db first 524 525 spindles, err := db.GetSpindles( 525 526 ddb, 526 - db.FilterEq("owner", did), 527 - db.FilterEq("instance", instance), 527 + orm.FilterEq("owner", did), 528 + orm.FilterEq("instance", instance), 528 529 ) 529 530 if err != nil || len(spindles) != 1 { 530 531 return fmt.Errorf("failed to get spindles: %w, len(spindles) = %d", err, len(spindles)) ··· 543 544 // remove spindle members first 544 545 err = db.RemoveSpindleMember( 545 546 tx, 546 - db.FilterEq("owner", did), 547 - db.FilterEq("instance", instance), 547 + orm.FilterEq("owner", did), 548 + orm.FilterEq("instance", instance), 548 549 ) 549 550 if err != nil { 550 551 return err ··· 552 553 553 554 err = db.DeleteSpindle( 554 555 tx, 555 - db.FilterEq("owner", did), 556 - db.FilterEq("instance", instance), 556 + orm.FilterEq("owner", did), 557 + orm.FilterEq("instance", instance), 557 558 ) 558 559 if err != nil { 559 560 return err ··· 621 622 case jmodels.CommitOperationDelete: 622 623 if err := db.DeleteString( 623 624 ddb, 624 - db.FilterEq("did", did), 625 - db.FilterEq("rkey", rkey), 625 + orm.FilterEq("did", did), 626 + orm.FilterEq("rkey", rkey), 626 627 ); err != nil { 627 628 l.Error("failed to delete", "err", err) 628 629 return fmt.Errorf("failed to delete string record: %w", err) ··· 740 741 // get record from db first 741 742 registrations, err := db.GetRegistrations( 742 743 ddb, 743 - db.FilterEq("domain", domain), 744 - db.FilterEq("did", did), 744 + orm.FilterEq("domain", domain), 745 + orm.FilterEq("did", did), 745 746 ) 746 747 if err != nil { 747 748 return fmt.Errorf("failed to get registration: %w", err) ··· 762 763 763 764 err = db.DeleteKnot( 764 765 tx, 765 - db.FilterEq("did", did), 766 - db.FilterEq("domain", domain), 766 + orm.FilterEq("did", did), 767 + orm.FilterEq("domain", domain), 767 768 ) 768 769 if err != nil { 769 770 return err ··· 915 916 case jmodels.CommitOperationDelete: 916 917 if err := db.DeleteIssueComments( 917 918 ddb, 918 - db.FilterEq("did", did), 919 - db.FilterEq("rkey", rkey), 919 + orm.FilterEq("did", did), 920 + orm.FilterEq("rkey", rkey), 920 921 ); err != nil { 921 922 return fmt.Errorf("failed to delete issue comment record: %w", err) 922 923 } ··· 969 970 case jmodels.CommitOperationDelete: 970 971 if err := db.DeleteLabelDefinition( 971 972 ddb, 972 - db.FilterEq("did", did), 973 - db.FilterEq("rkey", rkey), 973 + orm.FilterEq("did", did), 974 + orm.FilterEq("rkey", rkey), 974 975 ); err != nil { 975 976 return fmt.Errorf("failed to delete labeldef record: %w", err) 976 977 } ··· 1010 1011 var repo *models.Repo 1011 1012 switch collection { 1012 1013 case tangled.RepoIssueNSID: 1013 - i, err := db.GetIssues(ddb, db.FilterEq("at_uri", subject)) 1014 + i, err := db.GetIssues(ddb, orm.FilterEq("at_uri", subject)) 1014 1015 if err != nil || len(i) != 1 { 1015 1016 return fmt.Errorf("failed to find subject: %w || subject count %d", err, len(i)) 1016 1017 } ··· 1019 1020 return fmt.Errorf("unsupport label subject: %s", collection) 1020 1021 } 1021 1022 1022 - actx, err := db.NewLabelApplicationCtx(ddb, db.FilterIn("at_uri", repo.Labels)) 1023 + actx, err := db.NewLabelApplicationCtx(ddb, orm.FilterIn("at_uri", repo.Labels)) 1023 1024 if err != nil { 1024 1025 return fmt.Errorf("failed to build label application ctx: %w", err) 1025 1026 }
+16 -15
appview/issues/issues.go
··· 29 29 "tangled.org/core/appview/reporesolver" 30 30 "tangled.org/core/appview/validator" 31 31 "tangled.org/core/idresolver" 32 + "tangled.org/core/orm" 32 33 "tangled.org/core/rbac" 33 34 "tangled.org/core/tid" 34 35 ) ··· 113 114 114 115 labelDefs, err := db.GetLabelDefinitions( 115 116 rp.db, 116 - db.FilterIn("at_uri", f.Labels), 117 - db.FilterContains("scope", tangled.RepoIssueNSID), 117 + orm.FilterIn("at_uri", f.Labels), 118 + orm.FilterContains("scope", tangled.RepoIssueNSID), 118 119 ) 119 120 if err != nil { 120 121 l.Error("failed to fetch labels", "err", err) ··· 314 315 if isIssueOwner || isRepoOwner || isCollaborator { 315 316 err = db.CloseIssues( 316 317 rp.db, 317 - db.FilterEq("id", issue.Id), 318 + orm.FilterEq("id", issue.Id), 318 319 ) 319 320 if err != nil { 320 321 l.Error("failed to close issue", "err", err) ··· 361 362 if isCollaborator || isRepoOwner || isIssueOwner { 362 363 err := db.ReopenIssues( 363 364 rp.db, 364 - db.FilterEq("id", issue.Id), 365 + orm.FilterEq("id", issue.Id), 365 366 ) 366 367 if err != nil { 367 368 l.Error("failed to reopen issue", "err", err) ··· 506 507 commentId := chi.URLParam(r, "commentId") 507 508 comments, err := db.GetIssueComments( 508 509 rp.db, 509 - db.FilterEq("id", commentId), 510 + orm.FilterEq("id", commentId), 510 511 ) 511 512 if err != nil { 512 513 l.Error("failed to fetch comment", "id", commentId) ··· 542 543 commentId := chi.URLParam(r, "commentId") 543 544 comments, err := db.GetIssueComments( 544 545 rp.db, 545 - db.FilterEq("id", commentId), 546 + orm.FilterEq("id", commentId), 546 547 ) 547 548 if err != nil { 548 549 l.Error("failed to fetch comment", "id", commentId) ··· 652 653 commentId := chi.URLParam(r, "commentId") 653 654 comments, err := db.GetIssueComments( 654 655 rp.db, 655 - db.FilterEq("id", commentId), 656 + orm.FilterEq("id", commentId), 656 657 ) 657 658 if err != nil { 658 659 l.Error("failed to fetch comment", "id", commentId) ··· 688 689 commentId := chi.URLParam(r, "commentId") 689 690 comments, err := db.GetIssueComments( 690 691 rp.db, 691 - db.FilterEq("id", commentId), 692 + orm.FilterEq("id", commentId), 692 693 ) 693 694 if err != nil { 694 695 l.Error("failed to fetch comment", "id", commentId) ··· 724 725 commentId := chi.URLParam(r, "commentId") 725 726 comments, err := db.GetIssueComments( 726 727 rp.db, 727 - db.FilterEq("id", commentId), 728 + orm.FilterEq("id", commentId), 728 729 ) 729 730 if err != nil { 730 731 l.Error("failed to fetch comment", "id", commentId) ··· 751 752 752 753 // optimistic deletion 753 754 deleted := time.Now() 754 - err = db.DeleteIssueComments(rp.db, db.FilterEq("id", comment.Id)) 755 + err = db.DeleteIssueComments(rp.db, orm.FilterEq("id", comment.Id)) 755 756 if err != nil { 756 757 l.Error("failed to delete comment", "err", err) 757 758 rp.pages.Notice(w, fmt.Sprintf("comment-%s-status", commentId), "failed to delete comment") ··· 840 841 841 842 issues, err = db.GetIssues( 842 843 rp.db, 843 - db.FilterIn("id", res.Hits), 844 + orm.FilterIn("id", res.Hits), 844 845 ) 845 846 if err != nil { 846 847 l.Error("failed to get issues", "err", err) ··· 856 857 issues, err = db.GetIssuesPaginated( 857 858 rp.db, 858 859 page, 859 - db.FilterEq("repo_at", f.RepoAt()), 860 - db.FilterEq("open", openInt), 860 + orm.FilterEq("repo_at", f.RepoAt()), 861 + orm.FilterEq("open", openInt), 861 862 ) 862 863 if err != nil { 863 864 l.Error("failed to get issues", "err", err) ··· 868 869 869 870 labelDefs, err := db.GetLabelDefinitions( 870 871 rp.db, 871 - db.FilterIn("at_uri", f.Labels), 872 - db.FilterContains("scope", tangled.RepoIssueNSID), 872 + orm.FilterIn("at_uri", f.Labels), 873 + orm.FilterContains("scope", tangled.RepoIssueNSID), 873 874 ) 874 875 if err != nil { 875 876 l.Error("failed to fetch labels", "err", err)
+19 -18
appview/knots/knots.go
··· 21 21 "tangled.org/core/appview/xrpcclient" 22 22 "tangled.org/core/eventconsumer" 23 23 "tangled.org/core/idresolver" 24 + "tangled.org/core/orm" 24 25 "tangled.org/core/rbac" 25 26 "tangled.org/core/tid" 26 27 ··· 72 73 user := k.OAuth.GetUser(r) 73 74 registrations, err := db.GetRegistrations( 74 75 k.Db, 75 - db.FilterEq("did", user.Did), 76 + orm.FilterEq("did", user.Did), 76 77 ) 77 78 if err != nil { 78 79 k.Logger.Error("failed to fetch knot registrations", "err", err) ··· 102 103 103 104 registrations, err := db.GetRegistrations( 104 105 k.Db, 105 - db.FilterEq("did", user.Did), 106 - db.FilterEq("domain", domain), 106 + orm.FilterEq("did", user.Did), 107 + orm.FilterEq("domain", domain), 107 108 ) 108 109 if err != nil { 109 110 l.Error("failed to get registrations", "err", err) ··· 127 128 repos, err := db.GetRepos( 128 129 k.Db, 129 130 0, 130 - db.FilterEq("knot", domain), 131 + orm.FilterEq("knot", domain), 131 132 ) 132 133 if err != nil { 133 134 l.Error("failed to get knot repos", "err", err) ··· 293 294 // get record from db first 294 295 registrations, err := db.GetRegistrations( 295 296 k.Db, 296 - db.FilterEq("did", user.Did), 297 - db.FilterEq("domain", domain), 297 + orm.FilterEq("did", user.Did), 298 + orm.FilterEq("domain", domain), 298 299 ) 299 300 if err != nil { 300 301 l.Error("failed to get registration", "err", err) ··· 321 322 322 323 err = db.DeleteKnot( 323 324 tx, 324 - db.FilterEq("did", user.Did), 325 - db.FilterEq("domain", domain), 325 + orm.FilterEq("did", user.Did), 326 + orm.FilterEq("domain", domain), 326 327 ) 327 328 if err != nil { 328 329 l.Error("failed to delete registration", "err", err) ··· 402 403 // get record from db first 403 404 registrations, err := db.GetRegistrations( 404 405 k.Db, 405 - db.FilterEq("did", user.Did), 406 - db.FilterEq("domain", domain), 406 + orm.FilterEq("did", user.Did), 407 + orm.FilterEq("domain", domain), 407 408 ) 408 409 if err != nil { 409 410 l.Error("failed to get registration", "err", err) ··· 493 494 // Get updated registration to show 494 495 registrations, err = db.GetRegistrations( 495 496 k.Db, 496 - db.FilterEq("did", user.Did), 497 - db.FilterEq("domain", domain), 497 + orm.FilterEq("did", user.Did), 498 + orm.FilterEq("domain", domain), 498 499 ) 499 500 if err != nil { 500 501 l.Error("failed to get registration", "err", err) ··· 529 530 530 531 registrations, err := db.GetRegistrations( 531 532 k.Db, 532 - db.FilterEq("did", user.Did), 533 - db.FilterEq("domain", domain), 534 - db.FilterIsNot("registered", "null"), 533 + orm.FilterEq("did", user.Did), 534 + orm.FilterEq("domain", domain), 535 + orm.FilterIsNot("registered", "null"), 535 536 ) 536 537 if err != nil { 537 538 l.Error("failed to get registration", "err", err) ··· 637 638 638 639 registrations, err := db.GetRegistrations( 639 640 k.Db, 640 - db.FilterEq("did", user.Did), 641 - db.FilterEq("domain", domain), 642 - db.FilterIsNot("registered", "null"), 641 + orm.FilterEq("did", user.Did), 642 + orm.FilterEq("domain", domain), 643 + orm.FilterIsNot("registered", "null"), 643 644 ) 644 645 if err != nil { 645 646 l.Error("failed to get registration", "err", err)
+5 -4
appview/labels/labels.go
··· 16 16 "tangled.org/core/appview/oauth" 17 17 "tangled.org/core/appview/pages" 18 18 "tangled.org/core/appview/validator" 19 + "tangled.org/core/orm" 19 20 "tangled.org/core/rbac" 20 21 "tangled.org/core/tid" 21 22 ··· 88 89 repoAt := r.Form.Get("repo") 89 90 subjectUri := r.Form.Get("subject") 90 91 91 - repo, err := db.GetRepo(l.db, db.FilterEq("at_uri", repoAt)) 92 + repo, err := db.GetRepo(l.db, orm.FilterEq("at_uri", repoAt)) 92 93 if err != nil { 93 94 fail("Failed to get repository.", err) 94 95 return 95 96 } 96 97 97 98 // find all the labels that this repo subscribes to 98 - repoLabels, err := db.GetRepoLabels(l.db, db.FilterEq("repo_at", repoAt)) 99 + repoLabels, err := db.GetRepoLabels(l.db, orm.FilterEq("repo_at", repoAt)) 99 100 if err != nil { 100 101 fail("Failed to get labels for this repository.", err) 101 102 return ··· 106 107 labelAts = append(labelAts, rl.LabelAt.String()) 107 108 } 108 109 109 - actx, err := db.NewLabelApplicationCtx(l.db, db.FilterIn("at_uri", labelAts)) 110 + actx, err := db.NewLabelApplicationCtx(l.db, orm.FilterIn("at_uri", labelAts)) 110 111 if err != nil { 111 112 fail("Invalid form data.", err) 112 113 return 113 114 } 114 115 115 116 // calculate the start state by applying already known labels 116 - existingOps, err := db.GetLabelOps(l.db, db.FilterEq("subject", subjectUri)) 117 + existingOps, err := db.GetLabelOps(l.db, orm.FilterEq("subject", subjectUri)) 117 118 if err != nil { 118 119 fail("Invalid form data.", err) 119 120 return
+3 -2
appview/middleware/middleware.go
··· 18 18 "tangled.org/core/appview/pagination" 19 19 "tangled.org/core/appview/reporesolver" 20 20 "tangled.org/core/idresolver" 21 + "tangled.org/core/orm" 21 22 "tangled.org/core/rbac" 22 23 ) 23 24 ··· 217 218 218 219 repo, err := db.GetRepo( 219 220 mw.db, 220 - db.FilterEq("did", id.DID.String()), 221 - db.FilterEq("name", repoName), 221 + orm.FilterEq("did", id.DID.String()), 222 + orm.FilterEq("name", repoName), 222 223 ) 223 224 if err != nil { 224 225 log.Println("failed to resolve repo", "err", err)
+5 -4
appview/notifications/notifications.go
··· 11 11 "tangled.org/core/appview/oauth" 12 12 "tangled.org/core/appview/pages" 13 13 "tangled.org/core/appview/pagination" 14 + "tangled.org/core/orm" 14 15 ) 15 16 16 17 type Notifications struct { ··· 53 54 54 55 total, err := db.CountNotifications( 55 56 n.db, 56 - db.FilterEq("recipient_did", user.Did), 57 + orm.FilterEq("recipient_did", user.Did), 57 58 ) 58 59 if err != nil { 59 60 l.Error("failed to get total notifications", "err", err) ··· 64 65 notifications, err := db.GetNotificationsWithEntities( 65 66 n.db, 66 67 page, 67 - db.FilterEq("recipient_did", user.Did), 68 + orm.FilterEq("recipient_did", user.Did), 68 69 ) 69 70 if err != nil { 70 71 l.Error("failed to get notifications", "err", err) ··· 96 97 97 98 count, err := db.CountNotifications( 98 99 n.db, 99 - db.FilterEq("recipient_did", user.Did), 100 - db.FilterEq("read", 0), 100 + orm.FilterEq("recipient_did", user.Did), 101 + orm.FilterEq("read", 0), 101 102 ) 102 103 if err != nil { 103 104 http.Error(w, "Failed to get unread count", http.StatusInternalServerError)
+11 -10
appview/notify/db/db.go
··· 12 12 "tangled.org/core/appview/models" 13 13 "tangled.org/core/appview/notify" 14 14 "tangled.org/core/idresolver" 15 + "tangled.org/core/orm" 15 16 ) 16 17 17 18 const ( ··· 42 43 return 43 44 } 44 45 var err error 45 - repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(star.RepoAt))) 46 + repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", string(star.RepoAt))) 46 47 if err != nil { 47 48 log.Printf("NewStar: failed to get repos: %v", err) 48 49 return ··· 80 81 // - collaborators in the repo 81 82 var recipients []syntax.DID 82 83 recipients = append(recipients, syntax.DID(issue.Repo.Did)) 83 - collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", issue.Repo.RepoAt())) 84 + collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", issue.Repo.RepoAt())) 84 85 if err != nil { 85 86 log.Printf("failed to fetch collaborators: %v", err) 86 87 return ··· 119 120 } 120 121 121 122 func (n *databaseNotifier) NewIssueComment(ctx context.Context, comment *models.IssueComment, mentions []syntax.DID) { 122 - issues, err := db.GetIssues(n.db, db.FilterEq("at_uri", comment.IssueAt)) 123 + issues, err := db.GetIssues(n.db, orm.FilterEq("at_uri", comment.IssueAt)) 123 124 if err != nil { 124 125 log.Printf("NewIssueComment: failed to get issues: %v", err) 125 126 return ··· 207 208 } 208 209 209 210 func (n *databaseNotifier) NewPull(ctx context.Context, pull *models.Pull) { 210 - repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(pull.RepoAt))) 211 + repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", string(pull.RepoAt))) 211 212 if err != nil { 212 213 log.Printf("NewPull: failed to get repos: %v", err) 213 214 return ··· 218 219 // - collaborators in the repo 219 220 var recipients []syntax.DID 220 221 recipients = append(recipients, syntax.DID(repo.Did)) 221 - collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", repo.RepoAt())) 222 + collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", repo.RepoAt())) 222 223 if err != nil { 223 224 log.Printf("failed to fetch collaborators: %v", err) 224 225 return ··· 258 259 return 259 260 } 260 261 261 - repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", comment.RepoAt)) 262 + repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", comment.RepoAt)) 262 263 if err != nil { 263 264 log.Printf("NewPullComment: failed to get repos: %v", err) 264 265 return ··· 327 328 // - all issue participants 328 329 var recipients []syntax.DID 329 330 recipients = append(recipients, syntax.DID(issue.Repo.Did)) 330 - collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", issue.Repo.RepoAt())) 331 + collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", issue.Repo.RepoAt())) 331 332 if err != nil { 332 333 log.Printf("failed to fetch collaborators: %v", err) 333 334 return ··· 366 367 367 368 func (n *databaseNotifier) NewPullState(ctx context.Context, actor syntax.DID, pull *models.Pull) { 368 369 // Get repo details 369 - repo, err := db.GetRepo(n.db, db.FilterEq("at_uri", string(pull.RepoAt))) 370 + repo, err := db.GetRepo(n.db, orm.FilterEq("at_uri", string(pull.RepoAt))) 370 371 if err != nil { 371 372 log.Printf("NewPullState: failed to get repos: %v", err) 372 373 return ··· 377 378 // - all pull participants 378 379 var recipients []syntax.DID 379 380 recipients = append(recipients, syntax.DID(repo.Did)) 380 - collaborators, err := db.GetCollaborators(n.db, db.FilterEq("repo_at", repo.RepoAt())) 381 + collaborators, err := db.GetCollaborators(n.db, orm.FilterEq("repo_at", repo.RepoAt())) 381 382 if err != nil { 382 383 log.Printf("failed to fetch collaborators: %v", err) 383 384 return ··· 443 444 444 445 prefMap, err := db.GetNotificationPreferences( 445 446 n.db, 446 - db.FilterIn("user_did", slices.Collect(maps.Keys(recipientSet))), 447 + orm.FilterIn("user_did", slices.Collect(maps.Keys(recipientSet))), 447 448 ) 448 449 if err != nil { 449 450 // failed to get prefs for users
+3 -2
appview/oauth/handler.go
··· 16 16 "tangled.org/core/api/tangled" 17 17 "tangled.org/core/appview/db" 18 18 "tangled.org/core/consts" 19 + "tangled.org/core/orm" 19 20 "tangled.org/core/tid" 20 21 ) 21 22 ··· 97 98 // and create an sh.tangled.spindle.member record with that 98 99 spindleMembers, err := db.GetSpindleMembers( 99 100 o.Db, 100 - db.FilterEq("instance", "spindle.tangled.sh"), 101 - db.FilterEq("subject", did), 101 + orm.FilterEq("instance", "spindle.tangled.sh"), 102 + orm.FilterEq("subject", did), 102 103 ) 103 104 if err != nil { 104 105 l.Error("failed to get spindle members", "err", err)
+12 -11
appview/pipelines/pipelines.go
··· 16 16 "tangled.org/core/appview/reporesolver" 17 17 "tangled.org/core/eventconsumer" 18 18 "tangled.org/core/idresolver" 19 + "tangled.org/core/orm" 19 20 "tangled.org/core/rbac" 20 21 spindlemodel "tangled.org/core/spindle/models" 21 22 ··· 81 82 ps, err := db.GetPipelineStatuses( 82 83 p.db, 83 84 30, 84 - db.FilterEq("repo_owner", f.Did), 85 - db.FilterEq("repo_name", f.Name), 86 - db.FilterEq("knot", f.Knot), 85 + orm.FilterEq("repo_owner", f.Did), 86 + orm.FilterEq("repo_name", f.Name), 87 + orm.FilterEq("knot", f.Knot), 87 88 ) 88 89 if err != nil { 89 90 l.Error("failed to query db", "err", err) ··· 122 123 ps, err := db.GetPipelineStatuses( 123 124 p.db, 124 125 1, 125 - db.FilterEq("repo_owner", f.Did), 126 - db.FilterEq("repo_name", f.Name), 127 - db.FilterEq("knot", f.Knot), 128 - db.FilterEq("id", pipelineId), 126 + orm.FilterEq("repo_owner", f.Did), 127 + orm.FilterEq("repo_name", f.Name), 128 + orm.FilterEq("knot", f.Knot), 129 + orm.FilterEq("id", pipelineId), 129 130 ) 130 131 if err != nil { 131 132 l.Error("failed to query db", "err", err) ··· 189 190 ps, err := db.GetPipelineStatuses( 190 191 p.db, 191 192 1, 192 - db.FilterEq("repo_owner", f.Did), 193 - db.FilterEq("repo_name", f.Name), 194 - db.FilterEq("knot", f.Knot), 195 - db.FilterEq("id", pipelineId), 193 + orm.FilterEq("repo_owner", f.Did), 194 + orm.FilterEq("repo_name", f.Name), 195 + orm.FilterEq("knot", f.Knot), 196 + orm.FilterEq("id", pipelineId), 196 197 ) 197 198 if err != nil || len(ps) != 1 { 198 199 l.Error("pipeline query failed", "err", err, "count", len(ps))
+2 -1
appview/pulls/opengraph.go
··· 13 13 "tangled.org/core/appview/db" 14 14 "tangled.org/core/appview/models" 15 15 "tangled.org/core/appview/ogcard" 16 + "tangled.org/core/orm" 16 17 "tangled.org/core/patchutil" 17 18 "tangled.org/core/types" 18 19 ) ··· 276 277 } 277 278 278 279 // Get comment count from database 279 - comments, err := db.GetPullComments(s.db, db.FilterEq("pull_id", pull.ID)) 280 + comments, err := db.GetPullComments(s.db, orm.FilterEq("pull_id", pull.ID)) 280 281 if err != nil { 281 282 log.Printf("failed to get pull comments: %v", err) 282 283 }
+19 -18
appview/pulls/pulls.go
··· 30 30 "tangled.org/core/appview/validator" 31 31 "tangled.org/core/appview/xrpcclient" 32 32 "tangled.org/core/idresolver" 33 + "tangled.org/core/orm" 33 34 "tangled.org/core/patchutil" 34 35 "tangled.org/core/rbac" 35 36 "tangled.org/core/tid" ··· 190 191 ps, err := db.GetPipelineStatuses( 191 192 s.db, 192 193 len(shas), 193 - db.FilterEq("repo_owner", f.Did), 194 - db.FilterEq("repo_name", f.Name), 195 - db.FilterEq("knot", f.Knot), 196 - db.FilterIn("sha", shas), 194 + orm.FilterEq("repo_owner", f.Did), 195 + orm.FilterEq("repo_name", f.Name), 196 + orm.FilterEq("knot", f.Knot), 197 + orm.FilterIn("sha", shas), 197 198 ) 198 199 if err != nil { 199 200 log.Printf("failed to fetch pipeline statuses: %s", err) ··· 217 218 218 219 labelDefs, err := db.GetLabelDefinitions( 219 220 s.db, 220 - db.FilterIn("at_uri", f.Labels), 221 - db.FilterContains("scope", tangled.RepoPullNSID), 221 + orm.FilterIn("at_uri", f.Labels), 222 + orm.FilterContains("scope", tangled.RepoPullNSID), 222 223 ) 223 224 if err != nil { 224 225 log.Println("failed to fetch labels", err) ··· 597 598 598 599 pulls, err := db.GetPulls( 599 600 s.db, 600 - db.FilterIn("id", ids), 601 + orm.FilterIn("id", ids), 601 602 ) 602 603 if err != nil { 603 604 log.Println("failed to get pulls", err) ··· 648 649 ps, err := db.GetPipelineStatuses( 649 650 s.db, 650 651 len(shas), 651 - db.FilterEq("repo_owner", f.Did), 652 - db.FilterEq("repo_name", f.Name), 653 - db.FilterEq("knot", f.Knot), 654 - db.FilterIn("sha", shas), 652 + orm.FilterEq("repo_owner", f.Did), 653 + orm.FilterEq("repo_name", f.Name), 654 + orm.FilterEq("knot", f.Knot), 655 + orm.FilterIn("sha", shas), 655 656 ) 656 657 if err != nil { 657 658 log.Printf("failed to fetch pipeline statuses: %s", err) ··· 664 665 665 666 labelDefs, err := db.GetLabelDefinitions( 666 667 s.db, 667 - db.FilterIn("at_uri", f.Labels), 668 - db.FilterContains("scope", tangled.RepoPullNSID), 668 + orm.FilterIn("at_uri", f.Labels), 669 + orm.FilterContains("scope", tangled.RepoPullNSID), 669 670 ) 670 671 if err != nil { 671 672 log.Println("failed to fetch labels", err) ··· 1498 1499 // fork repo 1499 1500 repo, err := db.GetRepo( 1500 1501 s.db, 1501 - db.FilterEq("did", forkOwnerDid), 1502 - db.FilterEq("name", forkName), 1502 + orm.FilterEq("did", forkOwnerDid), 1503 + orm.FilterEq("name", forkName), 1503 1504 ) 1504 1505 if err != nil { 1505 1506 log.Println("failed to get repo", "did", forkOwnerDid, "name", forkName, "err", err) ··· 2066 2067 tx, 2067 2068 p.ParentChangeId, 2068 2069 // these should be enough filters to be unique per-stack 2069 - db.FilterEq("repo_at", p.RepoAt.String()), 2070 - db.FilterEq("owner_did", p.OwnerDid), 2071 - db.FilterEq("change_id", p.ChangeId), 2070 + orm.FilterEq("repo_at", p.RepoAt.String()), 2071 + orm.FilterEq("owner_did", p.OwnerDid), 2072 + orm.FilterEq("change_id", p.ChangeId), 2072 2073 ) 2073 2074 2074 2075 if err != nil {
+10 -9
appview/repo/artifact.go
··· 15 15 "tangled.org/core/appview/models" 16 16 "tangled.org/core/appview/pages" 17 17 "tangled.org/core/appview/xrpcclient" 18 + "tangled.org/core/orm" 18 19 "tangled.org/core/tid" 19 20 "tangled.org/core/types" 20 21 ··· 155 156 156 157 artifacts, err := db.GetArtifact( 157 158 rp.db, 158 - db.FilterEq("repo_at", f.RepoAt()), 159 - db.FilterEq("tag", tag.Tag.Hash[:]), 160 - db.FilterEq("name", filename), 159 + orm.FilterEq("repo_at", f.RepoAt()), 160 + orm.FilterEq("tag", tag.Tag.Hash[:]), 161 + orm.FilterEq("name", filename), 161 162 ) 162 163 if err != nil { 163 164 log.Println("failed to get artifacts", err) ··· 234 235 235 236 artifacts, err := db.GetArtifact( 236 237 rp.db, 237 - db.FilterEq("repo_at", f.RepoAt()), 238 - db.FilterEq("tag", tag[:]), 239 - db.FilterEq("name", filename), 238 + orm.FilterEq("repo_at", f.RepoAt()), 239 + orm.FilterEq("tag", tag[:]), 240 + orm.FilterEq("name", filename), 240 241 ) 241 242 if err != nil { 242 243 log.Println("failed to get artifacts", err) ··· 276 277 defer tx.Rollback() 277 278 278 279 err = db.DeleteArtifact(tx, 279 - db.FilterEq("repo_at", f.RepoAt()), 280 - db.FilterEq("tag", artifact.Tag[:]), 281 - db.FilterEq("name", filename), 280 + orm.FilterEq("repo_at", f.RepoAt()), 281 + orm.FilterEq("tag", artifact.Tag[:]), 282 + orm.FilterEq("name", filename), 282 283 ) 283 284 if err != nil { 284 285 log.Println("failed to remove artifact record from db", err)
+3 -2
appview/repo/feed.go
··· 11 11 "tangled.org/core/appview/db" 12 12 "tangled.org/core/appview/models" 13 13 "tangled.org/core/appview/pagination" 14 + "tangled.org/core/orm" 14 15 15 16 "github.com/bluesky-social/indigo/atproto/identity" 16 17 "github.com/bluesky-social/indigo/atproto/syntax" ··· 20 21 func (rp *Repo) getRepoFeed(ctx context.Context, repo *models.Repo, ownerSlashRepo string) (*feeds.Feed, error) { 21 22 const feedLimitPerType = 100 22 23 23 - pulls, err := db.GetPullsWithLimit(rp.db, feedLimitPerType, db.FilterEq("repo_at", repo.RepoAt())) 24 + pulls, err := db.GetPullsWithLimit(rp.db, feedLimitPerType, orm.FilterEq("repo_at", repo.RepoAt())) 24 25 if err != nil { 25 26 return nil, err 26 27 } ··· 28 29 issues, err := db.GetIssuesPaginated( 29 30 rp.db, 30 31 pagination.Page{Limit: feedLimitPerType}, 31 - db.FilterEq("repo_at", repo.RepoAt()), 32 + orm.FilterEq("repo_at", repo.RepoAt()), 32 33 ) 33 34 if err != nil { 34 35 return nil, err
+3 -2
appview/repo/index.go
··· 23 23 "tangled.org/core/appview/models" 24 24 "tangled.org/core/appview/pages" 25 25 "tangled.org/core/appview/xrpcclient" 26 + "tangled.org/core/orm" 26 27 "tangled.org/core/types" 27 28 28 29 "github.com/go-chi/chi/v5" ··· 171 172 // first attempt to fetch from db 172 173 langs, err := db.GetRepoLanguages( 173 174 rp.db, 174 - db.FilterEq("repo_at", repo.RepoAt()), 175 - db.FilterEq("ref", currentRef), 175 + orm.FilterEq("repo_at", repo.RepoAt()), 176 + orm.FilterEq("ref", currentRef), 176 177 ) 177 178 178 179 if err != nil || langs == nil {
+3 -2
appview/repo/opengraph.go
··· 16 16 "tangled.org/core/appview/db" 17 17 "tangled.org/core/appview/models" 18 18 "tangled.org/core/appview/ogcard" 19 + "tangled.org/core/orm" 19 20 "tangled.org/core/types" 20 21 ) 21 22 ··· 338 339 var languageStats []types.RepoLanguageDetails 339 340 langs, err := db.GetRepoLanguages( 340 341 rp.db, 341 - db.FilterEq("repo_at", f.RepoAt()), 342 - db.FilterEq("is_default_ref", 1), 342 + orm.FilterEq("repo_at", f.RepoAt()), 343 + orm.FilterEq("is_default_ref", 1), 343 344 ) 344 345 if err != nil { 345 346 log.Printf("failed to get language stats from db: %v", err)
+17 -16
appview/repo/repo.go
··· 24 24 xrpcclient "tangled.org/core/appview/xrpcclient" 25 25 "tangled.org/core/eventconsumer" 26 26 "tangled.org/core/idresolver" 27 + "tangled.org/core/orm" 27 28 "tangled.org/core/rbac" 28 29 "tangled.org/core/tid" 29 30 "tangled.org/core/xrpc/serviceauth" ··· 345 346 // get form values 346 347 labelId := r.FormValue("label-id") 347 348 348 - label, err := db.GetLabelDefinition(rp.db, db.FilterEq("id", labelId)) 349 + label, err := db.GetLabelDefinition(rp.db, orm.FilterEq("id", labelId)) 349 350 if err != nil { 350 351 fail("Failed to find label definition.", err) 351 352 return ··· 409 410 410 411 err = db.UnsubscribeLabel( 411 412 tx, 412 - db.FilterEq("repo_at", f.RepoAt()), 413 - db.FilterEq("label_at", removedAt), 413 + orm.FilterEq("repo_at", f.RepoAt()), 414 + orm.FilterEq("label_at", removedAt), 414 415 ) 415 416 if err != nil { 416 417 fail("Failed to unsubscribe label.", err) 417 418 return 418 419 } 419 420 420 - err = db.DeleteLabelDefinition(tx, db.FilterEq("id", label.Id)) 421 + err = db.DeleteLabelDefinition(tx, orm.FilterEq("id", label.Id)) 421 422 if err != nil { 422 423 fail("Failed to delete label definition.", err) 423 424 return ··· 456 457 } 457 458 458 459 labelAts := r.Form["label"] 459 - _, err = db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", labelAts)) 460 + _, err = db.GetLabelDefinitions(rp.db, orm.FilterIn("at_uri", labelAts)) 460 461 if err != nil { 461 462 fail("Failed to subscribe to label.", err) 462 463 return ··· 542 543 } 543 544 544 545 labelAts := r.Form["label"] 545 - _, err = db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", labelAts)) 546 + _, err = db.GetLabelDefinitions(rp.db, orm.FilterIn("at_uri", labelAts)) 546 547 if err != nil { 547 548 fail("Failed to unsubscribe to label.", err) 548 549 return ··· 582 583 583 584 err = db.UnsubscribeLabel( 584 585 rp.db, 585 - db.FilterEq("repo_at", f.RepoAt()), 586 - db.FilterIn("label_at", labelAts), 586 + orm.FilterEq("repo_at", f.RepoAt()), 587 + orm.FilterIn("label_at", labelAts), 587 588 ) 588 589 if err != nil { 589 590 fail("Failed to unsubscribe label.", err) ··· 612 613 613 614 labelDefs, err := db.GetLabelDefinitions( 614 615 rp.db, 615 - db.FilterIn("at_uri", f.Labels), 616 - db.FilterContains("scope", subject.Collection().String()), 616 + orm.FilterIn("at_uri", f.Labels), 617 + orm.FilterContains("scope", subject.Collection().String()), 617 618 ) 618 619 if err != nil { 619 620 l.Error("failed to fetch label defs", "err", err) ··· 625 626 defs[l.AtUri().String()] = &l 626 627 } 627 628 628 - states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject)) 629 + states, err := db.GetLabels(rp.db, orm.FilterEq("subject", subject)) 629 630 if err != nil { 630 631 l.Error("failed to build label state", "err", err) 631 632 return ··· 660 661 661 662 labelDefs, err := db.GetLabelDefinitions( 662 663 rp.db, 663 - db.FilterIn("at_uri", f.Labels), 664 - db.FilterContains("scope", subject.Collection().String()), 664 + orm.FilterIn("at_uri", f.Labels), 665 + orm.FilterContains("scope", subject.Collection().String()), 665 666 ) 666 667 if err != nil { 667 668 l.Error("failed to fetch labels", "err", err) ··· 673 674 defs[l.AtUri().String()] = &l 674 675 } 675 676 676 - states, err := db.GetLabels(rp.db, db.FilterEq("subject", subject)) 677 + states, err := db.GetLabels(rp.db, orm.FilterEq("subject", subject)) 677 678 if err != nil { 678 679 l.Error("failed to build label state", "err", err) 679 680 return ··· 1036 1037 // in the user's account. 1037 1038 existingRepo, err := db.GetRepo( 1038 1039 rp.db, 1039 - db.FilterEq("did", user.Did), 1040 - db.FilterEq("name", forkName), 1040 + orm.FilterEq("did", user.Did), 1041 + orm.FilterEq("name", forkName), 1041 1042 ) 1042 1043 if err != nil { 1043 1044 if !errors.Is(err, sql.ErrNoRows) {
+5 -4
appview/repo/repo_util.go
··· 8 8 9 9 "tangled.org/core/appview/db" 10 10 "tangled.org/core/appview/models" 11 + "tangled.org/core/orm" 11 12 "tangled.org/core/types" 12 13 ) 13 14 ··· 102 103 ps, err := db.GetPipelineStatuses( 103 104 d, 104 105 len(shas), 105 - db.FilterEq("repo_owner", repo.Did), 106 - db.FilterEq("repo_name", repo.Name), 107 - db.FilterEq("knot", repo.Knot), 108 - db.FilterIn("sha", shas), 106 + orm.FilterEq("repo_owner", repo.Did), 107 + orm.FilterEq("repo_name", repo.Name), 108 + orm.FilterEq("knot", repo.Knot), 109 + orm.FilterIn("sha", shas), 109 110 ) 110 111 if err != nil { 111 112 return nil, err
+3 -2
appview/repo/settings.go
··· 14 14 "tangled.org/core/appview/oauth" 15 15 "tangled.org/core/appview/pages" 16 16 xrpcclient "tangled.org/core/appview/xrpcclient" 17 + "tangled.org/core/orm" 17 18 "tangled.org/core/types" 18 19 19 20 comatproto "github.com/bluesky-social/indigo/api/atproto" ··· 210 211 return 211 212 } 212 213 213 - defaultLabels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", rp.config.Label.DefaultLabelDefs)) 214 + defaultLabels, err := db.GetLabelDefinitions(rp.db, orm.FilterIn("at_uri", rp.config.Label.DefaultLabelDefs)) 214 215 if err != nil { 215 216 l.Error("failed to fetch labels", "err", err) 216 217 rp.pages.Error503(w) 217 218 return 218 219 } 219 220 220 - labels, err := db.GetLabelDefinitions(rp.db, db.FilterIn("at_uri", f.Labels)) 221 + labels, err := db.GetLabelDefinitions(rp.db, orm.FilterIn("at_uri", f.Labels)) 221 222 if err != nil { 222 223 l.Error("failed to fetch labels", "err", err) 223 224 rp.pages.Error503(w)
+2 -1
appview/repo/tags.go
··· 10 10 "tangled.org/core/appview/models" 11 11 "tangled.org/core/appview/pages" 12 12 xrpcclient "tangled.org/core/appview/xrpcclient" 13 + "tangled.org/core/orm" 13 14 "tangled.org/core/types" 14 15 15 16 indigoxrpc "github.com/bluesky-social/indigo/xrpc" ··· 44 45 rp.pages.Error503(w) 45 46 return 46 47 } 47 - artifacts, err := db.GetArtifact(rp.db, db.FilterEq("repo_at", f.RepoAt())) 48 + artifacts, err := db.GetArtifact(rp.db, orm.FilterEq("repo_at", f.RepoAt())) 48 49 if err != nil { 49 50 l.Error("failed grab artifacts", "err", err) 50 51 return
+5 -4
appview/serververify/verify.go
··· 9 9 "tangled.org/core/api/tangled" 10 10 "tangled.org/core/appview/db" 11 11 "tangled.org/core/appview/xrpcclient" 12 + "tangled.org/core/orm" 12 13 "tangled.org/core/rbac" 13 14 ) 14 15 ··· 76 77 // mark this spindle as verified in the db 77 78 rowId, err := db.VerifySpindle( 78 79 tx, 79 - db.FilterEq("owner", owner), 80 - db.FilterEq("instance", instance), 80 + orm.FilterEq("owner", owner), 81 + orm.FilterEq("instance", instance), 81 82 ) 82 83 if err != nil { 83 84 return 0, fmt.Errorf("failed to write to DB: %w", err) ··· 115 116 // mark as registered 116 117 err = db.MarkRegistered( 117 118 tx, 118 - db.FilterEq("did", owner), 119 - db.FilterEq("domain", domain), 119 + orm.FilterEq("did", owner), 120 + orm.FilterEq("domain", domain), 120 121 ) 121 122 if err != nil { 122 123 return fmt.Errorf("failed to register domain: %w", err)
+25 -24
appview/spindles/spindles.go
··· 20 20 "tangled.org/core/appview/serververify" 21 21 "tangled.org/core/appview/xrpcclient" 22 22 "tangled.org/core/idresolver" 23 + "tangled.org/core/orm" 23 24 "tangled.org/core/rbac" 24 25 "tangled.org/core/tid" 25 26 ··· 71 72 user := s.OAuth.GetUser(r) 72 73 all, err := db.GetSpindles( 73 74 s.Db, 74 - db.FilterEq("owner", user.Did), 75 + orm.FilterEq("owner", user.Did), 75 76 ) 76 77 if err != nil { 77 78 s.Logger.Error("failed to fetch spindles", "err", err) ··· 101 102 102 103 spindles, err := db.GetSpindles( 103 104 s.Db, 104 - db.FilterEq("instance", instance), 105 - db.FilterEq("owner", user.Did), 106 - db.FilterIsNot("verified", "null"), 105 + orm.FilterEq("instance", instance), 106 + orm.FilterEq("owner", user.Did), 107 + orm.FilterIsNot("verified", "null"), 107 108 ) 108 109 if err != nil || len(spindles) != 1 { 109 110 l.Error("failed to get spindle", "err", err, "len(spindles)", len(spindles)) ··· 123 124 repos, err := db.GetRepos( 124 125 s.Db, 125 126 0, 126 - db.FilterEq("spindle", instance), 127 + orm.FilterEq("spindle", instance), 127 128 ) 128 129 if err != nil { 129 130 l.Error("failed to get spindle repos", "err", err) ··· 290 291 291 292 spindles, err := db.GetSpindles( 292 293 s.Db, 293 - db.FilterEq("owner", user.Did), 294 - db.FilterEq("instance", instance), 294 + orm.FilterEq("owner", user.Did), 295 + orm.FilterEq("instance", instance), 295 296 ) 296 297 if err != nil || len(spindles) != 1 { 297 298 l.Error("failed to retrieve instance", "err", err, "len(spindles)", len(spindles)) ··· 319 320 // remove spindle members first 320 321 err = db.RemoveSpindleMember( 321 322 tx, 322 - db.FilterEq("did", user.Did), 323 - db.FilterEq("instance", instance), 323 + orm.FilterEq("did", user.Did), 324 + orm.FilterEq("instance", instance), 324 325 ) 325 326 if err != nil { 326 327 l.Error("failed to remove spindle members", "err", err) ··· 330 331 331 332 err = db.DeleteSpindle( 332 333 tx, 333 - db.FilterEq("owner", user.Did), 334 - db.FilterEq("instance", instance), 334 + orm.FilterEq("owner", user.Did), 335 + orm.FilterEq("instance", instance), 335 336 ) 336 337 if err != nil { 337 338 l.Error("failed to delete spindle", "err", err) ··· 410 411 411 412 spindles, err := db.GetSpindles( 412 413 s.Db, 413 - db.FilterEq("owner", user.Did), 414 - db.FilterEq("instance", instance), 414 + orm.FilterEq("owner", user.Did), 415 + orm.FilterEq("instance", instance), 415 416 ) 416 417 if err != nil || len(spindles) != 1 { 417 418 l.Error("failed to retrieve instance", "err", err, "len(spindles)", len(spindles)) ··· 453 454 454 455 verifiedSpindle, err := db.GetSpindles( 455 456 s.Db, 456 - db.FilterEq("id", rowId), 457 + orm.FilterEq("id", rowId), 457 458 ) 458 459 if err != nil || len(verifiedSpindle) != 1 { 459 460 l.Error("failed get new spindle", "err", err) ··· 486 487 487 488 spindles, err := db.GetSpindles( 488 489 s.Db, 489 - db.FilterEq("owner", user.Did), 490 - db.FilterEq("instance", instance), 490 + orm.FilterEq("owner", user.Did), 491 + orm.FilterEq("instance", instance), 491 492 ) 492 493 if err != nil || len(spindles) != 1 { 493 494 l.Error("failed to retrieve instance", "err", err, "len(spindles)", len(spindles)) ··· 622 623 623 624 spindles, err := db.GetSpindles( 624 625 s.Db, 625 - db.FilterEq("owner", user.Did), 626 - db.FilterEq("instance", instance), 626 + orm.FilterEq("owner", user.Did), 627 + orm.FilterEq("instance", instance), 627 628 ) 628 629 if err != nil || len(spindles) != 1 { 629 630 l.Error("failed to retrieve instance", "err", err, "len(spindles)", len(spindles)) ··· 672 673 // get the record from the DB first: 673 674 members, err := db.GetSpindleMembers( 674 675 s.Db, 675 - db.FilterEq("did", user.Did), 676 - db.FilterEq("instance", instance), 677 - db.FilterEq("subject", memberId.DID), 676 + orm.FilterEq("did", user.Did), 677 + orm.FilterEq("instance", instance), 678 + orm.FilterEq("subject", memberId.DID), 678 679 ) 679 680 if err != nil || len(members) != 1 { 680 681 l.Error("failed to get member", "err", err) ··· 685 686 // remove from db 686 687 if err = db.RemoveSpindleMember( 687 688 tx, 688 - db.FilterEq("did", user.Did), 689 - db.FilterEq("instance", instance), 690 - db.FilterEq("subject", memberId.DID), 689 + orm.FilterEq("did", user.Did), 690 + orm.FilterEq("instance", instance), 691 + orm.FilterEq("subject", memberId.DID), 691 692 ); err != nil { 692 693 l.Error("failed to remove spindle member", "err", err) 693 694 fail()
+6 -5
appview/state/gfi.go
··· 11 11 "tangled.org/core/appview/pages" 12 12 "tangled.org/core/appview/pagination" 13 13 "tangled.org/core/consts" 14 + "tangled.org/core/orm" 14 15 ) 15 16 16 17 func (s *State) GoodFirstIssues(w http.ResponseWriter, r *http.Request) { ··· 20 21 21 22 goodFirstIssueLabel := s.config.Label.GoodFirstIssue 22 23 23 - gfiLabelDef, err := db.GetLabelDefinition(s.db, db.FilterEq("at_uri", goodFirstIssueLabel)) 24 + gfiLabelDef, err := db.GetLabelDefinition(s.db, orm.FilterEq("at_uri", goodFirstIssueLabel)) 24 25 if err != nil { 25 26 log.Println("failed to get gfi label def", err) 26 27 s.pages.Error500(w) 27 28 return 28 29 } 29 30 30 - repoLabels, err := db.GetRepoLabels(s.db, db.FilterEq("label_at", goodFirstIssueLabel)) 31 + repoLabels, err := db.GetRepoLabels(s.db, orm.FilterEq("label_at", goodFirstIssueLabel)) 31 32 if err != nil { 32 33 log.Println("failed to get repo labels", err) 33 34 s.pages.Error503(w) ··· 55 56 pagination.Page{ 56 57 Limit: 500, 57 58 }, 58 - db.FilterIn("repo_at", repoUris), 59 - db.FilterEq("open", 1), 59 + orm.FilterIn("repo_at", repoUris), 60 + orm.FilterEq("open", 1), 60 61 ) 61 62 if err != nil { 62 63 log.Println("failed to get issues", err) ··· 132 133 } 133 134 134 135 if len(uriList) > 0 { 135 - allLabelDefs, err = db.GetLabelDefinitions(s.db, db.FilterIn("at_uri", uriList)) 136 + allLabelDefs, err = db.GetLabelDefinitions(s.db, orm.FilterIn("at_uri", uriList)) 136 137 if err != nil { 137 138 log.Println("failed to fetch labels", err) 138 139 }
+6 -5
appview/state/knotstream.go
··· 16 16 ec "tangled.org/core/eventconsumer" 17 17 "tangled.org/core/eventconsumer/cursor" 18 18 "tangled.org/core/log" 19 + "tangled.org/core/orm" 19 20 "tangled.org/core/rbac" 20 21 "tangled.org/core/workflow" 21 22 ··· 30 31 31 32 knots, err := db.GetRegistrations( 32 33 d, 33 - db.FilterIsNot("registered", "null"), 34 + orm.FilterIsNot("registered", "null"), 34 35 ) 35 36 if err != nil { 36 37 return nil, err ··· 143 144 repos, err := db.GetRepos( 144 145 d, 145 146 0, 146 - db.FilterEq("did", record.RepoDid), 147 - db.FilterEq("name", record.RepoName), 147 + orm.FilterEq("did", record.RepoDid), 148 + orm.FilterEq("name", record.RepoName), 148 149 ) 149 150 if err != nil { 150 151 return fmt.Errorf("failed to look for repo in DB (%s/%s): %w", record.RepoDid, record.RepoName, err) ··· 209 210 repos, err := db.GetRepos( 210 211 d, 211 212 0, 212 - db.FilterEq("did", record.TriggerMetadata.Repo.Did), 213 - db.FilterEq("name", record.TriggerMetadata.Repo.Repo), 213 + orm.FilterEq("did", record.TriggerMetadata.Repo.Did), 214 + orm.FilterEq("name", record.TriggerMetadata.Repo.Repo), 214 215 ) 215 216 if err != nil { 216 217 return fmt.Errorf("failed to look for repo in DB: nsid %s, rkey %s, %w", msg.Nsid, msg.Rkey, err)
+13 -12
appview/state/profile.go
··· 19 19 "tangled.org/core/appview/db" 20 20 "tangled.org/core/appview/models" 21 21 "tangled.org/core/appview/pages" 22 + "tangled.org/core/orm" 22 23 ) 23 24 24 25 func (s *State) Profile(w http.ResponseWriter, r *http.Request) { ··· 56 57 return nil, fmt.Errorf("failed to get profile: %w", err) 57 58 } 58 59 59 - repoCount, err := db.CountRepos(s.db, db.FilterEq("did", did)) 60 + repoCount, err := db.CountRepos(s.db, orm.FilterEq("did", did)) 60 61 if err != nil { 61 62 return nil, fmt.Errorf("failed to get repo count: %w", err) 62 63 } 63 64 64 - stringCount, err := db.CountStrings(s.db, db.FilterEq("did", did)) 65 + stringCount, err := db.CountStrings(s.db, orm.FilterEq("did", did)) 65 66 if err != nil { 66 67 return nil, fmt.Errorf("failed to get string count: %w", err) 67 68 } 68 69 69 - starredCount, err := db.CountStars(s.db, db.FilterEq("did", did)) 70 + starredCount, err := db.CountStars(s.db, orm.FilterEq("did", did)) 70 71 if err != nil { 71 72 return nil, fmt.Errorf("failed to get starred repo count: %w", err) 72 73 } ··· 86 87 startOfYear := time.Date(now.Year(), 1, 1, 0, 0, 0, 0, time.UTC) 87 88 punchcard, err := db.MakePunchcard( 88 89 s.db, 89 - db.FilterEq("did", did), 90 - db.FilterGte("date", startOfYear.Format(time.DateOnly)), 91 - db.FilterLte("date", now.Format(time.DateOnly)), 90 + orm.FilterEq("did", did), 91 + orm.FilterGte("date", startOfYear.Format(time.DateOnly)), 92 + orm.FilterLte("date", now.Format(time.DateOnly)), 92 93 ) 93 94 if err != nil { 94 95 return nil, fmt.Errorf("failed to get punchcard for %s: %w", did, err) ··· 123 124 repos, err := db.GetRepos( 124 125 s.db, 125 126 0, 126 - db.FilterEq("did", profile.UserDid), 127 + orm.FilterEq("did", profile.UserDid), 127 128 ) 128 129 if err != nil { 129 130 l.Error("failed to fetch repos", "err", err) ··· 193 194 repos, err := db.GetRepos( 194 195 s.db, 195 196 0, 196 - db.FilterEq("did", profile.UserDid), 197 + orm.FilterEq("did", profile.UserDid), 197 198 ) 198 199 if err != nil { 199 200 l.Error("failed to get repos", "err", err) ··· 219 220 } 220 221 l = l.With("profileDid", profile.UserDid) 221 222 222 - stars, err := db.GetRepoStars(s.db, 0, db.FilterEq("did", profile.UserDid)) 223 + stars, err := db.GetRepoStars(s.db, 0, orm.FilterEq("did", profile.UserDid)) 223 224 if err != nil { 224 225 l.Error("failed to get stars", "err", err) 225 226 s.pages.Error500(w) ··· 248 249 } 249 250 l = l.With("profileDid", profile.UserDid) 250 251 251 - strings, err := db.GetStrings(s.db, 0, db.FilterEq("did", profile.UserDid)) 252 + strings, err := db.GetStrings(s.db, 0, orm.FilterEq("did", profile.UserDid)) 252 253 if err != nil { 253 254 l.Error("failed to get strings", "err", err) 254 255 s.pages.Error500(w) ··· 300 301 followDids = append(followDids, extractDid(follow)) 301 302 } 302 303 303 - profiles, err := db.GetProfiles(s.db, db.FilterIn("did", followDids)) 304 + profiles, err := db.GetProfiles(s.db, orm.FilterIn("did", followDids)) 304 305 if err != nil { 305 306 l.Error("failed to get profiles", "followDids", followDids, "err", err) 306 307 return &params, err ··· 703 704 log.Printf("getting profile data for %s: %s", user.Did, err) 704 705 } 705 706 706 - repos, err := db.GetRepos(s.db, 0, db.FilterEq("did", user.Did)) 707 + repos, err := db.GetRepos(s.db, 0, orm.FilterEq("did", user.Did)) 707 708 if err != nil { 708 709 log.Printf("getting repos for %s: %s", user.Did, err) 709 710 }
+2 -1
appview/state/spindlestream.go
··· 17 17 ec "tangled.org/core/eventconsumer" 18 18 "tangled.org/core/eventconsumer/cursor" 19 19 "tangled.org/core/log" 20 + "tangled.org/core/orm" 20 21 "tangled.org/core/rbac" 21 22 spindle "tangled.org/core/spindle/models" 22 23 ) ··· 27 28 28 29 spindles, err := db.GetSpindles( 29 30 d, 30 - db.FilterIsNot("verified", "null"), 31 + orm.FilterIsNot("verified", "null"), 31 32 ) 32 33 if err != nil { 33 34 return nil, err
+9 -8
appview/state/state.go
··· 30 30 "tangled.org/core/jetstream" 31 31 "tangled.org/core/log" 32 32 tlog "tangled.org/core/log" 33 + "tangled.org/core/orm" 33 34 "tangled.org/core/rbac" 34 35 "tangled.org/core/tid" 35 36 ··· 299 300 return 300 301 } 301 302 302 - gfiLabel, err := db.GetLabelDefinition(s.db, db.FilterEq("at_uri", s.config.Label.GoodFirstIssue)) 303 + gfiLabel, err := db.GetLabelDefinition(s.db, orm.FilterEq("at_uri", s.config.Label.GoodFirstIssue)) 303 304 if err != nil { 304 305 // non-fatal 305 306 } ··· 323 324 324 325 regs, err := db.GetRegistrations( 325 326 s.db, 326 - db.FilterEq("did", user.Did), 327 - db.FilterEq("needs_upgrade", 1), 327 + orm.FilterEq("did", user.Did), 328 + orm.FilterEq("needs_upgrade", 1), 328 329 ) 329 330 if err != nil { 330 331 l.Error("non-fatal: failed to get registrations", "err", err) ··· 332 333 333 334 spindles, err := db.GetSpindles( 334 335 s.db, 335 - db.FilterEq("owner", user.Did), 336 - db.FilterEq("needs_upgrade", 1), 336 + orm.FilterEq("owner", user.Did), 337 + orm.FilterEq("needs_upgrade", 1), 337 338 ) 338 339 if err != nil { 339 340 l.Error("non-fatal: failed to get spindles", "err", err) ··· 504 505 // Check for existing repos 505 506 existingRepo, err := db.GetRepo( 506 507 s.db, 507 - db.FilterEq("did", user.Did), 508 - db.FilterEq("name", repoName), 508 + orm.FilterEq("did", user.Did), 509 + orm.FilterEq("name", repoName), 509 510 ) 510 511 if err == nil && existingRepo != nil { 511 512 l.Info("repo exists") ··· 665 666 } 666 667 667 668 func BackfillDefaultDefs(e db.Execer, r *idresolver.Resolver, defaults []string) error { 668 - defaultLabels, err := db.GetLabelDefinitions(e, db.FilterIn("at_uri", defaults)) 669 + defaultLabels, err := db.GetLabelDefinitions(e, orm.FilterIn("at_uri", defaults)) 669 670 if err != nil { 670 671 return err 671 672 }
+7 -6
appview/strings/strings.go
··· 17 17 "tangled.org/core/appview/pages" 18 18 "tangled.org/core/appview/pages/markup" 19 19 "tangled.org/core/idresolver" 20 + "tangled.org/core/orm" 20 21 "tangled.org/core/tid" 21 22 22 23 "github.com/bluesky-social/indigo/api/atproto" ··· 108 109 strings, err := db.GetStrings( 109 110 s.Db, 110 111 0, 111 - db.FilterEq("did", id.DID), 112 - db.FilterEq("rkey", rkey), 112 + orm.FilterEq("did", id.DID), 113 + orm.FilterEq("rkey", rkey), 113 114 ) 114 115 if err != nil { 115 116 l.Error("failed to fetch string", "err", err) ··· 199 200 all, err := db.GetStrings( 200 201 s.Db, 201 202 0, 202 - db.FilterEq("did", id.DID), 203 - db.FilterEq("rkey", rkey), 203 + orm.FilterEq("did", id.DID), 204 + orm.FilterEq("rkey", rkey), 204 205 ) 205 206 if err != nil { 206 207 l.Error("failed to fetch string", "err", err) ··· 408 409 409 410 if err := db.DeleteString( 410 411 s.Db, 411 - db.FilterEq("did", user.Did), 412 - db.FilterEq("rkey", rkey), 412 + orm.FilterEq("did", user.Did), 413 + orm.FilterEq("rkey", rkey), 413 414 ); err != nil { 414 415 fail("Failed to delete string.", err) 415 416 return
+2 -1
appview/validator/issue.go
··· 6 6 7 7 "tangled.org/core/appview/db" 8 8 "tangled.org/core/appview/models" 9 + "tangled.org/core/orm" 9 10 ) 10 11 11 12 func (v *Validator) ValidateIssueComment(comment *models.IssueComment) error { 12 13 // if comments have parents, only ingest ones that are 1 level deep 13 14 if comment.ReplyTo != nil { 14 - parents, err := db.GetIssueComments(v.db, db.FilterEq("at_uri", *comment.ReplyTo)) 15 + parents, err := db.GetIssueComments(v.db, orm.FilterEq("at_uri", *comment.ReplyTo)) 15 16 if err != nil { 16 17 return fmt.Errorf("failed to fetch parent comment: %w", err) 17 18 }
+122
orm/orm.go
··· 1 + package orm 2 + 3 + import ( 4 + "context" 5 + "database/sql" 6 + "fmt" 7 + "log/slog" 8 + "reflect" 9 + "strings" 10 + ) 11 + 12 + type migrationFn = func(*sql.Tx) error 13 + 14 + func RunMigration(c *sql.Conn, logger *slog.Logger, name string, migrationFn migrationFn) error { 15 + logger = logger.With("migration", name) 16 + 17 + tx, err := c.BeginTx(context.Background(), nil) 18 + if err != nil { 19 + return err 20 + } 21 + defer tx.Rollback() 22 + 23 + var exists bool 24 + err = tx.QueryRow("select exists (select 1 from migrations where name = ?)", name).Scan(&exists) 25 + if err != nil { 26 + return err 27 + } 28 + 29 + if !exists { 30 + // run migration 31 + err = migrationFn(tx) 32 + if err != nil { 33 + logger.Error("failed to run migration", "err", err) 34 + return err 35 + } 36 + 37 + // mark migration as complete 38 + _, err = tx.Exec("insert into migrations (name) values (?)", name) 39 + if err != nil { 40 + logger.Error("failed to mark migration as complete", "err", err) 41 + return err 42 + } 43 + 44 + // commit the transaction 45 + if err := tx.Commit(); err != nil { 46 + return err 47 + } 48 + 49 + logger.Info("migration applied successfully") 50 + } else { 51 + logger.Warn("skipped migration, already applied") 52 + } 53 + 54 + return nil 55 + } 56 + 57 + type Filter struct { 58 + Key string 59 + arg any 60 + Cmp string 61 + } 62 + 63 + func newFilter(key, cmp string, arg any) Filter { 64 + return Filter{ 65 + Key: key, 66 + arg: arg, 67 + Cmp: cmp, 68 + } 69 + } 70 + 71 + func FilterEq(key string, arg any) Filter { return newFilter(key, "=", arg) } 72 + func FilterNotEq(key string, arg any) Filter { return newFilter(key, "<>", arg) } 73 + func FilterGte(key string, arg any) Filter { return newFilter(key, ">=", arg) } 74 + func FilterLte(key string, arg any) Filter { return newFilter(key, "<=", arg) } 75 + func FilterIs(key string, arg any) Filter { return newFilter(key, "is", arg) } 76 + func FilterIsNot(key string, arg any) Filter { return newFilter(key, "is not", arg) } 77 + func FilterIn(key string, arg any) Filter { return newFilter(key, "in", arg) } 78 + func FilterLike(key string, arg any) Filter { return newFilter(key, "like", arg) } 79 + func FilterNotLike(key string, arg any) Filter { return newFilter(key, "not like", arg) } 80 + func FilterContains(key string, arg any) Filter { 81 + return newFilter(key, "like", fmt.Sprintf("%%%v%%", arg)) 82 + } 83 + 84 + func (f Filter) Condition() string { 85 + rv := reflect.ValueOf(f.arg) 86 + kind := rv.Kind() 87 + 88 + // if we have `FilterIn(k, [1, 2, 3])`, compile it down to `k in (?, ?, ?)` 89 + if (kind == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8) || kind == reflect.Array { 90 + if rv.Len() == 0 { 91 + // always false 92 + return "1 = 0" 93 + } 94 + 95 + placeholders := make([]string, rv.Len()) 96 + for i := range placeholders { 97 + placeholders[i] = "?" 98 + } 99 + 100 + return fmt.Sprintf("%s %s (%s)", f.Key, f.Cmp, strings.Join(placeholders, ", ")) 101 + } 102 + 103 + return fmt.Sprintf("%s %s ?", f.Key, f.Cmp) 104 + } 105 + 106 + func (f Filter) Arg() []any { 107 + rv := reflect.ValueOf(f.arg) 108 + kind := rv.Kind() 109 + if (kind == reflect.Slice && rv.Type().Elem().Kind() != reflect.Uint8) || kind == reflect.Array { 110 + if rv.Len() == 0 { 111 + return nil 112 + } 113 + 114 + out := make([]any, rv.Len()) 115 + for i := range rv.Len() { 116 + out[i] = rv.Index(i).Interface() 117 + } 118 + return out 119 + } 120 + 121 + return []any{f.arg} 122 + }

History

1 round 3 comments
sign up or login to add to the discussion
oppi.li submitted #0
1 commit
expand
orm: extract orm package from appview
expand 3 comments

This PR is only about code organization right? Seems good to me.

About migration logic, how do you think about using up/down style migrations by maybe using external tools? We can still use our own ORM but migration helpers like goose/v3 or migrate/v4 seems useful.

not entirely convinced yet that something like migrate/v4 adds a lot of value. the onus is still on the developer to write idempotent migrations (i.e., if an up migration adds a column, the down migration should remove it, and the library does not really assist in ensuring this property).

This PR is only about code organization right? Seems good to me.

but yes, this is only for organization, i want to be able to write migrations for knotserver and spindle + be able to use the query builder as well.

pull request successfully merged