Skip to content

Commit

Permalink
enhance filter handling in the sql share drivers
Browse files Browse the repository at this point in the history
  • Loading branch information
David Christofas committed Sep 8, 2021
1 parent eacfb8a commit 8f0de6e
Show file tree
Hide file tree
Showing 2 changed files with 199 additions and 24 deletions.
110 changes: 99 additions & 11 deletions pkg/cbox/share/sql/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ import (
_ "github.com/go-sql-driver/mysql"
)

const (
shareTypeUser = 0
shareTypeGroup = 1
)

func init() {
registry.Register("sql", New)
}
Expand Down Expand Up @@ -276,18 +281,25 @@ func (m *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference

func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.Share, error) {
uid := conversions.FormatUserID(ctxpkg.ContextMustGetUser(ctx).Id)
query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, id, stime, permissions, share_type FROM oc_share WHERE (orphan = 0 or orphan IS NULL) AND (uid_owner=? or uid_initiator=?) AND (share_type=? OR share_type=?)"
var filterQuery string
params := []interface{}{uid, uid, 0, 1}
for i, f := range filters {
if f.Type == collaboration.Filter_TYPE_RESOURCE_ID {
filterQuery += "(fileid_prefix=? AND item_source=?)"
if i != len(filters)-1 {
filterQuery += " AND "
}
params = append(params, f.GetResourceId().StorageId, f.GetResourceId().OpaqueId)
}
query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(fileid_prefix, '') as fileid_prefix, coalesce(item_source, '') as item_source, id, stime, permissions, share_type FROM oc_share WHERE (orphan = 0 or orphan IS NULL) AND (uid_owner=? or uid_initiator=?)"
params := []interface{}{uid, uid}
var (
filterQuery string
filterParams []interface{}
err error
)
if len(filters) == 0 {
filterQuery += "(share_type=? OR share_type=?)"
params = append(params, shareTypeUser)
params = append(params, shareTypeGroup)
}

filterQuery, filterParams, err = translateFilters(filters)
if err != nil {
return nil, err
}
params = append(params, filterParams...)

if filterQuery != "" {
query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
}
Expand Down Expand Up @@ -330,6 +342,16 @@ func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.F
query += "AND (share_with=?)"
}

filterQuery, filterParams, err := translateFilters(filters)
if err != nil {
return nil, err
}
params = append(params, filterParams...)

if filterQuery != "" {
query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
}

rows, err := m.db.Query(query, params...)
if err != nil {
return nil, err
Expand Down Expand Up @@ -464,3 +486,69 @@ func (m *mgr) UpdateReceivedShare(ctx context.Context, ref *collaboration.ShareR
rs.State = f.GetState()
return rs, nil
}

func groupFiltersByType(filters []*collaboration.Filter) map[collaboration.Filter_Type][]*collaboration.Filter {
sorted := make(map[collaboration.Filter_Type][]*collaboration.Filter)
for _, f := range filters {
sorted[f.Type] = append(sorted[f.Type], f)
}
return sorted
}

func granteeTypeToShareType(granteeType provider.GranteeType) int {
switch granteeType {
case provider.GranteeType_GRANTEE_TYPE_USER:
return shareTypeUser
case provider.GranteeType_GRANTEE_TYPE_GROUP:
return shareTypeGroup
}
return -1
}

// translateFilters translates the filters to sql queries
func translateFilters(filters []*collaboration.Filter) (string, []interface{}, error) {
var (
filterQuery string
params []interface{}
)

sortedFilters := groupFiltersByType(filters)
// If multiple filters of the same type are passed to this function, they need to be combined with the `OR` operator.
// That is why the filters got grouped by type.
// For every given filter type, iterate over the filters and if there are more than one combine them.
// Combine the different filter types using `AND`
var filterCounter = 0
for filterType, filters := range sortedFilters {
switch filterType {
case collaboration.Filter_TYPE_RESOURCE_ID:
filterQuery += "("
for i, f := range filters {
filterQuery += "item_source=?"
params = append(params, f.GetResourceId().OpaqueId)

if i != len(filters)-1 {
filterQuery += " OR "
}
}
filterQuery += ")"
case collaboration.Filter_TYPE_GRANTEE_TYPE:
filterQuery += "("
for i, f := range filters {
filterQuery += "share_type=?"
params = append(params, granteeTypeToShareType(f.GetGranteeType()))

if i != len(filters)-1 {
filterQuery += " OR "
}
}
filterQuery += ")"
default:
return "", nil, fmt.Errorf("filter type is not supported")
}
if filterCounter != len(sortedFilters)-1 {
filterQuery += " AND "
}
filterCounter++
}
return filterQuery, params, nil
}
113 changes: 100 additions & 13 deletions pkg/share/manager/sql/sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ import (
_ "github.com/go-sql-driver/mysql"
)

const (
shareTypeUser = 0
shareTypeGroup = 1
)

func init() {
registry.Register("oc10-sql", NewMysql)
}
Expand Down Expand Up @@ -271,20 +276,26 @@ func (m *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference

func (m *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.Share, error) {
uid := ctxpkg.ContextMustGetUser(ctx).Username
query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(item_source, '') as item_source, id, stime, permissions, share_type FROM oc_share WHERE (uid_owner=? or uid_initiator=?) AND (share_type=? OR share_type=?)"
var filterQuery string
params := []interface{}{uid, uid, 0, 1}
for i, f := range filters {
if f.Type == collaboration.Filter_TYPE_RESOURCE_ID {
filterQuery += "(item_source=?)"
if i != len(filters)-1 {
filterQuery += " AND "
}
params = append(params, f.GetResourceId().OpaqueId)
} else {
return nil, fmt.Errorf("filter type is not supported")
}
query := "select coalesce(uid_owner, '') as uid_owner, coalesce(uid_initiator, '') as uid_initiator, coalesce(share_with, '') as share_with, coalesce(item_source, '') as item_source, id, stime, permissions, share_type FROM oc_share WHERE (uid_owner=? or uid_initiator=?)"
params := []interface{}{uid, uid}

var (
filterQuery string
filterParams []interface{}
err error
)
if len(filters) == 0 {
filterQuery += "(share_type=? OR share_type=?)"
params = append(params, shareTypeUser)
params = append(params, shareTypeGroup)
}

filterQuery, filterParams, err = translateFilters(filters)
if err != nil {
return nil, err
}
params = append(params, filterParams...)

if filterQuery != "" {
query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
}
Expand Down Expand Up @@ -337,6 +348,16 @@ func (m *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.F
query += "AND (share_with=?)"
}

filterQuery, filterParams, err := translateFilters(filters)
if err != nil {
return nil, err
}
params = append(params, filterParams...)

if filterQuery != "" {
query = fmt.Sprintf("%s AND (%s)", query, filterQuery)
}

rows, err := m.db.Query(query, params...)
if err != nil {
return nil, err
Expand Down Expand Up @@ -500,3 +521,69 @@ func (m *mgr) getReceivedByKey(ctx context.Context, key *collaboration.ShareKey)
}
return m.convertToCS3ReceivedShare(ctx, s, m.storageMountID)
}

func groupFiltersByType(filters []*collaboration.Filter) map[collaboration.Filter_Type][]*collaboration.Filter {
sorted := make(map[collaboration.Filter_Type][]*collaboration.Filter)
for _, f := range filters {
sorted[f.Type] = append(sorted[f.Type], f)
}
return sorted
}

func granteeTypeToShareType(granteeType provider.GranteeType) int {
switch granteeType {
case provider.GranteeType_GRANTEE_TYPE_USER:
return shareTypeUser
case provider.GranteeType_GRANTEE_TYPE_GROUP:
return shareTypeGroup
}
return -1
}

// translateFilters translates the filters to sql queries
func translateFilters(filters []*collaboration.Filter) (string, []interface{}, error) {
var (
filterQuery string
params []interface{}
)

sortedFilters := groupFiltersByType(filters)
// If multiple filters of the same type are passed to this function, they need to be combined with the `OR` operator.
// That is why the filters got grouped by type.
// For every given filter type, iterate over the filters and if there are more than one combine them.
// Combine the different filter types using `AND`
var filterCounter = 0
for filterType, filters := range sortedFilters {
switch filterType {
case collaboration.Filter_TYPE_RESOURCE_ID:
filterQuery += "("
for i, f := range filters {
filterQuery += "item_source=?"
params = append(params, f.GetResourceId().OpaqueId)

if i != len(filters)-1 {
filterQuery += " OR "
}
}
filterQuery += ")"
case collaboration.Filter_TYPE_GRANTEE_TYPE:
filterQuery += "("
for i, f := range filters {
filterQuery += "share_type=?"
params = append(params, granteeTypeToShareType(f.GetGranteeType()))

if i != len(filters)-1 {
filterQuery += " OR "
}
}
filterQuery += ")"
default:
return "", nil, fmt.Errorf("filter type is not supported")
}
if filterCounter != len(sortedFilters)-1 {
filterQuery += " AND "
}
filterCounter++
}
return filterQuery, params, nil
}

0 comments on commit 8f0de6e

Please sign in to comment.