# TAGS specifications

Main case is 3373 https://rockfish.ayanova.com/default.htm#!/rfcaseEdit/3373


RESEARCH:
https://www.databasesoup.com/2015/01/tag-all-things.html
https://www.npgsql.org/efcore/mapping/array.html
https://www.postgresql.org/docs/current/arrays.html


2018-12-05 Research showed that actually I'm doing tags all wrong and the multi table method is not correct performance wise or simplicity wise
The winning method in a test using postgres was a text array of tags with a "gin" index see databasesoup link above.



FORMAT
=-=-=-
Copied from stack overflow
tags ...

    must be no longer than 255 characters (35 in Stack overflow, but why limit it?)
    spaces are replaced by dashes, no spaces in a tag
    always converts to lower invariant culture
    - (probably not this, utf-8 ok: must use the ascii character set a-z 0-9 + # - .)

SCHEMA

USE-CASES
Add a tag to an object type and id, start typing and a selection list fills in to select from
    - Don't allow the same tag more than once
    - Create a tag if not present (rights?)
Show tags on an object
Find any type or specific type items by a set of tags (and/or tag groups) to include and a set of tags to exclude (i.e. has "red, yellow" but not "green")
Search for text must allow specifying tags (and/or tag groups) to refine
Reporting will require filtering sources of report data by tags (and/or tag groups)

METHODS REQUIRED IN TAG CONTROLLER

- GET tag text by id
- GET tag id by tag text 
- CREATE tag for tagging something
- REMOVE tag (and all tagmap entities)


- GET TAGMAPS LIST (get all object/id entities with this tag)
- CREATE TAGMAP Apply tag to an object / id 
- REMOVE TAGMAP remove tag from object/id
- GET TAGS for object (name id list, main display route)


ROLES / RIGHTS
- Limited roles can tag stuff and remove tags as per their rights to the object type in question but can't make new tags or change existing tags 
- Full roles can make new tags and can edit or delete existing tags
    

RETRIEVAL

Will need to query tags as follows:

ObjectType and Id list of tags (most common)
Objects with one or more tags
Objects that have a set of tags but do not have another set of tags
Objects of a certain type but any id that have a certain tag

V7IMPORT
See case 3373 for a list of things that will become tags


OLD DEPRECATED STUFF BELOW HERE
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

TAG GROUP DEPRECATED 2018-12-05 
    I'm deprecating this as it's surplus to requirements: users will be able to specify multiple tags in a filter and they can save filters so no need for bags of tags

            TAG-GROUP - bag of tags
            Modify the below and coded and tests and tables to now have feature for tag groups
            They will be in their own table with a dictionary table of tag ids and tag group id's to link
            They are used for read purposes, you never tag an item with a tag group, only query by group.
            If a group is deleted tags it contains are NOT deleted or changed
            If a tag is deleted it must be removed from any tag groups and if there are no other items in that tag group then the tag group must be deleted as well??
                - Or maybe is just an empty group with a warning symbol in ui
            Tag groups will become a major way to save filters for things because a lot of filtering will be by tags so this should be a solid feature.
            - RETRIEVAL / LISTS: need to modify the tag list to optionally return TAGGROUP names as well as identify they are group so UI can feature differently

            FILTERING AND SORTING BY TAG-GROUP
                - All code that filters and sorts by tag should accept a tag group as a separate type of input and dynamically build the tag filter list from the group and individual tags separately
                rather than storing a list of tags at the moment a group is applied.  
                In this way the filters are always dynamically linked to the tags in the group and reflect the most recent changes to the group
                tl/dr: don't store the tag id's from a group in the filter, store the group id separately and build the list on query

 