Monorepo for Tangled
0

Configure Feed

Select the types of activity you want to include in your feed.

appview/db: scope reverse-mapping queries

multiple `defer rows.Close()` call in same scope can be dangerous as
underlying value will change.
avoid that by splitting reverse-mapping queries into scoped blocks.

Signed-off-by: Seongmin Lee <git@boltless.me>

Seongmin Lee (May 10, 2026, 12:45 AM +0900) 6c1b67de 040c9272

+142 -128
+142 -128
appview/db/repos.go
··· 138 138 } 139 139 140 140 // get labels for all repos 141 - labelsQuery := fmt.Sprintf( 142 - `select repo_at, label_at from repo_labels where repo_at in (%s)`, 143 - inClause, 144 - ) 141 + { 142 + labelsQuery := fmt.Sprintf( 143 + `select repo_at, label_at from repo_labels where repo_at in (%s)`, 144 + inClause, 145 + ) 145 146 146 - rows, err = e.Query(labelsQuery, args...) 147 - if err != nil { 148 - return nil, err 149 - } 150 - defer rows.Close() 147 + rows, err = e.Query(labelsQuery, args...) 148 + if err != nil { 149 + return nil, fmt.Errorf("failed to execute repo_labels query: %w", err) 150 + } 151 + defer rows.Close() 151 152 152 - for rows.Next() { 153 - var repoat, labelat string 154 - if err := rows.Scan(&repoat, &labelat); err != nil { 155 - continue 153 + for rows.Next() { 154 + var repoat, labelat string 155 + if err := rows.Scan(&repoat, &labelat); err != nil { 156 + log.Println("err", err) 157 + continue 158 + } 159 + if r, ok := repoMap[syntax.ATURI(repoat)]; ok { 160 + r.Labels = append(r.Labels, labelat) 161 + } 156 162 } 157 - if r, ok := repoMap[syntax.ATURI(repoat)]; ok { 158 - r.Labels = append(r.Labels, labelat) 163 + if err = rows.Err(); err != nil { 164 + return nil, fmt.Errorf("failed to execute repo_labels query: %w", err) 159 165 } 160 166 } 161 167 162 168 // get primary language for all repos 163 - languageQuery := fmt.Sprintf(` 164 - select repo_at, language 165 - from ( 166 - select 167 - repo_at, language, 168 - row_number() over ( 169 - partition by repo_at 170 - order by bytes desc 171 - ) as rn 172 - from repo_languages 173 - where repo_at in (%s) 174 - and is_default_ref = 1 175 - and language <> '' 176 - ) 177 - where rn = 1 178 - `, inClause) 169 + { 170 + languageQuery := fmt.Sprintf(` 171 + select repo_at, language 172 + from ( 173 + select 174 + repo_at, language, 175 + row_number() over ( 176 + partition by repo_at 177 + order by bytes desc 178 + ) as rn 179 + from repo_languages 180 + where repo_at in (%s) 181 + and is_default_ref = 1 182 + and language <> '' 183 + ) 184 + where rn = 1 185 + `, inClause) 179 186 180 - rows, err = e.Query(languageQuery, args...) 181 - if err != nil { 182 - return nil, fmt.Errorf("failed to execute lang query: %w", err) 183 - } 184 - defer rows.Close() 187 + rows, err = e.Query(languageQuery, args...) 188 + if err != nil { 189 + return nil, fmt.Errorf("failed to execute lang query: %w", err) 190 + } 191 + defer rows.Close() 185 192 186 - for rows.Next() { 187 - var repoat, lang string 188 - if err := rows.Scan(&repoat, &lang); err != nil { 189 - log.Println("err", "err", err) 190 - continue 193 + for rows.Next() { 194 + var repoat, lang string 195 + if err := rows.Scan(&repoat, &lang); err != nil { 196 + log.Println("err", err) 197 + continue 198 + } 199 + if r, ok := repoMap[syntax.ATURI(repoat)]; ok { 200 + r.RepoStats.Language = lang 201 + } 191 202 } 192 - if r, ok := repoMap[syntax.ATURI(repoat)]; ok { 193 - r.RepoStats.Language = lang 203 + if err = rows.Err(); err != nil { 204 + return nil, fmt.Errorf("failed to execute lang query: %w", err) 194 205 } 195 206 } 196 - if err = rows.Err(); err != nil { 197 - return nil, fmt.Errorf("failed to execute lang query: %w", err) 198 - } 199 207 200 208 // get star counts 201 - starCountQuery := fmt.Sprintf( 202 - `select subject_at, count(1) from stars where subject_at in (%s) group by subject_at`, 203 - inClause, 204 - ) 209 + { 210 + starCountQuery := fmt.Sprintf( 211 + `select subject_at, count(1) from stars where subject_at in (%s) group by subject_at`, 212 + inClause, 213 + ) 205 214 206 - rows, err = e.Query(starCountQuery, args...) 207 - if err != nil { 208 - return nil, fmt.Errorf("failed to execute star-count query: %w", err) 209 - } 210 - defer rows.Close() 215 + rows, err = e.Query(starCountQuery, args...) 216 + if err != nil { 217 + return nil, fmt.Errorf("failed to execute star-count query: %w", err) 218 + } 219 + defer rows.Close() 211 220 212 - for rows.Next() { 213 - var repoat string 214 - var count int 215 - if err := rows.Scan(&repoat, &count); err != nil { 216 - log.Println("err", "err", err) 217 - continue 221 + for rows.Next() { 222 + var repoat string 223 + var count int 224 + if err := rows.Scan(&repoat, &count); err != nil { 225 + log.Println("err", "err", err) 226 + continue 227 + } 228 + if r, ok := repoMap[syntax.ATURI(repoat)]; ok { 229 + r.RepoStats.StarCount = count 230 + } 218 231 } 219 - if r, ok := repoMap[syntax.ATURI(repoat)]; ok { 220 - r.RepoStats.StarCount = count 232 + if err = rows.Err(); err != nil { 233 + return nil, fmt.Errorf("failed to execute star-count query: %w", err) 221 234 } 222 235 } 223 - if err = rows.Err(); err != nil { 224 - return nil, fmt.Errorf("failed to execute star-count query: %w", err) 225 - } 226 236 227 237 // get issue counts 228 - issueCountQuery := fmt.Sprintf(` 229 - select 230 - repo_at, 231 - count(case when open = 1 then 1 end) as open_count, 232 - count(case when open = 0 then 1 end) as closed_count 233 - from issues 234 - where repo_at in (%s) 235 - group by repo_at 236 - `, inClause) 238 + { 239 + issueCountQuery := fmt.Sprintf(` 240 + select 241 + repo_at, 242 + count(case when open = 1 then 1 end) as open_count, 243 + count(case when open = 0 then 1 end) as closed_count 244 + from issues 245 + where repo_at in (%s) 246 + group by repo_at 247 + `, inClause) 237 248 238 - rows, err = e.Query(issueCountQuery, args...) 239 - if err != nil { 240 - return nil, fmt.Errorf("failed to execute issue-count query: %w", err) 241 - } 242 - defer rows.Close() 249 + rows, err = e.Query(issueCountQuery, args...) 250 + if err != nil { 251 + return nil, fmt.Errorf("failed to execute issue-count query: %w", err) 252 + } 253 + defer rows.Close() 243 254 244 - for rows.Next() { 245 - var repoat string 246 - var open, closed int 247 - if err := rows.Scan(&repoat, &open, &closed); err != nil { 248 - log.Println("err", "err", err) 249 - continue 255 + for rows.Next() { 256 + var repoat string 257 + var open, closed int 258 + if err := rows.Scan(&repoat, &open, &closed); err != nil { 259 + log.Println("err", err) 260 + continue 261 + } 262 + if r, ok := repoMap[syntax.ATURI(repoat)]; ok { 263 + r.RepoStats.IssueCount.Open = open 264 + r.RepoStats.IssueCount.Closed = closed 265 + } 250 266 } 251 - if r, ok := repoMap[syntax.ATURI(repoat)]; ok { 252 - r.RepoStats.IssueCount.Open = open 253 - r.RepoStats.IssueCount.Closed = closed 267 + if err = rows.Err(); err != nil { 268 + return nil, fmt.Errorf("failed to execute issue-count query: %w", err) 254 269 } 255 270 } 256 - if err = rows.Err(); err != nil { 257 - return nil, fmt.Errorf("failed to execute issue-count query: %w", err) 258 - } 259 271 260 272 // get pull counts 261 - pullCountQuery := fmt.Sprintf(` 262 - select 263 - repo_at, 264 - count(case when state = ? then 1 end) as open_count, 265 - count(case when state = ? then 1 end) as merged_count, 266 - count(case when state = ? then 1 end) as closed_count, 267 - count(case when state = ? then 1 end) as deleted_count 268 - from pulls 269 - where repo_at in (%s) 270 - group by repo_at 271 - `, inClause) 273 + { 274 + pullCountQuery := fmt.Sprintf(` 275 + select 276 + repo_at, 277 + count(case when state = ? then 1 end) as open_count, 278 + count(case when state = ? then 1 end) as merged_count, 279 + count(case when state = ? then 1 end) as closed_count, 280 + count(case when state = ? then 1 end) as deleted_count 281 + from pulls 282 + where repo_at in (%s) 283 + group by repo_at 284 + `, inClause) 272 285 273 - pullArgs := append([]any{ 274 - models.PullOpen, 275 - models.PullMerged, 276 - models.PullClosed, 277 - models.PullAbandoned, 278 - }, args...) 286 + pullArgs := append([]any{ 287 + models.PullOpen, 288 + models.PullMerged, 289 + models.PullClosed, 290 + models.PullAbandoned, 291 + }, args...) 279 292 280 - rows, err = e.Query(pullCountQuery, pullArgs...) 281 - if err != nil { 282 - return nil, fmt.Errorf("failed to execute pulls-count query: %w", err) 283 - } 284 - defer rows.Close() 293 + rows, err = e.Query(pullCountQuery, pullArgs...) 294 + if err != nil { 295 + return nil, fmt.Errorf("failed to execute pulls-count query: %w", err) 296 + } 297 + defer rows.Close() 285 298 286 - for rows.Next() { 287 - var repoat string 288 - var open, merged, closed, deleted int 289 - if err := rows.Scan(&repoat, &open, &merged, &closed, &deleted); err != nil { 290 - log.Println("err", "err", err) 291 - continue 299 + for rows.Next() { 300 + var repoat string 301 + var open, merged, closed, deleted int 302 + if err := rows.Scan(&repoat, &open, &merged, &closed, &deleted); err != nil { 303 + log.Println("err", "err", err) 304 + continue 305 + } 306 + if r, ok := repoMap[syntax.ATURI(repoat)]; ok { 307 + r.RepoStats.PullCount.Open = open 308 + r.RepoStats.PullCount.Merged = merged 309 + r.RepoStats.PullCount.Closed = closed 310 + r.RepoStats.PullCount.Deleted = deleted 311 + } 292 312 } 293 - if r, ok := repoMap[syntax.ATURI(repoat)]; ok { 294 - r.RepoStats.PullCount.Open = open 295 - r.RepoStats.PullCount.Merged = merged 296 - r.RepoStats.PullCount.Closed = closed 297 - r.RepoStats.PullCount.Deleted = deleted 313 + if err = rows.Err(); err != nil { 314 + return nil, fmt.Errorf("failed to execute pulls-count query: %w", err) 298 315 } 299 - } 300 - if err = rows.Err(); err != nil { 301 - return nil, fmt.Errorf("failed to execute pulls-count query: %w", err) 302 316 } 303 317 304 318 var repos []models.Repo