···421421 on delete cascade
422422 );
423423424424+ create table if not exists repo_languages (
425425+ -- identifiers
426426+ id integer primary key autoincrement,
427427+428428+ -- repo identifiers
429429+ repo_at text not null,
430430+ ref text not null,
431431+432432+ -- language breakdown
433433+ language text not null,
434434+ bytes integer not null check (bytes >= 0),
435435+436436+ unique(repo_at, ref, language)
437437+ );
438438+424439 create table if not exists migrations (
425440 id integer primary key autoincrement,
426441 name text unique
+81
appview/db/language.go
···11+package db
22+33+import (
44+ "fmt"
55+ "strings"
66+77+ "github.com/bluesky-social/indigo/atproto/syntax"
88+)
99+1010+type RepoLanguage struct {
1111+ Id int64
1212+ RepoAt syntax.ATURI
1313+ Ref string
1414+ Language string
1515+ Bytes int64
1616+}
1717+1818+func GetRepoLanguages(e Execer, filters ...filter) ([]RepoLanguage, error) {
1919+ var conditions []string
2020+ var args []any
2121+ for _, filter := range filters {
2222+ conditions = append(conditions, filter.Condition())
2323+ args = append(args, filter.Arg()...)
2424+ }
2525+2626+ whereClause := ""
2727+ if conditions != nil {
2828+ whereClause = " where " + strings.Join(conditions, " and ")
2929+ }
3030+3131+ query := fmt.Sprintf(
3232+ `select id, repo_at, ref, language, bytes from repo_languages %s`,
3333+ whereClause,
3434+ )
3535+ rows, err := e.Query(query, args...)
3636+3737+ if err != nil {
3838+ return nil, fmt.Errorf("failed to execute query: %w ", err)
3939+ }
4040+4141+ var langs []RepoLanguage
4242+ for rows.Next() {
4343+ var rl RepoLanguage
4444+4545+ err := rows.Scan(
4646+ &rl.Id,
4747+ &rl.RepoAt,
4848+ &rl.Ref,
4949+ &rl.Language,
5050+ &rl.Bytes,
5151+ )
5252+ if err != nil {
5353+ return nil, fmt.Errorf("failed to scan: %w ", err)
5454+ }
5555+5656+ langs = append(langs, rl)
5757+ }
5858+ if err = rows.Err(); err != nil {
5959+ return nil, fmt.Errorf("failed to scan rows: %w ", err)
6060+ }
6161+6262+ return langs, nil
6363+}
6464+6565+func InsertRepoLanguages(e Execer, langs []RepoLanguage) error {
6666+ stmt, err := e.Prepare(
6767+ "insert or replace into repo_languages (repo_at, ref, language, bytes) values (?, ?, ?, ?)",
6868+ )
6969+ if err != nil {
7070+ return err
7171+ }
7272+7373+ for _, l := range langs {
7474+ _, err := stmt.Exec(l.RepoAt, l.Ref, l.Language, l.Bytes)
7575+ if err != nil {
7676+ return err
7777+ }
7878+ }
7979+8080+ return nil
8181+}