Skip to content

Commit

Permalink
Update Find command to parse name prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
tingxuanp committed Oct 14, 2024
1 parent 6f54a4b commit 7189dda
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 69 deletions.
51 changes: 7 additions & 44 deletions src/main/java/seedu/address/logic/commands/FindCommand.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.model.Model;
import seedu.address.model.person.NameContainsKeywordsPredicate;

/**
* Finds and lists all persons in address book whose name contains any of the argument keywords.
* Keyword matching is case-insensitive and allows partial matching.
*/
public class FindCommand extends Command {
public abstract class FindCommand extends Command {

public static final String COMMAND_WORD = "find";

Expand All @@ -23,43 +18,11 @@ public class FindCommand extends Command {

public static final String MESSAGE_FIND_PERSON_UNSUCCESSFUL = "No contacts found.";

private final NameContainsKeywordsPredicate predicate;

public FindCommand(NameContainsKeywordsPredicate predicate) {
this.predicate = predicate;
}

@Override
public CommandResult execute(Model model) {
requireNonNull(model);
model.updateFilteredPersonList(predicate);

if (!model.getFilteredPersonList().isEmpty()) {
return new CommandResult(String.format(MESSAGE_FIND_PERSON_SUCCESS, predicate.getDisplayString()));
} else {
return new CommandResult(MESSAGE_FIND_PERSON_UNSUCCESSFUL);
}
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof FindCommand)) {
return false;
}

FindCommand otherFindCommand = (FindCommand) other;
return predicate.equals(otherFindCommand.predicate);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("predicate", predicate)
.toString();
}
//@Override
//public String toString() {
// return new ToStringBuilder(this)
// .add("predicate", predicate)
// .toString();
//}
}
74 changes: 74 additions & 0 deletions src/main/java/seedu/address/logic/commands/FindNameCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.model.Model;
import seedu.address.model.person.NameContainsKeywordsPredicate;

/**
* Finds and lists all persons in address book whose name contains any of the argument keywords.
* Keyword matching is case-insensitive and allows partial matching.
*/
public class FindNameCommand extends FindCommand {

public static final String COMMAND_WORD = "find";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names contain any of "
+ "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ "Parameters: KEYWORD [MORE_KEYWORDS]...\n"
+ "Example: " + COMMAND_WORD + " alice bob charlie";

public static final String MESSAGE_FIND_NAME_PERSON_SUCCESS = "Search for \"%s\" by name was successful. "
+ " Showing results:";

public static final String MESSAGE_FIND_NAME_PERSON_UNSUCCESSFUL = "No contacts found.";

private final NameContainsKeywordsPredicate predicate;

/**
* Command to filter contacts in WedLinker based on names using partial matching.
* This command allows users to search for contacts by providing one or more keywords.
* The search is case-insensitive and matches any part of the contact names.
*
* @param predicate Keywords used to filter contacts by name.
*/
public FindNameCommand(NameContainsKeywordsPredicate predicate) {
super();
this.predicate = predicate;
}

@Override
public CommandResult execute(Model model) {
requireNonNull(model);
model.updateFilteredPersonList(predicate);

if (!model.getFilteredPersonList().isEmpty()) {
return new CommandResult(String.format(MESSAGE_FIND_NAME_PERSON_SUCCESS, predicate.getDisplayString()));
} else {
return new CommandResult(MESSAGE_FIND_NAME_PERSON_UNSUCCESSFUL);
}
}

@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

// instanceof handles nulls
if (!(other instanceof FindNameCommand)) {
return false;
}

FindNameCommand otherFindCommand = (FindNameCommand) other;
return predicate.equals(otherFindCommand.predicate);
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("predicate", predicate)
.toString();
}
}
33 changes: 31 additions & 2 deletions src/main/java/seedu/address/logic/parser/FindCommandParser.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,18 @@
package seedu.address.logic.parser;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_ADDRESS;
import static seedu.address.logic.parser.CliSyntax.PREFIX_EMAIL;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PHONE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;

import java.util.Arrays;
import java.util.List;

import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.FindNameCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.NameContainsKeywordsPredicate;

Expand All @@ -13,21 +21,42 @@
*/
public class FindCommandParser implements Parser<FindCommand> {




/**
* Parses the given {@code String} of arguments in the context of the FindCommand
* and returns a FindCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public FindCommand parse(String args) throws ParseException {
requireNonNull(args);
ArgumentMultimap argMultimap =
ArgumentTokenizer.tokenize(args, PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS, PREFIX_TAG);

argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_NAME, PREFIX_PHONE, PREFIX_EMAIL, PREFIX_ADDRESS);


String trimmedArgs = args.trim();
if (trimmedArgs.isEmpty()) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
}

String[] nameKeywords = trimmedArgs.split("\\s+");
// Check for the presence of any prefix
boolean hasNamePrefix = argMultimap.getValue(PREFIX_NAME).isPresent();
boolean hasPhonePrefix = argMultimap.getValue(PREFIX_PHONE).isPresent();
boolean hasEmailPrefix = argMultimap.getValue(PREFIX_EMAIL).isPresent();
boolean hasAddressPrefix = argMultimap.getValue(PREFIX_ADDRESS).isPresent();

if (hasNamePrefix) {
String nameInput = argMultimap.getValue(PREFIX_NAME).get().trim(); // Get the actual name input
List<String> nameKeywords = Arrays.asList(nameInput.split("\\s+"));
return new FindNameCommand(new NameContainsKeywordsPredicate((nameKeywords)));
}

return new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList(nameKeywords)));
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
}

}

30 changes: 15 additions & 15 deletions src/test/java/seedu/address/logic/commands/FindCommandTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
import static seedu.address.logic.commands.FindCommand.MESSAGE_FIND_PERSON_SUCCESS;
import static seedu.address.logic.commands.FindCommand.MESSAGE_FIND_PERSON_UNSUCCESSFUL;
import static seedu.address.logic.commands.FindNameCommand.MESSAGE_FIND_NAME_PERSON_SUCCESS;
import static seedu.address.testutil.TypicalPersons.ALICE;
import static seedu.address.testutil.TypicalPersons.BENSON;
import static seedu.address.testutil.TypicalPersons.CARL;
Expand Down Expand Up @@ -39,14 +39,14 @@ public void equals() {
NameContainsKeywordsPredicate secondPredicate =
new NameContainsKeywordsPredicate(Collections.singletonList("second"));

FindCommand findFirstCommand = new FindCommand(firstPredicate);
FindCommand findSecondCommand = new FindCommand(secondPredicate);
FindNameCommand findFirstCommand = new FindNameCommand(firstPredicate);
FindNameCommand findSecondCommand = new FindNameCommand(secondPredicate);

// same object -> returns true
assertTrue(findFirstCommand.equals(findFirstCommand));

// same values -> returns true
FindCommand findFirstCommandCopy = new FindCommand(firstPredicate);
FindCommand findFirstCommandCopy = new FindNameCommand(firstPredicate);
assertTrue(findFirstCommand.equals(findFirstCommandCopy));

// different types -> returns false
Expand All @@ -63,7 +63,7 @@ public void equals() {
public void execute_zeroKeywords_noPersonFound() {
String expectedMessage = MESSAGE_FIND_PERSON_UNSUCCESSFUL;
NameContainsKeywordsPredicate predicate = preparePredicate(" ");
FindCommand command = new FindCommand(predicate);
FindNameCommand command = new FindNameCommand(predicate);
expectedModel.updateFilteredPersonList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
assertEquals(Collections.emptyList(), model.getFilteredPersonList());
Expand All @@ -72,8 +72,8 @@ public void execute_zeroKeywords_noPersonFound() {
@Test
public void execute_multipleKeywords_multiplePersonsFound() {
NameContainsKeywordsPredicate predicate = preparePredicate("Kurz Elle Kunz");
String expectedMessage = String.format(MESSAGE_FIND_PERSON_SUCCESS, predicate.getDisplayString());
FindCommand command = new FindCommand(predicate);
String expectedMessage = String.format(MESSAGE_FIND_NAME_PERSON_SUCCESS, predicate.getDisplayString());
FindNameCommand command = new FindNameCommand(predicate);
expectedModel.updateFilteredPersonList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
assertEquals(Arrays.asList(CARL, ELLE, FIONA), model.getFilteredPersonList());
Expand All @@ -82,8 +82,8 @@ public void execute_multipleKeywords_multiplePersonsFound() {
@Test
public void execute_partialMatchKeyword_correctPersonFound() {
NameContainsKeywordsPredicate predicate = preparePredicate("ell");
String expectedMessage = String.format(MESSAGE_FIND_PERSON_SUCCESS, predicate.getDisplayString());
FindCommand command = new FindCommand(predicate);
String expectedMessage = String.format(MESSAGE_FIND_NAME_PERSON_SUCCESS, predicate.getDisplayString());
FindNameCommand command = new FindNameCommand(predicate);
expectedModel.updateFilteredPersonList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
assertEquals(Arrays.asList(ELLE), model.getFilteredPersonList());
Expand All @@ -92,8 +92,8 @@ public void execute_partialMatchKeyword_correctPersonFound() {
@Test
public void execute_partialMatchKeyword_multiplePersonsFound() {
NameContainsKeywordsPredicate predicate = preparePredicate("e");
String expectedMessage = String.format(MESSAGE_FIND_PERSON_SUCCESS, predicate.getDisplayString());
FindCommand command = new FindCommand(predicate);
String expectedMessage = String.format(MESSAGE_FIND_NAME_PERSON_SUCCESS, predicate.getDisplayString());
FindNameCommand command = new FindNameCommand(predicate);
expectedModel.updateFilteredPersonList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
assertEquals(Arrays.asList(ALICE, BENSON, DANIEL, ELLE, GEORGE), model.getFilteredPersonList());
Expand All @@ -103,7 +103,7 @@ public void execute_partialMatchKeyword_multiplePersonsFound() {
public void execute_absentPartialMatchKeyword_noPersonFound() {
NameContainsKeywordsPredicate predicate = preparePredicate("x");
String expectedMessage = MESSAGE_FIND_PERSON_UNSUCCESSFUL;
FindCommand command = new FindCommand(predicate);
FindNameCommand command = new FindNameCommand(predicate);
expectedModel.updateFilteredPersonList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
assertEquals(Collections.emptyList(), model.getFilteredPersonList());
Expand All @@ -112,9 +112,9 @@ public void execute_absentPartialMatchKeyword_noPersonFound() {
@Test
public void toStringMethod() {
NameContainsKeywordsPredicate predicate = new NameContainsKeywordsPredicate(Arrays.asList("keyword"));
FindCommand findCommand = new FindCommand(predicate);
String expected = FindCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
assertEquals(expected, findCommand.toString());
FindNameCommand findNameCommand = new FindNameCommand(predicate);
String expected = FindNameCommand.class.getCanonicalName() + "{predicate=" + predicate + "}";
assertEquals(expected, findNameCommand.toString());
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.FilterCommand;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.FindNameCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
import seedu.address.logic.commands.TagCommand;
Expand Down Expand Up @@ -76,9 +77,9 @@ public void parseCommand_exit() throws Exception {
@Test
public void parseCommand_find() throws Exception {
List<String> keywords = Arrays.asList("foo", "bar", "baz");
FindCommand command = (FindCommand) parser.parseCommand(
FindCommand.COMMAND_WORD + " " + keywords.stream().collect(Collectors.joining(" ")));
assertEquals(new FindCommand(new NameContainsKeywordsPredicate(keywords)), command);
FindNameCommand command = (FindNameCommand) parser.parseCommand(
FindCommand.COMMAND_WORD + " n/" + keywords.stream().collect(Collectors.joining(" ")));
assertEquals(new FindNameCommand(new NameContainsKeywordsPredicate(keywords)), command);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.junit.jupiter.api.Test;

import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.FindNameCommand;
import seedu.address.model.person.NameContainsKeywordsPredicate;

public class FindCommandParserTest {
Expand All @@ -17,18 +18,25 @@ public class FindCommandParserTest {

@Test
public void parse_emptyArg_throwsParseException() {
assertParseFailure(parser, " ", String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
assertParseFailure(parser, " ",
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
}

@Test
public void parse_missingNamePrefix_throwsParseException() {
assertParseFailure(parser, "find amy",
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
}

@Test
public void parse_validArgs_returnsFindCommand() {
// no leading and trailing whitespaces
FindCommand expectedFindCommand =
new FindCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
assertParseSuccess(parser, "Alice Bob", expectedFindCommand);
FindNameCommand expectedFindCommand =
new FindNameCommand(new NameContainsKeywordsPredicate(Arrays.asList("Alice", "Bob")));
assertParseSuccess(parser, "find n/Alice Bob", expectedFindCommand);

// multiple whitespaces between keywords
assertParseSuccess(parser, " \n Alice \n \t Bob \t", expectedFindCommand);
assertParseSuccess(parser, "find n/ \n Alice \n \t Bob \t", expectedFindCommand);
}

}

0 comments on commit 7189dda

Please sign in to comment.