@@ -29,16 +29,17 @@ import (
|
||||
|
||||
type (
|
||||
Control struct {
|
||||
ID gid.GID `db:"id"`
|
||||
FrameworkID gid.GID `db:"framework_id"`
|
||||
Category string `db:"category"`
|
||||
Name string `db:"name"`
|
||||
Description string `db:"description"`
|
||||
State ControlState `db:"state"`
|
||||
ContentRef string `db:"content_ref"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
Version int `db:"version"`
|
||||
ID gid.GID `db:"id"`
|
||||
FrameworkID gid.GID `db:"framework_id"`
|
||||
Category string `db:"category"`
|
||||
Name string `db:"name"`
|
||||
Description string `db:"description"`
|
||||
Importance ControlImportance `db:"importance"`
|
||||
State ControlState `db:"state"`
|
||||
ContentRef string `db:"content_ref"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
Version int `db:"version"`
|
||||
}
|
||||
|
||||
Controls []*Control
|
||||
@@ -49,6 +50,7 @@ type (
|
||||
Description *string
|
||||
Category *string
|
||||
State *ControlState
|
||||
Importance *ControlImportance
|
||||
}
|
||||
)
|
||||
|
||||
@@ -70,6 +72,7 @@ SELECT
|
||||
name,
|
||||
description,
|
||||
state,
|
||||
importance,
|
||||
content_ref,
|
||||
created_at,
|
||||
updated_at,
|
||||
@@ -115,6 +118,7 @@ INSERT INTO
|
||||
framework_id,
|
||||
category,
|
||||
name,
|
||||
importance,
|
||||
state,
|
||||
description,
|
||||
content_ref,
|
||||
@@ -128,6 +132,7 @@ VALUES (
|
||||
@framework_id,
|
||||
@category,
|
||||
@name,
|
||||
@importance,
|
||||
@state,
|
||||
@description,
|
||||
@content_ref,
|
||||
@@ -149,6 +154,7 @@ VALUES (
|
||||
"created_at": c.CreatedAt,
|
||||
"updated_at": c.UpdatedAt,
|
||||
"state": c.State,
|
||||
"importance": c.Importance,
|
||||
}
|
||||
_, err := conn.Exec(ctx, q, args)
|
||||
return err
|
||||
@@ -169,6 +175,7 @@ SELECT
|
||||
name,
|
||||
description,
|
||||
state,
|
||||
importance,
|
||||
content_ref,
|
||||
created_at,
|
||||
updated_at,
|
||||
@@ -213,6 +220,7 @@ UPDATE controls SET
|
||||
description = COALESCE(@description, description),
|
||||
category = COALESCE(@category, category),
|
||||
state = COALESCE(@state, state),
|
||||
importance = COALESCE(@importance, importance),
|
||||
updated_at = @updated_at,
|
||||
version = version + 1
|
||||
WHERE %s
|
||||
@@ -224,6 +232,7 @@ RETURNING
|
||||
category,
|
||||
name,
|
||||
description,
|
||||
importance,
|
||||
state,
|
||||
content_ref,
|
||||
created_at,
|
||||
@@ -235,23 +244,16 @@ RETURNING
|
||||
args := pgx.NamedArgs{
|
||||
"control_id": c.ID,
|
||||
"expected_version": params.ExpectedVersion,
|
||||
"name": params.Name,
|
||||
"description": params.Description,
|
||||
"category": params.Category,
|
||||
"state": params.State,
|
||||
"importance": params.Importance,
|
||||
"updated_at": time.Now(),
|
||||
}
|
||||
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
if params.Name != nil {
|
||||
args["name"] = *params.Name
|
||||
}
|
||||
if params.Description != nil {
|
||||
args["description"] = *params.Description
|
||||
}
|
||||
if params.Category != nil {
|
||||
args["category"] = *params.Category
|
||||
}
|
||||
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
|
||||
rows, err := conn.Query(ctx, q, args)
|
||||
if err != nil {
|
||||
return fmt.Errorf("cannot query controls: %w", err)
|
||||
|
||||
100
pkg/coredata/control_importance.go
Normal file
100
pkg/coredata/control_importance.go
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// Permission to use, copy, modify, and/or distribute this software for any
|
||||
// purpose with or without fee is hereby granted, provided that the above
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
||||
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
package coredata
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ControlImportance uint8
|
||||
|
||||
const (
|
||||
ControlImportanceMandatory ControlImportance = iota
|
||||
ControlImportancePreferred
|
||||
ControlImportanceAdvanced
|
||||
)
|
||||
|
||||
func (i ControlImportance) String() string {
|
||||
return []string{"MANDATORY", "PREFERRED", "ADVANCED"}[i]
|
||||
}
|
||||
|
||||
func (i *ControlImportance) Scan(value interface{}) error {
|
||||
switch v := value.(type) {
|
||||
case uint8:
|
||||
*i = ControlImportance(v)
|
||||
case string:
|
||||
switch v {
|
||||
case "MANDATORY":
|
||||
*i = ControlImportanceMandatory
|
||||
case "PREFERRED":
|
||||
*i = ControlImportancePreferred
|
||||
case "ADVANCED":
|
||||
*i = ControlImportanceAdvanced
|
||||
default:
|
||||
return fmt.Errorf("invalid ControlImportance value: %q", v)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unsupported type for ControlImportance: %T", value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i ControlImportance) Value() (driver.Value, error) {
|
||||
return i.String(), nil
|
||||
}
|
||||
|
||||
func (i ControlImportance) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.String())
|
||||
}
|
||||
|
||||
func (i *ControlImportance) UnmarshalJSON(data []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(data, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch s {
|
||||
case "MANDATORY":
|
||||
*i = ControlImportanceMandatory
|
||||
case "PREFERRED":
|
||||
*i = ControlImportancePreferred
|
||||
case "ADVANCED":
|
||||
*i = ControlImportanceAdvanced
|
||||
default:
|
||||
return fmt.Errorf("invalid ControlImportance value: %q", s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *ControlImportance) UnmarshalText(text []byte) error {
|
||||
var s string
|
||||
if err := json.Unmarshal(text, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch s {
|
||||
case "MANDATORY":
|
||||
*i = ControlImportanceMandatory
|
||||
case "PREFERRED":
|
||||
*i = ControlImportancePreferred
|
||||
case "ADVANCED":
|
||||
*i = ControlImportanceAdvanced
|
||||
default:
|
||||
return fmt.Errorf("invalid ControlImportance value: %q", s)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
8
pkg/coredata/migrations/20250312T180800Z.sql
Normal file
8
pkg/coredata/migrations/20250312T180800Z.sql
Normal file
@@ -0,0 +1,8 @@
|
||||
CREATE TYPE control_importance AS ENUM ('MANDATORY', 'PREFERRED', 'ADVANCED');
|
||||
|
||||
ALTER TABLE controls ADD COLUMN importance control_importance NOT NULL DEFAULT 'MANDATORY';
|
||||
ALTER TABLE controls ALTER COLUMN importance DROP DEFAULT;
|
||||
|
||||
ALTER TABLE tasks ADD COLUMN time_estimate INTERVAL NOT NULL DEFAULT '00:30:00';
|
||||
ALTER TABLE tasks ALTER COLUMN time_estimate DROP DEFAULT;
|
||||
|
||||
Reference in New Issue
Block a user