Группировка видов работ
У некоторых клиентов в базе существует очень большое количество видов работ — несколько десятков и более. Из-за этого трудно выбрать какой-то конкретный вид из выпадающего списка при, скажем, создании задачи. Для решения проблемы предлагается организовать группировку видов работ. Группа — это новая сущность в БД и REST, которая характеризуется только id и именем. Каждый вид работ может принадлежать ровно одной группе либо не принадлежать ни одной из них. Клиентские программы при старте помимо списка видов работ будут запрашивать список групп и самостоятельно отражать группировку в своем интерфейсе так, как это будет удобно пользователю.
Т.к. группировка является необязательной (вид работ может не входить ни в одну из групп), то при создании и редактировании вида работ id группы может опускаться. Этим достигается совместимость с более ранними версиями клиентов.
Настоятельных требований по вложенности групп в группы не поступало, поэтому такую задачу мы не выполняем. Срочной необходимости сделать группы «назначаемыми» (т.е. чтобы группы также были и видами работ) тоже нет. Реализация этого потребовала бы использовать для групп ту же самую таблицу в БД, что и для видов работ. Можно предположить, что в дальнейшем потребовалось бы сделать «назначаемыми» не все группы, но только некоторые из них. Возникает возня с флагами назначения и проч. Но самой большой проблемой будет наличие устаревших клиентов, которые воспримут неназначаемые группы как самостоятельные виды работ. Чтобы избежать таких проблем, группы реализуются как отдельная сущность.
База данных
Таблица issues.type_groups, связана с issues.types по fk issues.types.group_id.
Название колонки | Тип | NULL?
------------------------+----------+------
id | int | f
name | varchar| f
Модели
Добавляется новая модель models.Group с двумя свойствами — id и name.
В models.Type добавляется поле Group group и соответствующие getter и setter. Поле связывается с БД через аннотацию @ManyToOne
. Getter помечается как @JsonIgnore
, чтобы предотвратить полную выгрузку группы на клиент. Вместо всей группы будет выгружаться только её id; для этого создается метод getGroupId()
. В getter’е нужно предусмотреть, чтобы при отсутствии группы не возникал NPE.
REST
В запрос GET /newstype добавляется поле group, содержащее информацию о группе, в которую попадает данный вид работ. Это происходит автоматически за счет добавления getter’а getGroupId() в модель models.Type
// ...
"group_id": "1" // или null в случае, если вид работ не привязан к группе
// ...
Запросы POST /newstype и PUT /newstype должны позволять задавать группу, к которой привязан вид работ. Для этого в form.TypeIn и form.TypeUpdate добавляются поля Integer group_id:
- значение null (либо отсутствие поля в JSON) означает, что нужно оставить текущее значение;
- значение 0 означает, что нужно удалить этот вид работ из текущей группы;
- положительные значения трактуются как id группы, к которой нужно привязать этот вид работ;
- прочие значения являются некорректными.
Например:
// PUT /newstype/5
{
"group_id": 2
}
// ответ сервера
{
"res": "1", "resText": "",
"newstype": {
// ...
"group": {
"id": "2",
"name": "имя только назначенной группы видов работ"
}
// ,...
}
}
[AI] POST /newstype/group
Создать группу.
/* IN --> */ {
"name": "имя вида работ, обязательное поле"
}
/* OUT <-- */ {
"res": "1", "resText": "",
"group": {
"id": "1",
"name": "имя группы работ"
}
}
[AI] PUT /newstype/group/:id
Изменить группу
/* IN --> */ {
"name": "измененное имя вида работ"
}
/* OUT <-- */ {
"res": "1", "resText": "",
"group": {
"id": "1",
"name": "измененное имя группы работ"
}
}
[AI] GET /newstype/group/:id
Получить группу.
/* OUT <-- */ {
"res": "1", "resText": "",
"group": {
"id": "1",
"name": "имя группы работ"
}
}
[AI] DELETE /newstype/group/:id
Удалить группу.
/* OUT <-- */ {
"res": "1", "resText": "" // стандартный ответ
}
[AI] GET /newstype/group/list
Получить список всех групп.
/* OUT <-- */ {
"res": "1", "resText": "",
"groups": [
{
"id": "1",
"name": "имя группы работ"
}
// , ...
]
}
Изменить тип новости, добавив его в группу (при этом происходит проверка на существование данной группы):
/* IN --> */ {
"name":"новый тип","icon":"icon_158.png","icon3d":"icon3d_158.png","map_icon":"default_iconmap.png","map_icon_highlight":"default_iconmap_highlight.png",
"default_type":"f","period_of_review":"2","period_of_review_in_sec":"172800","deadline_type":"1","departments":[1,2,3],"group_id":"8"
}
/* OUT <-- */ {
"res":1,"resText":"","newstype":{"id":"8","name":"новый тип","icon":"icon_158.png","icon3d":"icon3d_158.png","map_icon":"default_iconmap.png",
"map_icon_highlight":"default_iconmap_highlight.png","map_icon_highlight_done":"default_iconmap_highlight.png","default_type":"f",
"period_of_review":"2","icon3d_done":"icon3d_done_155.png","icon_done":"icon_done_155.png","map_icon_done":"map_icon_done_155.png",
"iconmap":null,"iconmap_highlight":null,"iconmap_done":null,"iconmap_highlight_done":null,"period_of_review_in_sec":"172800",
"deadline_type":"AT_UPDATE","departments":["1","2","3"],"group_id":"8",
"news_type_id":"8","logo":"icon3d_158.png"}
}