Monorepo for Tangled
Something went wrong. Try again.
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359package db
import ( "database/sql" "fmt" "maps" "slices" "strings" "time"
"github.com/bluesky-social/indigo/atproto/syntax" "tangled.org/core/appview/models" "tangled.org/core/orm")
// no updating type for nowfunc AddLabelDefinition(e Execer, l *models.LabelDefinition) (int64, error) { result, err := e.Exec( `insert into label_definitions ( did, rkey, name, value_type, value_format, value_enum, scope, color, multiple, created ) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) on conflict(did, rkey) do update set name = excluded.name, scope = excluded.scope, color = excluded.color, multiple = excluded.multiple`, l.Did, l.Rkey, l.Name, l.ValueType.Type, l.ValueType.Format, strings.Join(l.ValueType.Enum, ","), strings.Join(l.Scope, ","), l.Color, l.Multiple, l.Created.Format(time.RFC3339), time.Now().Format(time.RFC3339), ) if err != nil { return 0, err }
id, err := result.LastInsertId() if err != nil { return 0, err }
l.Id = id
return id, nil}
func DeleteLabelDefinition(e Execer, filters ...orm.Filter) error { var conditions []string var args []any for _, filter := range filters { conditions = append(conditions, filter.Condition()) args = append(args, filter.Arg()...) } whereClause := "" if conditions != nil { whereClause = " where " + strings.Join(conditions, " and ") } query := fmt.Sprintf(`delete from label_definitions %s`, whereClause) _, err := e.Exec(query, args...) return err}
func GetLabelDefinitions(e Execer, filters ...orm.Filter) ([]models.LabelDefinition, error) { var labelDefinitions []models.LabelDefinition var conditions []string var args []any
for _, filter := range filters { conditions = append(conditions, filter.Condition()) args = append(args, filter.Arg()...) }
whereClause := "" if conditions != nil { whereClause = " where " + strings.Join(conditions, " and ") }
query := fmt.Sprintf( ` select id, did, rkey, name, value_type, value_format, value_enum, scope, color, multiple, created from label_definitions %s order by created `, whereClause, )
rows, err := e.Query(query, args...) if err != nil { return nil, err } defer rows.Close()
for rows.Next() { var labelDefinition models.LabelDefinition var createdAt, enumVariants, scopes string var color sql.Null[string] var multiple int
if err := rows.Scan( &labelDefinition.Id, &labelDefinition.Did, &labelDefinition.Rkey, &labelDefinition.Name, &labelDefinition.ValueType.Type, &labelDefinition.ValueType.Format, &enumVariants, &scopes, &color, &multiple, &createdAt, ); err != nil { return nil, err }
labelDefinition.Created, err = time.Parse(time.RFC3339, createdAt) if err != nil { labelDefinition.Created = time.Now() }
if color.Valid { labelDefinition.Color = &color.V }
if multiple != 0 { labelDefinition.Multiple = true }
if enumVariants != "" { labelDefinition.ValueType.Enum = strings.Split(enumVariants, ",") }
for s := range strings.SplitSeq(scopes, ",") { labelDefinition.Scope = append(labelDefinition.Scope, s) }
labelDefinitions = append(labelDefinitions, labelDefinition) }
return labelDefinitions, nil}
// helper to get exactly one label deffunc GetLabelDefinition(e Execer, filters ...orm.Filter) (*models.LabelDefinition, error) { labels, err := GetLabelDefinitions(e, filters...) if err != nil { return nil, err }
if labels == nil { return nil, sql.ErrNoRows }
if len(labels) != 1 { return nil, fmt.Errorf("too many rows returned") }
return &labels[0], nil}
func AddLabelOp(e Execer, l *models.LabelOp) (int64, error) { result, err := e.Exec( `insert into label_ops ( did, rkey, subject, operation, operand_key, operand_value, performed ) values (?, ?, ?, ?, ?, ?, ?) on conflict(did, rkey, subject, operand_key, operand_value) do update set operation = excluded.operation, operand_value = excluded.operand_value, performed = excluded.performed`, l.Did, l.Rkey, l.Subject.String(), string(l.Operation), l.OperandKey, l.OperandValue, l.PerformedAt.Format(time.RFC3339), ) if err != nil { return 0, err }
id, err := result.LastInsertId() if err != nil { return 0, err }
l.Id = id
return id, nil}
func DeleteLabelOps(e Execer, filters ...orm.Filter) error { var conditions []string var args []any for _, filter := range filters { conditions = append(conditions, filter.Condition()) args = append(args, filter.Arg()...) } whereClause := "" if conditions != nil { whereClause = " where " + strings.Join(conditions, " and ") } query := fmt.Sprintf(`delete from label_ops %s`, whereClause) _, err := e.Exec(query, args...) return err}
func GetLabelOps(e Execer, filters ...orm.Filter) ([]models.LabelOp, error) { var labelOps []models.LabelOp var conditions []string var args []any
for _, filter := range filters { conditions = append(conditions, filter.Condition()) args = append(args, filter.Arg()...) }
whereClause := "" if conditions != nil { whereClause = " where " + strings.Join(conditions, " and ") }
query := fmt.Sprintf( ` select id, did, rkey, subject, operation, operand_key, operand_value, performed from label_ops %s order by id `, whereClause, )
rows, err := e.Query(query, args...) if err != nil { return nil, err } defer rows.Close()
for rows.Next() { var labelOp models.LabelOp var performedAt string
if err := rows.Scan( &labelOp.Id, &labelOp.Did, &labelOp.Rkey, &labelOp.Subject, &labelOp.Operation, &labelOp.OperandKey, &labelOp.OperandValue, &performedAt, ); err != nil { return nil, err }
labelOp.PerformedAt, err = time.Parse(time.RFC3339, performedAt) if err != nil { labelOp.PerformedAt = time.Time{} }
labelOps = append(labelOps, labelOp) }
return labelOps, nil}
// get labels for a given list of subject URIsfunc GetLabels(e Execer, filters ...orm.Filter) (map[syntax.ATURI]models.LabelState, error) { ops, err := GetLabelOps(e, filters...) if err != nil { return nil, err }
// group ops by subject opsBySubject := make(map[syntax.ATURI][]models.LabelOp) for _, op := range ops { subject := syntax.ATURI(op.Subject) opsBySubject[subject] = append(opsBySubject[subject], op) }
// get all unique labelats for creating the context labelAtSet := make(map[string]bool) for _, op := range ops { labelAtSet[op.OperandKey] = true } labelAts := slices.Collect(maps.Keys(labelAtSet))
actx, err := NewLabelApplicationCtx(e, orm.FilterIn("at_uri", labelAts)) if err != nil { return nil, err }
// apply label ops for each subject and collect results results := make(map[syntax.ATURI]models.LabelState) for subject, subjectOps := range opsBySubject { state := models.NewLabelState() actx.ApplyLabelOps(state, subjectOps) results[subject] = state }
return results, nil}
func NewLabelApplicationCtx(e Execer, filters ...orm.Filter) (*models.LabelApplicationCtx, error) { labels, err := GetLabelDefinitions(e, filters...) if err != nil { return nil, err }
defs := make(map[string]*models.LabelDefinition) for _, l := range labels { defs[l.AtUri().String()] = &l }
return &models.LabelApplicationCtx{Defs: defs}, nil}