package webutility import "gopkg.in/rana/ora.v3" type ListOptions struct { GlobalFilter bool `json:"globalFilter"` LocalFilters bool `json:"localFilters"` RemoteFilters bool `json:"remoteFilters"` Pagination bool `json:"pagination"` PageSize uint64 `json:"pageSize"` Pivot bool `json:"pivot"` Detail bool `json:"detail"` Total bool `json:"total"` } type ListFilter struct { Position uint32 `json:"-"` ObjectType string `json:"-"` FiltersField string `json:"filtersField"` DefaultValues string `json:"defaultValues"` FiltersType string `json:"filtersType"` FiltersLabel string `json:"filtersLabel"` DropdownConfig Dropdown `json:"dropdownConfig"` } type Dropdown struct { ObjectType string `json:"objectType"` FiltersField string `json:"filtersField"` IDField string `json:"idField"` LabelField string `json:"labelField"` } type ListGraph struct { ObjectType string `json:"objectType"` X string `json:"xField"` Y string `json:"yField"` GroupField string `json:"groupField"` Label string `json:"label"` } type ListActions struct { Create bool `json:"create"` Update bool `json:"update"` Delete bool `json:"delete"` Export bool `json:"export"` Print bool `json:"print"` Graph bool `json:"graph"` } type ListNavNode struct { ObjectType string `json:"objectType"` LabelField string `json:"label"` Icon string `json:"icon"` ParentObjectType string `json:"parentObjectType"` ParentIDField string `json:"parentIdField"` } type ListParentNode struct { ObjectType string `json:"objectType"` LabelField string `json:"labelField"` FilterField string `json:"filterField"` } type ListPivot struct { ObjectType string `json:"objectType"` GroupField string `json:"groupField"` DistinctField string `json:"distinctField"` Value string `json:"valueField"` } type ListDetails struct { ObjectType string `json:"objectType"` ParentObjectType string `json:"parentObjectType"` ParentFilterField string `json:"parentFilterField"` SingleDetail bool `json:"singleDetail"` } type ListConfig struct { ObjectType string `json:"objectType"` Title string `json:"title"` LazyLoad bool `json:"lazyLoad"` InlineEdit bool `json:"inlineEdit"` Options ListOptions `json:"options"` Filters []ListFilter `json:"defaultFilters"` Graphs []ListGraph `json:"graphs"` Actions ListActions `json:"actions"` Parent []ListParentNode `json:"parent"` Navigation []ListNavNode `json:"navigation"` Pivots []ListPivot `json:"pivots"` Details ListDetails `json:"details"` } // GetListConfig returns list configuration for the provided object type for the front-end application // or an error if it fails. func GetListConfig(db *ora.Ses, objType string) (ListConfig, error) { resp := newDefaultList(objType) var err error err = setListParams(db, &resp, objType) resp.Navigation, err = getListNavigation(db, objType) resp.Actions, err = getListActions(db, objType) resp.Filters, err = getListFilters(db, objType) resp.Options, err = getListOptions(db, objType) resp.Parent, err = getListParent(db, objType) resp.Graphs, err = getListGraph(db, objType) resp.Pivots, err = getListPivot(db, objType) resp.Details, err = getListDetails(db, objType) if err != nil { return ListConfig{}, err } return resp, nil } // GetListConfigObjectIDField takes in database connection and an object type and it returns the // ID field name for the provided object type. func GetListConfigObjectIDField(db *ora.Ses, otype string) string { var resp string var err error var stmt *ora.Stmt stmt, err = db.Prep(`SELECT ID_FIELD FROM LIST_CONFIG_ID_FIELD WHERE OBJECT_TYPE = '` + otype + `'`, ora.S) defer stmt.Close() if err != nil { return "" } rset, err := stmt.Qry() if rset.Next() { resp = rset.Row[0].(string) } if rset.Err != nil { return "" } return resp } // newDefaultList returns default configuration for the provided object type. func newDefaultList(objType string) ListConfig { list := ListConfig{ ObjectType: objType, Title: objType, LazyLoad: false, Options: ListOptions{ GlobalFilter: true, LocalFilters: true, RemoteFilters: false, Pagination: true, PageSize: 20, }, Filters: nil, Actions: ListActions{ Create: false, Update: false, Delete: false, Export: false, Print: false, Graph: false, }, Parent: nil, Navigation: nil, } return list } // setListParams sets the default parameters of the provided configuration list for the provided object type. func setListParams(db *ora.Ses, list *ListConfig, objType string) error { var err error var stmt *ora.Stmt query := `SELECT OBJECT_TYPE, TITLE, LAZY_LOAD, INLINE_EDIT FROM LIST_CONFIG WHERE OBJECT_TYPE = '` + objType + `'` stmt, err = db.Prep(query, ora.S, ora.S, ora.U32, ora.U32) if err != nil { return err } defer stmt.Close() rset, err := stmt.Qry() if err != nil { return err } if rset.Next() { otype := rset.Row[0].(string) if otype != "" { list.ObjectType = otype } title := rset.Row[1].(string) if title != "" { list.Title = title } list.LazyLoad = rset.Row[2].(uint32) != 0 list.InlineEdit = rset.Row[3].(uint32) != 0 } if rset.Err != nil { return rset.Err } return nil } // getListNavigation returns list navigation node slice for the provided objectType. func getListNavigation(db *ora.Ses, listObjType string) ([]ListNavNode, error) { resp := make([]ListNavNode, 0) var err error var stmt *ora.Stmt query := `SELECT a.OBJECT_TYPE, a.PARENT_OBJECT_TYPE, a.LABEL, a.ICON, b.PARENT_ID_FIELD, b.RB FROM LIST_CONFIG_NAVIGATION b JOIN LIST_CONFIG_CHILD a ON b.PARENT_CHILD_ID = a.PARENT_CHILD_ID WHERE b.LIST_OBJECT_TYPE = '`+listObjType+`' ORDER BY b.RB ASC` stmt, err = db.Prep(query, ora.S, ora.S, ora.S, ora.S, ora.S) if err != nil { return resp, err } defer stmt.Close() rset, err := stmt.Qry() if err != nil { return resp, err } for rset.Next() { resp = append(resp, ListNavNode{ ObjectType: rset.Row[0].(string), ParentObjectType: rset.Row[1].(string), LabelField: rset.Row[2].(string), Icon: rset.Row[3].(string), ParentIDField: rset.Row[4].(string), }) } if rset.Err != nil { return nil, rset.Err } return resp, nil } // getListActions returns list actions for the provided object type. func getListActions(db *ora.Ses, objType string) (ListActions, error) { var resp ListActions var err error var stmt *ora.Stmt query := `SELECT ACTION_CREATE, ACTION_UPDATE, ACTION_DELETE, ACTION_EXPORT, ACTION_PRINT, ACTION_GRAPH FROM LIST_CONFIG WHERE OBJECT_TYPE = '` + objType + `'` stmt, err = db.Prep(query, ora.U32, ora.U32, ora.U32, ora.U32, ora.U32, ora.U32) if err != nil { return ListActions{}, err } defer stmt.Close() rset, err := stmt.Qry() if err != nil { return ListActions{}, err } if rset.Next() { resp.Create = rset.Row[0].(uint32) != 0 resp.Update = rset.Row[1].(uint32) != 0 resp.Delete = rset.Row[2].(uint32) != 0 resp.Export = rset.Row[3].(uint32) != 0 resp.Print = rset.Row[4].(uint32) != 0 resp.Graph = rset.Row[5].(uint32) != 0 } if rset.Err != nil { return ListActions{}, rset.Err } return resp, nil } // getListFiters returns list filter slice for the provided object type. func getListFilters(db *ora.Ses, objType string) ([]ListFilter, error) { resp := make([]ListFilter, 0) filtersFields, err := getFilterFieldsAndPosition(db, objType) if err != nil { return nil, err } for field, pos := range filtersFields { filters, _ := getFiltersByFilterField(db, field) for _, filter := range filters { var f ListFilter f.Position = pos f.ObjectType = objType f.FiltersField = field f.DefaultValues = filter.DefaultValues f.FiltersLabel = filter.Label f.FiltersType = filter.Type if filter.Type == "dropdown" { f.DropdownConfig, err = getFilterDropdownConfig(db, field) if err != nil { return nil, err } } resp = append(resp, f) } } sortFilters(resp) return resp, nil } // getFilterFieldsAndPosition returns a map of filter fields and their respective position in the menu. func getFilterFieldsAndPosition(db *ora.Ses, objType string) (map[string]uint32, error) { filtersField := make(map[string]uint32, 0) var err error var stmt *ora.Stmt query := `SELECT FILTERS_FIELD, RB FROM LIST_CONFIG_FILTERS WHERE OBJECT_TYPE = '` + objType + `'` stmt, err = db.Prep(query, ora.S, ora.U32) if err != nil { return nil, err } defer stmt.Close() rset, err := stmt.Qry() if err != nil { return nil, err } for rset.Next() { filtersField[rset.Row[0].(string)] = rset.Row[1].(uint32) } if rset.Err != nil { return nil, rset.Err } return filtersField, nil } type _filter struct { DefaultValues string Label string Type string } // getFiltersByFilterField returns filter slice for the provided filter field. func getFiltersByFilterField(db *ora.Ses, filtersField string) ([]_filter, error) { resp := make([]_filter, 0) var err error var stmt *ora.Stmt query := `SELECT FILTERS_TYPE, FILTERS_LABEL, DEFAULT_VALUES FROM LIST_FILTERS_FIELD WHERE FILTERS_FIELD = '` + filtersField + `'` stmt, err = db.Prep(query, ora.S, ora.S, ora.S) if err != nil { return resp, err } defer stmt.Close() rset, err := stmt.Qry() if err != nil { return resp, err } for rset.Next() { resp = append(resp, _filter{ Type: rset.Row[0].(string), Label: rset.Row[1].(string), DefaultValues: rset.Row[2].(string), }) } if rset.Err != nil { return resp, rset.Err } return resp, nil } // getFilterDropdownConfig returns dropdown menu for the provided filter field. func getFilterDropdownConfig(db *ora.Ses, filtersField string) (Dropdown, error) { var resp Dropdown var err error var stmt *ora.Stmt query := `SELECT FILTERS_FIELD, OBJECT_TYPE, ID_FIELD, LABEL_FIELD FROM LIST_DROPDOWN_FILTER WHERE FILTERS_FIELD = '` + filtersField + `'` stmt, err = db.Prep(query, ora.S, ora.S, ora.S, ora.S) if err != nil { return resp, err } defer stmt.Close() rset, err := stmt.Qry() if err != nil { return resp, err } if rset.Next() { resp.FiltersField = rset.Row[0].(string) resp.ObjectType = rset.Row[1].(string) resp.IDField = rset.Row[2].(string) resp.LabelField = rset.Row[3].(string) } if rset.Err != nil { return resp, rset.Err } return resp, nil } // sortFilters bubble sorts provided filters slice by position field. func sortFilters(filters []ListFilter) { done := false var temp ListFilter for !done { done = true for i := 0; i < len(filters) - 1; i++ { if filters[i].Position > filters[i+1].Position { done = false temp = filters[i] filters[i] = filters[i+1] filters[i+1] = temp } } } } // getListGraph return list graph slice for the provided object type. func getListGraph(db *ora.Ses, objType string) ([]ListGraph, error) { resp := make([]ListGraph, 0) var err error var stmt *ora.Stmt query := `SELECT OBJECT_TYPE, X_FIELD, Y_FIELD, GROUP_FIELD, LABEL FROM LIST_GRAPHS WHERE OBJECT_TYPE = '` + objType + `'` stmt, err = db.Prep(query, ora.S, ora.S, ora.S, ora.S) if err != nil { return resp, err } defer stmt.Close() rset, err := stmt.Qry() if err != nil { return resp, err } for rset.Next() { resp = append(resp, ListGraph{ ObjectType: rset.Row[0].(string), X: rset.Row[1].(string), Y: rset.Row[2].(string), GroupField: rset.Row[3].(string), Label: rset.Row[4].(string), }) } if rset.Err != nil { return resp, rset.Err } return resp, nil } // getListOptions returns list options for the provided object type. func getListOptions(db *ora.Ses, objType string) (ListOptions, error) { var resp ListOptions var err error var stmt *ora.Stmt query := `SELECT GLOBAL_FILTER, LOCAL_FILTER, REMOTE_FILTER, PAGINATION, PAGE_SIZE, PIVOT, DETAIL, TOTAL FROM LIST_CONFIG WHERE OBJECT_TYPE = '` + objType + `'` stmt, err = db.Prep(query, ora.U32, ora.U32, ora.U32, ora.U32, ora.U64, ora.U64, ora.U32, ora.U32) if err != nil { return ListOptions{}, err } defer stmt.Close() rset, err := stmt.Qry() if err != nil { return ListOptions{}, err } if rset.Next() { resp.GlobalFilter = rset.Row[0].(uint32) != 0 resp.LocalFilters = rset.Row[1].(uint32) != 0 resp.RemoteFilters = rset.Row[2].(uint32) != 0 resp.Pagination = rset.Row[3].(uint32) != 0 resp.PageSize = rset.Row[4].(uint64) resp.Pivot = rset.Row[5].(uint64) != 0 resp.Detail = rset.Row[6].(uint32) != 0 resp.Total = rset.Row[7].(uint32) != 0 } if rset.Err != nil { return ListOptions{}, rset.Err } return resp, nil } // getListParent returns list parent node slice for the provided object type. func getListParent(db *ora.Ses, objType string) ([]ListParentNode, error) { resp := make([]ListParentNode, 0) var err error var stmt *ora.Stmt query := `SELECT PARENT_OBJECT_TYPE, PARENT_LABEL_FIELD, PARENT_FILTER_FIELD FROM LIST_CONFIG_CHILD WHERE OBJECT_TYPE = '` + objType + `'` stmt, err = db.Prep(query, ora.S, ora.S, ora.S) if err != nil { return resp, err } defer stmt.Close() rset, err := stmt.Qry() if err != nil { return resp, err } for rset.Next() { resp = append(resp, ListParentNode{ ObjectType: rset.Row[0].(string), LabelField: rset.Row[1].(string), FilterField: rset.Row[2].(string), }) } if rset.Err != nil { return nil, rset.Err } return resp, nil } // getListPivot list pivot slice for the provided object type. func getListPivot(db *ora.Ses, objType string) ([]ListPivot, error) { resp := make([]ListPivot, 0) var err error var stmt *ora.Stmt query := `SELECT OBJECT_TYPE, GROUP_FIELD, DISTINCT_FIELD, VALUE_FIELD FROM LIST_PIVOTS WHERE OBJECT_TYPE = '` + objType + `'` stmt, err = db.Prep(query, ora.S, ora.S, ora.S, ora.S) if err != nil { return resp, err } defer stmt.Close() rset, err := stmt.Qry() if err != nil { return resp, err } for rset.Next() { resp = append(resp, ListPivot{ ObjectType: rset.Row[0].(string), GroupField: rset.Row[1].(string), DistinctField: rset.Row[2].(string), Value: rset.Row[3].(string), }) } if rset.Err != nil { return nil, rset.Err } return resp, nil } // getListDetails returns list details for the provided object type. func getListDetails(db *ora.Ses, objType string) (ListDetails, error) { var resp ListDetails var err error var stmt *ora.Stmt query := `SELECT OBJECT_TYPE, PARENT_OBJECT_TYPE, PARENT_FILTER_FIELD, SINGLE_DETAIL FROM LIST_CONFIG_DETAIL WHERE PARENT_OBJECT_TYPE = '` + objType + `'` stmt, err = db.Prep(query, ora.S, ora.S, ora.S, ora.U32) if err != nil { return resp, err } defer stmt.Close() rset, err := stmt.Qry() if err != nil { return resp, err } if rset.Next() { resp.ObjectType = rset.Row[0].(string) resp.ParentObjectType = rset.Row[1].(string) resp.ParentFilterField = rset.Row[2].(string) resp.SingleDetail = rset.Row[3].(uint32) != 0 } if rset.Err != nil { return resp, rset.Err } return resp, nil }