Skip to content

fix: [AH-2825]: fix for download stat query#78

Open
abhinavcode wants to merge 2 commits into
mainfrom
AH-2825-fixx
Open

fix: [AH-2825]: fix for download stat query#78
abhinavcode wants to merge 2 commits into
mainfrom
AH-2825-fixx

Conversation

@abhinavcode

@abhinavcode abhinavcode commented Feb 19, 2026

Copy link
Copy Markdown
Owner

Summary by CodeRabbit

  • Bug Fixes
    • Improved download statistics tracking to correctly handle cases where artifact type information may not be specified, ensuring more accurate recording of download events across different scenarios.

@coderabbitai

coderabbitai Bot commented Feb 19, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The change modifies the download stat database operation to dynamically construct query arguments instead of using a fixed parameter list. The artifactType parameter is now conditionally appended only when it's non-nil and non-empty, adjusting the query behavior based on whether filtering by image type is needed.

Changes

Cohort / File(s) Summary
Download Stat Query Parameter Construction
registry/app/store/database/download_stat.go
Modified to build arguments dynamically using UnixMilli timestamps and conditionally include artifactType based on its presence and value, replacing fixed parameter passing (+9/-3).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A rabbit hops through database rows,
With timestamps flowing, parameters now,
When artifact types aren't defined,
The query adapts, cleverly designed—
Conditional logic, dancing just right! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: fixing a download stat query issue, with reference to the tracking ticket AH-2825.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch AH-2825-fixx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
registry/app/store/database/download_stat.go (2)

133-141: Missing query observability — inconsistent with peer methods.

Every other method in this file logs the formatted SQL query before execution via util.FormatQuery + log.Ctx(ctx).Debug(). CreateByRegistryIDImageAndArtifactName omits this, making it harder to diagnose production query issues.

♻️ Proposed addition
+	finalQuery := util.FormatQuery(sqlStr, args)
+	log.Ctx(ctx).Debug().Str("sql", finalQuery).Msg("Executing CreateByRegistryIDImageAndArtifactName query")
+
 	_, err = db.ExecContext(ctx, sqlStr, args...)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/store/database/download_stat.go` around lines 133 - 141,
CreateByRegistryIDImageAndArtifactName is missing the SQL observability present
in its peers; before calling db.ExecContext, call util.FormatQuery(sqlStr,
args...) and log it with log.Ctx(ctx).Debug() so the executed query (with
parameters) is emitted to logs. Locate the block in download_stat.go where args
are built and db.ExecContext is invoked, format the query using
util.FormatQuery(sqlStr, args...) into a variable, and pass that to
log.Ctx(ctx).Debug() (matching the pattern used by other methods in this file)
immediately before executing the query.

122-141: Fragile manual arg ordering — squirrel-generated args silently discarded.

The squirrel builder accumulates args alongside ? placeholders for Where() calls, but those args are thrown away (_ at line 123) and rebuilt by hand. Any future edit — adding a WHERE condition, reordering columns, or changing the Select(...) literal count — must keep this manual args slice in sync, with no compiler or runtime guard until the query executes. The rest of the file binds values directly in squirrel (e.g., sq.Eq{...}) so the returned args are correct by construction.

Consider binding values inline so squirrel tracks them:

♻️ Sketch of a squirrel-native binding
-	selectQuery := databaseg.Builder.
-		Select(
-			"a.artifact_id",
-			"?",
-			"?",
-			"?",
-			"?",
-			"?",
-		).
-		From("artifacts a").
-		Join("images i ON a.artifact_image_id = i.image_id").
-		Where("a.artifact_version = ? AND i.image_registry_id = ? AND i.image_name = ? ")
-	if artifactType != nil && *artifactType != "" {
-		selectQuery = selectQuery.Where("i.image_type = ?")
-	} else {
-		selectQuery = selectQuery.Where("i.image_type IS NULL")
-	}
-	selectQuery = selectQuery.Limit(1)

+	now := time.Now().UnixMilli()
+	session, _ := request.AuthSessionFrom(ctx)
+	user := session.Principal.ID
+
+	selectQuery := databaseg.Builder.
+		Select(
+			"a.artifact_id",
+			sq.Expr("?", now),
+			sq.Expr("?", now),
+			sq.Expr("?", now),
+			sq.Expr("?", user),
+			sq.Expr("?", user),
+		).
+		From("artifacts a").
+		Join("images i ON a.artifact_image_id = i.image_id").
+		Where("a.artifact_version = ? AND i.image_registry_id = ? AND i.image_name = ?",
+			version, regID, image)
+	if artifactType != nil && *artifactType != "" {
+		selectQuery = selectQuery.Where("i.image_type = ?", *artifactType)
+	} else {
+		selectQuery = selectQuery.Where("i.image_type IS NULL")
+	}
+	selectQuery = selectQuery.Limit(1)

 	insertQuery := databaseg.Builder.
 		Insert("download_stats").
 		Columns(
 			"download_stat_artifact_id",
 			"download_stat_timestamp",
 			"download_stat_created_at",
 			"download_stat_updated_at",
 			"download_stat_created_by",
 			"download_stat_updated_by",
 		).
 		Select(selectQuery)

-	sqlStr, _, err := insertQuery.ToSql()
+	sqlStr, args, err := insertQuery.ToSql()
 	if err != nil {
 		return fmt.Errorf("failed to generate SQL: %w", err)
 	}
-
-	session, _ := request.AuthSessionFrom(ctx)
-	user := session.Principal.ID
 	db := dbtx.GetAccessor(ctx, d.db)

-	now := time.Now().UnixMilli()
-	args := []interface{}{now, now, now, user, user, version, regID, image}
-
-	// Only add artifactType parameter if the WHERE clause includes it
-	if artifactType != nil && *artifactType != "" {
-		args = append(args, artifactType)
-	}
-
 	_, err = db.ExecContext(ctx, sqlStr, args...)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@registry/app/store/database/download_stat.go` around lines 122 - 141, The
code discards squirrel's generated args (using `_` from insertQuery.ToSql()) and
rebuilds them manually, which is fragile; instead capture the args returned by
insertQuery.ToSql() (replace `sqlStr, _, err := insertQuery.ToSql()` with
`sqlStr, args, err := insertQuery.ToSql()`), remove the manual args slice and
any manual artifactType appending, ensure the squirrel
`insertQuery`/`Where`/`Set` calls include the now/user/version/regID/image and
optional artifactType bindings so squirrel produces the correct placeholders,
and then call db.ExecContext(ctx, sqlStr, args...) (references: insertQuery,
ToSql(), artifactType, db.ExecContext).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@registry/app/store/database/download_stat.go`:
- Around line 133-141: CreateByRegistryIDImageAndArtifactName is missing the SQL
observability present in its peers; before calling db.ExecContext, call
util.FormatQuery(sqlStr, args...) and log it with log.Ctx(ctx).Debug() so the
executed query (with parameters) is emitted to logs. Locate the block in
download_stat.go where args are built and db.ExecContext is invoked, format the
query using util.FormatQuery(sqlStr, args...) into a variable, and pass that to
log.Ctx(ctx).Debug() (matching the pattern used by other methods in this file)
immediately before executing the query.
- Around line 122-141: The code discards squirrel's generated args (using `_`
from insertQuery.ToSql()) and rebuilds them manually, which is fragile; instead
capture the args returned by insertQuery.ToSql() (replace `sqlStr, _, err :=
insertQuery.ToSql()` with `sqlStr, args, err := insertQuery.ToSql()`), remove
the manual args slice and any manual artifactType appending, ensure the squirrel
`insertQuery`/`Where`/`Set` calls include the now/user/version/regID/image and
optional artifactType bindings so squirrel produces the correct placeholders,
and then call db.ExecContext(ctx, sqlStr, args...) (references: insertQuery,
ToSql(), artifactType, db.ExecContext).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants