Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ownership Attribute #208

Merged
merged 10 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/resources/cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ resource "materialize_cluster" "example_cluster" {

- `name` (String) The identifier for the cluster.

### Optional

- `ownership_role` (String) The owernship role of the object.

### Read-Only

- `id` (String) The ID of this resource.
Expand Down
1 change: 1 addition & 0 deletions docs/resources/table.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ resource "materialize_table" "simple_table" {

- `column` (Block List) Column of the table. (see [below for nested schema](#nestedblock--column))
- `database_name` (String) The identifier for the table database. Defaults to `MZ_DATABASE` environment variable if set or `materialize` if environment variable is not set.
- `ownership_role` (String) The owernship role of the object.
- `schema_name` (String) The identifier for the table schema. Defaults to `public`.

### Read-Only
Expand Down
21 changes: 15 additions & 6 deletions pkg/materialize/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ type ClusterBuilder struct {
clusterName string
}

func NewClusterBuilder(conn *sqlx.DB, clusterName string) *ClusterBuilder {
func NewClusterBuilder(conn *sqlx.DB, obj ObjectSchemaStruct) *ClusterBuilder {
return &ClusterBuilder{
ddl: Builder{conn, Cluster},
clusterName: clusterName,
clusterName: obj.Name,
}
}

Expand All @@ -39,13 +39,22 @@ func (b *ClusterBuilder) Drop() error {
type ClusterParams struct {
ClusterId sql.NullString `db:"id"`
ClusterName sql.NullString `db:"name"`
OwnerName sql.NullString `db:"owner_name"`
Privileges sql.NullString `db:"privileges"`
}

var clusterQuery = NewBaseQuery(`SELECT id, name, privileges FROM mz_clusters`)
var clusterQuery = NewBaseQuery(`
SELECT
mz_clusters.id,
mz_clusters.name,
mz_roles.name AS owner_name,
mz_clusters.privileges
FROM mz_clusters
JOIN mz_roles
ON mz_clusters.owner_id = mz_roles.id`)

func ClusterId(conn *sqlx.DB, clusterName string) (string, error) {
q := clusterQuery.QueryPredicate(map[string]string{"name": clusterName})
func ClusterId(conn *sqlx.DB, obj ObjectSchemaStruct) (string, error) {
q := clusterQuery.QueryPredicate(map[string]string{"mz_clusters.name": obj.Name})

var c ClusterParams
if err := conn.Get(&c, q); err != nil {
Expand All @@ -56,7 +65,7 @@ func ClusterId(conn *sqlx.DB, clusterName string) (string, error) {
}

func ScanCluster(conn *sqlx.DB, id string) (ClusterParams, error) {
q := clusterQuery.QueryPredicate(map[string]string{"id": id})
q := clusterQuery.QueryPredicate(map[string]string{"mz_clusters.id": id})

var c ClusterParams
if err := conn.Get(&c, q); err != nil {
Expand Down
6 changes: 4 additions & 2 deletions pkg/materialize/cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ func TestClusterCreate(t *testing.T) {
testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
mock.ExpectExec(`CREATE CLUSTER "cluster" REPLICAS \(\);`).WillReturnResult(sqlmock.NewResult(1, 1))

if err := NewClusterBuilder(db, "cluster").Create(); err != nil {
o := ObjectSchemaStruct{Name: "cluster"}
if err := NewClusterBuilder(db, o).Create(); err != nil {
t.Fatal(err)
}
})
Expand All @@ -22,7 +23,8 @@ func TestClusterDrop(t *testing.T) {
testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
mock.ExpectExec(`DROP CLUSTER "cluster";`).WillReturnResult(sqlmock.NewResult(1, 1))

if err := NewClusterBuilder(db, "cluster").Drop(); err != nil {
o := ObjectSchemaStruct{Name: "cluster"}
if err := NewClusterBuilder(db, o).Drop(); err != nil {
t.Fatal(err)
}
})
Expand Down
81 changes: 4 additions & 77 deletions pkg/materialize/ownership.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
package materialize

import (
"database/sql"
"fmt"
"strings"

"github.com/jmoiron/sqlx"
)
Expand All @@ -12,13 +10,13 @@ type OwnershipBuilder struct {
ddl Builder
objectType string
object ObjectSchemaStruct
roleName string
}

func NewOwnershipBuilder(conn *sqlx.DB, objectType string) *OwnershipBuilder {
func NewOwnershipBuilder(conn *sqlx.DB, objectType string, object ObjectSchemaStruct) *OwnershipBuilder {
return &OwnershipBuilder{
ddl: Builder{conn, Ownership},
objectType: objectType,
object: object,
}
}

Expand All @@ -27,78 +25,7 @@ func (b *OwnershipBuilder) Object(o ObjectSchemaStruct) *OwnershipBuilder {
return b
}

func (b *OwnershipBuilder) RoleName(r string) *OwnershipBuilder {
b.roleName = r
return b
}

// generate a unique id `ownership|object_type|id` as there is no catalog id
func OwnershipResourceId(objectType, catalogId string) string {
lo := strings.ToLower(objectType)
fo := strings.ReplaceAll(lo, " ", "_")
return fmt.Sprintf("ownership|%s|%s", fo, catalogId)
}

func OwnershipCatalogId(resourceId string) string {
ci := strings.Split(resourceId, "|")
return ci[len(ci)-1]
}

func (b *OwnershipBuilder) Alter() error {
q := fmt.Sprintf(`ALTER %s %s OWNER TO %s;`, b.objectType, b.object.QualifiedName(), b.roleName)
func (b *OwnershipBuilder) Alter(roleName string) error {
q := fmt.Sprintf(`ALTER %s %s OWNER TO "%s";`, b.objectType, b.object.QualifiedName(), roleName)
return b.ddl.exec(q)
}

type OwnershipParams struct {
ObjectId sql.NullString `db:"id"`
ObjectType sql.NullString `db:"obj_type"`
OwnershipId sql.NullString `db:"owner_id"`
RoleName sql.NullString `db:"role_name"`
}

var ownershipQuery = NewBaseQuery(`
SELECT
mz_objects.id,
mz_objects.type AS obj_type,
mz_objects.owner_id AS schema_name,
mz_roles.name AS role_name
FROM mz_objects
JOIN mz_roles
ON mz_objects.owner_id = mz_roles.id
LEFT JOIN mz_schemas
ON mz_objects.schema_id = mz_schemas.id
LEFT JOIN mz_databases
ON mz_schemas.database_id = mz_databases.id;`)

func OwnershipId(conn *sqlx.DB, objectType, objectName, schemaName, databaseName string) (string, error) {
p := map[string]string{
"mz_objects.type": objectType,
"mz_objects.name": objectName,
"mz_schemas.name": schemaName,
"mz_database.name": databaseName,
}
q := ownershipQuery.QueryPredicate(p)

var c OwnershipParams
if err := conn.Get(&c, q); err != nil {
return "", err
}

return OwnershipResourceId(objectType, c.OwnershipId.String), nil
}

func ScanOwnership(conn *sqlx.DB, id, objectType string) (OwnershipParams, error) {
p := map[string]string{
"mz_objects.type": objectType,
"mz_objects.id": id,
}

q := ownershipQuery.QueryPredicate(p)

var c OwnershipParams
if err := conn.Get(&c, q); err != nil {
return c, err
}

return c, nil
}
32 changes: 5 additions & 27 deletions pkg/materialize/ownership_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,23 @@ import (
"testing"

"github.com/MaterializeInc/terraform-provider-materialize/pkg/testhelpers"
"github.com/stretchr/testify/require"

sqlmock "github.com/DATA-DOG/go-sqlmock"
"github.com/jmoiron/sqlx"
)

func TestOwnershipResourceId(t *testing.T) {
r := require.New(t)

table := OwnershipResourceId("TABLE", "u1")
r.Equal(`ownership|table|u1`, table)

mview := OwnershipResourceId("MATERIALIZED VIEW", "u1")
r.Equal("ownership|materialized_view|u1", mview)
}

func TestOwnershipCatalogId(t *testing.T) {
r := require.New(t)

table := OwnershipCatalogId("ownership|table|u1")
r.Equal("u1", table)

mview := OwnershipCatalogId("ownership|materialized_view|u1")
r.Equal("u1", mview)
}

func TestOwnershipAlter(t *testing.T) {
testhelpers.WithMockDb(t, func(db *sqlx.DB, mock sqlmock.Sqlmock) {
mock.ExpectExec(`ALTER TABLE "database"."schema"."table" OWNER TO my_role;`).WillReturnResult(sqlmock.NewResult(1, 1))
mock.ExpectExec(`ALTER TABLE "database"."schema"."table" OWNER TO "my_role";`).WillReturnResult(sqlmock.NewResult(1, 1))

b := NewOwnershipBuilder(db, "TABLE")
b.RoleName("my_role")
b.Object(ObjectSchemaStruct{
o := ObjectSchemaStruct{
DatabaseName: "database",
SchemaName: "schema",
Name: "table",
})
}
b := NewOwnershipBuilder(db, "TABLE", o)

if err := b.Alter(); err != nil {
if err := b.Alter("my_role"); err != nil {
t.Fatal(err)
}
})
Expand Down
6 changes: 4 additions & 2 deletions pkg/materialize/privilege.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ func PrivilegeId(conn *sqlx.DB, object PrivilegeObjectStruct, roleId, privilege
id = i

case "TABLE":
i, err := TableId(conn, object.Name, object.SchemaName, object.DatabaseName)
o := ObjectSchemaStruct{Name: object.Name, SchemaName: object.SchemaName, DatabaseName: object.DatabaseName}
i, err := TableId(conn, o)
if err != nil {
return "", err
}
Expand Down Expand Up @@ -247,7 +248,8 @@ func PrivilegeId(conn *sqlx.DB, object PrivilegeObjectStruct, roleId, privilege
id = i

case "CLUSTER":
i, err := ClusterId(conn, object.Name)
o := ObjectSchemaStruct{Name: object.Name}
i, err := ClusterId(conn, o)
if err != nil {
return "", err
}
Expand Down
22 changes: 13 additions & 9 deletions pkg/materialize/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ type TableBuilder struct {
column []TableColumn
}

func NewTableBuilder(conn *sqlx.DB, tableName, schemaName, databaseName string) *TableBuilder {
func NewTableBuilder(conn *sqlx.DB, obj ObjectSchemaStruct) *TableBuilder {
return &TableBuilder{
ddl: Builder{conn, Table},
tableName: tableName,
schemaName: schemaName,
databaseName: databaseName,
tableName: obj.Name,
schemaName: obj.SchemaName,
databaseName: obj.DatabaseName,
}
}

Expand Down Expand Up @@ -90,6 +90,7 @@ type TableParams struct {
TableName sql.NullString `db:"name"`
SchemaName sql.NullString `db:"schema_name"`
DatabaseName sql.NullString `db:"database_name"`
OwnerName sql.NullString `db:"owner_name"`
Privileges sql.NullString `db:"privileges"`
}

Expand All @@ -99,18 +100,21 @@ var tableQuery = NewBaseQuery(`
mz_tables.name,
mz_schemas.name AS schema_name,
mz_databases.name AS database_name,
mz_roles.name AS owner_name,
mz_tables.privileges
FROM mz_tables
JOIN mz_schemas
ON mz_tables.schema_id = mz_schemas.id
JOIN mz_databases
ON mz_schemas.database_id = mz_databases.id`)
ON mz_schemas.database_id = mz_databases.id
JOIN mz_roles
ON mz_tables.owner_id = mz_roles.id`)

func TableId(conn *sqlx.DB, tableName, schemaName, databaseName string) (string, error) {
func TableId(conn *sqlx.DB, obj ObjectSchemaStruct) (string, error) {
p := map[string]string{
"mz_tables.name": tableName,
"mz_schemas.name": schemaName,
"mz_databases.name": databaseName,
"mz_tables.name": obj.Name,
"mz_schemas.name": obj.SchemaName,
"mz_databases.name": obj.DatabaseName,
}
q := tableQuery.QueryPredicate(p)

Expand Down
9 changes: 6 additions & 3 deletions pkg/materialize/table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ func TestTableCreate(t *testing.T) {
`CREATE TABLE "database"."schema"."table" \(column_1 int, column_2 text NOT NULL\);`,
).WillReturnResult(sqlmock.NewResult(1, 1))

b := NewTableBuilder(db, "table", "schema", "database")
o := ObjectSchemaStruct{Name: "table", SchemaName: "schema", DatabaseName: "database"}
b := NewTableBuilder(db, o)
b.Column([]TableColumn{
{
ColName: "column_1",
Expand All @@ -39,7 +40,8 @@ func TestTableRename(t *testing.T) {
`ALTER TABLE "database"."schema"."table" RENAME TO "new_table";`,
).WillReturnResult(sqlmock.NewResult(1, 1))

if err := NewTableBuilder(db, "table", "schema", "database").Rename("new_table"); err != nil {
o := ObjectSchemaStruct{Name: "table", SchemaName: "schema", DatabaseName: "database"}
if err := NewTableBuilder(db, o).Rename("new_table"); err != nil {
t.Fatal(err)
}
})
Expand All @@ -51,7 +53,8 @@ func TestTableDrop(t *testing.T) {
`DROP TABLE "database"."schema"."table";`,
).WillReturnResult(sqlmock.NewResult(1, 1))

if err := NewTableBuilder(db, "table", "schema", "database").Drop(); err != nil {
o := ObjectSchemaStruct{Name: "table", SchemaName: "schema", DatabaseName: "database"}
if err := NewTableBuilder(db, o).Drop(); err != nil {
t.Fatal(err)
}
})
Expand Down
Loading