From 09bcf9f355a3cf21d568ee62b32c8d1e83325b64 Mon Sep 17 00:00:00 2001 From: Christoph Kluge Date: Mon, 20 Feb 2023 10:20:08 +0100 Subject: [PATCH] Better implementation for querying multiple users --- api/schema.graphqls | 2 +- internal/graph/generated/generated.go | 54 +++++-------------------- internal/graph/model/models_gen.go | 10 ++--- internal/repository/query.go | 14 +++---- internal/routerConfig/routes.go | 18 +++++---- web/frontend/src/filters/Filters.svelte | 15 ++++--- 6 files changed, 41 insertions(+), 72 deletions(-) diff --git a/api/schema.graphqls b/api/schema.graphqls index fc6167f..13b2887 100644 --- a/api/schema.graphqls +++ b/api/schema.graphqls @@ -201,7 +201,6 @@ input JobFilter { jobId: StringInput arrayJobId: Int user: StringInput - multiUser: [String] project: StringInput jobName: StringInput cluster: StringInput @@ -237,6 +236,7 @@ input StringInput { contains: String startsWith: String endsWith: String + in: [String!] } input IntRange { from: Int!, to: Int! } diff --git a/internal/graph/generated/generated.go b/internal/graph/generated/generated.go index 0d018b3..c4a098f 100644 --- a/internal/graph/generated/generated.go +++ b/internal/graph/generated/generated.go @@ -1592,7 +1592,6 @@ input JobFilter { jobId: StringInput arrayJobId: Int user: StringInput - multiUser: [String] project: StringInput jobName: StringInput cluster: StringInput @@ -1628,6 +1627,7 @@ input StringInput { contains: String startsWith: String endsWith: String + in: [String!] } input IntRange { from: Int!, to: Int! } @@ -10445,7 +10445,7 @@ func (ec *executionContext) unmarshalInputJobFilter(ctx context.Context, obj int asMap[k] = v } - fieldsInOrder := [...]string{"tags", "jobId", "arrayJobId", "user", "multiUser", "project", "jobName", "cluster", "partition", "duration", "minRunningFor", "numNodes", "numAccelerators", "numHWThreads", "startTime", "state", "flopsAnyAvg", "memBwAvg", "loadAvg", "memUsedMax"} + fieldsInOrder := [...]string{"tags", "jobId", "arrayJobId", "user", "project", "jobName", "cluster", "partition", "duration", "minRunningFor", "numNodes", "numAccelerators", "numHWThreads", "startTime", "state", "flopsAnyAvg", "memBwAvg", "loadAvg", "memUsedMax"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -10484,14 +10484,6 @@ func (ec *executionContext) unmarshalInputJobFilter(ctx context.Context, obj int if err != nil { return it, err } - case "multiUser": - var err error - - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("multiUser")) - it.MultiUser, err = ec.unmarshalOString2ᚕᚖstring(ctx, v) - if err != nil { - return it, err - } case "project": var err error @@ -10701,7 +10693,7 @@ func (ec *executionContext) unmarshalInputStringInput(ctx context.Context, obj i asMap[k] = v } - fieldsInOrder := [...]string{"eq", "contains", "startsWith", "endsWith"} + fieldsInOrder := [...]string{"eq", "contains", "startsWith", "endsWith", "in"} for _, k := range fieldsInOrder { v, ok := asMap[k] if !ok { @@ -10740,6 +10732,14 @@ func (ec *executionContext) unmarshalInputStringInput(ctx context.Context, obj i if err != nil { return it, err } + case "in": + var err error + + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("in")) + it.In, err = ec.unmarshalOString2ᚕstringᚄ(ctx, v) + if err != nil { + return it, err + } } } @@ -14671,38 +14671,6 @@ func (ec *executionContext) marshalOString2ᚕstringᚄ(ctx context.Context, sel return ret } -func (ec *executionContext) unmarshalOString2ᚕᚖstring(ctx context.Context, v interface{}) ([]*string, error) { - if v == nil { - return nil, nil - } - var vSlice []interface{} - if v != nil { - vSlice = graphql.CoerceList(v) - } - var err error - res := make([]*string, len(vSlice)) - for i := range vSlice { - ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) - res[i], err = ec.unmarshalOString2ᚖstring(ctx, vSlice[i]) - if err != nil { - return nil, err - } - } - return res, nil -} - -func (ec *executionContext) marshalOString2ᚕᚖstring(ctx context.Context, sel ast.SelectionSet, v []*string) graphql.Marshaler { - if v == nil { - return graphql.Null - } - ret := make(graphql.Array, len(v)) - for i := range v { - ret[i] = ec.marshalOString2ᚖstring(ctx, sel, v[i]) - } - - return ret -} - func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { if v == nil { return nil, nil diff --git a/internal/graph/model/models_gen.go b/internal/graph/model/models_gen.go index 2ff3b94..0828b88 100644 --- a/internal/graph/model/models_gen.go +++ b/internal/graph/model/models_gen.go @@ -41,7 +41,6 @@ type JobFilter struct { JobID *StringInput `json:"jobId"` ArrayJobID *int `json:"arrayJobId"` User *StringInput `json:"user"` - MultiUser []*string `json:"multiUser"` Project *StringInput `json:"project"` JobName *StringInput `json:"jobName"` Cluster *StringInput `json:"cluster"` @@ -104,10 +103,11 @@ type PageRequest struct { } type StringInput struct { - Eq *string `json:"eq"` - Contains *string `json:"contains"` - StartsWith *string `json:"startsWith"` - EndsWith *string `json:"endsWith"` + Eq *string `json:"eq"` + Contains *string `json:"contains"` + StartsWith *string `json:"startsWith"` + EndsWith *string `json:"endsWith"` + In []string `json:"in"` } type TimeRangeOutput struct { diff --git a/internal/repository/query.go b/internal/repository/query.go index d2f5c33..183b89b 100644 --- a/internal/repository/query.go +++ b/internal/repository/query.go @@ -118,13 +118,6 @@ func BuildWhereClause(filter *model.JobFilter, query sq.SelectBuilder) sq.Select if filter.User != nil { query = buildStringCondition("job.user", filter.User, query) } - if filter.MultiUser != nil { - queryUsers := make([]string, len(filter.MultiUser)) - for i, val := range filter.MultiUser { - queryUsers[i] = *val - } - query = query.Where(sq.Or{sq.Eq{"job.user": queryUsers}}) - } if filter.Project != nil { query = buildStringCondition("job.project", filter.Project, query) } @@ -213,6 +206,13 @@ func buildStringCondition(field string, cond *model.StringInput, query sq.Select if cond.Contains != nil { return query.Where(field+" LIKE ?", fmt.Sprint("%", *cond.Contains, "%")) } + if cond.In != nil { + queryUsers := make([]string, len(cond.In)) + for i, val := range cond.In { + queryUsers[i] = val + } + return query.Where(sq.Or{sq.Eq{"job.user": queryUsers}}) + } return query } diff --git a/internal/routerConfig/routes.go b/internal/routerConfig/routes.go index 04b6c7a..f7e57f2 100644 --- a/internal/routerConfig/routes.go +++ b/internal/routerConfig/routes.go @@ -184,12 +184,14 @@ func buildFilterPresets(query url.Values) map[string]interface{} { if query.Get("jobName") != "" { filterPresets["jobName"] = query.Get("jobName") } - if query.Get("user") != "" { - filterPresets["user"] = query.Get("user") - filterPresets["userMatch"] = "contains" - } - if len(query["multiUser"]) != 0 { - filterPresets["multiUser"] = query["multiUser"] + if len(query["user"]) != 0 { + if len(query["user"]) == 1 { + filterPresets["user"] = query.Get("user") + filterPresets["userMatch"] = "contains" + } else { + filterPresets["user"] = query["user"] + filterPresets["userMatch"] = "in" + } } if len(query["state"]) != 0 { filterPresets["state"] = query["state"] @@ -339,8 +341,8 @@ func HandleSearchBar(rw http.ResponseWriter, r *http.Request, api *api.RestApi) http.Redirect(rw, r, "/monitoring/user/"+usernames[0], http.StatusTemporaryRedirect) return } else if len(usernames) > 1 { - joinedNames := strings.Join(usernames, "&multiUser=") - http.Redirect(rw, r, "/monitoring/users/?multiUser="+joinedNames, http.StatusTemporaryRedirect) // > 1 Matches: Redirect to user table + joinedNames := strings.Join(usernames, "&user=") + http.Redirect(rw, r, "/monitoring/users/?user="+joinedNames, http.StatusTemporaryRedirect) // > 1 Matches: Redirect to user table return } else { http.Redirect(rw, r, "/monitoring/users/?user=NotFound", http.StatusTemporaryRedirect) // Workaround to display correctly empty table diff --git a/web/frontend/src/filters/Filters.svelte b/web/frontend/src/filters/Filters.svelte index 71e2485..f1b8274 100644 --- a/web/frontend/src/filters/Filters.svelte +++ b/web/frontend/src/filters/Filters.svelte @@ -46,7 +46,6 @@ user: filterPresets.user || '', project: filterPresets.project || '', jobName: filterPresets.jobName || '', - multiUser: filterPresets.multiUser || [], numNodes: filterPresets.numNodes || { from: null, to: null }, numHWThreads: filterPresets.numHWThreads || { from: null, to: null }, @@ -94,8 +93,6 @@ items.push({ numAccelerators: { from: filters.numAccelerators.from, to: filters.numAccelerators.to } }) if (filters.user) items.push({ user: { [filters.userMatch]: filters.user } }) - if (filters.multiUser.length != 0) - items.push({ multiUser: filters.multiUser }) if (filters.project) items.push({ project: { [filters.projectMatch]: filters.project } }) if (filters.jobName) @@ -129,11 +126,13 @@ opts.push(`numNodes=${filters.numNodes.from}-${filters.numNodes.to}`) if (filters.numAccelerators.from && filters.numAccelerators.to) opts.push(`numAccelerators=${filters.numAccelerators.from}-${filters.numAccelerators.to}`) - if (filters.user) - opts.push(`user=${filters.user}`) - if (filters.multiUser.length != 0) - for (let singleUser of filters.multiUser) - opts.push(`multiUser=${singleUser}`) + if (filters.user.length != 0) + if (filters.userMatch != 'in') { + opts.push(`user=${filters.user}`) + } else { + for (let singleUser of filters.user) + opts.push(`user=${singleUser}`) + } if (filters.userMatch != 'contains') opts.push(`userMatch=${filters.userMatch}`) if (filters.project)