Skip to content

Commit

Permalink
Ownership Attribute (#208)
Browse files Browse the repository at this point in the history
  • Loading branch information
dehume authored Jun 22, 2023
1 parent 74dd71a commit c3c61f6
Show file tree
Hide file tree
Showing 23 changed files with 285 additions and 411 deletions.
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

0 comments on commit c3c61f6

Please sign in to comment.