-
Notifications
You must be signed in to change notification settings - Fork 0
Examples
To persist something you need a POJO that contains its data in a form that Jackson can map it to JSON. It is possible to use other ways of converting the data, but it is expected that you'll use JSON and Jackson in most cases.
The POJO needs to have a field marked with the Key annotation and needs a getter and setter for that field.
You can either provide the key field when you save the object or can provide a key generator.
Example of a simple POJO with a key field:
public class IntegerKeyedDocument {
@Key
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
To persist this, you need an instance of the Engine
class for which EngineImpl
is the key implementation. The engine needs a storage manager for which there's StorageManagerInMemory
for use if you're doing testing or running an in-memory only database for some reason. Most commonly you would use `StorageManagerFileSystem" which will persist every POJO into a directory of your choice in subdirectories according to the type of object it is storing.
// Construct an engine to store files in "tempTestDb" directory
Engine engine = new EngineImpl(new StorageManagerFileSystem("tempTestDb/"));
Storing an object is very straightforward. Providing it has either a value in its key field or a null key and a key generator specified in the @Key attribute, then you simply can call store or storeNew
// Save an object
Pojo someObject = new Pojo( ... ); // construct your object
engine.store(someObject); // save the object (assumes singleton instance of the engine)
storeNew
is the same as store, but will throw an exception if the object already exists.
For objects with generated keys, the store method keeps calling storeNew with new keys until it stores a unique one.
Retrieving an object requires the key field:
// retrieves an object of type ExampleDocument with key "myKey"
ExampleDocument found = engine.find("myKey", ExampleDocument.class);
To delete an object provide its key to the engine
// delete object with key "toDelete"
engine.delete("toDelete", SomeClass.class);
To find all the keys for a particular type:
// retrieve all keys - note you get a set of Strings, this is the internal representation
// not sorted, not converted into the original value of a key
Set<String> allKeys = engine.findAllKeys(SomeClass.class);
You can sort the keys into order by their string contents if this is useful - in reality it might be more useful to order the objects by some other criteria. However, for cases where the keys have meaning as string you can specify your own comparator or use one of the ones provided.
// retrieve keys in ascending string order
List<String> allKeysSorted = engine.findAllKeys(SomeClass.class, new StringAscending());
Queries return a ListWithKeys
object, which can be used as a list of keys with the getKey(int index)
function, or can be used as though all the objects from the datasource are in memory within the list. In actual fact, the items are loaded just in time as you iterate through the list and you get a fresh instance of the object every time you use a list get method.
Note: the list that is returned can be used as a front end to the database for adding and removing objects. Use it carefully. While the list starts life as a filter of the objects you originally extracted, it becomes a view of that data that you're modifying with changes happening live. List changes are applied to the engine, but object changes are not - you need to re-save an object for its changes to be persisted.
// retrieve all items
List<MyItem> allItems = engine.findAll(MyItem.class); // actually returns ListWithKeys which extends List
The Predicate
class is used to filter items for inclusion in the target set. The Mapping
class can be used to extract from an item into something else which can be used for sorting, perhaps a single value or some custom pojo. This leads to the most complex find method which allows you to specify the predicate for whether an item is extracted, the mapping for how that item will be seen by the sort algorithm and then the comparator used in the sort.
// retrieve all items and sort by the numeric key field
ListWithKeys<IntegerKeyedPojo> = engine.findAll(IntegerKeyedPojo.class,
new SomePredicate(), // custom class to decide if an IntegerKeyedPojo is to be included
new SomeMapping(), // in this case a class than implements Mapping<IntegerKeyedPojo, Integer>
new IntegerAscending()); // would implement Comparator<Integer> in this instance
See the unit tests for some examples of this.
A transformation can be performed like a query. It would normally be used to find the max or sum of a type of field, for which there are default implementations. A transformation is run according to the following pseudo code:
for each item that passes through the filter defined in predicate
if this is the first item
build the transformation from the item
else
aggregate to the current transformation with the item
end
Example of a max transformation:
Integer max = engine.createTransformation(IntegerKeyedDocument.class,
new All<IntegerKeyedDocument>(), // all is a predicate which returns all
new IntegerMax<IntegerKeyedDocument>(getIntegerKeyedDocumentKey())); // IntegerMax needs a mapping to integer from the custom type