Write on the margins of the internet. Powered by the AT Protocol. margin.at
extension web atproto comments
at main 395 lines 13 kB view raw
1package db 2 3import ( 4 "time" 5) 6 7func (db *DB) CreateAnnotation(a *Annotation) error { 8 _, err := db.Exec(db.Rebind(` 9 INSERT INTO annotations (uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid) 10 VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) 11 ON CONFLICT(uri) DO UPDATE SET 12 motivation = excluded.motivation, 13 body_value = excluded.body_value, 14 body_format = excluded.body_format, 15 body_uri = excluded.body_uri, 16 target_source = excluded.target_source, 17 target_hash = excluded.target_hash, 18 target_title = excluded.target_title, 19 selector_json = excluded.selector_json, 20 tags_json = excluded.tags_json, 21 indexed_at = excluded.indexed_at, 22 cid = excluded.cid 23 `), a.URI, a.AuthorDID, a.Motivation, a.BodyValue, a.BodyFormat, a.BodyURI, a.TargetSource, a.TargetHash, a.TargetTitle, a.SelectorJSON, a.TagsJSON, a.CreatedAt, a.IndexedAt, a.CID) 24 return err 25} 26 27func (db *DB) GetAnnotationByURI(uri string) (*Annotation, error) { 28 var a Annotation 29 err := db.QueryRow(db.Rebind(` 30 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 31 FROM annotations 32 WHERE uri = ? 33 `), uri).Scan(&a.URI, &a.AuthorDID, &a.Motivation, &a.BodyValue, &a.BodyFormat, &a.BodyURI, &a.TargetSource, &a.TargetHash, &a.TargetTitle, &a.SelectorJSON, &a.TagsJSON, &a.CreatedAt, &a.IndexedAt, &a.CID) 34 if err != nil { 35 return nil, err 36 } 37 return &a, nil 38} 39 40func (db *DB) GetAnnotationsByTargetHash(targetHash string, limit, offset int) ([]Annotation, error) { 41 rows, err := db.Query(db.Rebind(` 42 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 43 FROM annotations 44 WHERE target_hash = ? 45 ORDER BY created_at DESC 46 LIMIT ? OFFSET ? 47 `), targetHash, limit, offset) 48 if err != nil { 49 return nil, err 50 } 51 defer rows.Close() 52 53 return scanAnnotations(rows) 54} 55 56func (db *DB) GetAnnotationsByAuthor(authorDID string, limit, offset int) ([]Annotation, error) { 57 rows, err := db.Query(db.Rebind(` 58 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 59 FROM annotations 60 WHERE author_did = ? 61 ORDER BY created_at DESC 62 LIMIT ? OFFSET ? 63 `), authorDID, limit, offset) 64 if err != nil { 65 return nil, err 66 } 67 defer rows.Close() 68 69 return scanAnnotations(rows) 70} 71 72func (db *DB) GetMarginAnnotationsByAuthor(authorDID string, limit, offset int) ([]Annotation, error) { 73 rows, err := db.Query(db.Rebind(` 74 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 75 FROM annotations 76 WHERE author_did = ? AND uri NOT LIKE '%network.cosmik%' 77 ORDER BY created_at DESC 78 LIMIT ? OFFSET ? 79 `), authorDID, limit, offset) 80 if err != nil { 81 return nil, err 82 } 83 defer rows.Close() 84 85 return scanAnnotations(rows) 86} 87 88func (db *DB) GetSembleAnnotationsByAuthor(authorDID string, limit, offset int) ([]Annotation, error) { 89 rows, err := db.Query(db.Rebind(` 90 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 91 FROM annotations 92 WHERE author_did = ? AND uri LIKE '%network.cosmik%' 93 ORDER BY created_at DESC 94 LIMIT ? OFFSET ? 95 `), authorDID, limit, offset) 96 if err != nil { 97 return nil, err 98 } 99 defer rows.Close() 100 101 return scanAnnotations(rows) 102} 103 104func (db *DB) GetAnnotationsByMotivation(motivation string, limit, offset int) ([]Annotation, error) { 105 rows, err := db.Query(db.Rebind(` 106 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 107 FROM annotations 108 WHERE motivation = ? 109 ORDER BY created_at DESC 110 LIMIT ? OFFSET ? 111 `), motivation, limit, offset) 112 if err != nil { 113 return nil, err 114 } 115 defer rows.Close() 116 117 return scanAnnotations(rows) 118} 119 120func (db *DB) GetRecentAnnotations(limit, offset int) ([]Annotation, error) { 121 rows, err := db.Query(db.Rebind(` 122 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 123 FROM annotations 124 ORDER BY created_at DESC 125 LIMIT ? OFFSET ? 126 `), limit, offset) 127 if err != nil { 128 return nil, err 129 } 130 defer rows.Close() 131 132 return scanAnnotations(rows) 133} 134 135func (db *DB) GetPopularAnnotations(limit, offset int) ([]Annotation, error) { 136 since := time.Now().AddDate(0, 0, -14) 137 rows, err := db.Query(db.Rebind(` 138 SELECT 139 a.uri, a.author_did, a.motivation, a.body_value, a.body_format, 140 a.body_uri, a.target_source, a.target_hash, a.target_title, 141 a.selector_json, a.tags_json, a.created_at, a.indexed_at, a.cid 142 FROM annotations a 143 LEFT JOIN ( 144 SELECT subject_uri, COUNT(*) as cnt FROM likes GROUP BY subject_uri 145 ) l ON l.subject_uri = a.uri 146 LEFT JOIN ( 147 SELECT root_uri, COUNT(*) as cnt FROM replies GROUP BY root_uri 148 ) r ON r.root_uri = a.uri 149 WHERE a.created_at > ? AND (COALESCE(l.cnt, 0) + COALESCE(r.cnt, 0)) > 0 150 ORDER BY (COALESCE(l.cnt, 0) + COALESCE(r.cnt, 0)) DESC, a.created_at DESC 151 LIMIT ? OFFSET ? 152 `), since, limit, offset) 153 if err != nil { 154 return nil, err 155 } 156 defer rows.Close() 157 158 return scanAnnotations(rows) 159} 160 161func (db *DB) GetShelvedAnnotations(limit, offset int) ([]Annotation, error) { 162 olderThan := time.Now().AddDate(0, 0, -1) 163 since := time.Now().AddDate(0, 0, -14) 164 rows, err := db.Query(db.Rebind(` 165 SELECT 166 a.uri, a.author_did, a.motivation, a.body_value, a.body_format, 167 a.body_uri, a.target_source, a.target_hash, a.target_title, 168 a.selector_json, a.tags_json, a.created_at, a.indexed_at, a.cid 169 FROM annotations a 170 LEFT JOIN ( 171 SELECT subject_uri, COUNT(*) as cnt FROM likes GROUP BY subject_uri 172 ) l ON l.subject_uri = a.uri 173 LEFT JOIN ( 174 SELECT root_uri, COUNT(*) as cnt FROM replies GROUP BY root_uri 175 ) r ON r.root_uri = a.uri 176 WHERE a.created_at < ? AND a.created_at > ? AND (COALESCE(l.cnt, 0) + COALESCE(r.cnt, 0)) = 0 177 ORDER BY RANDOM() 178 LIMIT ? OFFSET ? 179 `), olderThan, since, limit, offset) 180 if err != nil { 181 return nil, err 182 } 183 defer rows.Close() 184 185 return scanAnnotations(rows) 186} 187 188func (db *DB) GetMarginAnnotations(limit, offset int) ([]Annotation, error) { 189 rows, err := db.Query(db.Rebind(` 190 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 191 FROM annotations 192 WHERE uri NOT LIKE '%network.cosmik%' 193 ORDER BY created_at DESC 194 LIMIT ? OFFSET ? 195 `), limit, offset) 196 if err != nil { 197 return nil, err 198 } 199 defer rows.Close() 200 201 return scanAnnotations(rows) 202} 203 204func (db *DB) GetSembleAnnotations(limit, offset int) ([]Annotation, error) { 205 rows, err := db.Query(db.Rebind(` 206 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 207 FROM annotations 208 WHERE uri LIKE '%network.cosmik%' 209 ORDER BY created_at DESC 210 LIMIT ? OFFSET ? 211 `), limit, offset) 212 if err != nil { 213 return nil, err 214 } 215 defer rows.Close() 216 217 return scanAnnotations(rows) 218} 219 220func (db *DB) GetAnnotationsByTag(tag string, limit, offset int) ([]Annotation, error) { 221 pattern := "%\"" + tag + "\"%" 222 rows, err := db.Query(db.Rebind(` 223 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 224 FROM annotations 225 WHERE tags_json LIKE ? 226 ORDER BY created_at DESC 227 LIMIT ? OFFSET ? 228 `), pattern, limit, offset) 229 if err != nil { 230 return nil, err 231 } 232 defer rows.Close() 233 234 return scanAnnotations(rows) 235} 236 237func (db *DB) GetMarginAnnotationsByTag(tag string, limit, offset int) ([]Annotation, error) { 238 pattern := "%\"" + tag + "\"%" 239 rows, err := db.Query(db.Rebind(` 240 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 241 FROM annotations 242 WHERE tags_json LIKE ? AND uri NOT LIKE '%network.cosmik%' 243 ORDER BY created_at DESC 244 LIMIT ? OFFSET ? 245 `), pattern, limit, offset) 246 if err != nil { 247 return nil, err 248 } 249 defer rows.Close() 250 251 return scanAnnotations(rows) 252} 253 254func (db *DB) GetSembleAnnotationsByTag(tag string, limit, offset int) ([]Annotation, error) { 255 pattern := "%\"" + tag + "\"%" 256 rows, err := db.Query(db.Rebind(` 257 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 258 FROM annotations 259 WHERE tags_json LIKE ? AND uri LIKE '%network.cosmik%' 260 ORDER BY created_at DESC 261 LIMIT ? OFFSET ? 262 `), pattern, limit, offset) 263 if err != nil { 264 return nil, err 265 } 266 defer rows.Close() 267 268 return scanAnnotations(rows) 269} 270 271func (db *DB) DeleteAnnotation(uri string) error { 272 _, err := db.Exec(db.Rebind(`DELETE FROM annotations WHERE uri = ?`), uri) 273 return err 274} 275 276func (db *DB) UpdateAnnotation(uri, bodyValue, tagsJSON, cid string) error { 277 _, err := db.Exec(db.Rebind(` 278 UPDATE annotations 279 SET body_value = ?, tags_json = ?, cid = ?, indexed_at = ? 280 WHERE uri = ? 281 `), bodyValue, tagsJSON, cid, time.Now(), uri) 282 return err 283} 284 285func (db *DB) GetAnnotationsByTagAndAuthor(tag, authorDID string, limit, offset int) ([]Annotation, error) { 286 pattern := "%\"" + tag + "\"%" 287 rows, err := db.Query(db.Rebind(` 288 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 289 FROM annotations 290 WHERE author_did = ? AND tags_json LIKE ? 291 ORDER BY created_at DESC 292 LIMIT ? OFFSET ? 293 `), authorDID, pattern, limit, offset) 294 if err != nil { 295 return nil, err 296 } 297 defer rows.Close() 298 299 return scanAnnotations(rows) 300} 301 302func (db *DB) GetMarginAnnotationsByTagAndAuthor(tag, authorDID string, limit, offset int) ([]Annotation, error) { 303 pattern := "%\"" + tag + "\"%" 304 rows, err := db.Query(db.Rebind(` 305 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 306 FROM annotations 307 WHERE author_did = ? AND tags_json LIKE ? AND uri NOT LIKE '%network.cosmik%' 308 ORDER BY created_at DESC 309 LIMIT ? OFFSET ? 310 `), authorDID, pattern, limit, offset) 311 if err != nil { 312 return nil, err 313 } 314 defer rows.Close() 315 316 return scanAnnotations(rows) 317} 318 319func (db *DB) GetSembleAnnotationsByTagAndAuthor(tag, authorDID string, limit, offset int) ([]Annotation, error) { 320 pattern := "%\"" + tag + "\"%" 321 rows, err := db.Query(db.Rebind(` 322 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 323 FROM annotations 324 WHERE author_did = ? AND tags_json LIKE ? AND uri LIKE '%network.cosmik%' 325 ORDER BY created_at DESC 326 LIMIT ? OFFSET ? 327 `), authorDID, pattern, limit, offset) 328 if err != nil { 329 return nil, err 330 } 331 defer rows.Close() 332 333 return scanAnnotations(rows) 334} 335 336func (db *DB) GetAnnotationsByAuthorAndTargetHash(authorDID, targetHash string, limit, offset int) ([]Annotation, error) { 337 rows, err := db.Query(db.Rebind(` 338 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 339 FROM annotations 340 WHERE author_did = ? AND target_hash = ? 341 ORDER BY created_at DESC 342 LIMIT ? OFFSET ? 343 `), authorDID, targetHash, limit, offset) 344 if err != nil { 345 return nil, err 346 } 347 defer rows.Close() 348 349 return scanAnnotations(rows) 350} 351 352func (db *DB) GetAnnotationsByURIs(uris []string) ([]Annotation, error) { 353 if len(uris) == 0 { 354 return []Annotation{}, nil 355 } 356 357 query := db.Rebind(` 358 SELECT uri, author_did, motivation, body_value, body_format, body_uri, target_source, target_hash, target_title, selector_json, tags_json, created_at, indexed_at, cid 359 FROM annotations 360 WHERE uri IN (` + buildPlaceholders(len(uris)) + `) 361 `) 362 363 args := make([]interface{}, len(uris)) 364 for i, uri := range uris { 365 args[i] = uri 366 } 367 368 rows, err := db.Query(query, args...) 369 if err != nil { 370 return nil, err 371 } 372 defer rows.Close() 373 374 return scanAnnotations(rows) 375} 376 377func (db *DB) GetAnnotationURIs(authorDID string) ([]string, error) { 378 rows, err := db.Query(db.Rebind(` 379 SELECT uri FROM annotations WHERE author_did = ? 380 `), authorDID) 381 if err != nil { 382 return nil, err 383 } 384 defer rows.Close() 385 386 var uris []string 387 for rows.Next() { 388 var uri string 389 if err := rows.Scan(&uri); err != nil { 390 return nil, err 391 } 392 uris = append(uris, uri) 393 } 394 return uris, nil 395}