t-manager 0.1.2
Tagging arbitrary data
Requires Python: >=3.9

<h1>TagManager</h1>

**TagManager** is a Python library that allows tagging arbitrary data and 
managing tags both in pure Python and using databases. 
The library supports PostgreSQL. 
Integration with other databases is also possible: for this, you need to 
describe a subclass of the `DataStorage` class to interact with a database.

<h2>Table of contents</h2>

- [Description](#description)
- [Project structure](#structure)
- [Usage](#usage)
  - [Get started](#import)
  - [Interaction via CLI](#CLI)

<h2 id="description">Description</h2>

The library allows working with data that consists of a set of entries with 
unique identifiers. When adding entries to the tag manager, you only need to 
specify their identifiers.

You can create tags and group them into groups. 
Tags in different groups can have the same names.

<u>Example</u>:
7 tags divided into 2 groups
```text
group: "color"
  tags: "red", "green", "orange", "blue"
group: "fruit"
  tags: "apple", "orange", "banana"
```

Created tags can be used to mark added entries.

<h2 id="structure">Project structure</h2>

```text
tag_manager/
├── __init__.py
├── typing.py        # The types used
├── errors.py        # The possible errors
├── data_storage.py  # Tagged data storages
├── tag_manager.py   # The main class for tag management
└── cli.py           # The command line interface
```

<h2 id="usage">Usage</h2>

<h3 id="import">Get started</h3>

- Creating a tagged data storage using only Python.
  ```python3
  from tag_manager import TagManager, SimpleOrderedDataStorage, autocli
  
  tm = TagManager(SimpleOrderedDataStorage())
  storage_name = 'example_storage'
  
  cli = autocli(tm, storage_name)
  cli.run()
  ```
- Creating a tagged data storage using PostgreSQL.
  ```python3
  from tag_manager import TagManager, PostgresDataStorage, autocli
  
  # You must store the password in the DB_PASSWORD environment variable.
  # You can use this BASH command:
  # $ read -s DB_PASSWORD && export DB_PASSWORD
  
  login, host, port, db_name = ...
  tm = TagManager(PostgresDataStorage(login, host, port, db_name))
  
  cli = autocli(tm, db_name)
  cli.run()
  ```

<h3 id="CLI">Interaction via CLI</h3>

<details><summary>Basic commands:</summary>

* `groups` \
View the list of tag groups.
* `groups ? <group>` \
Check if the \<group\> exists.
* `groups + <group>*` \
Add groups.
* `groups - <group>*` \
Delete groups.
* `groups r <old_group> <new_group>` \
Rename \<old_group\> to \<new_group\>. \
If the \<new_group\> already exists, the renaming will not take place.
* `groups m <old_group> <new_group>` \
Rename \<old_group\> to \<new_group\>. \
If the \<new_group\> already exists, a merge will occur: 
all tags from the \<old_group\> will move to the \<new_group\>, 
and the \<old_group\> will be deleted.
* `tags` \
View the list of tags.
* `tags <group>` \
View the list of tags from the \<group\>.
* `tags <group> ? <tag>` \
Check if the \<tag\> exists in the \<group\>.
* `tags <group> + <tag>*` \
Add tags to the \<group\>.
* `tags <group> - <tag>*` \
Delete tags from the \<group\>.
* `tags <group> r <old_tag> <new_group> <new_tag>` \
Move the tag from the group \<group\> to the group \<new_group\> and rename 
\<old_tag\> to \<new_tag\>. 
If \<new_tag\> already exists, the operation will not be performed.
* `tags <group> m <old_tag> <new_group> <new_tag>` \
Move the tag from the group <group> to the group \<new_group\> and rename 
\<old_tag\> to \<new_tag\>. 
If both tags already exist, a merge will occur: 
all entries containing \<old_tag\> will contain \<new_tag\>.

* `entries` \
View the list of entries.
* `entries ? <entry_id>` \
Check if the entry with \<entry_id\> exists.
* `entries + <entry_id>*` \
Add entries with the specified ids.
* `entries - <entry_id>*` \
Delete entries with the specified ids.
* `entries r <old_id> <new_id>` \
Rename \<old_id\> to \<new_id\>. 
If \<new_id\> already exists, the renaming will not take place.
* `entries m <old_id> <new_id>` \
Rename \<old_id\> to \<new_id\>. 
If \<new_id\> already exists, a merge will occur: 
all tags from the entry with \<old_id\> will be added to the entry with 
\<new_id\>, and the entry with \<old_id\> will be deleted.

* `entries t <entry_id>` \
View the list of tags for the entry with \<entry_id\>.
* `entries t <entry_id>  ? <group> <tag>` \
Check if the entry with \<entry_id\> contains the \<tag\> from the \<group\>.
* `entries t <entry_id>* + <group> <tag>*` \
Add tags from the \<group\> to the entries with the specified ids.
* `entries t <entry_id>* - <group> <tag>*` \
Delete tags from the \<group\> from the entries with the specified ids.
</details>