From be6e70360f03e7bde959d3a58fa0c30d5936af11 Mon Sep 17 00:00:00 2001 From: Don Browne Date: Fri, 15 Mar 2024 14:24:23 +0000 Subject: [PATCH] Define DB schema for bundles and subscriptions (#2670) Relates to #2543 Define the subscriptions and bundles table. Add a foreign key reference to subscriptions in both the profiles and rule type tables. --- .../000029_bundle_subscription.down.sql | 19 ++++++++ .../000029_bundle_subscription.up.sql | 43 +++++++++++++++++++ internal/db/models.go | 37 +++++++++++----- internal/db/projects.sql.go | 24 +++++++---- internal/db/rule_types.sql.go | 15 ++++--- 5 files changed, 114 insertions(+), 24 deletions(-) create mode 100644 database/migrations/000029_bundle_subscription.down.sql create mode 100644 database/migrations/000029_bundle_subscription.up.sql diff --git a/database/migrations/000029_bundle_subscription.down.sql b/database/migrations/000029_bundle_subscription.down.sql new file mode 100644 index 0000000000..1e6ddb764f --- /dev/null +++ b/database/migrations/000029_bundle_subscription.down.sql @@ -0,0 +1,19 @@ +-- Copyright 2024 Stacklok, Inc +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +ALTER TABLE projects DROP COLUMN subscription_id; +ALTER TABLE rule_type DROP COLUMN subscription_id; + +DROP TABLE IF EXISTS subscriptions; +DROP TABLE IF EXISTS bundles; \ No newline at end of file diff --git a/database/migrations/000029_bundle_subscription.up.sql b/database/migrations/000029_bundle_subscription.up.sql new file mode 100644 index 0000000000..ce2331ba43 --- /dev/null +++ b/database/migrations/000029_bundle_subscription.up.sql @@ -0,0 +1,43 @@ +-- Copyright 2024 Stacklok, Inc +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +CREATE TABLE bundles( + -- I have given this a separate PK to simplify some of the queries + -- the combination of the remaining columns are unique + id UUID NOT NULL DEFAULT gen_random_uuid() PRIMARY KEY, + namespace TEXT NOT NULL, + name TEXT NOT NULL, + UNIQUE (namespace, name) +); + +CREATE TABLE subscriptions( + -- same comment as for PK of `bundles` + id UUID NOT NULL DEFAULT gen_random_uuid() PRIMARY KEY, + project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE, + -- this FK is not ON DELETE CASCADE + -- this prevents deletion of bundles which are still in use + bundle_id UUID NOT NULL REFERENCES bundles(id), + current_version TEXT NOT NULL, + UNIQUE (bundle_id, project_id) +); + +-- none of these FKs are ON DELETE CASCADE +-- prevents deletion of an in-use subscription +ALTER TABLE projects + ADD COLUMN subscription_id UUID DEFAULT NULL + REFERENCES subscriptions(id); + +ALTER TABLE rule_type + ADD COLUMN subscription_id UUID DEFAULT NULL + REFERENCES subscriptions(id); diff --git a/internal/db/models.go b/internal/db/models.go index 7a33fe5488..6c6362569e 100644 --- a/internal/db/models.go +++ b/internal/db/models.go @@ -381,6 +381,12 @@ type Artifact struct { UpdatedAt time.Time `json:"updated_at"` } +type Bundle struct { + ID uuid.UUID `json:"id"` + Namespace string `json:"namespace"` + Name string `json:"name"` +} + type Entitlement struct { ID uuid.UUID `json:"id"` Feature string `json:"feature"` @@ -461,6 +467,7 @@ type Project struct { ParentID uuid.NullUUID `json:"parent_id"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` + SubscriptionID uuid.NullUUID `json:"subscription_id"` } type Provider struct { @@ -551,17 +558,18 @@ type RuleEvaluation struct { } type RuleType struct { - ID uuid.UUID `json:"id"` - Name string `json:"name"` - Provider string `json:"provider"` - ProjectID uuid.UUID `json:"project_id"` - Description string `json:"description"` - Guidance string `json:"guidance"` - Definition json.RawMessage `json:"definition"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - SeverityValue Severity `json:"severity_value"` - ProviderID uuid.UUID `json:"provider_id"` + ID uuid.UUID `json:"id"` + Name string `json:"name"` + Provider string `json:"provider"` + ProjectID uuid.UUID `json:"project_id"` + Description string `json:"description"` + Guidance string `json:"guidance"` + Definition json.RawMessage `json:"definition"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + SeverityValue Severity `json:"severity_value"` + ProviderID uuid.UUID `json:"provider_id"` + SubscriptionID uuid.NullUUID `json:"subscription_id"` } type SessionStore struct { @@ -576,6 +584,13 @@ type SessionStore struct { RemoteUser sql.NullString `json:"remote_user"` } +type Subscription struct { + ID uuid.UUID `json:"id"` + ProjectID uuid.UUID `json:"project_id"` + BundleID uuid.UUID `json:"bundle_id"` + CurrentVersion string `json:"current_version"` +} + type User struct { ID int32 `json:"id"` IdentitySubject string `json:"identity_subject"` diff --git a/internal/db/projects.sql.go b/internal/db/projects.sql.go index 5cb9ec45a9..9c182e5fed 100644 --- a/internal/db/projects.sql.go +++ b/internal/db/projects.sql.go @@ -20,7 +20,7 @@ INSERT INTO projects ( metadata ) VALUES ( $1, $2, $3::jsonb -) RETURNING id, name, is_organization, metadata, parent_id, created_at, updated_at +) RETURNING id, name, is_organization, metadata, parent_id, created_at, updated_at, subscription_id ` type CreateProjectParams struct { @@ -40,6 +40,7 @@ func (q *Queries) CreateProject(ctx context.Context, arg CreateProjectParams) (P &i.ParentID, &i.CreatedAt, &i.UpdatedAt, + &i.SubscriptionID, ) return i, err } @@ -51,7 +52,7 @@ INSERT INTO projects ( metadata ) VALUES ( $1, $2, $3::jsonb -) RETURNING id, name, is_organization, metadata, parent_id, created_at, updated_at +) RETURNING id, name, is_organization, metadata, parent_id, created_at, updated_at, subscription_id ` type CreateProjectWithIDParams struct { @@ -71,6 +72,7 @@ func (q *Queries) CreateProjectWithID(ctx context.Context, arg CreateProjectWith &i.ParentID, &i.CreatedAt, &i.UpdatedAt, + &i.SubscriptionID, ) return i, err } @@ -269,7 +271,7 @@ func (q *Queries) GetParentProjectsUntil(ctx context.Context, arg GetParentProje } const getProjectByID = `-- name: GetProjectByID :one -SELECT id, name, is_organization, metadata, parent_id, created_at, updated_at FROM projects +SELECT id, name, is_organization, metadata, parent_id, created_at, updated_at, subscription_id FROM projects WHERE id = $1 AND is_organization = FALSE LIMIT 1 ` @@ -284,12 +286,13 @@ func (q *Queries) GetProjectByID(ctx context.Context, id uuid.UUID) (Project, er &i.ParentID, &i.CreatedAt, &i.UpdatedAt, + &i.SubscriptionID, ) return i, err } const getProjectByName = `-- name: GetProjectByName :one -SELECT id, name, is_organization, metadata, parent_id, created_at, updated_at FROM projects +SELECT id, name, is_organization, metadata, parent_id, created_at, updated_at, subscription_id FROM projects WHERE name = $1 AND is_organization = FALSE LIMIT 1 ` @@ -304,13 +307,14 @@ func (q *Queries) GetProjectByName(ctx context.Context, name string) (Project, e &i.ParentID, &i.CreatedAt, &i.UpdatedAt, + &i.SubscriptionID, ) return i, err } const listNonOrgProjects = `-- name: ListNonOrgProjects :many -SELECT id, name, is_organization, metadata, parent_id, created_at, updated_at FROM projects +SELECT id, name, is_organization, metadata, parent_id, created_at, updated_at, subscription_id FROM projects WHERE is_organization = FALSE ` @@ -334,6 +338,7 @@ func (q *Queries) ListNonOrgProjects(ctx context.Context) ([]Project, error) { &i.ParentID, &i.CreatedAt, &i.UpdatedAt, + &i.SubscriptionID, ); err != nil { return nil, err } @@ -350,7 +355,7 @@ func (q *Queries) ListNonOrgProjects(ctx context.Context) ([]Project, error) { const listOldOrgProjects = `-- name: ListOldOrgProjects :many -SELECT id, name, is_organization, metadata, parent_id, created_at, updated_at FROM projects +SELECT id, name, is_organization, metadata, parent_id, created_at, updated_at, subscription_id FROM projects WHERE is_organization = TRUE ` @@ -374,6 +379,7 @@ func (q *Queries) ListOldOrgProjects(ctx context.Context) ([]Project, error) { &i.ParentID, &i.CreatedAt, &i.UpdatedAt, + &i.SubscriptionID, ); err != nil { return nil, err } @@ -392,7 +398,7 @@ const orphanProject = `-- name: OrphanProject :one UPDATE projects SET metadata = $2, parent_id = NULL -WHERE id = $1 RETURNING id, name, is_organization, metadata, parent_id, created_at, updated_at +WHERE id = $1 RETURNING id, name, is_organization, metadata, parent_id, created_at, updated_at, subscription_id ` type OrphanProjectParams struct { @@ -412,6 +418,7 @@ func (q *Queries) OrphanProject(ctx context.Context, arg OrphanProjectParams) (P &i.ParentID, &i.CreatedAt, &i.UpdatedAt, + &i.SubscriptionID, ) return i, err } @@ -419,7 +426,7 @@ func (q *Queries) OrphanProject(ctx context.Context, arg OrphanProjectParams) (P const updateProjectMeta = `-- name: UpdateProjectMeta :one UPDATE projects SET metadata = $2 -WHERE id = $1 RETURNING id, name, is_organization, metadata, parent_id, created_at, updated_at +WHERE id = $1 RETURNING id, name, is_organization, metadata, parent_id, created_at, updated_at, subscription_id ` type UpdateProjectMetaParams struct { @@ -438,6 +445,7 @@ func (q *Queries) UpdateProjectMeta(ctx context.Context, arg UpdateProjectMetaPa &i.ParentID, &i.CreatedAt, &i.UpdatedAt, + &i.SubscriptionID, ) return i, err } diff --git a/internal/db/rule_types.sql.go b/internal/db/rule_types.sql.go index a54b4e727f..39c02bd0fe 100644 --- a/internal/db/rule_types.sql.go +++ b/internal/db/rule_types.sql.go @@ -22,7 +22,7 @@ INSERT INTO rule_type ( definition, severity_value, provider_id - ) VALUES ($1, $2, $3, $4, $5, $6::jsonb, $7, $8) RETURNING id, name, provider, project_id, description, guidance, definition, created_at, updated_at, severity_value, provider_id + ) VALUES ($1, $2, $3, $4, $5, $6::jsonb, $7, $8) RETURNING id, name, provider, project_id, description, guidance, definition, created_at, updated_at, severity_value, provider_id, subscription_id ` type CreateRuleTypeParams struct { @@ -60,6 +60,7 @@ func (q *Queries) CreateRuleType(ctx context.Context, arg CreateRuleTypeParams) &i.UpdatedAt, &i.SeverityValue, &i.ProviderID, + &i.SubscriptionID, ) return i, err } @@ -74,7 +75,7 @@ func (q *Queries) DeleteRuleType(ctx context.Context, id uuid.UUID) error { } const getRuleTypeByID = `-- name: GetRuleTypeByID :one -SELECT id, name, provider, project_id, description, guidance, definition, created_at, updated_at, severity_value, provider_id FROM rule_type WHERE id = $1 +SELECT id, name, provider, project_id, description, guidance, definition, created_at, updated_at, severity_value, provider_id, subscription_id FROM rule_type WHERE id = $1 ` func (q *Queries) GetRuleTypeByID(ctx context.Context, id uuid.UUID) (RuleType, error) { @@ -92,12 +93,13 @@ func (q *Queries) GetRuleTypeByID(ctx context.Context, id uuid.UUID) (RuleType, &i.UpdatedAt, &i.SeverityValue, &i.ProviderID, + &i.SubscriptionID, ) return i, err } const getRuleTypeByName = `-- name: GetRuleTypeByName :one -SELECT id, name, provider, project_id, description, guidance, definition, created_at, updated_at, severity_value, provider_id FROM rule_type WHERE provider = $1 AND project_id = $2 AND name = $3 +SELECT id, name, provider, project_id, description, guidance, definition, created_at, updated_at, severity_value, provider_id, subscription_id FROM rule_type WHERE provider = $1 AND project_id = $2 AND name = $3 ` type GetRuleTypeByNameParams struct { @@ -121,12 +123,13 @@ func (q *Queries) GetRuleTypeByName(ctx context.Context, arg GetRuleTypeByNamePa &i.UpdatedAt, &i.SeverityValue, &i.ProviderID, + &i.SubscriptionID, ) return i, err } const listRuleTypesByProviderAndProject = `-- name: ListRuleTypesByProviderAndProject :many -SELECT id, name, provider, project_id, description, guidance, definition, created_at, updated_at, severity_value, provider_id FROM rule_type WHERE provider = $1 AND project_id = $2 +SELECT id, name, provider, project_id, description, guidance, definition, created_at, updated_at, severity_value, provider_id, subscription_id FROM rule_type WHERE provider = $1 AND project_id = $2 ` type ListRuleTypesByProviderAndProjectParams struct { @@ -155,6 +158,7 @@ func (q *Queries) ListRuleTypesByProviderAndProject(ctx context.Context, arg Lis &i.UpdatedAt, &i.SeverityValue, &i.ProviderID, + &i.SubscriptionID, ); err != nil { return nil, err } @@ -173,7 +177,7 @@ const updateRuleType = `-- name: UpdateRuleType :one UPDATE rule_type SET description = $2, definition = $3::jsonb, severity_value = $4 WHERE id = $1 - RETURNING id, name, provider, project_id, description, guidance, definition, created_at, updated_at, severity_value, provider_id + RETURNING id, name, provider, project_id, description, guidance, definition, created_at, updated_at, severity_value, provider_id, subscription_id ` type UpdateRuleTypeParams struct { @@ -203,6 +207,7 @@ func (q *Queries) UpdateRuleType(ctx context.Context, arg UpdateRuleTypeParams) &i.UpdatedAt, &i.SeverityValue, &i.ProviderID, + &i.SubscriptionID, ) return i, err }