diff --git a/docs/DeveloperGuide.md b/docs/DeveloperGuide.md
index d141ac62070..77429b4373b 100644
--- a/docs/DeveloperGuide.md
+++ b/docs/DeveloperGuide.md
@@ -117,7 +117,7 @@ The sequence diagram below illustrates the interactions within the `Logic` compo
-**Note:**
The lifeline for `DeleteCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+**Note:**
The lifeline for `DeleteCommandParser` and `DeleteCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
How the `Logic` component works:
@@ -181,11 +181,14 @@ This section describes some noteworthy details on how certain features are imple
This feature allows users to assign tags to / remove tags from customers in EzContact, increasing the recognizability
of customers to users.
-The activity diagram below shows the action sequence of updating the tags of a customer.
+###### **Overview**
+
+The activity diagram below shows the action sequence of updating the tags of a customer. Note that definition of not
+valid indexes/tags/tag set will be defined later in following sections.
-### Implementation
+
###### **Implementing `Tag`**
@@ -195,13 +198,14 @@ Hence, a `Person` will now also be associated to any number of `Tag`s.
-###### **Integrating a command for handling tag features into the execution logic**
+###### **Integrating a command for handling tag features into the overall execution logic**
In order to integrate the command for handling tag features into the execution logic as described in [LogicComponent](#logic-component),
-we first update the `AddressBookParser` to recognise the `tag` _command word_ and will create a `TagCommandParser` subsequently.
-The `TagCommandParser` will then parse the _command arguments_ to create a `TagCommand` that can be executed.
-
-
+there are 3 main steps we need to implement:
+1. Modify `AddressBookParser` to recognise the **tag** _command word_ and will create a `TagCommandParser` subsequently.
+(Modification required is trivial and hence not described in detail)
+2. Implement a `TagCommandParser` class that will parse the _command arguments_ and construct a `TagCommand` accordingly.
+3. Implement a `TagCommand` class that will handle the main execution logic of the tag features and return a `CommandResult` accordingly.
The sequence diagram below illustrates the interactions within the `Logic` component when executing a tag command,
taking `execute("tag 1 at/tall dt/short at/handsome")` API call to `LogicManager` as an example.
@@ -209,49 +213,36 @@ taking `execute("tag 1 at/tall dt/short at/handsome")` API call to `LogicManager
-**Note:**
The lifeline for `TagCommandParser` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
+**Note:**
The lifeline for `TagCommandParser` and `TagCommand` should end at the destroy marker (X) but due to a limitation of PlantUML, the lifeline reaches the end of diagram.
###### **Implementing `TagCommandParser`**
`TagCommandParser` plays the role of parsing _command arguments_ into two information:
-* `index` indicating the index of the targeted customer in the displayed customer list, and
-* `descriptor` encapsulating tags to add to/delete from the targeted customer.
+* **index** indicating the index of the targeted customer in the displayed customer list, and
+* **descriptor** encapsulating tags to add to and/or delete from the targeted customer.
-Both `index` and `updatePersonTagsDescriptor` will be used to create the `TagCommand` to be executed.
-The parsing steps are as follows:
-1. Parse the command arguments into `index`, `tagsToAdd` and `tagsToDelete`(throws ParseException if there are format errors).
-1. Create the `UpdatePersonTagsDescriptor` using `tagsToAdd` and `tagsToDelete`.
-1. Verify that there is at least one tag to add/delete(throws ParseException if no tag to update is provided).
-1. Construct and return the `TagCommand`.
+Both **index** and **descriptor** will then be used to construct a `TagCommand`.
Note that **duplicate tags will be ignored** (see [Design Considerations](#design-considerations) for more information).
The sequence diagram below illustrates the interactions of `TagCommandParser#parse(String arguments)`,
-taking `parse(1 at/tall dt/short at/handsome)` call to the `TagCommandParser` as an example. Note that the
-**reference frames have been omitted** as the operations performed are trivial.
+taking `parse(1 at/tall dt/short at/handsome)` call to the `TagCommandParser` as an example.
###### **Implementing `TagCommand`**
-The following class diagram illustrates how a `TagCommand` hold information required for its execution.
+The following class diagram illustrates how a `TagCommand` holds information required for its execution.
-`TagCommand` plays the role of executing the tag command on a `Model`, it will update the `Model` accordingly to
-reflect the changes after the tag command completes its execution. Note that if there are conflicting tags(i.e. there
-is a common tag to add and delete), the command execution will fail.
-The execution steps are as follows:
-1. Verify that the `TagCommand` is executable(i.e. there is no conflicting tag in the `updatePersonDescriptor`).
-1. Retrieve `personToUpdate` from the model using `index`.
-1. Retrieve `tagsToAdd` and `tagsToDelete` from `updatePersonTagsDescriptor`.
-1. Create the `updatedPerson` from the above information.
-1. Verify that the `updatedPerson` has a different tag set from `personToUpdate` (i.e. the command execution will change the person).
-1. Verify that the `updatedPerson` has a valid number of tags (i.e. not exceeding the maximum allowed tag count).
-1. Set the `personToUpdate` to `updatedPerson` in the `Model`.
-1. Returns the `CommandResult` of the execution.
+`TagCommand` plays the role of executing the main logic of the tag feature, it will:
+* Use information encapsulated in it to create the updated `Person` object accordingly.
+* Update the `Model` accordingly to reflect the changes.
+
+Note that a `TagCommand` is **non-executable** if there are **conflicting tags** (i.e. there are common tags to add and delete).
The sequence diagram below illustrates the interations of `TagCommand#execute(Model model)`,
taking `execute(m)` call to the `TagCommand` as an example. Note that the **reference frames have been omitted**
@@ -261,15 +252,12 @@ as the operations performed are trivial.
###### **Wrapping up the tag feature**
-As reaching this point, we have completed the implementation of the tag feature, where users are allowed to add and delete
-tags of a person in the same command. The following section will discuss certain design considerations when implementing
-this feature.
+As reaching this point, we have completed the implementation of the tag feature.
+The following section will discuss certain design considerations when implementing this feature.
-
-
### Design considerations:
###### **Aspect: Data structure to store tags in a Person object:**
@@ -299,8 +287,6 @@ Alternative 1 was chosen over alternative 2 based on the following reasons:
* Repeated action signals the users' strong intention of performing that action(e.g. wanting to add the same tag twice shows the importance of that tag).
* The target audience is forgetful and careless, it is common for the users to enter duplicate tags without realising it, blocking such actions brings no value to the product.
-
-
###### **Aspect: Deletion of non-existing tags:**
* **Alternative 1(current choice):** Simply ignore such deletions.
* Pros: Users will not be blocked from their action(other tags will still be added/deleted) even though the command consists of such deletions.
@@ -772,9 +758,8 @@ Priorities: High - `* * *`, Medium - `* *`, Low - `*`
**Use Case: UC01 - add a customer**
**MSS:**
- 1. User enters the details of a customer to be added.
- 2. System adds the customer.
- 3. System displays the details of customer added by user.
+ 1. User provides the details of a customer to be added.
+ 2. System displays the details of the customer added by user.
Use case ends.
**Extensions:**
@@ -922,18 +907,22 @@ Priorities: High - `* * *`, Medium - `* *`, Low - `*`
**Use Case: UC09 - update tags of a customer**
**Mss:**
- 1. User requests to list out the customers.
- 2. System displays the requested list of customers to the user.
- 3. User enters index of targeted customer and information of tags to add or delete.
- 4. System updates the tags of the specified customer accordingly.
- 5. System displays the details of the updated customer.
+ 1. User requests a list of customers by filtering customers(UC02).
+ 2. User provides index of the targeted customer in the displayed list.
+ 3. User provides information of tags to add to and/or delete from the targeted customer.
+ 4. System displays the details of the updated customer to the User.
Use case ends.
**Extensions:**
- 3a. User provided invalid index or information.
- 3a1. System displays an error message to alert the User.
+ 1a. Requested list is empty.
+ Use case ends.
+ 2a. User provided invalid index.
+ 2a1. System displays an error message to alert the User.
Use case ends.
- 3b. User provided information that will not update the specified customer.
+ 3a. User provided invalid information of tags.
+ 3a1. Systems displays an error message to alert the User.
+ Use case ends.
+ 3b. User provided information of tags that will not update the targeted customer.
3b1. Systems displays an error message to alert the User.
Use case ends.
@@ -969,7 +958,7 @@ Priorities: High - `* * *`, Medium - `* *`, Low - `*`
5. The application should gracefully handle errors to prevent system crashes and data corruption.
6. The application should be offered as a free service to the public.
7. The application should be able to respond within one second.
-8. The application should be able to handle and support manual edits to the data file.
+8. The application should be able to handle and support manual edits to the data file, erroneous data files should not crash the application.
## Glossary
@@ -985,10 +974,7 @@ Priorities: High - `* * *`, Medium - `* *`, Low - `*`
This section covers the enhancements we plan to implement in the future.
-###### **Aspect: Searching for Multiple Insurances or Tags:**
-
-
-#### Enhancement 1 : Deletion of all tags(and insurances) in a single command
+#### Enhancement 1 : Deletion of all tags in a single command
**Feature flaw:**
As a customer might have many tags, and they could potentially want to remove all the
@@ -1021,12 +1007,6 @@ Expected: Error, an error message showing the usage of tag command is shown to t
Expected: Error, an error message informing the user that they should input `deleteall` to confirm the deletion of all tags
is shown to the user.
-**Additional notes:**
-As the behaviour of the `insurance` command is nearly identical to `tag` command, this planned enhancement applies to
-the `insurance` command too, the proposed enhancements and behaviours will be identical. The following is the updated
-command format for `insurance` command:
-`insurance [ai/]... [di/]... [dai/deleteall]`
-
#### Enhancement 2: Edit appointment details
**Feature flaw:**
@@ -1096,7 +1076,6 @@ This modification allows the find feature to accommodate duplicate prefixes for
The enhanced feature ensures accurate and targeted search results.
-
--------------------------------------------------------------------------------------------------------------------
diff --git a/docs/diagrams/DeleteSequenceDiagram.puml b/docs/diagrams/DeleteSequenceDiagram.puml
index 40ea6c9dc4c..21c6d5d52d6 100644
--- a/docs/diagrams/DeleteSequenceDiagram.puml
+++ b/docs/diagrams/DeleteSequenceDiagram.puml
@@ -65,6 +65,10 @@ deactivate CommandResult
DeleteCommand --> LogicManager : result
deactivate DeleteCommand
-[<--LogicManager
+'Hidden arrow to position the destroy marker below the end of the activation bar.
+DeleteCommand -[hidden]-> LogicManager
+destroy DeleteCommand
+
+[<--LogicManager : result
deactivate LogicManager
@enduml
diff --git a/docs/diagrams/tag-feature/ExecuteActivityDiagram.puml b/docs/diagrams/tag-feature/ExecuteActivityDiagram.puml
index efcaca2d4c4..85e7f3ad008 100644
--- a/docs/diagrams/tag-feature/ExecuteActivityDiagram.puml
+++ b/docs/diagrams/tag-feature/ExecuteActivityDiagram.puml
@@ -3,19 +3,27 @@ skin rose
skinparam ActivityFontSize 15
skinparam ArrowFontSize 12
start
-:User provides tags to add and delete;
+:User provides index of the targeted
+customer in the displayed list;
-'Since the beta syntax does not support placing the condition outside the
-'diamond we place it as the true branch instead.
if () then
- :Update tags of targeted customer;
+ :User provides tags to add to and/or \ndelete from the targeted customer;
+
+ 'Since the beta syntax does not support placing the condition outside the
+ 'diamond we place it as the true branch instead.
if () then
- :Save updated customer to Model;
- else ([updated customer's tag set unchanged or invalid])
+ :System update tags of targeted customer;
+ if () then
+ :System saves updated customer to Model;
+ else ([updated customer's tag set is not valid])
+ stop
+ endif
+ stop
+ else ([tags provided is not valid])
stop
endif
- stop
-else ([has conflicting tags to add and delete])
+else ([index provided is not valid])
stop
endif
+
@enduml
diff --git a/docs/diagrams/tag-feature/ExecuteSequenceDiagram.puml b/docs/diagrams/tag-feature/ExecuteSequenceDiagram.puml
index 27d854f54cd..aec5878ae29 100644
--- a/docs/diagrams/tag-feature/ExecuteSequenceDiagram.puml
+++ b/docs/diagrams/tag-feature/ExecuteSequenceDiagram.puml
@@ -16,7 +16,7 @@ end box
TagCommand -> TagCommand: verifyCommandExecutable(m)
|||
-ref over TagCommand, Model: retrieve information required
+ref over TagCommand, Model: retrieve information required\n(i.e. personToUpdate, tagsToAdd, and tagsToDelete)
|||
TagCommand -> PersonClass: createPersonWithUpdatedTags(personToUpdate, tagsToAdd, tagsToDelete)
diff --git a/docs/diagrams/tag-feature/ParseSequenceDiagram.puml b/docs/diagrams/tag-feature/ParseSequenceDiagram.puml
index afa16f2a540..e00d7c57913 100644
--- a/docs/diagrams/tag-feature/ParseSequenceDiagram.puml
+++ b/docs/diagrams/tag-feature/ParseSequenceDiagram.puml
@@ -7,17 +7,25 @@ participant ":UpdatePersonTagsDescriptor" as UpdatePersonTagsDescriptor LOGIC_CO
participant ":TagCommand" as TagCommand LOGIC_COLOR
[-> TagCommandParser : parse("1 at/tall \ndt/short at/handsome")
-ref over TagCommandParser: parse command arguments
+
+|||
+
+TagCommandParser -> TagCommandParser: parseArguments("1 at/tall dt/short at/handsome")
+
|||
+
create UpdatePersonTagsDescriptor
-TagCommandParser -> UpdatePersonTagsDescriptor
+TagCommandParser -> UpdatePersonTagsDescriptor: UpdatePersonTagsDescriptor(tagsToAdd, tagsToDelete)
activate UpdatePersonTagsDescriptor
return descriptor
+
|||
-ref over TagCommandParser: verify has tag to update
+
+TagCommandParser -> TagCommandParser: verifyHasTagToUpdate(descriptor)
+
|||
create TagCommand
- TagCommandParser -> TagCommand: TagCommand(1, descriptor)
+ TagCommandParser -> TagCommand: TagCommand(index, descriptor)
activate TagCommand
return command
[<--TagCommandParser : command
diff --git a/docs/diagrams/tag-feature/PersonClassDiagram.puml b/docs/diagrams/tag-feature/PersonClassDiagram.puml
index b5c0414b584..903e7b26f83 100644
--- a/docs/diagrams/tag-feature/PersonClassDiagram.puml
+++ b/docs/diagrams/tag-feature/PersonClassDiagram.puml
@@ -11,6 +11,7 @@ note right of Person
which are ommited here as they are irrelevant
when discussing the tag feature.
end note
+
Class Tag
Person --> "*" Tag
diff --git a/docs/diagrams/tag-feature/TagCommandClassDiagram.puml b/docs/diagrams/tag-feature/TagCommandClassDiagram.puml
index 21ebf223c9e..62c4c253185 100644
--- a/docs/diagrams/tag-feature/TagCommandClassDiagram.puml
+++ b/docs/diagrams/tag-feature/TagCommandClassDiagram.puml
@@ -11,7 +11,7 @@ Class Tag
TagCommand --> "1" Index
TagCommand --> "1" UpdatePersonTagsDescriptor
-UpdatePersonTagsDescriptor --> "~* tags to add" Tag
-UpdatePersonTagsDescriptor --> "~* tags to delete" Tag
+UpdatePersonTagsDescriptor --> "~* tagsToAdd" Tag
+UpdatePersonTagsDescriptor --> "~* tagsToDelete" Tag
@enduml
diff --git a/docs/diagrams/tag-feature/TagSequenceDiagram.puml b/docs/diagrams/tag-feature/TagSequenceDiagram.puml
index 34bcf54fb0c..8354bd8ac43 100644
--- a/docs/diagrams/tag-feature/TagSequenceDiagram.puml
+++ b/docs/diagrams/tag-feature/TagSequenceDiagram.puml
@@ -57,6 +57,6 @@ deactivate TagCommand
TagCommand -[hidden]-> LogicManager
destroy TagCommand
-[<--LogicManager
+[<--LogicManager : result
deactivate LogicManager
@enduml
diff --git a/src/main/java/seedu/address/logic/parser/TagCommandParser.java b/src/main/java/seedu/address/logic/parser/TagCommandParser.java
index 5c1576b4c49..5b7c6d6bf02 100644
--- a/src/main/java/seedu/address/logic/parser/TagCommandParser.java
+++ b/src/main/java/seedu/address/logic/parser/TagCommandParser.java
@@ -1,6 +1,7 @@
package seedu.address.logic.parser;
import static java.util.Objects.requireNonNull;
+import static seedu.address.commons.util.CollectionUtil.requireAllNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADD_TAG;
import static seedu.address.logic.parser.CliSyntax.PREFIX_DELETE_TAG;
@@ -27,6 +28,10 @@ public class TagCommandParser implements Parser {
private static final Prefix[] validPrefixes = new Prefix[] { PREFIX_ADD_TAG, PREFIX_DELETE_TAG };
+ private Index index;
+ private Set tagsToAdd;
+ private Set tagsToDelete;
+
/**
* Parses the given {@code String} of arguments in the context of the TagCommand
* and returns a TagCommand object for execution.
@@ -36,14 +41,28 @@ public TagCommand parse(String args) throws ParseException {
requireNonNull(args);
logger.fine("TagCommandParser parsing: " + args);
- ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, validPrefixes);
+ parseArguments(args);
+ requireAllNonNull(index, tagsToAdd, tagsToDelete); // defensive, to ensure that parsing succeeded
+
+ UpdatePersonTagsDescriptor descriptor = new UpdatePersonTagsDescriptor(tagsToAdd, tagsToDelete);
+ verifyHasTagsToUpdate(descriptor); // defensive, verifies that at least one tag is provided
- Index index = extractIndex(argMultimap);
- UpdatePersonTagsDescriptor updatePersonTagsDescriptor = extractUpdatePersonTagsDescriptor(argMultimap);
+ return new TagCommand(index, descriptor);
+ }
- verifyHasTagsToUpdate(updatePersonTagsDescriptor);
+ /**
+ * Parses a {@code String index} into a {@code Index}.
+ * @throws ParseException if {@code index} could not be successfully parsed.
+ */
+ private Index parseIndex(String index) throws ParseException {
+ requireNonNull(index);
- return new TagCommand(index, updatePersonTagsDescriptor);
+ try {
+ return ParserUtil.parseIndex(index);
+ } catch (ParseException pe) {
+ logger.finer("TagCommandParser parse failed due to invalid index: " + index);
+ throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, TagCommand.MESSAGE_USAGE), pe);
+ }
}
/**
@@ -60,33 +79,14 @@ private Optional> parseTags(Collection tags) throws ParseExcept
return Optional.of(ParserUtil.parseTags(tags));
}
- /**
- * Extracts and returns the index from the {@code argMultimap}.
- * @throws ParseException if the index is not an unsigned positive integer.
- */
- private Index extractIndex(ArgumentMultimap argMultimap) throws ParseException {
- requireNonNull(argMultimap);
-
- try {
- return ParserUtil.parseIndex(argMultimap.getPreamble());
- } catch (ParseException pe) {
- logger.finer("TagCommandParser parse failed due to invalid index: " + argMultimap);
- throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, TagCommand.MESSAGE_USAGE), pe);
- }
- }
+ private void parseArguments(String args) throws ParseException {
+ requireNonNull(args);
- /**
- * Extracts the tags to add and delete from the {@code argMultimap},
- * and returns a {@code UpdatePersonTagsDescriptor}.
- * @throws ParseException if there are tags that are invalid.
- */
- private UpdatePersonTagsDescriptor extractUpdatePersonTagsDescriptor(ArgumentMultimap argMultimap)
- throws ParseException {
- requireNonNull(argMultimap);
- Set tagsToAdd = parseTags(argMultimap.getAllValues(PREFIX_ADD_TAG)).orElse(new HashSet<>());
- Set tagsToDelete = parseTags(argMultimap.getAllValues(PREFIX_DELETE_TAG)).orElse(new HashSet<>());
- return new UpdatePersonTagsDescriptor(tagsToAdd, tagsToDelete);
+ ArgumentMultimap argMultimap = ArgumentTokenizer.tokenize(args, validPrefixes);
+ index = parseIndex(argMultimap.getPreamble());
+ tagsToAdd = parseTags(argMultimap.getAllValues(PREFIX_ADD_TAG)).orElse(new HashSet<>());
+ tagsToDelete = parseTags(argMultimap.getAllValues(PREFIX_DELETE_TAG)).orElse(new HashSet<>());
}
/**