LIST / GRAPH FILTERING AND PAGING

This all applies equally to a report or a list or a graph so all work basically the same but will refer only to "list" for simplicity:

At client user can view a list and select from a dropdown of saved filters for that type of list which corresponds to an api route.
User creates filters in separate UI from the actual list, i.e. clicks on the filter button above a list to make or edit filter.
Two types of filters Named or Default:
    User can save a filter with a name for later selection or it will always default to "Default" (localized) if not edited but will always require saving to server.
    Generic "default" filter is always personal, not public / shared
Named filters can be made public or personal.  If public then all users with rights to that object can see them, personal are always only personal.
Filter is constructed from an FILTEROPTIONS object fetched from the server list route that has a list type name which is unique to that list route 
and also lists all the fields filterable, their type and the locale key to display it
    - e.g.: {list:"widget",fields:[{fld:"name",lt:"WidgetName",type:"text"},{fld:"dollarAmount",lt:"WidgetDollarAmount",type:"currency"}]}
Certain types have extended abilities, for example dates have the classic floating AyaNova date ranges pre-defined or specific dates
Filters are saved to the database:
    - Filter: Name, OwnerId, Public, ListKey, Filter (Json string) 
        - Filter format:
            - Array [{fld:"fieldname",op:"See filtercomparisonoperator class",value:"compareValue"},...] these are all AND in sql, no OR 
            - fld=name of field to filter by
                - Straight up field name like "name"
                - Could be compound for joins like "table.name" (no a prepends the table name)
                - Special indirect values such as "[TAGS]" which means cross filter with tags
            - op=one of the values specified in the FilterComparisonOperator class in Biz namespace
            - value= straight up direct comparison value
                - If string then a string fragment, case is sensitive
                - If date then iso style date
                - could be whole number or decimal number
                - Could be a special "macro" filter value like "[THIS_MONTH]" (always surrounded by square brackets, no need to disambiguate with a string because only applies to non string values)
                - Could be a series of id values like this "[23,45,56,123]" as in tag id's or something related to that case.
   
Upon user selecting a filter to use the list query string has the regular paging info but also the filter id as a query parameter 
    - Server loads the filter if it's public or has the user ID if it's personal only
    - If list not found then it will return a 404 instead of the list    
    - server loads the filter, generates the sql based on the stored filter, adds the sort by and offset / page, runs the query and then returns the data as json collection to the client




LIST FILTERING TODO
    - DONE test for fetching widget filter options (localized, so have two users test each for expected response)
Add test for excercising all of DataFilterController route including rights to non personal alternative owner etc
Add test for correctly validated Widget datafilter when saved or updated via datafiltercontroller (sanity check of the filter settings and options IFilterableObject implemented)

Add test for providing saved filter id to widgetlist and recieving correct filtered / paged / sorted results (test all those)
    - Requires filter to sql code to be written and changes to the widgetlist route

- Client side
  - Implement filter editor dialog and test


