Skip to content

Commit

Permalink
Merge pull request #75 from ashleyy2444/branch-addFilterPL
Browse files Browse the repository at this point in the history
Add Filter Programming Language Feature
  • Loading branch information
ashleyy2444 authored Apr 3, 2024
2 parents ba26e93 + 99fc307 commit af1770b
Show file tree
Hide file tree
Showing 16 changed files with 374 additions and 19 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package seedu.address.logic.commands;

import static java.util.Objects.requireNonNull;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.model.Model;
import seedu.address.model.language.ProgrammingLanguageContainsKeywordsPredicate;

/**
* Filters and lists all persons in address book whose programming language contains any of the argument keywords.
*/
public class FilterProgrammingLanguageCommand extends FilterCommand {

public static final String COMMAND_WORD = FilterCommand.COMMAND_WORD + " " + PREFIX_PROGRAMMING_LANGUAGE;

public static final String MESSAGE_USAGE = COMMAND_WORD + ": Filters all contacts whose programming language "
+ "contain any of the specified tags and displays them as a list with index numbers.\n"
+ "Parameters: PROGRAMMING_LANGUAGE [MORE_PROGRAMMING_LANGUAGES]...\n"
+ "Example: " + COMMAND_WORD + " Java";

private final ProgrammingLanguageContainsKeywordsPredicate predicate;

public FilterProgrammingLanguageCommand(ProgrammingLanguageContainsKeywordsPredicate predicate) {
this.predicate = predicate;
}

@Override

public CommandResult execute(Model model) {
requireNonNull(model);
model.updateFilteredPersonList(predicate);
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 FilterProgrammingLanguageCommand)) {
return false;
}

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

@Override
public String toString() {
return new ToStringBuilder(this)
.add("programming_language", predicate)
.toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.model.Model;
import seedu.address.model.person.TagContainsKeywordsPredicate;
import seedu.address.model.tag.TagContainsKeywordsPredicate;


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;
import static seedu.address.logic.parser.CliSyntax.PREFIX_INTERVIEWTIME;
import static seedu.address.logic.parser.CliSyntax.PREFIX_PROGRAMMING_LANGUAGE;
import static seedu.address.logic.parser.CliSyntax.PREFIX_SALARY;
import static seedu.address.logic.parser.CliSyntax.PREFIX_TAG;

Expand All @@ -24,18 +25,22 @@ public class FilterCommandParser implements Parser<FilterCommand> {
public FilterCommand parse(String args) throws ParseException {
ArgumentMultimap argMultimap =
ArgumentTokenizer.tokenize(
args, PREFIX_SALARY, PREFIX_TAG, PREFIX_INTERVIEWTIME);
if (!exactlyOnePrefixPresent(argMultimap, PREFIX_SALARY, PREFIX_TAG, PREFIX_INTERVIEWTIME)
|| !argMultimap.getPreamble().isEmpty()) {
args, PREFIX_SALARY, PREFIX_TAG, PREFIX_INTERVIEWTIME, PREFIX_PROGRAMMING_LANGUAGE);
if (!exactlyOnePrefixPresent(argMultimap, PREFIX_SALARY, PREFIX_TAG, PREFIX_INTERVIEWTIME,
PREFIX_PROGRAMMING_LANGUAGE) || !argMultimap.getPreamble().isEmpty()) {
throw new ParseException(String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterCommand.MESSAGE_USAGE));
}

argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_SALARY, PREFIX_TAG, PREFIX_INTERVIEWTIME);
argMultimap.verifyNoDuplicatePrefixesFor(PREFIX_SALARY, PREFIX_TAG, PREFIX_INTERVIEWTIME,
PREFIX_PROGRAMMING_LANGUAGE);

if (argMultimap.getValue(PREFIX_SALARY).isPresent()) {
return new FilterSalaryCommandParser().parse(argMultimap.getValue(PREFIX_SALARY).get());
} else if (argMultimap.getValue(PREFIX_TAG).isPresent()) {
return new FilterTagCommandParser().parse(argMultimap.getValue(PREFIX_TAG).get());
} else if (argMultimap.getValue(PREFIX_PROGRAMMING_LANGUAGE).isPresent()) {
return new FilterProgrammingLanguageCommandParser().parse(argMultimap.getValue(PREFIX_PROGRAMMING_LANGUAGE)
.get());
} else {
return new FilterInterviewTimeCommandParser().parse(argMultimap.getValue(PREFIX_INTERVIEWTIME).get());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package seedu.address.logic.parser;

import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import java.util.ArrayList;
import java.util.List;

import seedu.address.logic.commands.FilterProgrammingLanguageCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.language.ProgrammingLanguage;
import seedu.address.model.language.ProgrammingLanguageContainsKeywordsPredicate;

/**
* Parses input arguments and creates a new FindCommand object
*/
public class FilterProgrammingLanguageCommandParser implements Parser<FilterProgrammingLanguageCommand> {
/**
* Parses the given {@code String} of arguments in the context of the FilterProgrammingLanguageCommand
* and returns a FilterProgrammingLanguageCommand object for execution.
* @throws ParseException if the user input does not conform the expected format
*/
public FilterProgrammingLanguageCommand parse(String args) throws ParseException {
String trimmedArgs = args.trim();
if (trimmedArgs.isEmpty()) {
throw new ParseException(
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FilterProgrammingLanguageCommand.MESSAGE_USAGE));
}
String[] languageKeywords = trimmedArgs.split("\\s+");
return new FilterProgrammingLanguageCommand(
new ProgrammingLanguageContainsKeywordsPredicate(createLanguages(languageKeywords)));
}

/**
* Parses {@code languageKeywords} into a {@code List<ProgrammingLanguage>}.
*/
public static List<ProgrammingLanguage> createLanguages(String... languageKeywords) throws ParseException {
List<ProgrammingLanguage> languages = new ArrayList<>();
for (String keyword : languageKeywords) {
languages.add(ParserUtil.parseProgrammingLanguage(keyword.toLowerCase())); // Convert to lowercase
}
return languages;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

import seedu.address.logic.commands.FilterTagCommand;
import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.person.TagContainsKeywordsPredicate;
import seedu.address.model.tag.Tag;
import seedu.address.model.tag.TagContainsKeywordsPredicate;


/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,15 @@ public ProgrammingLanguage(String languageName) {
this.languageName = languageName;
}

/**
* Returns the name of this programming language.
*
* @return The name of this programming language.
*/
public String getLanguageName() {
return languageName;
}

/**
* Returns true if a given string is a valid programming language name.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package seedu.address.model.language;

import static java.util.Objects.requireNonNull;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.model.person.Person;

/**
* Tests that a {@code Person}'s {@code Tag} matches any of the keywords given.
*/
public class ProgrammingLanguageContainsKeywordsPredicate implements Predicate<Person> {
private final List<ProgrammingLanguage> originalLanguages;
private final List<String> lowercaseLanguageNames;
/**
* Constructs a {@code ProgrammingLanguageContainsKeywordsPredicate} with the given list of programming languages.
* Creates two lists: one to store the original ProgrammingLanguage objects and another to store their lowercase
* string representations.
*
* @param languages The list of programming languages to be used in the predicate.
* @throws NullPointerException if {@code languages} is null.
*/
public ProgrammingLanguageContainsKeywordsPredicate(List<ProgrammingLanguage> languages) {
requireNonNull(languages);
this.originalLanguages = new ArrayList<>(languages);
this.lowercaseLanguageNames = languages.stream()
.map(ProgrammingLanguage::getLanguageName)
.map(String::toLowerCase)
.collect(Collectors.toList());
}

@Override
public boolean test(Person person) {
Set<ProgrammingLanguage> personProgrammingLanguages = person.getProgrammingLanguages();
return personProgrammingLanguages.stream()
.map(ProgrammingLanguage::getLanguageName)
.map(String::toLowerCase)
.anyMatch(lowercaseLanguageNames::contains);
}

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

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

ProgrammingLanguageContainsKeywordsPredicate otherProgrammingLanguageContainsKeywordsPredicate =
(ProgrammingLanguageContainsKeywordsPredicate) other;
return originalLanguages.equals(otherProgrammingLanguageContainsKeywordsPredicate.originalLanguages);
}

@Override
public String toString() {
return new ToStringBuilder(this).add("programming_language", originalLanguages).toString();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package seedu.address.model.person;
package seedu.address.model.tag;

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

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.model.tag.Tag;
import seedu.address.model.person.Person;

/**
* Tests that a {@code Person}'s {@code Tag} matches any of the keywords given.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package seedu.address.logic.commands;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static seedu.address.logic.Messages.MESSAGE_PERSONS_LISTED_OVERVIEW;
import static seedu.address.logic.commands.CommandTestUtil.assertCommandSuccess;
import static seedu.address.logic.parser.FilterProgrammingLanguageCommandParser.createLanguages;
import static seedu.address.testutil.TypicalPersons.getTypicalAddressBook;

import java.util.Collections;

import org.junit.jupiter.api.Test;

import seedu.address.logic.parser.exceptions.ParseException;
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
import seedu.address.model.language.ProgrammingLanguageContainsKeywordsPredicate;

/**
* Contains integration tests (interaction with the Model) for {@code FilterProgrammingLanguageCommand}.
*/
public class FilterProgrammingLanguageCommandTest {
private Model model = new ModelManager(getTypicalAddressBook(), new UserPrefs());
private Model expectedModel = new ModelManager(getTypicalAddressBook(), new UserPrefs());

@Test
public void equals() throws ParseException {
ProgrammingLanguageContainsKeywordsPredicate firstPredicate =
new ProgrammingLanguageContainsKeywordsPredicate(createLanguages("Java"));
ProgrammingLanguageContainsKeywordsPredicate secondPredicate =
new ProgrammingLanguageContainsKeywordsPredicate(createLanguages("Python"));

FilterProgrammingLanguageCommand filterProgrammingLanguageFirstCommand =
new FilterProgrammingLanguageCommand(firstPredicate);
FilterProgrammingLanguageCommand filterProgrammingLanguageSecondCommand =
new FilterProgrammingLanguageCommand(secondPredicate);

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

// same values -> returns true
FilterProgrammingLanguageCommand filterProgrammingLanguageFirstCommandCopy =
new FilterProgrammingLanguageCommand(firstPredicate);
assertTrue(filterProgrammingLanguageFirstCommand.equals(filterProgrammingLanguageFirstCommandCopy));

// different types -> returns false
assertFalse(filterProgrammingLanguageFirstCommand.equals(1));

// null -> returns false
assertFalse(filterProgrammingLanguageFirstCommand.equals(null));

// different person -> returns false
assertFalse(filterProgrammingLanguageFirstCommand.equals(filterProgrammingLanguageSecondCommand));
}

@Test
public void execute_zeroKeywords_noPersonFound() throws ParseException {
String expectedMessage = String.format(MESSAGE_PERSONS_LISTED_OVERVIEW, 0);
ProgrammingLanguageContainsKeywordsPredicate predicate =
preparePredicate(" ");
FilterProgrammingLanguageCommand command = new FilterProgrammingLanguageCommand(predicate);
expectedModel.updateFilteredPersonList(predicate);
assertCommandSuccess(command, model, expectedMessage, expectedModel);
assertEquals(Collections.emptyList(), model.getFilteredPersonList());
}
/**
* Parses {@code userInput} into a {@code ProgrammingLanguageContainsKeywordsPredicate}.
*/
private ProgrammingLanguageContainsKeywordsPredicate preparePredicate(String userInput) throws ParseException {
return new ProgrammingLanguageContainsKeywordsPredicate(createLanguages(userInput.split("\\s+")));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,24 @@ public void equals() {
SalaryContainsKeywordsPredicate secondPredicate =
new SalaryContainsKeywordsPredicate(Collections.singletonList(new SalaryRange("2000-5000")));

FilterSalaryCommand FilterSalaryFirstCommand = new FilterSalaryCommand(firstPredicate);
FilterSalaryCommand FilterSalarySecondCommand = new FilterSalaryCommand(secondPredicate);
FilterSalaryCommand filterSalaryFirstCommand = new FilterSalaryCommand(firstPredicate);
FilterSalaryCommand filterSalarySecondCommand = new FilterSalaryCommand(secondPredicate);

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

// same values -> returns true
FilterSalaryCommand findSalaryFirstCommandCopy = new FilterSalaryCommand(firstPredicate);
assertTrue(FilterSalaryFirstCommand.equals(findSalaryFirstCommandCopy));
assertTrue(filterSalaryFirstCommand.equals(findSalaryFirstCommandCopy));

// different types -> returns false
assertFalse(FilterSalaryFirstCommand.equals(1));
assertFalse(filterSalaryFirstCommand.equals(1));

// null -> returns false
assertFalse(FilterSalaryFirstCommand.equals(null));
assertFalse(filterSalaryFirstCommand.equals(null));

// different person -> returns false
assertFalse(FilterSalaryFirstCommand.equals(FilterSalarySecondCommand));
assertFalse(filterSalaryFirstCommand.equals(filterSalarySecondCommand));
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import seedu.address.model.Model;
import seedu.address.model.ModelManager;
import seedu.address.model.UserPrefs;
import seedu.address.model.person.TagContainsKeywordsPredicate;
import seedu.address.model.tag.TagContainsKeywordsPredicate;


/**
Expand Down
Loading

0 comments on commit af1770b

Please sign in to comment.