Skip to content

Commit

Permalink
feat: get multiple users by id (#6210)
Browse files Browse the repository at this point in the history
* feat: introduce InTextQuery, and the ability to get multiple users by id

* added in query tests

* remove append call

* fix lints
  • Loading branch information
ahmednfwela authored Aug 12, 2023
1 parent faf547f commit 133789f
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 1 deletion.
6 changes: 6 additions & 0 deletions internal/api/grpc/user/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ func UserQueryToQuery(query *user_pb.SearchQuery) (query.SearchQuery, error) {
return LoginNameQueryToQuery(q.LoginNameQuery)
case *user_pb.SearchQuery_ResourceOwner:
return ResourceOwnerQueryToQuery(q.ResourceOwner)
case *user_pb.SearchQuery_InUserIdsQuery:
return InUserIdsQueryToQuery(q.InUserIdsQuery)
default:
return nil, errors.ThrowInvalidArgument(nil, "GRPC-vR9nC", "List.Query.Invalid")
}
Expand Down Expand Up @@ -84,3 +86,7 @@ func LoginNameQueryToQuery(q *user_pb.LoginNameQuery) (query.SearchQuery, error)
func ResourceOwnerQueryToQuery(q *user_pb.ResourceOwnerQuery) (query.SearchQuery, error) {
return query.NewUserResourceOwnerSearchQuery(q.OrgID, query.TextEquals)
}

func InUserIdsQueryToQuery(q *user_pb.InUserIDQuery) (query.SearchQuery, error) {
return query.NewUserInUserIdsSearchQuery(q.UserIds)
}
29 changes: 28 additions & 1 deletion internal/query/search_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ const (
columnCompareMax
)

type InTextQuery struct {
Column Column
Values []string
}
type TextQuery struct {
Column Column
Text string
Expand All @@ -167,8 +171,22 @@ var (
ErrInvalidCompare = errors.New("invalid compare")
ErrMissingColumn = errors.New("missing column")
ErrInvalidNumber = errors.New("value is no number")
ErrEmptyValues = errors.New("values array must not be empty")
)

func NewInTextQuery(col Column, values []string) (*InTextQuery, error) {
if len(values) == 0 {
return nil, ErrEmptyValues
}
if col.isZero() {
return nil, ErrMissingColumn
}
return &InTextQuery{
Column: col,
Values: values,
}, nil
}

func NewTextQuery(col Column, value string, compare TextComparison) (*TextQuery, error) {
if compare < 0 || compare >= textCompareMax {
return nil, ErrInvalidCompare
Expand All @@ -183,6 +201,15 @@ func NewTextQuery(col Column, value string, compare TextComparison) (*TextQuery,
}, nil
}

func (q *InTextQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
return query.Where(q.comp())
}

func (s *InTextQuery) comp() sq.Sqlizer {
// This translates to an IN query
return sq.Eq{s.Column.identifier(): s.Values}
}

func (q *TextQuery) toQuery(query sq.SelectBuilder) sq.SelectBuilder {
return query.Where(q.comp())
}
Expand Down Expand Up @@ -269,7 +296,7 @@ func NewNumberQuery(c Column, value interface{}, compare NumberComparison) (*Num
}
switch reflect.TypeOf(value).Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
//everything fine
// everything fine
default:
return nil, ErrInvalidNumber
}
Expand Down
115 changes: 115 additions & 0 deletions internal/query/search_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1382,3 +1382,118 @@ func TestNumberComparisonFromMethod(t *testing.T) {
})
}
}

func TestNewInTextQuery(t *testing.T) {
type args struct {
column Column
value []string
}
tests := []struct {
name string
args args
want *InTextQuery
wantErr func(error) bool
}{
{
name: "empty values",
args: args{
column: testCol,
value: []string{},
},
wantErr: func(err error) bool {
return errors.Is(err, ErrEmptyValues)
},
},
{
name: "no column",
args: args{
column: Column{},
value: []string{"adler", "hurst"},
},
wantErr: func(err error) bool {
return errors.Is(err, ErrMissingColumn)
},
},
{
name: "no column name",
args: args{
column: testNoCol,
value: []string{"adler", "hurst"},
},
wantErr: func(err error) bool {
return errors.Is(err, ErrMissingColumn)
},
},
{
name: "correct",
args: args{
column: testCol,
value: []string{"adler", "hurst"},
},
want: &InTextQuery{
Column: testCol,
Values: []string{"adler", "hurst"},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := NewInTextQuery(tt.args.column, tt.args.value)
if err != nil && tt.wantErr == nil {
t.Errorf("NewTextQuery() no error expected got %v", err)
return
} else if tt.wantErr != nil && !tt.wantErr(err) {
t.Errorf("NewTextQuery() unexpeted error = %v", err)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("NewTextQuery() = %v, want %v", got, tt.want)
}
})
}
}

func TestInTextQuery_comp(t *testing.T) {
type fields struct {
Column Column
Values []string
}
type want struct {
query interface{}
isNil bool
}
tests := []struct {
name string
fields fields
want want
}{
{
name: "equals",
fields: fields{
Column: testCol,
Values: []string{"Adler", "Hurst"},
},
want: want{
query: sq.Eq{"test_table.test_col": []string{"Adler", "Hurst"}},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
s := &InTextQuery{
Column: tt.fields.Column,
Values: tt.fields.Values,
}
query := s.comp()
if query == nil && tt.want.isNil {
return
} else if tt.want.isNil && query != nil {
t.Error("query should not be nil")
}

if !reflect.DeepEqual(query, tt.want.query) {
t.Errorf("wrong query: want: %v, (%T), got: %v, (%T)", tt.want.query, tt.want.query, query, query)
}
})
}
}
4 changes: 4 additions & 0 deletions internal/query/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,10 @@ func (r *UserSearchQueries) AppendMyResourceOwnerQuery(orgID string) error {
return nil
}

func NewUserInUserIdsSearchQuery(values []string) (SearchQuery, error) {
return NewInTextQuery(UserIDCol, values)
}

func NewUserResourceOwnerSearchQuery(value string, comparison TextComparison) (SearchQuery, error) {
return NewTextQuery(UserResourceOwnerCol, value, comparison)
}
Expand Down
10 changes: 10 additions & 0 deletions proto/zitadel/user.proto
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,19 @@ message SearchQuery {
StateQuery state_query = 7;
TypeQuery type_query = 8;
LoginNameQuery login_name_query = 9;
InUserIDQuery in_user_ids_query = 10;
}
}

message InUserIDQuery {
repeated string user_ids = 1 [
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
description: "the ids of the users to include"
example: "[\"69629023906488334\",\"69622366012355662\"]";
}
];
}

message UserNameQuery {
string user_name = 1 [
(validate.rules).string = {max_len: 200},
Expand Down

1 comment on commit 133789f

@vercel
Copy link

@vercel vercel bot commented on 133789f Aug 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

docs – ./

zitadel-docs.vercel.app
docs-zitadel.vercel.app
docs-git-main-zitadel.vercel.app

Please sign in to comment.