Skip to content

Commit

Permalink
Merge pull request nus-cs2103-AY2425S1#62 from jessica2828/filter-com…
Browse files Browse the repository at this point in the history
…mand

Refactor Find command to Filter
  • Loading branch information
juliantayyc authored Oct 16, 2024
2 parents 8dbf3fd + 15f1657 commit 65d284d
Show file tree
Hide file tree
Showing 13 changed files with 478 additions and 154 deletions.
108 changes: 108 additions & 0 deletions src/main/java/seedu/address/logic/commands/FilterCommand.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.model.Model;
import seedu.address.model.person.CourseContainsKeywordsPredicate;
import seedu.address.model.person.ModuleContainsKeywordsPredicate;
import seedu.address.model.person.NameContainsKeywordsPredicate;

/**
* Finds and lists all persons in address book whose name matches the specified keywords
* or whose course matches the specified course.
* Keyword matching is case insensitive.
*/
public class FilterCommand extends Command {

public static final String COMMAND_WORD = "filter";

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Finds all persons whose names match "
+ "the specified keywords (case-insensitive) and displays them as a list with index numbers.\n"
+ "Parameters: NAME_KEYWORD [MORE_NAME_KEYWORDS]...\n"
+ "or: MODULE_KEYWORD\n"
+ "or: COURSE_KEYWORD\n"
+ "Example NAME: " + COMMAND_WORD + " n/alice bob charlie\n"
+ "Example MODULE: " + COMMAND_WORD + " m/CS2103T\n"
+ "Example COURSE: " + COMMAND_WORD + " c/Computer Science";

private final NameContainsKeywordsPredicate namePredicate;
private final ModuleContainsKeywordsPredicate modulePredicate;
private final CourseContainsKeywordsPredicate coursePredicate;

/**
* Constructs a {@code FilterCommand} with a {@code NameContainsKeywordsPredicate}.
* The {@code modulePredicate} will be set to {@code null}.
*
* @param namePredicate the predicate to filter the list by name keywords
*/
public FilterCommand(NameContainsKeywordsPredicate namePredicate) {
this.coursePredicate = null;
this.namePredicate = namePredicate;
this.modulePredicate = null;
}

/**
* Constructs a {@code FilterCommand} with a {@code ModuleContainsKeywordsPredicate}.
* The {@code namePredicate} will be set to {@code null}.
*
* @param modulePredicate the predicate to filter the list by module keywords
*/
public FilterCommand(ModuleContainsKeywordsPredicate modulePredicate) {
this.coursePredicate = null;
this.modulePredicate = modulePredicate;
this.namePredicate = null;
}

/**
* Constructs a {@code FilterCommand} with a {@code CourseContainsKeywordsPredicate}.
* The {@code namePredicate} and {@code modulePredicate} will be set to {@code null}.
*
* @param coursePredicate the predicate to filter the list by course keywords
*/
public FilterCommand(CourseContainsKeywordsPredicate coursePredicate) {
this.coursePredicate = coursePredicate;
this.namePredicate = null;
this.modulePredicate = null;
}

@Override
public CommandResult execute(Model model) {
requireNonNull(model);
if (namePredicate != null) {
model.updateFilteredPersonList(namePredicate);
} else if (modulePredicate != null) {
model.updateFilteredPersonList(modulePredicate);
} else if (coursePredicate != null) {
model.updateFilteredPersonList(coursePredicate);
}
return new CommandResult(
String.format(Messages.MESSAGE_PERSONS_LISTED_OVERVIEW, model.getFilteredPersonList().size()));
}
@Override
public boolean equals(Object other) {
if (other == this) {
return true;
}

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

FilterCommand otherFilterCommand = (FilterCommand) other;
return (namePredicate != null && namePredicate.equals(otherFilterCommand.namePredicate))
|| (modulePredicate != null && modulePredicate.equals(otherFilterCommand.modulePredicate))
|| (coursePredicate != null && coursePredicate.equals(otherFilterCommand.coursePredicate));
}

@Override
public String toString() {
return new ToStringBuilder(this)
.add("namePredicate", namePredicate)
.add("modulePredicate", modulePredicate)
.add("coursePredicate", coursePredicate)
.toString();
}
}
58 changes: 0 additions & 58 deletions src/main/java/seedu/address/logic/commands/FindCommand.java

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
import seedu.address.logic.commands.DeleteCommand;
import seedu.address.logic.commands.EditCommand;
import seedu.address.logic.commands.ExitCommand;
import seedu.address.logic.commands.FindCommand;
import seedu.address.logic.commands.FilterCommand;
import seedu.address.logic.commands.GradeCommand;
import seedu.address.logic.commands.HelpCommand;
import seedu.address.logic.commands.ListCommand;
Expand Down Expand Up @@ -70,8 +70,8 @@ public Command parseCommand(String userInput) throws ParseException {
case ClearCommand.COMMAND_WORD:
return new ClearCommand();

case FindCommand.COMMAND_WORD:
return new FindCommandParser().parse(arguments);
case FilterCommand.COMMAND_WORD:
return new FilterCommandParser().parse(arguments);

case ListCommand.COMMAND_WORD:
return new ListCommand();
Expand Down
69 changes: 69 additions & 0 deletions src/main/java/seedu/address/logic/parser/FilterCommandParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package seedu.address.logic.parser;

import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_COURSE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_MODULE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_NAME;

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

import seedu.address.logic.commands.FilterCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.CourseContainsKeywordsPredicate;
import seedu.address.model.person.ModuleContainsKeywordsPredicate;
import seedu.address.model.person.NameContainsKeywordsPredicate;

/**
* Parses input arguments and creates a new FilterCommand object
*/
public class FilterCommandParser implements Parser<FilterCommand> {

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

validateArguments(argMultimap);

if (argMultimap.getValue(PREFIX_NAME).isPresent()) {
return createFilterCommandByName(argMultimap);
} else if (argMultimap.getValue(PREFIX_MODULE).isPresent()) {
return createFilterCommandByModule(argMultimap);
} else if (argMultimap.getValue(PREFIX_COURSE).isPresent()) {
return createFilterCommandByCourse(argMultimap);
}

throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCommand.MESSAGE_USAGE));
}

private void validateArguments(ArgumentMultimap argMultimap) throws ParseException {
if (!argMultimap.getPreamble().isEmpty()
|| argMultimap.getValue(PREFIX_NAME).isPresent()
&& argMultimap.getValue(PREFIX_NAME).get().isEmpty()
|| argMultimap.getValue(PREFIX_MODULE).isPresent()
&& argMultimap.getValue(PREFIX_MODULE).get().isEmpty()
|| argMultimap.getValue(PREFIX_COURSE).isPresent()
&& argMultimap.getValue(PREFIX_COURSE).get().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCommand.MESSAGE_USAGE));
}
}

private FilterCommand createFilterCommandByName(ArgumentMultimap argMultimap) {
List<String> nameKeywords = Arrays.asList(argMultimap.getValue(PREFIX_NAME).get().split("\\s+"));
return new FilterCommand(new NameContainsKeywordsPredicate(nameKeywords));
}

private FilterCommand createFilterCommandByModule(ArgumentMultimap argMultimap) {
String moduleKeyword = argMultimap.getValue(PREFIX_MODULE).get();
return new FilterCommand(new ModuleContainsKeywordsPredicate(moduleKeyword));
}

private FilterCommand createFilterCommandByCourse(ArgumentMultimap argMultimap) {
List<String> courseKeywords = Arrays.asList(argMultimap.getValue(PREFIX_COURSE).get().split("\\s+"));
return new FilterCommand(new CourseContainsKeywordsPredicate(courseKeywords));
}
}
33 changes: 0 additions & 33 deletions src/main/java/seedu/address/logic/parser/FindCommandParser.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package seedu.address.model.person;

import java.util.List;
import java.util.function.Predicate;

import seedu.address.commons.util.ToStringBuilder;

/**
* Tests that a {@code Person}'s {@code Course} matches any of the keywords given.
*/
public class CourseContainsKeywordsPredicate implements Predicate<Person> {
private final List<String> keywords;

/**
* Creates a CourseContainsKeywordsPredicate with the specified keywords.
*
* @param keywords A list of keywords to filter by.
*/
public CourseContainsKeywordsPredicate(List<String> keywords) {
this.keywords = keywords;
}

@Override
public boolean test(Person person) {
String course = person.getCourse().toString().toLowerCase();
return keywords.stream().anyMatch(keyword -> {
String keywordLower = keyword.toLowerCase();
if (course.equals(keywordLower)) {
return true;
}
// for partial match
return course.startsWith(keywordLower);
});
}

@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
// instanceof handles nulls
if (!(other instanceof CourseContainsKeywordsPredicate)) {
return false;
}

CourseContainsKeywordsPredicate otherCourseContainsKeywordsPredicate = (CourseContainsKeywordsPredicate) other;
return keywords.equals(otherCourseContainsKeywordsPredicate.keywords);
}

@Override
public String toString() {
return new ToStringBuilder(this).add("keywords", keywords).toString();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package seedu.address.model.person;

import java.util.function.Predicate;

import seedu.address.commons.util.ToStringBuilder;

/**
* Tests that a {@code Person}'s {@code Module} matches the keyword given.
*/
public class ModuleContainsKeywordsPredicate implements Predicate<Person> {
private final String keyword;

public ModuleContainsKeywordsPredicate(String keyword) {
this.keyword = keyword;
}

@Override
public boolean test(Person person) {
return person.getModules().stream()
.anyMatch(module -> module.toString().toLowerCase().contains(keyword.toLowerCase()));
}

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

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

ModuleContainsKeywordsPredicate otherModulePredicate = (ModuleContainsKeywordsPredicate) other;
return keyword.equals(otherModulePredicate.keyword);
}

@Override
public String toString() {
return new ToStringBuilder(this).add("keywords", keyword).toString();
}
}
Loading

0 comments on commit 65d284d

Please sign in to comment.