diff --git a/appview/db/db.go b/appview/db/db.go --- a/appview/db/db.go +++ b/appview/db/db.go @@ -330,7 +330,23 @@ verified text, -- time of verification created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')), - unique(instance) + unique(did, instance) + ); + + create table if not exists spindle_members ( + -- identifiers for the record + id integer primary key autoincrement, + did text not null, + rkey text not null, + + -- data + instance text not null, + subject text not null, + created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')), + + -- constraints + foreign key (did, instance) references spindles(owner, instance) on delete cascade, + unique (did, instance, subject) ); create table if not exists pipelines ( diff --git a/appview/db/spindle.go b/appview/db/spindle.go --- a/appview/db/spindle.go +++ b/appview/db/spindle.go @@ -17,6 +17,15 @@ Created time.Time } +type SpindleMember struct { + Id int + Did syntax.DID // owner of the record + Rkey string // rkey of the record + Instance string + Subject syntax.DID // the member being added + Created time.Time +} + func GetSpindles(e Execer, filters ...filter) ([]Spindle, error) { var spindles []Spindle @@ -133,4 +142,91 @@ _, err := e.Exec(query, args...) return err +} + +func AddSpindleMember(e Execer, member SpindleMember) error { + _, err := e.Exec( + `insert or ignore into spindle_members (did, rkey, instance, subject) values (?, ?, ?, ?)`, + member.Did, + member.Rkey, + member.Instance, + member.Subject, + ) + return err +} + +func RemoveSpindleMember(e Execer, filters ...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 spindle_members %s`, whereClause) + + _, err := e.Exec(query, args...) + return err +} + +func GetSpindleMembers(e Execer, filters ...filter) ([]SpindleMember, error) { + var members []SpindleMember + + 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, instance, subject, created + from spindle_members + %s + order by created + `, + whereClause, + ) + + rows, err := e.Query(query, args...) + + if err != nil { + return nil, err + } + defer rows.Close() + + for rows.Next() { + var member SpindleMember + var createdAt string + + if err := rows.Scan( + &member.Id, + &member.Did, + &member.Rkey, + &member.Instance, + &member.Subject, + &createdAt, + ); err != nil { + return nil, err + } + + member.Created, err = time.Parse(time.RFC3339, createdAt) + if err != nil { + member.Created = time.Now() + } + + members = append(members, member) + } + + return members, nil }