-
Notifications
You must be signed in to change notification settings - Fork 1
Managers
RPF supplies a manager API to make the general process of storing data, retrieving, and editing it far more simple and intuitive. The default implementation supports any data structure, getAll, wildcard key based getters/"existors" (checking if a key/what it represents exists), population, and of course adding. There are also other implementations in the core & addons which add new types of managers. Currently, there's only two other implementations in RPF & it's addons, SearchableManager & MySQLManager. SearchableManager leverages the levenshtein distance algorithm via a port of python's fuzzywuzzy library to add similarity based string searching. MySQLManager will save the manager's data to a table at a configurable interval, and optionally auto populate the manager at startup from it's corresponding table.
There's currently 4 required methods when creating a manager. You'll need to configure the key config, inserting, deleting, and getting all. For example, here's what a manager using a List might look like:
@Singleton
public final class ExampleManager extends Manager<Person> {
private final List<Person> people = new ArrayList<>();
@Override
protected KeyTypeInfo configure(KeyTypeInfo.Builder builder) {
return builder
.key(String.class)
.list(people, (k, v) -> v.getName().equalsIgnoreCase(v))
.build();
}
@Override
protected void insert(Person person) {
people.add(person);
}
@Override
protected void delete(Person person) {
people.remove(person);
}
@Override
protected Collection<Person> retrieveAll() {
return people;
}
}
- @Singleton is required, otherwise the data will not persist upon different injections.
Most of this is self explanatory, except for the KeyTypeInfo. The system uses a lot of generic magic to allow the end user to get a value with different types of keys, without explicitely defining methods for them. The builder allows you to say which keys are allowed. Currently, the KeyTypeInfo builder has premade bindings for the List and Map data structures, but if you're not using one of them, you can easily create your own. An example of which is below (using map, even though you can use .map for it)
@Override
protected KeyTypeInfo configure(KeyTypeInfo.Builder builder) {
private static final String DEF = "null";
private final Map<String, String> map = new HashMap<>();
return builder
.key(String.class)
.exists(k -> map.exists(k))
.getter(k -> map.getOrDefault(k, DEF))
.bundle()
.build();
/*
* ^ is the same as:
* builder
* .key(String.class)
* .map(map, DEF)
* .build();
*/
}
When extending a searchable manager, none of the above changes, but a new public method is added - #search. You'll have to change your object to extend SearchUtils.Searchable, and implement getName(). This is the string that will be used for comparison against other searchables.
public final class Person implements Searchable {
private final String name;
public Person(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
}
public final class PersonSimilarityTest {
@Inject private PeopleManager people;
public void test() {
people.add(new Person("bill"));
people.add(new Person("joe"));
Stream.of(
"bill", "joe", "jo",
"billy", "jeo", "ibll"
).map(people::search).map(l -> l.get(0)).map(Person::getName).forEach(System.out::println);
}
}
Upon running PersonSimilarityTest#test, the following would be outputted
bill
joe
joe
bill
joe
bill
Refer to the MySQL Module.