Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement substring search feature #166

Merged
merged 16 commits into from
Apr 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 16 additions & 14 deletions docs/UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,14 +250,16 @@ Example: `asset old/hammer new/screwdriver` edits the asset `hammer`, changing i

### Finding Contacts: `find`

Finds contacts whose names, tags or assets contain any of the given keywords.
Finds contacts by names, tags or assets.

Format: `find KEYWORD [KEYWORD]...`
Format: `find QUERY`

Example: `find John` searches all contact names, tags and assets for the keyword `John`.
Example: `find John` searches all contact names, tags and assets for the query `John`.

* At least one keyword must be provided.
* Keywords are case-insensitive.
* The query is case-insensitive.
* All whitespaces in both the query and fields will be ignored.
* Each field is individually checked against the query.
* A match is found if the query is a substring of the field being checked.

--------------------------------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -326,15 +328,15 @@ Furthermore, certain edits can cause the AssetBook-3 to behave in unexpected way

## Command summary

Action | Format | Example
-----------------|-------------------------------------------------------------------------------|---
**Add** | `add n/NAME p/PHONE e/EMAIL o/OFFICE [t/TAG]... [a/ASSET]...` | `add n/John Doe e/johndoe@example.com p/+12345678 a/L293D`
**Delete** | `delete INDEX` | `delete 1`
**Edit contact** | `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [o/OFFICE] [t/TAG]... [a/ASSET]...` | `edit 1 e/newemail@example.com`
**Edit asset** | `asset old/OLD_ASSET_NAME new/NEW_ASSET_NAME` | `asset old/hammer new/screwdriver`
**Find** | `find KEYWORD [KEYWORD]...` | `find John`
**Undo** | `undo` | `undo`
**Exit** | `exit` | `exit`
Action | Format | Example
-----------------|------------------------------------------------------------------------------|---
**Add** | `add n/NAME p/PHONE e/EMAIL o/OFFICE [t/TAG]... [a/ASSET]...` | `add n/John Doe e/johndoe@example.com p/+12345678 a/L293D`
**Delete** | `delete INDEX` | `delete 1`
**Edit contact** | `edit INDEX [n/NAME] [p/PHONE] [e/EMAIL] [o/OFFICE] [t/TAG]... [a/ASSET]...` | `edit 1 e/newemail@example.com`
**Edit asset** | `asset old/OLD_ASSET_NAME new/NEW_ASSET_NAME` | `asset old/hammer new/screwdriver`
**Find** | `find QUERY` | `find John`
**Undo** | `undo` | `undo`
**Exit** | `exit` | `exit`

---{.double}

Expand Down
34 changes: 13 additions & 21 deletions src/main/java/seedu/address/logic/commands/FindCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,31 @@
import static java.util.Objects.requireNonNull;
import static seedu.address.logic.Messages.MESSAGE_INVALID_COMMAND_FORMAT;

import java.util.Arrays;
import java.util.function.Predicate;

import seedu.address.commons.util.ToStringBuilder;
import seedu.address.logic.Messages;
import seedu.address.model.Model;
import seedu.address.model.person.PersonMatchesKeywordsPredicate;
import seedu.address.model.person.Person;
import seedu.address.model.person.PersonMatchesQueryPredicate;

/**
* Finds and lists all persons in address book whose name contains any of the argument keywords.
* Keyword matching is case insensitive.
* Finds and lists all persons in the address book such that certain fields match the predicate.
* See {@code PersonMatchesQueryPredicate}.
*/
public class FindCommand extends Command {

public static final String COMMAND_WORD = "find";

public static final String MESSAGE_USAGE = COMMAND_WORD
+ ": Finds all persons whose names, assets or tags 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";
+ ": Finds all persons whose names, assets or tags contains "
+ "the specified query (case-insensitive) and displays them as a list with index numbers.\n"
+ "All whitespaces are ignored.\n"
+ "Parameters: QUERY\n"
+ "Example: " + COMMAND_WORD + " alex";

private final PersonMatchesKeywordsPredicate predicate;
private final Predicate<Person> predicate;

public FindCommand(PersonMatchesKeywordsPredicate predicate) {
public FindCommand(Predicate<Person> predicate) {
this.predicate = predicate;
}

Expand All @@ -49,9 +50,7 @@ public static FindCommand of(String args) throws IllegalArgumentException {
String.format(MESSAGE_INVALID_COMMAND_FORMAT, FindCommand.MESSAGE_USAGE));
}

String[] nameKeywords = trimmedArgs.split("\\s+");

return new FindCommand(new PersonMatchesKeywordsPredicate(Arrays.asList(nameKeywords)));
return new FindCommand(new PersonMatchesQueryPredicate(trimmedArgs));
}

@Override
Expand All @@ -69,11 +68,4 @@ public boolean equals(Object other) {
return predicate.equals(otherFindCommand.predicate);
}

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

}

This file was deleted.

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

import static java.util.Objects.requireNonNull;

import java.util.function.Predicate;

/**
* Tests that a {@code Person}'s {@code Name}, {@code Tags} or {@code Assets} matches the search query.
* The algorithm removes all whitespaces and checks if the query is a substring of a field.
* The substring matching is case-insensitive.
*/
public class PersonMatchesQueryPredicate implements Predicate<Person> {

private static final String STRIP_WHITESPACE_REGEX = "\\s+";
private static final String EMPTY_STRING = "";

private final String query;

/**
* Processes the query string and constructs the object.
* @param query the query string.
* @throws NullPointerException if the query string is null.
* @throws AssertionError if the query string is empty.
*/
public PersonMatchesQueryPredicate(String query) {
requireNonNull(query);
assert !query.isEmpty();
this.query = processString(query);
}

private static String processString(String str) {
return str.toLowerCase().replaceAll(STRIP_WHITESPACE_REGEX, EMPTY_STRING);
}

//@@author rizkidelta
@Override
public boolean test(Person person) {
return doesStringMatchQuery(person.getName().toString(), query)
|| person.getTags().stream().anyMatch(tag -> doesStringMatchQuery(tag.get(), query)
|| person.getAssets().stream().anyMatch(asset -> doesStringMatchQuery(asset.get(), query)));
}

//@@author rizkidelta
private static boolean doesStringMatchQuery(String text, String query) {
requireNonNull(text);

// only need to process text, as query is already processed in the constructor
text = processString(text);
return text.contains(query);
}

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

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

PersonMatchesQueryPredicate otherPersonMatchesQueryPredicate = (PersonMatchesQueryPredicate) other;
return query.equals(otherPersonMatchesQueryPredicate.query);
}

}
2 changes: 1 addition & 1 deletion src/main/java/seedu/address/model/tag/Tag.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

/**
* Represents a Tag in the address book.
* Guarantees: immutable; name is valid as declared in {@link #isValidTagName(String)}
* Guarantees: immutable; name is valid as declared in {@link #isValid(String)}
*/
public class Tag {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@
import static seedu.address.testutil.Assert.assertThrows;

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

import seedu.address.commons.core.index.Index;
import seedu.address.logic.commands.exceptions.CommandException;
import seedu.address.model.AddressBook;
import seedu.address.model.Model;
import seedu.address.model.person.Person;
import seedu.address.model.person.PersonMatchesKeywordsPredicate;
import seedu.address.model.person.PersonMatchesQueryPredicate;
import seedu.address.testutil.EditPersonDescriptorBuilder;

/**
Expand Down Expand Up @@ -118,7 +117,7 @@ public static void showPersonAtIndex(Model model, Index targetIndex) {

Person person = model.getFilteredPersonList().get(targetIndex.getZeroBased());
final String[] splitName = person.getName().toString().split("\\s+");
model.updateFilteredPersonList(new PersonMatchesKeywordsPredicate(Arrays.asList(splitName[0])));
model.updateFilteredPersonList(new PersonMatchesQueryPredicate(splitName[0]));

assertEquals(1, model.getFilteredPersonList().size());
}
Expand Down
Loading