pkg/storage/job_query.go (67 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates.
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
package storage
import (
"fmt"
"reflect"
"github.com/facebookincubator/contest/pkg/job"
)
type JobQueryField interface {
queryFieldPointer(query *JobQuery) interface{}
}
type JobQueryFields []JobQueryField
type JobQuery struct {
States []job.State
Tags []string
ServerID string
}
type jobQueryFieldStates []job.State
type jobQueryFieldTags []string
type jobQueryFieldServerID string
func QueryJobStates(states ...job.State) JobQueryField { return jobQueryFieldStates(states) }
func (value jobQueryFieldStates) queryFieldPointer(query *JobQuery) interface{} {
return &query.States
}
func QueryJobTags(tags ...string) JobQueryField { return jobQueryFieldTags(tags) }
func (value jobQueryFieldTags) queryFieldPointer(query *JobQuery) interface{} {
return &query.Tags
}
func QueryJobServerID(serverID string) JobQueryField { return jobQueryFieldServerID(serverID) }
func (value jobQueryFieldServerID) queryFieldPointer(query *JobQuery) interface{} {
return &query.ServerID
}
func BuildJobQuery(queryFields ...JobQueryField) (*JobQuery, error) {
return JobQueryFields(queryFields).BuildQuery()
}
func (queryFields JobQueryFields) BuildQuery() (*JobQuery, error) {
query := &JobQuery{}
for idx, queryField := range queryFields {
if err := ApplyJobQueryField(queryField.queryFieldPointer(query), queryField); err != nil {
return nil, fmt.Errorf("unable to apply field %d:%T(%v): %w", idx, queryField, queryField, err)
}
}
return query, nil
}
type ErrJobQueryFieldIsAlreadySet struct {
FieldValue interface{}
QueryField JobQueryField
}
func (err ErrJobQueryFieldIsAlreadySet) Error() string {
return fmt.Sprintf("field %T is set multiple times: cur_value:%v new_value:%v",
err.QueryField, err.FieldValue, err.QueryField)
}
// ErrQueryFieldHasZeroValue is returned when a QueryFields failed validation
// due to a QueryField with a zero value (this is unexpected and forbidden).
type ErrJobQueryFieldHasZeroValue struct {
QueryField JobQueryField
}
func (err ErrJobQueryFieldHasZeroValue) Error() string {
return fmt.Sprintf("field %T has a zero value", err.QueryField)
}
func ApplyJobQueryField(fieldPtr interface{}, queryField JobQueryField) error {
if reflect.ValueOf(queryField).IsZero() {
return ErrJobQueryFieldHasZeroValue{QueryField: queryField}
}
field := reflect.ValueOf(fieldPtr).Elem()
if !reflect.ValueOf(field.Interface()).IsZero() {
return ErrJobQueryFieldIsAlreadySet{FieldValue: field.Interface(), QueryField: queryField}
}
field.Set(reflect.ValueOf(queryField).Convert(field.Type()))
return nil
}