Skip to content

Commit 010d12e

Browse files
committed
fix linter, add indexes for tags
1 parent 5a55fd8 commit 010d12e

File tree

3 files changed

+45
-5
lines changed

3 files changed

+45
-5
lines changed

packages/api/internal/handlers/template_tags.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ func (a *APIStore) PostTemplatesTemplateIDTags(c *gin.Context, templateIDOrAlias
2424
body, err := utils.ParseBody[api.AssignTemplateTagRequest](ctx, c)
2525
if err != nil {
2626
a.sendAPIStoreError(c, http.StatusBadRequest, fmt.Sprintf("Invalid request body: %s", err))
27+
2728
return
2829
}
2930

3031
// Validate tag name
3132
if body.Tag == "" {
3233
a.sendAPIStoreError(c, http.StatusBadRequest, "Tag name is required")
3334
telemetry.ReportError(ctx, "tag name is required", nil)
35+
3436
return
3537
}
3638

@@ -50,11 +52,13 @@ func (a *APIStore) PostTemplatesTemplateIDTags(c *gin.Context, templateIDOrAlias
5052
}
5153
a.sendAPIStoreError(c, http.StatusNotFound, fmt.Sprintf("Template '%s' with tag '%s' not found", templateIDOrAlias, tag))
5254
telemetry.ReportError(ctx, "template or source tag not found", err, telemetry.WithTemplateID(templateIDOrAlias))
55+
5356
return
5457
}
5558

5659
telemetry.ReportError(ctx, "error when getting template with build", err)
5760
a.sendAPIStoreError(c, http.StatusInternalServerError, "Error getting template")
61+
5862
return
5963
}
6064

@@ -66,6 +70,7 @@ func (a *APIStore) PostTemplatesTemplateIDTags(c *gin.Context, templateIDOrAlias
6670
if apiErr != nil {
6771
a.sendAPIStoreError(c, apiErr.Code, apiErr.ClientMsg)
6872
telemetry.ReportCriticalError(ctx, "error when getting team", apiErr.Err)
73+
6974
return
7075
}
7176

@@ -78,6 +83,7 @@ func (a *APIStore) PostTemplatesTemplateIDTags(c *gin.Context, templateIDOrAlias
7883
if template.TeamID != team.ID {
7984
a.sendAPIStoreError(c, http.StatusForbidden, fmt.Sprintf("You don't have access to sandbox template '%s'", templateIDOrAlias))
8085
telemetry.ReportError(ctx, "no access to the template", nil, telemetry.WithTemplateID(template.ID))
86+
8187
return
8288
}
8389

@@ -90,6 +96,7 @@ func (a *APIStore) PostTemplatesTemplateIDTags(c *gin.Context, templateIDOrAlias
9096
if err != nil {
9197
telemetry.ReportCriticalError(ctx, "error when creating tag assignment", err)
9298
a.sendAPIStoreError(c, http.StatusInternalServerError, "Error creating tag assignment")
99+
93100
return
94101
}
95102

@@ -121,6 +128,7 @@ func (a *APIStore) DeleteTemplatesTemplateIDTagsTag(c *gin.Context, templateIDOr
121128
if tag == id.DefaultTag {
122129
a.sendAPIStoreError(c, http.StatusBadRequest, fmt.Sprintf("Cannot delete the '%s' tag", id.DefaultTag))
123130
telemetry.ReportError(ctx, "cannot delete default tag", nil)
131+
124132
return
125133
}
126134

@@ -130,11 +138,13 @@ func (a *APIStore) DeleteTemplatesTemplateIDTagsTag(c *gin.Context, templateIDOr
130138
if dberrors.IsNotFoundError(err) {
131139
a.sendAPIStoreError(c, http.StatusNotFound, fmt.Sprintf("Template '%s' not found", templateIDOrAlias))
132140
telemetry.ReportError(ctx, "template not found", err, telemetry.WithTemplateID(templateIDOrAlias))
141+
133142
return
134143
}
135144

136145
telemetry.ReportError(ctx, "error when getting template", err)
137146
a.sendAPIStoreError(c, http.StatusInternalServerError, "Error getting template")
147+
138148
return
139149
}
140150

@@ -143,6 +153,7 @@ func (a *APIStore) DeleteTemplatesTemplateIDTagsTag(c *gin.Context, templateIDOr
143153
if apiErr != nil {
144154
a.sendAPIStoreError(c, apiErr.Code, apiErr.ClientMsg)
145155
telemetry.ReportCriticalError(ctx, "error when getting team", apiErr.Err)
156+
146157
return
147158
}
148159

@@ -155,6 +166,7 @@ func (a *APIStore) DeleteTemplatesTemplateIDTagsTag(c *gin.Context, templateIDOr
155166
if template.TeamID != team.ID {
156167
a.sendAPIStoreError(c, http.StatusForbidden, fmt.Sprintf("You don't have access to sandbox template '%s'", templateIDOrAlias))
157168
telemetry.ReportError(ctx, "no access to the template", nil, telemetry.WithTemplateID(template.ID))
169+
158170
return
159171
}
160172

@@ -166,6 +178,7 @@ func (a *APIStore) DeleteTemplatesTemplateIDTagsTag(c *gin.Context, templateIDOr
166178
if err != nil {
167179
telemetry.ReportCriticalError(ctx, "error when deleting tag assignment", err)
168180
a.sendAPIStoreError(c, http.StatusInternalServerError, "Error deleting tag assignment")
181+
169182
return
170183
}
171184

packages/db/migrations/20251216120000_allow_m_n_builds_with_tags.sql renamed to packages/db/migrations/20251218160000_allow_m_n_builds_with_tags.sql

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
11
-- +goose Up
2+
-- +goose StatementBegin
3+
-- 0. Create helper function to safely cast text to UUID (returns NULL if invalid)
4+
-- This is needed for PostgreSQL < 16 (which has pg_input_is_valid)
5+
CREATE OR REPLACE FUNCTION try_cast_uuid(p_value text) RETURNS uuid AS $$
6+
BEGIN
7+
RETURN p_value::uuid;
8+
EXCEPTION WHEN invalid_text_representation THEN
9+
RETURN NULL;
10+
END;
11+
$$ LANGUAGE plpgsql IMMUTABLE;
12+
-- +goose StatementEnd
13+
214
-- +goose StatementBegin
315
-- 1. Create the new env_build_assignments table
416
CREATE TABLE env_build_assignments (
@@ -25,6 +37,13 @@ CREATE TABLE env_build_assignments (
2537
UNIQUE (build_id, tag, created_at)
2638
);
2739
ALTER TABLE "public"."env_build_assignments" ENABLE ROW LEVEL SECURITY;
40+
41+
-- Create indexes for efficient lookups
42+
CREATE INDEX idx_env_build_assignments_env_tag_created
43+
ON env_build_assignments (env_id, tag, created_at DESC);
44+
45+
CREATE INDEX idx_env_build_assignments_env_build
46+
ON env_build_assignments (env_id, build_id);
2847
-- +goose StatementEnd
2948

3049
-- +goose StatementBegin
@@ -85,7 +104,18 @@ DROP FUNCTION IF EXISTS sync_env_build_assignment();
85104
-- +goose StatementEnd
86105

87106
-- +goose StatementBegin
88-
-- 3. Drop the assignments table
107+
-- 3. Drop indexes
108+
DROP INDEX IF EXISTS idx_env_build_assignments_env_tag_created;
109+
DROP INDEX IF EXISTS idx_env_build_assignments_env_build;
110+
-- +goose StatementEnd
111+
112+
-- +goose StatementBegin
113+
-- 4. Drop the assignments table
89114
DROP TABLE IF EXISTS env_build_assignments;
90115
-- +goose StatementEnd
91116

117+
-- +goose StatementBegin
118+
-- 5. Drop helper function
119+
DROP FUNCTION IF EXISTS try_cast_uuid(text);
120+
-- +goose StatementEnd
121+

packages/db/queries/templates/get_template_with_build_by_tag.sql

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,7 @@ JOIN public.env_build_assignments AS eba ON eba.env_id = e.id
1919
eba.tag = COALESCE(sqlc.narg(tag), 'latest')
2020
OR
2121
-- Match by build_id if the tag parameter is a valid UUID
22-
(
23-
sqlc.narg(tag) IS NOT NULL
24-
AND eba.build_id::text = sqlc.narg(tag)
25-
)
22+
eba.build_id = try_cast_uuid(sqlc.narg(tag))
2623
)
2724
JOIN public.env_builds AS eb ON eb.id = eba.build_id
2825
AND eb.status = 'uploaded'

0 commit comments

Comments
 (0)