diff --git a/bigtable/admin.go b/bigtable/admin.go index 85ef439ccc77..0a3ab5ea840a 100644 --- a/bigtable/admin.go +++ b/bigtable/admin.go @@ -2190,26 +2190,30 @@ type AuthorizedViewConf struct { TableID string AuthorizedViewID string - AuthorizedViewTypeConf AuthorizedViewTypeConf - DeletionProtection DeletionProtection + // Types that are valid to be assigned to AuthorizedView: + // *SubsetView + AuthorizedView isAuthorizedView + DeletionProtection DeletionProtection } -// AuthorizedViewTypeConf contains information about the type of an authorized view. -type AuthorizedViewTypeConf struct { - AuthorizedViewType AuthorizedViewType +// SubsetView is currently the only supported type as an AuthorizedView. +type SubsetView struct { + subsetView SubsetViewConf +} - SubsetView *SubsetViewConf +// A private interface that currently only implemented by SubsetView, ensuring that only SubsetView instances are accepted as an AuthorizedView. +// In the future if a new type of AuthorizedView is introduced, it should also implements this interface. +type isAuthorizedView interface { + isAuthorizedView() } -// AuthorizedViewType represents the type of an authorized view. -type AuthorizedViewType int +func (*SubsetView) isAuthorizedView() {} -const ( - // AuthorizedViewTypeUnspecified represents an unspecified authorized view type. - AuthorizedViewTypeUnspecified AuthorizedViewType = iota - // AuthorizedViewTypeSubsetView represents subset view type of an authorized view. - AuthorizedViewTypeSubsetView -) +// SubsetViewConf contains configuration specific to an authorized view of subset view type. +type SubsetViewConf struct { + RowPrefixes [][]byte + FamilySubsets map[string]FamilySubset +} func (av AuthorizedViewConf) proto() *btapb.AuthorizedView { var avp btapb.AuthorizedView @@ -2223,10 +2227,10 @@ func (av AuthorizedViewConf) proto() *btapb.AuthorizedView { break } - switch avt := av.AuthorizedViewTypeConf.AuthorizedViewType; avt { - case AuthorizedViewTypeSubsetView: + switch avt := av.AuthorizedView.(type) { + case *SubsetView: avp.AuthorizedView = &btapb.AuthorizedView_SubsetView_{ - SubsetView: av.AuthorizedViewTypeConf.SubsetView.proto(), + SubsetView: avt.subsetView.proto(), } default: break @@ -2234,19 +2238,20 @@ func (av AuthorizedViewConf) proto() *btapb.AuthorizedView { return &avp } -// SetSubsetView sets the AuthorizedViewType to AuthorizedViewTypeSubsetView and the subsetView pointer accordingly -func (av *AuthorizedViewTypeConf) SetSubsetView(s SubsetViewConf) error { - av.AuthorizedViewType = AuthorizedViewTypeSubsetView - av.SubsetView = &s +// SetSubsetView sets the AuthorizedView as SubsetView type with the specified config. +func (av *AuthorizedViewConf) SetSubsetView(s SubsetViewConf) error { + av.AuthorizedView = &SubsetView{subsetView: s} return nil } -// GetSubsetView returns an error if the type is not AuthorizedViewTypeSubsetView. -func (av *AuthorizedViewTypeConf) GetSubsetView() (*SubsetViewConf, error) { - if av.AuthorizedViewType != AuthorizedViewTypeSubsetView { - return nil, fmt.Errorf("not a subset view: :%v", av.AuthorizedViewType) +// GetSubsetView returns an error if the type of the AuthorizedView is not SubsetView. +func (av *AuthorizedViewConf) GetSubsetView() (*SubsetViewConf, error) { + switch avt := av.AuthorizedView.(type) { + case *SubsetView: + return &avt.subsetView, nil + default: + return nil, fmt.Errorf("not a subset view: %v", avt) } - return av.SubsetView, nil } // FamilySubset represents a subset of a column family. @@ -2255,12 +2260,6 @@ type FamilySubset struct { QualifierPrefixes [][]byte } -// SubsetViewConf contains configuration specific to an authorized view of subset view type. -type SubsetViewConf struct { - RowPrefixes [][]byte - FamilySubsets map[string]FamilySubset -} - // AddRowPrefix adds a new row prefix to the subset view. func (s *SubsetViewConf) AddRowPrefix(prefix []byte) { s.RowPrefixes = append(s.RowPrefixes, prefix) @@ -2324,9 +2323,6 @@ func (ac *AdminClient) CreateAuthorizedView(ctx context.Context, conf *Authorize if conf.TableID == "" || conf.AuthorizedViewID == "" { return errors.New("both AuthorizedViewID and TableID are required") } - if conf.AuthorizedViewTypeConf.AuthorizedViewType == AuthorizedViewTypeUnspecified { - return errors.New("AuthorizedViewType must be specified") - } ctx = mergeOutgoingMetadata(ctx, ac.md) req := &btapb.CreateAuthorizedViewRequest{ @@ -2345,7 +2341,6 @@ func (ac *AdminClient) GetAuthorizedView(ctx context.Context, tableID, authorize Name: fmt.Sprintf("%s/tables/%s/authorizedViews/%s", ac.instancePrefix(), tableID, authorizedViewID), } var res *btapb.AuthorizedView - av := &AuthorizedViewConf{TableID: tableID, AuthorizedViewID: authorizedViewID} err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error { var err error @@ -2357,6 +2352,7 @@ func (ac *AdminClient) GetAuthorizedView(ctx context.Context, tableID, authorize return nil, err } + av := &AuthorizedViewConf{TableID: tableID, AuthorizedViewID: authorizedViewID} if res.DeletionProtection { av.DeletionProtection = Protected } else { @@ -2365,18 +2361,18 @@ func (ac *AdminClient) GetAuthorizedView(ctx context.Context, tableID, authorize if res.GetSubsetView() != nil { s := SubsetViewConf{} s.fillConf(res.GetSubsetView()) - av.AuthorizedViewTypeConf.SetSubsetView(s) + av.SetSubsetView(s) } return av, nil } -// AuthorizedViews returns a list of the authorized views in the table. The names returned are fully -// qualified as projects//instances//tables//authorizedViews/ +// AuthorizedViews returns a list of the authorized views in the table. func (ac *AdminClient) AuthorizedViews(ctx context.Context, tableID string) ([]string, error) { names := []string{} + prefix := fmt.Sprintf("%s/tables/%s", ac.instancePrefix(), tableID) req := &btapb.ListAuthorizedViewsRequest{ - Parent: fmt.Sprintf("%s/tables/%s", ac.instancePrefix(), tableID), + Parent: prefix, View: btapb.AuthorizedView_NAME_ONLY, } var res *btapb.ListAuthorizedViewsResponse @@ -2390,7 +2386,7 @@ func (ac *AdminClient) AuthorizedViews(ctx context.Context, tableID string) ([]s } for _, av := range res.AuthorizedViews { - names = append(names, av.Name) + names = append(names, strings.TrimPrefix(av.Name, prefix+"/authorizedViews/")) } return names, nil } @@ -2398,7 +2394,6 @@ func (ac *AdminClient) AuthorizedViews(ctx context.Context, tableID string) ([]s // UpdateAuthorizedViewConf contains all the information necessary to update or partial update an authorized view. type UpdateAuthorizedViewConf struct { AuthorizedViewConf AuthorizedViewConf - UpdateMask []string IgnoreWarnings bool } @@ -2410,9 +2405,19 @@ func (ac *AdminClient) UpdateAuthorizedView(ctx context.Context, conf UpdateAuth } av := conf.AuthorizedViewConf.proto() av.Name = ac.authorizedViewPath(conf.AuthorizedViewConf.TableID, conf.AuthorizedViewConf.AuthorizedViewID) + + updateMask := &field_mask.FieldMask{ + Paths: []string{}, + } + if conf.AuthorizedViewConf.DeletionProtection != None { + updateMask.Paths = append(updateMask.Paths, "deletion_protection") + } + if _, err := conf.AuthorizedViewConf.GetSubsetView(); err == nil { + updateMask.Paths = append(updateMask.Paths, "subset_view") + } req := &btapb.UpdateAuthorizedViewRequest{ AuthorizedView: av, - UpdateMask: &field_mask.FieldMask{Paths: conf.UpdateMask}, + UpdateMask: updateMask, IgnoreWarnings: conf.IgnoreWarnings, } lro, err := ac.tClient.UpdateAuthorizedView(ctx, req) diff --git a/bigtable/admin_test.go b/bigtable/admin_test.go index 7e159fca5116..f9e25f24703a 100644 --- a/bigtable/admin_test.go +++ b/bigtable/admin_test.go @@ -317,12 +317,9 @@ func TestTableAdmin_CreateAuthorizedView_DeletionProtection_Protected(t *testing deletionProtection := Protected err = c.CreateAuthorizedView(context.Background(), &AuthorizedViewConf{ - TableID: "my-cool-table", - AuthorizedViewID: "my-cool-authorized-view", - AuthorizedViewTypeConf: AuthorizedViewTypeConf{ - AuthorizedViewType: AuthorizedViewTypeSubsetView, - SubsetView: &SubsetViewConf{}, - }, + TableID: "my-cool-table", + AuthorizedViewID: "my-cool-authorized-view", + AuthorizedView: &SubsetView{subsetView: SubsetViewConf{}}, DeletionProtection: deletionProtection, }) if err != nil { @@ -346,12 +343,9 @@ func TestTableAdmin_CreateAuthorizedView_DeletionProtection_Unprotected(t *testi deletionProtection := Unprotected err := c.CreateAuthorizedView(context.Background(), &AuthorizedViewConf{ - TableID: "my-cool-table", - AuthorizedViewID: "my-cool-authorized-view", - AuthorizedViewTypeConf: AuthorizedViewTypeConf{ - AuthorizedViewType: AuthorizedViewTypeSubsetView, - SubsetView: &SubsetViewConf{}, - }, + TableID: "my-cool-table", + AuthorizedViewID: "my-cool-authorized-view", + AuthorizedView: &SubsetView{subsetView: SubsetViewConf{}}, DeletionProtection: deletionProtection, }) if err != nil { @@ -381,7 +375,6 @@ func TestTableAdmin_UpdateAuthorizedViewWithDeletionProtection(t *testing.T) { AuthorizedViewID: "my-cool-authorized-view", DeletionProtection: deletionProtection, }, - UpdateMask: []string{"deletion_protection"}, }) if err != nil { t.Fatalf("UpdateAuthorizedView failed: %v", err) @@ -401,6 +394,32 @@ func TestTableAdmin_UpdateAuthorizedViewWithDeletionProtection(t *testing.T) { } } +func TestTableAdmin_UpdateAuthorizedViewWithSubsetView(t *testing.T) { + mock := &mockTableAdminClock{} + c := setupTableClient(t, mock) + + err := c.UpdateAuthorizedView(context.Background(), UpdateAuthorizedViewConf{ + AuthorizedViewConf: AuthorizedViewConf{ + TableID: "my-cool-table", + AuthorizedViewID: "my-cool-authorized-view", + AuthorizedView: &SubsetView{subsetView: SubsetViewConf{}}, + }, + }) + if err != nil { + t.Fatalf("UpdateAuthorizedView failed: %v", err) + } + updateAuthorizedViewReq := mock.updateAuthorizedViewReq + if !cmp.Equal(updateAuthorizedViewReq.AuthorizedView.Name, "projects/my-cool-project/instances/my-cool-instance/tables/my-cool-table/authorizedViews/my-cool-authorized-view") { + t.Errorf("UpdateAuthorizedViewRequest does not match: AuthorizedViewName: %v, expected %v", updateAuthorizedViewReq.AuthorizedView.Name, "projects/my-cool-project/instances/my-cool-instance/tables/my-cool-table/authorizedViews/my-cool-authorized-view") + } + if !cmp.Equal(len(updateAuthorizedViewReq.UpdateMask.Paths), 1) { + t.Errorf("UpdateAuthorizedViewRequest does not match: UpdateMask has length of %d, expected %v", len(updateAuthorizedViewReq.UpdateMask.Paths), 1) + } + if !cmp.Equal(updateAuthorizedViewReq.UpdateMask.Paths[0], "subset_view") { + t.Errorf("UpdateAuthorizedViewRequest does not match: updateAuthorizedViewReq.UpdateMask.Paths[0]: %v, expected: %v", updateAuthorizedViewReq.UpdateMask.Paths[0], "subset_view") + } +} + type mockAdminClock struct { btapb.BigtableInstanceAdminClient diff --git a/bigtable/bigtable.go b/bigtable/bigtable.go index f23484198b24..9299294bf4dd 100644 --- a/bigtable/bigtable.go +++ b/bigtable/bigtable.go @@ -248,17 +248,13 @@ func (t *Table) ReadRows(ctx context.Context, arg RowSet, f func(Row) bool, opts var prevRowKey string attrMap := make(map[string]interface{}) err = gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error { - var req *btpb.ReadRowsRequest + req := &btpb.ReadRowsRequest{ + AppProfileId: t.c.appProfile, + } if t.authorizedView == "" { - req = &btpb.ReadRowsRequest{ - TableName: t.c.fullTableName(t.table), - AppProfileId: t.c.appProfile, - } + req.TableName = t.c.fullTableName(t.table) } else { - req = &btpb.ReadRowsRequest{ - AuthorizedViewName: t.c.fullAuthorizedViewName(t.table, t.authorizedView), - AppProfileId: t.c.appProfile, - } + req.AuthorizedViewName = t.c.fullAuthorizedViewName(t.table, t.authorizedView) } if arg != nil { @@ -893,21 +889,15 @@ func (t *Table) Apply(ctx context.Context, row string, m *Mutation, opts ...Appl var callOptions []gax.CallOption if m.cond == nil { - var req *btpb.MutateRowRequest + req := &btpb.MutateRowRequest{ + AppProfileId: t.c.appProfile, + RowKey: []byte(row), + Mutations: m.ops, + } if t.authorizedView == "" { - req = &btpb.MutateRowRequest{ - TableName: t.c.fullTableName(t.table), - AppProfileId: t.c.appProfile, - RowKey: []byte(row), - Mutations: m.ops, - } + req.TableName = t.c.fullTableName(t.table) } else { - req = &btpb.MutateRowRequest{ - AuthorizedViewName: t.c.fullAuthorizedViewName(t.table, t.authorizedView), - AppProfileId: t.c.appProfile, - RowKey: []byte(row), - Mutations: m.ops, - } + req.AuthorizedViewName = t.c.fullAuthorizedViewName(t.table, t.authorizedView) } if mutationsAreRetryable(m.ops) { callOptions = retryOptions @@ -924,21 +914,15 @@ func (t *Table) Apply(ctx context.Context, row string, m *Mutation, opts ...Appl return err } - var req *btpb.CheckAndMutateRowRequest + req := &btpb.CheckAndMutateRowRequest{ + AppProfileId: t.c.appProfile, + RowKey: []byte(row), + PredicateFilter: m.cond.proto(), + } if t.authorizedView == "" { - req = &btpb.CheckAndMutateRowRequest{ - TableName: t.c.fullTableName(t.table), - AppProfileId: t.c.appProfile, - RowKey: []byte(row), - PredicateFilter: m.cond.proto(), - } + req.TableName = t.c.fullTableName(t.table) } else { - req = &btpb.CheckAndMutateRowRequest{ - AuthorizedViewName: t.c.fullAuthorizedViewName(t.table, t.authorizedView), - AppProfileId: t.c.appProfile, - RowKey: []byte(row), - PredicateFilter: m.cond.proto(), - } + req.AuthorizedViewName = t.c.fullAuthorizedViewName(t.table, t.authorizedView) } if m.mtrue != nil { if m.mtrue.cond != nil { @@ -1172,19 +1156,14 @@ func (t *Table) doApplyBulk(ctx context.Context, entryErrs []*entryErr, opts ... for i, entryErr := range entryErrs { entries[i] = entryErr.Entry } - var req *btpb.MutateRowsRequest + req := &btpb.MutateRowsRequest{ + AppProfileId: t.c.appProfile, + Entries: entries, + } if t.authorizedView == "" { - req = &btpb.MutateRowsRequest{ - TableName: t.c.fullTableName(t.table), - AppProfileId: t.c.appProfile, - Entries: entries, - } + req.TableName = t.c.fullTableName(t.table) } else { - req = &btpb.MutateRowsRequest{ - AuthorizedViewName: t.c.fullAuthorizedViewName(t.table, t.authorizedView), - AppProfileId: t.c.appProfile, - Entries: entries, - } + req.AuthorizedViewName = t.c.fullAuthorizedViewName(t.table, t.authorizedView) } stream, err := t.c.client.MutateRows(ctx, req) if err != nil { @@ -1267,21 +1246,15 @@ func (ts Timestamp) TruncateToMilliseconds() Timestamp { // It returns the newly written cells. func (t *Table) ApplyReadModifyWrite(ctx context.Context, row string, m *ReadModifyWrite) (Row, error) { ctx = mergeOutgoingMetadata(ctx, t.md) - var req *btpb.ReadModifyWriteRowRequest + req := &btpb.ReadModifyWriteRowRequest{ + AppProfileId: t.c.appProfile, + RowKey: []byte(row), + Rules: m.ops, + } if t.authorizedView == "" { - req = &btpb.ReadModifyWriteRowRequest{ - TableName: t.c.fullTableName(t.table), - AppProfileId: t.c.appProfile, - RowKey: []byte(row), - Rules: m.ops, - } + req.TableName = t.c.fullTableName(t.table) } else { - req = &btpb.ReadModifyWriteRowRequest{ - AuthorizedViewName: t.c.fullAuthorizedViewName(t.table, t.authorizedView), - AppProfileId: t.c.appProfile, - RowKey: []byte(row), - Rules: m.ops, - } + req.AuthorizedViewName = t.c.fullAuthorizedViewName(t.table, t.authorizedView) } res, err := t.c.client.ReadModifyWriteRow(ctx, req) if err != nil { @@ -1341,17 +1314,13 @@ func (t *Table) SampleRowKeys(ctx context.Context) ([]string, error) { var sampledRowKeys []string err := gax.Invoke(ctx, func(ctx context.Context, _ gax.CallSettings) error { sampledRowKeys = nil - var req *btpb.SampleRowKeysRequest + req := &btpb.SampleRowKeysRequest{ + AppProfileId: t.c.appProfile, + } if t.authorizedView == "" { - req = &btpb.SampleRowKeysRequest{ - TableName: t.c.fullTableName(t.table), - AppProfileId: t.c.appProfile, - } + req.TableName = t.c.fullTableName(t.table) } else { - req = &btpb.SampleRowKeysRequest{ - AuthorizedViewName: t.c.fullAuthorizedViewName(t.table, t.authorizedView), - AppProfileId: t.c.appProfile, - } + req.AuthorizedViewName = t.c.fullAuthorizedViewName(t.table, t.authorizedView) } ctx, cancel := context.WithCancel(ctx) // for aborting the stream defer cancel() diff --git a/bigtable/integration_test.go b/bigtable/integration_test.go index 6439f2e461b0..b121729bf248 100644 --- a/bigtable/integration_test.go +++ b/bigtable/integration_test.go @@ -2034,12 +2034,9 @@ func TestIntegration_AuthorizedViewIAM(t *testing.T) { defer adminClient.DeleteAuthorizedView(ctx, table, authorizedView) if err = adminClient.CreateAuthorizedView(ctx, &AuthorizedViewConf{ - TableID: table, - AuthorizedViewID: authorizedView, - AuthorizedViewTypeConf: AuthorizedViewTypeConf{ - AuthorizedViewType: AuthorizedViewTypeSubsetView, - SubsetView: &SubsetViewConf{}, - }, + TableID: table, + AuthorizedViewID: authorizedView, + AuthorizedView: &SubsetView{subsetView: SubsetViewConf{}}, DeletionProtection: Unprotected, }); err != nil { t.Fatalf("Creating authorizedView: %v", err) @@ -3541,12 +3538,9 @@ func TestIntegration_AdminAuthorizedView(t *testing.T) { authorizedViewConf := AuthorizedViewConf{ TableID: tblConf.TableID, AuthorizedViewID: authorizedView, - AuthorizedViewTypeConf: AuthorizedViewTypeConf{ - AuthorizedViewType: AuthorizedViewTypeSubsetView, - SubsetView: &SubsetViewConf{ - RowPrefixes: [][]byte{[]byte("r1")}, - }, - }, + AuthorizedView: &SubsetView{subsetView: SubsetViewConf{ + RowPrefixes: [][]byte{[]byte("r1")}, + }}, DeletionProtection: Protected, } if err = adminClient.CreateAuthorizedView(ctx, &authorizedViewConf); err != nil { @@ -3561,7 +3555,7 @@ func TestIntegration_AdminAuthorizedView(t *testing.T) { if got, want := len(authorizedViews), 1; got != want { t.Fatalf("Listing authorized views count: %d, want: != %d", got, want) } - if got, want := authorizedViews[0], fmt.Sprintf("%s/tables/%s/authorizedViews/%s", adminClient.instancePrefix(), tblConf.TableID, authorizedView); got != want { + if got, want := authorizedViews[0], authorizedView; got != want { t.Errorf("AuthorizedView Name: %s, want: %s", got, want) } @@ -3570,8 +3564,12 @@ func TestIntegration_AdminAuthorizedView(t *testing.T) { if err != nil { t.Fatalf("Getting authorized view: %v", err) } - if got, want := *av, authorizedViewConf; cmp.Equal(got, want) { - t.Errorf("AuthorizedViewConf: %v, want: %v", got, want) + got, err := av.GetSubsetView() + if err != nil { + t.Errorf("GetSubsetView failed: %v", err) + } + if want, _ := authorizedViewConf.GetSubsetView(); cmp.Equal(got, want) { + t.Errorf("SubsetViewConf: %v, want: %v", got, want) } // Cannot delete the authorized view because it is deletion protected @@ -3580,10 +3578,13 @@ func TestIntegration_AdminAuthorizedView(t *testing.T) { } // Update authorized view - authorizedViewConf.DeletionProtection = Unprotected + newAuthorizedViewConf := AuthorizedViewConf{ + TableID: tblConf.TableID, + AuthorizedViewID: authorizedView, + DeletionProtection: Unprotected, + } err = adminClient.UpdateAuthorizedView(ctx, UpdateAuthorizedViewConf{ - AuthorizedViewConf: authorizedViewConf, - UpdateMask: []string{"deletion_protection"}, + AuthorizedViewConf: newAuthorizedViewConf, }) if err != nil { t.Fatalf("UpdateAuthorizedView failed: %v", err) @@ -3597,6 +3598,14 @@ func TestIntegration_AdminAuthorizedView(t *testing.T) { if got, want := av.DeletionProtection, Unprotected; got != want { t.Errorf("AuthorizedView deletion protection: %v, want: %v", got, want) } + // Check that the subset_view field doesn't change + got, err = av.GetSubsetView() + if err != nil { + t.Errorf("GetSubsetView failed: %v", err) + } + if want, _ := authorizedViewConf.GetSubsetView(); cmp.Equal(got, want) { + t.Errorf("SubsetViewConf: %v, want: %v", got, want) + } // Delete authorized view if err = adminClient.DeleteAuthorizedView(ctx, tblConf.TableID, authorizedView); err != nil { @@ -3656,20 +3665,18 @@ func TestIntegration_DataAuthorizedView(t *testing.T) { authorizedViewConf := AuthorizedViewConf{ TableID: tblConf.TableID, AuthorizedViewID: authorizedView, - AuthorizedViewTypeConf: AuthorizedViewTypeConf{ - AuthorizedViewType: AuthorizedViewTypeSubsetView, - SubsetView: &SubsetViewConf{ - RowPrefixes: [][]byte{[]byte("r1")}, - FamilySubsets: map[string]FamilySubset{ - "fam1": { - QualifierPrefixes: [][]byte{[]byte("col")}, - }, - "fam2": { - Qualifiers: [][]byte{[]byte("col")}, - }, + AuthorizedView: &SubsetView{subsetView: SubsetViewConf{ + RowPrefixes: [][]byte{[]byte("r1")}, + FamilySubsets: map[string]FamilySubset{ + "fam1": { + QualifierPrefixes: [][]byte{[]byte("col")}, + }, + "fam2": { + Qualifiers: [][]byte{[]byte("col")}, }, }, }, + }, DeletionProtection: Unprotected, } if err = adminClient.CreateAuthorizedView(ctx, &authorizedViewConf); err != nil { @@ -3807,12 +3814,9 @@ func TestIntegration_DataAuthorizedView(t *testing.T) { if err = adminClient.CreateAuthorizedView(ctx, &AuthorizedViewConf{ TableID: presplitTable, AuthorizedViewID: authorizedView, - AuthorizedViewTypeConf: AuthorizedViewTypeConf{ - AuthorizedViewType: AuthorizedViewTypeSubsetView, - SubsetView: &SubsetViewConf{ - RowPrefixes: [][]byte{[]byte("r1")}, - }, - }, + AuthorizedView: &SubsetView{subsetView: SubsetViewConf{ + RowPrefixes: [][]byte{[]byte("r1")}, + }}, DeletionProtection: Unprotected, }); err != nil { t.Fatalf("Creating authorized view: %v", err)