···330330 verified text, -- time of verification
331331 created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
332332333333- unique(instance)
333333+ unique(did, instance)
334334+ );
335335+336336+ create table if not exists spindle_members (
337337+ -- identifiers for the record
338338+ id integer primary key autoincrement,
339339+ did text not null,
340340+ rkey text not null,
341341+342342+ -- data
343343+ instance text not null,
344344+ subject text not null,
345345+ created text not null default (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
346346+347347+ -- constraints
348348+ foreign key (did, instance) references spindles(owner, instance) on delete cascade,
349349+ unique (did, instance, subject)
334350 );
335351336352 create table if not exists pipelines (
+96
appview/db/spindle.go
···1717 Created time.Time
1818}
19192020+type SpindleMember struct {
2121+ Id int
2222+ Did syntax.DID // owner of the record
2323+ Rkey string // rkey of the record
2424+ Instance string
2525+ Subject syntax.DID // the member being added
2626+ Created time.Time
2727+}
2828+2029func GetSpindles(e Execer, filters ...filter) ([]Spindle, error) {
2130 var spindles []Spindle
2231···134143 _, err := e.Exec(query, args...)
135144 return err
136145}
146146+147147+func AddSpindleMember(e Execer, member SpindleMember) error {
148148+ _, err := e.Exec(
149149+ `insert or ignore into spindle_members (did, rkey, instance, subject) values (?, ?, ?, ?)`,
150150+ member.Did,
151151+ member.Rkey,
152152+ member.Instance,
153153+ member.Subject,
154154+ )
155155+ return err
156156+}
157157+158158+func RemoveSpindleMember(e Execer, filters ...filter) error {
159159+ var conditions []string
160160+ var args []any
161161+ for _, filter := range filters {
162162+ conditions = append(conditions, filter.Condition())
163163+ args = append(args, filter.Arg()...)
164164+ }
165165+166166+ whereClause := ""
167167+ if conditions != nil {
168168+ whereClause = " where " + strings.Join(conditions, " and ")
169169+ }
170170+171171+ query := fmt.Sprintf(`delete from spindle_members %s`, whereClause)
172172+173173+ _, err := e.Exec(query, args...)
174174+ return err
175175+}
176176+177177+func GetSpindleMembers(e Execer, filters ...filter) ([]SpindleMember, error) {
178178+ var members []SpindleMember
179179+180180+ var conditions []string
181181+ var args []any
182182+ for _, filter := range filters {
183183+ conditions = append(conditions, filter.Condition())
184184+ args = append(args, filter.Arg()...)
185185+ }
186186+187187+ whereClause := ""
188188+ if conditions != nil {
189189+ whereClause = " where " + strings.Join(conditions, " and ")
190190+ }
191191+192192+ query := fmt.Sprintf(
193193+ `select id, did, rkey, instance, subject, created
194194+ from spindle_members
195195+ %s
196196+ order by created
197197+ `,
198198+ whereClause,
199199+ )
200200+201201+ rows, err := e.Query(query, args...)
202202+203203+ if err != nil {
204204+ return nil, err
205205+ }
206206+ defer rows.Close()
207207+208208+ for rows.Next() {
209209+ var member SpindleMember
210210+ var createdAt string
211211+212212+ if err := rows.Scan(
213213+ &member.Id,
214214+ &member.Did,
215215+ &member.Rkey,
216216+ &member.Instance,
217217+ &member.Subject,
218218+ &createdAt,
219219+ ); err != nil {
220220+ return nil, err
221221+ }
222222+223223+ member.Created, err = time.Parse(time.RFC3339, createdAt)
224224+ if err != nil {
225225+ member.Created = time.Now()
226226+ }
227227+228228+ members = append(members, member)
229229+ }
230230+231231+ return members, nil
232232+}