mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 17:27:31 +00:00
perf(query): org permission function for resources (#9677)
# Which Problems Are Solved Classic permission checks execute for every returned row on resource based search APIs. Complete background and problem definition can be found here: https://github.com/zitadel/zitadel/issues/9188 # How the Problems Are Solved - PermissionClause function now support dynamic query building, so it supports multiple cases. - PermissionClause is applied to all list resources which support org level permissions. - Wrap permission logic into wrapper functions so we keep the business logic clean. # Additional Changes - Handle org ID optimization in the query package, so it is reusable for all resources, instead of extracting the filter in the API. - Cleanup and test system user conversion in the authz package. (context middleware) - Fix: `core_integration_db_up` make recipe was missing the postgres service. # Additional Context - Related to https://github.com/zitadel/zitadel/issues/9190
This commit is contained in:
@@ -225,3 +225,37 @@ func (d *NullDuration) Scan(src any) error {
|
||||
d.Duration, d.Valid = time.Duration(*duration), true
|
||||
return nil
|
||||
}
|
||||
|
||||
// JSONArray allows sending and receiving JSON arrays to and from the database.
|
||||
// It implements the [database/sql.Scanner] and [database/sql/driver.Valuer] interfaces.
|
||||
// Values are marshaled and unmarshaled using the [encoding/json] package.
|
||||
type JSONArray[T any] []T
|
||||
|
||||
// NewJSONArray wraps an existing slice into a JSONArray.
|
||||
func NewJSONArray[T any](a []T) JSONArray[T] {
|
||||
return JSONArray[T](a)
|
||||
}
|
||||
|
||||
// Scan implements the [database/sql.Scanner] interface.
|
||||
func (a *JSONArray[T]) Scan(src any) error {
|
||||
if src == nil {
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
bytes := src.([]byte)
|
||||
if len(bytes) == 0 {
|
||||
*a = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
return json.Unmarshal(bytes, a)
|
||||
}
|
||||
|
||||
// Value implements the [database/sql/driver.Valuer] interface.
|
||||
func (a JSONArray[T]) Value() (driver.Value, error) {
|
||||
if a == nil {
|
||||
return nil, nil
|
||||
}
|
||||
return json.Marshal(a)
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@ import (
|
||||
"database/sql/driver"
|
||||
"testing"
|
||||
|
||||
"github.com/muhlemmer/gu"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -452,3 +453,89 @@ func TestDuration_Scan(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONArray_Scan(t *testing.T) {
|
||||
type args struct {
|
||||
src any
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want *JSONArray[string]
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "nil",
|
||||
args: args{src: nil},
|
||||
want: new(JSONArray[string]),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "zero bytes",
|
||||
args: args{src: []byte("")},
|
||||
want: new(JSONArray[string]),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "empty",
|
||||
args: args{src: []byte("[]")},
|
||||
want: gu.Ptr(JSONArray[string]{}),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "ok",
|
||||
args: args{src: []byte("[\"a\", \"b\"]")},
|
||||
want: gu.Ptr(JSONArray[string]{"a", "b"}),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "json error",
|
||||
args: args{src: []byte("{\"a\": \"b\"}")},
|
||||
want: new(JSONArray[string]),
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := new(JSONArray[string])
|
||||
err := got.Scan(tt.args.src)
|
||||
if tt.wantErr {
|
||||
assert.Error(t, err)
|
||||
return
|
||||
}
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestJSONArray_Value(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
a []string
|
||||
want driver.Value
|
||||
}{
|
||||
{
|
||||
name: "nil",
|
||||
a: nil,
|
||||
want: nil,
|
||||
},
|
||||
{
|
||||
name: "empty",
|
||||
a: []string{},
|
||||
want: []byte("[]"),
|
||||
},
|
||||
{
|
||||
name: "ok",
|
||||
a: []string{"a", "b"},
|
||||
want: []byte("[\"a\",\"b\"]"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := NewJSONArray(tt.a).Value()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user