diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 689ebea74b..15ec99e7c6 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -3119,6 +3119,13 @@ func (q *querier) InsertPreset(ctx context.Context, arg database.InsertPresetPar return q.db.InsertPreset(ctx, arg) } +func (q *querier) InsertPresetParameters(ctx context.Context, arg database.InsertPresetParametersParams) ([]database.TemplateVersionPresetParameter, error) { + if err := q.authorizeContext(ctx, policy.ActionCreate, rbac.ResourceTemplate); err != nil { + return nil, err + } + return q.db.InsertPresetParameters(ctx, arg) +} + // TODO: We need to create a ProvisionerJob resource type func (q *querier) InsertProvisionerJob(ctx context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) { // if err := q.authorizeContext(ctx, policy.ActionCreate, rbac.ResourceSystem); err != nil { diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index a502af7f3a..ae5c3dbd8f 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -885,13 +885,54 @@ func (s *MethodTestSuite) TestOrganization() { InitiatorID: user.ID, JobID: job.ID, }) - params := database.InsertPresetParams{ + insertPresetParams := database.InsertPresetParams{ TemplateVersionID: workspaceBuild.TemplateVersionID, Name: "test", } - _, err := db.InsertPreset(context.Background(), params) + _, err := db.InsertPreset(context.Background(), insertPresetParams) require.NoError(s.T(), err) - check.Args(params).Asserts(rbac.ResourceTemplate, policy.ActionCreate) + check.Args(insertPresetParams).Asserts(rbac.ResourceTemplate, policy.ActionCreate) + })) + s.Run("InsertPreset", s.Subtest(func(db database.Store, check *expects) { + org := dbgen.Organization(s.T(), db, database.Organization{}) + user := dbgen.User(s.T(), db, database.User{}) + template := dbgen.Template(s.T(), db, database.Template{ + CreatedBy: user.ID, + OrganizationID: org.ID, + }) + templateVersion := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{ + TemplateID: uuid.NullUUID{UUID: template.ID, Valid: true}, + OrganizationID: org.ID, + CreatedBy: user.ID, + }) + workspace := dbgen.Workspace(s.T(), db, database.WorkspaceTable{ + OrganizationID: org.ID, + OwnerID: user.ID, + TemplateID: template.ID, + }) + job := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{ + OrganizationID: org.ID, + }) + workspaceBuild := dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{ + WorkspaceID: workspace.ID, + TemplateVersionID: templateVersion.ID, + InitiatorID: user.ID, + JobID: job.ID, + }) + insertPresetParams := database.InsertPresetParams{ + TemplateVersionID: workspaceBuild.TemplateVersionID, + Name: "test", + } + preset, err := db.InsertPreset(context.Background(), insertPresetParams) + require.NoError(s.T(), err) + insertPresetParametersParams := database.InsertPresetParametersParams{ + TemplateVersionPresetID: preset.ID, + Names: []string{"test"}, + Values: []string{"test"}, + } + _, err = db.InsertPresetParameters(context.Background(), insertPresetParametersParams) + require.NoError(s.T(), err) + check.Args(insertPresetParametersParams).Asserts(rbac.ResourceTemplate, policy.ActionCreate) })) s.Run("DeleteOrganizationMember", s.Subtest(func(db database.Store, check *expects) { o := dbgen.Organization(s.T(), db, database.Organization{}) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index f95306702d..0411c49533 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -8123,6 +8123,29 @@ func (q *FakeQuerier) InsertPreset(_ context.Context, arg database.InsertPresetP return preset, nil } +func (q *FakeQuerier) InsertPresetParameters(ctx context.Context, arg database.InsertPresetParametersParams) ([]database.TemplateVersionPresetParameter, error) { + err := validateDatabaseType(arg) + if err != nil { + return nil, err + } + + q.mutex.Lock() + defer q.mutex.Unlock() + + presetParameters := make([]database.TemplateVersionPresetParameter, 0, len(arg.Names)) + for i, v := range arg.Names { + presetParameter := database.TemplateVersionPresetParameter{ + TemplateVersionPresetID: arg.TemplateVersionPresetID, + Name: v, + Value: arg.Values[i], + } + presetParameters = append(presetParameters, presetParameter) + q.presetParameters = append(q.presetParameters, presetParameter) + } + + return presetParameters, nil +} + func (q *FakeQuerier) InsertProvisionerJob(_ context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) { if err := validateDatabaseType(arg); err != nil { return database.ProvisionerJob{}, err diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index 7145e46052..69365d96fc 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -1939,6 +1939,13 @@ func (m queryMetricsStore) InsertPreset(ctx context.Context, arg database.Insert return r0, r1 } +func (m queryMetricsStore) InsertPresetParameters(ctx context.Context, arg database.InsertPresetParametersParams) ([]database.TemplateVersionPresetParameter, error) { + start := time.Now() + r0, r1 := m.s.InsertPresetParameters(ctx, arg) + m.queryLatencies.WithLabelValues("InsertPresetParameters").Observe(time.Since(start).Seconds()) + return r0, r1 +} + func (m queryMetricsStore) InsertProvisionerJob(ctx context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) { start := time.Now() job, err := m.s.InsertProvisionerJob(ctx, arg) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 525dad9388..de0b97a2b5 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -4111,6 +4111,21 @@ func (mr *MockStoreMockRecorder) InsertPreset(arg0, arg1 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertPreset", reflect.TypeOf((*MockStore)(nil).InsertPreset), arg0, arg1) } +// InsertPresetParameters mocks base method. +func (m *MockStore) InsertPresetParameters(arg0 context.Context, arg1 database.InsertPresetParametersParams) ([]database.TemplateVersionPresetParameter, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "InsertPresetParameters", arg0, arg1) + ret0, _ := ret[0].([]database.TemplateVersionPresetParameter) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// InsertPresetParameters indicates an expected call of InsertPresetParameters. +func (mr *MockStoreMockRecorder) InsertPresetParameters(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InsertPresetParameters", reflect.TypeOf((*MockStore)(nil).InsertPresetParameters), arg0, arg1) +} + // InsertProvisionerJob mocks base method. func (m *MockStore) InsertProvisionerJob(ctx context.Context, arg database.InsertProvisionerJobParams) (database.ProvisionerJob, error) { m.ctrl.T.Helper() diff --git a/coderd/database/migrations/000288_workspace_parameter_presets.up.sql b/coderd/database/migrations/000288_workspace_parameter_presets.up.sql index a44450c885..c42ca7d803 100644 --- a/coderd/database/migrations/000288_workspace_parameter_presets.up.sql +++ b/coderd/database/migrations/000288_workspace_parameter_presets.up.sql @@ -1,3 +1,4 @@ +-- TODO (sasswart): add IF NOT EXISTS and other clauses to make the migration more robust CREATE TABLE template_version_presets ( id UUID PRIMARY KEY DEFAULT gen_random_uuid(), diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 0cb5990536..4ac8e94762 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -408,6 +408,7 @@ type sqlcQuerier interface { InsertOrganization(ctx context.Context, arg InsertOrganizationParams) (Organization, error) InsertOrganizationMember(ctx context.Context, arg InsertOrganizationMemberParams) (OrganizationMember, error) InsertPreset(ctx context.Context, arg InsertPresetParams) (TemplateVersionPreset, error) + InsertPresetParameters(ctx context.Context, arg InsertPresetParametersParams) ([]TemplateVersionPresetParameter, error) InsertProvisionerJob(ctx context.Context, arg InsertProvisionerJobParams) (ProvisionerJob, error) InsertProvisionerJobLogs(ctx context.Context, arg InsertProvisionerJobLogsParams) ([]ProvisionerJobLog, error) InsertProvisionerJobTimings(ctx context.Context, arg InsertProvisionerJobTimingsParams) ([]ProvisionerJobTiming, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 7f07b09f9d..b363c5e4f3 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -5520,6 +5520,50 @@ func (q *sqlQuerier) InsertPreset(ctx context.Context, arg InsertPresetParams) ( return i, err } +const insertPresetParameters = `-- name: InsertPresetParameters :many +INSERT INTO + template_version_preset_parameters (template_version_preset_id, name, value) +SELECT + $1, + unnest($2 :: TEXT[]), + unnest($3 :: TEXT[]) +RETURNING id, template_version_preset_id, name, value +` + +type InsertPresetParametersParams struct { + TemplateVersionPresetID uuid.UUID `db:"template_version_preset_id" json:"template_version_preset_id"` + Names []string `db:"names" json:"names"` + Values []string `db:"values" json:"values"` +} + +func (q *sqlQuerier) InsertPresetParameters(ctx context.Context, arg InsertPresetParametersParams) ([]TemplateVersionPresetParameter, error) { + rows, err := q.db.QueryContext(ctx, insertPresetParameters, arg.TemplateVersionPresetID, pq.Array(arg.Names), pq.Array(arg.Values)) + if err != nil { + return nil, err + } + defer rows.Close() + var items []TemplateVersionPresetParameter + for rows.Next() { + var i TemplateVersionPresetParameter + if err := rows.Scan( + &i.ID, + &i.TemplateVersionPresetID, + &i.Name, + &i.Value, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const deleteOldProvisionerDaemons = `-- name: DeleteOldProvisionerDaemons :exec DELETE FROM provisioner_daemons WHERE ( (created_at < (NOW() - INTERVAL '7 days') AND last_seen_at IS NULL) OR diff --git a/coderd/database/queries/presets.sql b/coderd/database/queries/presets.sql index 883d6c4214..b25c098f8c 100644 --- a/coderd/database/queries/presets.sql +++ b/coderd/database/queries/presets.sql @@ -4,13 +4,13 @@ INSERT INTO VALUES (@template_version_id, @name, @created_at) RETURNING *; --- InsertPresetParameter :one +-- name: InsertPresetParameters :many INSERT INTO template_version_preset_parameters (template_version_preset_id, name, value) SELECT @template_version_preset_id, - unnest(@name), - unnest(@value) + unnest(@names :: TEXT[]), + unnest(@values :: TEXT[]) RETURNING *; -- name: GetPresetsByTemplateVersionID :many