Skip to content

Commit beb88f5

Browse files
chore: look up tool variations by urn (#557)
Reverts #553 Unreverting a revert, which was blocked on `dev` having null values in the database. That has now been resolved. Dev: <img width="1242" height="218" alt="CleanShot 2025-10-15 at 11 40 00@2x" src="https://github.com/user-attachments/assets/3a954ad0-be7a-4b1c-aa66-cc1c67781329" /> Prod: <img width="1272" height="218" alt="CleanShot 2025-10-15 at 11 40 34@2x" src="https://github.com/user-attachments/assets/ea60ab32-94aa-4b5f-af29-356cb5cc764b" />
1 parent 5225e6d commit beb88f5

File tree

14 files changed

+96
-80
lines changed

14 files changed

+96
-80
lines changed

server/database/schema.sql

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ CREATE TABLE IF NOT EXISTS tool_variations (
751751
id uuid NOT NULL DEFAULT generate_uuidv7(),
752752
group_id uuid NOT NULL,
753753

754-
src_tool_urn TEXT,
754+
src_tool_urn TEXT NOT NULL,
755755
src_tool_name TEXT NOT NULL,
756756

757757
confirm TEXT,
@@ -771,13 +771,9 @@ CREATE TABLE IF NOT EXISTS tool_variations (
771771
CONSTRAINT tool_variations_group_id_fkey FOREIGN KEY (group_id) REFERENCES tool_variations_groups (id) ON DELETE CASCADE
772772
);
773773

774-
CREATE UNIQUE INDEX IF NOT EXISTS tool_variations_scoped_src_tool_name_key
775-
ON tool_variations (group_id, src_tool_name)
776-
WHERE deleted IS FALSE;
777-
778774
CREATE UNIQUE INDEX IF NOT EXISTS tool_variations_scoped_src_tool_urn_key
779775
ON tool_variations (group_id, src_tool_urn)
780-
WHERE src_tool_urn IS NOT NULL AND deleted IS FALSE;
776+
WHERE deleted IS FALSE;
781777

782778
CREATE TABLE IF NOT EXISTS prompt_templates (
783779
id uuid NOT NULL DEFAULT generate_uuidv7(),

server/database/sqlc.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@ overrides:
4141
go_type:
4242
import: github.com/speakeasy-api/gram/server/internal/conv
4343
type: Secret
44+
- column: tool_variations.src_tool_urn
45+
go_type:
46+
import: github.com/speakeasy-api/gram/server/internal/urn
47+
type: Tool
4448

4549
sql:
4650
- schema: schema.sql

server/internal/database/models.go

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

server/internal/mv/toolset.go

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -90,28 +90,22 @@ func DescribeToolsetEntry(
9090
return nil, oops.E(oops.CodeUnexpected, err, "failed to list tools in toolset").Log(ctx, logger)
9191
}
9292

93-
names := make([]string, 0, len(definitions))
94-
for _, def := range definitions {
95-
names = append(names, def.Name)
96-
}
97-
98-
// TODO variations by urns
99-
allVariations, err := variationsRepo.FindGlobalVariationsByToolNames(ctx, vr.FindGlobalVariationsByToolNamesParams{
93+
allVariations, err := variationsRepo.FindGlobalVariationsByToolURNs(ctx, vr.FindGlobalVariationsByToolURNsParams{
10094
ProjectID: pid,
101-
ToolNames: names,
95+
ToolUrns: toolUrns,
10296
})
10397
if err != nil {
10498
return nil, oops.E(oops.CodeUnexpected, err, "failed to list global tool variations").Log(ctx, logger)
10599
}
106100

107-
nameVariations := make(map[string]string)
101+
urnToVariedName := make(map[string]string)
108102
for _, variation := range allVariations {
109103
n := conv.FromPGText[string](variation.Name)
110104
if n == nil || *n == "" {
111105
continue
112106
}
113107

114-
nameVariations[variation.SrcToolName] = *n
108+
urnToVariedName[variation.SrcToolUrn.String()] = *n
115109
}
116110

117111
tools = make([]*types.ToolEntry, 0, len(definitions))
@@ -123,7 +117,7 @@ func DescribeToolsetEntry(
123117
}
124118
seen[def.ID.String()] = true
125119

126-
name := conv.Default(nameVariations[def.Name], def.Name)
120+
name := conv.Default(urnToVariedName[def.ToolUrn.String()], def.Name)
127121

128122
tool := &types.ToolEntry{
129123
Type: string(urn.ToolKindHTTP),
@@ -644,27 +638,29 @@ func readToolsetTools(
644638
func ApplyVariations(ctx context.Context, logger *slog.Logger, tx DBTX, projectID uuid.UUID, tools []*types.Tool) error {
645639
variationsRepo := vr.New(tx)
646640

647-
names := make([]string, 0, len(tools))
648-
for _, def := range tools {
649-
baseTool := conv.ToBaseTool(def)
650-
names = append(names, baseTool.Name)
641+
toolUrns := make([]string, 0, len(tools))
642+
for _, tool := range tools {
643+
toolURN, err := conv.GetToolURN(*tool)
644+
if err != nil || toolURN == nil {
645+
return oops.E(oops.CodeUnexpected, err, "failed to get tool urn").Log(ctx, logger)
646+
}
647+
toolUrns = append(toolUrns, toolURN.String())
651648
}
652649

653-
// TODO variations by urns
654-
allVariations, err := variationsRepo.FindGlobalVariationsByToolNames(ctx, vr.FindGlobalVariationsByToolNamesParams{
650+
allVariations, err := variationsRepo.FindGlobalVariationsByToolURNs(ctx, vr.FindGlobalVariationsByToolURNsParams{
655651
ProjectID: projectID,
656-
ToolNames: names,
652+
ToolUrns: toolUrns,
657653
})
658654
if err != nil {
659655
return oops.E(oops.CodeUnexpected, err, "failed to list global tool variations").Log(ctx, logger)
660656
}
661657

662-
keyedVariations := make(map[string]types.ToolVariation, len(allVariations))
658+
urnToVariation := make(map[string]types.ToolVariation, len(allVariations))
663659
for _, variation := range allVariations {
664-
keyedVariations[variation.SrcToolName] = types.ToolVariation{
660+
urnToVariation[variation.SrcToolUrn.String()] = types.ToolVariation{
665661
ID: variation.ID.String(),
666662
GroupID: variation.GroupID.String(),
667-
SrcToolUrn: variation.SrcToolUrn.String,
663+
SrcToolUrn: variation.SrcToolUrn.String(),
668664
SrcToolName: variation.SrcToolName,
669665
Confirm: conv.FromPGText[string](variation.Confirm),
670666
ConfirmPrompt: conv.FromPGText[string](variation.ConfirmPrompt),
@@ -680,9 +676,12 @@ func ApplyVariations(ctx context.Context, logger *slog.Logger, tx DBTX, projectI
680676
if tool == nil {
681677
continue
682678
}
683-
baseTool := conv.ToBaseTool(tool)
679+
toolURN, err := conv.GetToolURN(*tool)
680+
if err != nil || toolURN == nil {
681+
return oops.E(oops.CodeUnexpected, err, "failed to get tool urn").Log(ctx, logger)
682+
}
684683

685-
v, ok := keyedVariations[baseTool.Name]
684+
v, ok := urnToVariation[toolURN.String()]
686685
if ok {
687686
conv.ApplyVariation(*tool, v)
688687
}

server/internal/urn/tools.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func NewTool(kind ToolKind, source, name string) Tool {
3333
return t
3434
}
3535

36-
func newToolFromString(value string) (Tool, error) {
36+
func ParseTool(value string) (Tool, error) {
3737
if value == "" {
3838
return Tool{}, fmt.Errorf("%w: empty string", ErrInvalid)
3939
}
@@ -87,7 +87,7 @@ func (u *Tool) UnmarshalJSON(data []byte) error {
8787
return fmt.Errorf("read tool urn string from json: %w", err)
8888
}
8989

90-
parsed, err := newToolFromString(s)
90+
parsed, err := ParseTool(s)
9191
if err != nil {
9292
return fmt.Errorf("parse tool urn json string: %w", err)
9393
}
@@ -112,7 +112,7 @@ func (u *Tool) Scan(value interface{}) error {
112112
return fmt.Errorf("cannot scan %T into Tool", value)
113113
}
114114

115-
parsed, err := newToolFromString(s)
115+
parsed, err := ParseTool(s)
116116
if err != nil {
117117
return fmt.Errorf("scan database value: %w", err)
118118
}
@@ -139,7 +139,7 @@ func (u Tool) MarshalText() (text []byte, err error) {
139139
}
140140

141141
func (u *Tool) UnmarshalText(text []byte) error {
142-
parsed, err := newToolFromString(string(text))
142+
parsed, err := ParseTool(string(text))
143143
if err != nil {
144144
return fmt.Errorf("unmarshal tool urn text: %w", err)
145145
}

server/internal/variations/deleteglobal_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ func TestVariationsService_DeleteGlobal_Success(t *testing.T) {
2121
ApikeyToken: nil,
2222
SessionToken: nil,
2323
ProjectSlugInput: nil,
24-
SrcToolUrn: "tool:http:test:delete-test-tool",
24+
SrcToolUrn: "tools:http:test:delete-test-tool",
2525
SrcToolName: "",
2626
Confirm: nil,
2727
ConfirmPrompt: nil,
@@ -183,7 +183,7 @@ func TestVariationsService_DeleteGlobal_MultipleDeleteSameID(t *testing.T) {
183183
ApikeyToken: nil,
184184
SessionToken: nil,
185185
ProjectSlugInput: nil,
186-
SrcToolUrn: "tool:http:test:delete-twice-tool",
186+
SrcToolUrn: "tools:http:test:delete-twice-tool",
187187
SrcToolName: "delete-twice-tool",
188188
Confirm: nil,
189189
ConfirmPrompt: nil,
@@ -234,7 +234,7 @@ func TestVariationsService_DeleteGlobal_DeleteMultipleVariations(t *testing.T) {
234234
ApikeyToken: nil,
235235
SessionToken: nil,
236236
ProjectSlugInput: nil,
237-
SrcToolUrn: "tool:http:test:" + toolName,
237+
SrcToolUrn: "tools:http:test:" + toolName,
238238
SrcToolName: toolName,
239239
Confirm: nil,
240240
ConfirmPrompt: nil,
@@ -288,7 +288,7 @@ func TestVariationsService_DeleteGlobal_SoftDelete(t *testing.T) {
288288
ApikeyToken: nil,
289289
SessionToken: nil,
290290
ProjectSlugInput: nil,
291-
SrcToolUrn: "tool:http:test:soft-delete-tool",
291+
SrcToolUrn: "tools:http:test:soft-delete-tool",
292292
SrcToolName: "soft-delete-tool",
293293
Confirm: nil,
294294
ConfirmPrompt: nil,
@@ -318,7 +318,7 @@ func TestVariationsService_DeleteGlobal_SoftDelete(t *testing.T) {
318318
ApikeyToken: nil,
319319
SessionToken: nil,
320320
ProjectSlugInput: nil,
321-
SrcToolUrn: "tool:http:test:soft-delete-tool",
321+
SrcToolUrn: "tools:http:test:soft-delete-tool",
322322
SrcToolName: "soft-delete-tool", // Same tool name
323323
Confirm: nil,
324324
ConfirmPrompt: nil,
@@ -363,7 +363,7 @@ func createUpsertPayload(srcToolName string, overrides *gen.UpsertGlobalPayload)
363363
ApikeyToken: nil,
364364
SessionToken: nil,
365365
ProjectSlugInput: nil,
366-
SrcToolUrn: "tool:http:test:" + srcToolName,
366+
SrcToolUrn: "tools:http:test:" + srcToolName,
367367
SrcToolName: srcToolName,
368368
Confirm: nil,
369369
ConfirmPrompt: nil,

server/internal/variations/impl.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/speakeasy-api/gram/server/internal/middleware"
2626
"github.com/speakeasy-api/gram/server/internal/o11y"
2727
"github.com/speakeasy-api/gram/server/internal/oops"
28+
"github.com/speakeasy-api/gram/server/internal/urn"
2829
"github.com/speakeasy-api/gram/server/internal/variations/repo"
2930
)
3031

@@ -80,7 +81,7 @@ func (s *Service) ListGlobal(ctx context.Context, payload *gen.ListGlobalPayload
8081
variations = append(variations, &types.ToolVariation{
8182
ID: row.ToolVariation.ID.String(),
8283
GroupID: row.ToolVariation.GroupID.String(),
83-
SrcToolUrn: row.ToolVariation.SrcToolUrn.String,
84+
SrcToolUrn: row.ToolVariation.SrcToolUrn.String(),
8485
SrcToolName: row.ToolVariation.SrcToolName,
8586
Confirm: conv.FromPGText[string](row.ToolVariation.Confirm),
8687
ConfirmPrompt: conv.FromPGText[string](row.ToolVariation.ConfirmPrompt),
@@ -129,9 +130,14 @@ func (s *Service) UpsertGlobal(ctx context.Context, payload *gen.UpsertGlobalPay
129130
}
130131
}
131132

133+
srcToolUrn, err := urn.ParseTool(payload.SrcToolUrn)
134+
if err != nil {
135+
return nil, oops.E(oops.CodeInvalid, err, "invalid source tool urn").Log(ctx, s.logger)
136+
}
137+
132138
row, err := tx.UpsertToolVariation(ctx, repo.UpsertToolVariationParams{
133139
GroupID: groupID,
134-
SrcToolUrn: conv.ToPGTextEmpty(payload.SrcToolUrn),
140+
SrcToolUrn: srcToolUrn,
135141
SrcToolName: payload.SrcToolName,
136142
Confirm: conv.PtrToPGText(payload.Confirm),
137143
ConfirmPrompt: conv.PtrToPGText(payload.ConfirmPrompt),
@@ -153,7 +159,7 @@ func (s *Service) UpsertGlobal(ctx context.Context, payload *gen.UpsertGlobalPay
153159
Variation: &types.ToolVariation{
154160
ID: row.ID.String(),
155161
GroupID: row.GroupID.String(),
156-
SrcToolUrn: row.SrcToolUrn.String,
162+
SrcToolUrn: row.SrcToolUrn.String(),
157163
SrcToolName: row.SrcToolName,
158164
Confirm: conv.FromPGText[string](row.Confirm),
159165
ConfirmPrompt: conv.FromPGText[string](row.ConfirmPrompt),

server/internal/variations/listglobal_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ func TestVariationsService_ListGlobal_WithVariations(t *testing.T) {
6363
ApikeyToken: nil,
6464
SessionToken: nil,
6565
ProjectSlugInput: nil,
66-
SrcToolUrn: "tool:http:test:test-tool",
66+
SrcToolUrn: "tools:http:test:test-tool",
6767
SrcToolName: "test-tool",
6868
Confirm: &confirm,
6969
ConfirmPrompt: &confirmPrompt,
@@ -176,7 +176,7 @@ func TestVariationsService_ListGlobal_MultipleVariations(t *testing.T) {
176176
ApikeyToken: nil,
177177
SessionToken: nil,
178178
ProjectSlugInput: nil,
179-
SrcToolUrn: "tool:http:test:" + toolName,
179+
SrcToolUrn: "tools:http:test:" + toolName,
180180
SrcToolName: toolName,
181181
Confirm: nil,
182182
ConfirmPrompt: nil,
@@ -232,7 +232,7 @@ func TestVariationsService_ListGlobal_OrderedByID(t *testing.T) {
232232
ApikeyToken: nil,
233233
SessionToken: nil,
234234
ProjectSlugInput: nil,
235-
SrcToolUrn: "tool:http:test:first-tool",
235+
SrcToolUrn: "tools:http:test:first-tool",
236236
SrcToolName: "first-tool",
237237
Confirm: nil,
238238
ConfirmPrompt: nil,
@@ -250,7 +250,7 @@ func TestVariationsService_ListGlobal_OrderedByID(t *testing.T) {
250250
ApikeyToken: nil,
251251
SessionToken: nil,
252252
ProjectSlugInput: nil,
253-
SrcToolUrn: "tool:http:test:second-tool",
253+
SrcToolUrn: "tools:http:test:second-tool",
254254
SrcToolName: "second-tool",
255255
Confirm: nil,
256256
ConfirmPrompt: nil,

server/internal/variations/queries.sql

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ INSERT INTO tool_variations (
4646
@description,
4747
@tags,
4848
@summarizer
49-
) ON CONFLICT (group_id, src_tool_name) WHERE deleted IS FALSE DO UPDATE SET
50-
src_tool_urn = EXCLUDED.src_tool_urn,
49+
) ON CONFLICT (group_id, src_tool_urn) WHERE deleted IS FALSE DO UPDATE SET
5150
confirm = EXCLUDED.confirm,
5251
confirm_prompt = EXCLUDED.confirm_prompt,
5352
name = EXCLUDED.name,
@@ -70,7 +69,7 @@ WHERE
7069
AND tool_variations.deleted IS FALSE
7170
ORDER BY tool_variations.id DESC;
7271

73-
-- name: FindGlobalVariationsByToolNames :many
72+
-- name: FindGlobalVariationsByToolURNs :many
7473
WITH global_group AS (
7574
SELECT tool_variations_groups.id
7675
FROM tool_variations_groups
@@ -83,7 +82,7 @@ SELECT *
8382
FROM tool_variations
8483
WHERE
8584
group_id = (SELECT id FROM global_group)
86-
AND src_tool_name = ANY(@tool_names::text[])
85+
AND src_tool_urn = ANY(@tool_urns::text[])
8786
AND deleted IS FALSE;
8887

8988
-- name: DeleteGlobalToolVariation :one

server/internal/variations/repo/models.go

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)