A collection of CRUD components implementing a clean interface
I used to write these crud stores several times across use-cases, decided to create a simple interface, and some default
abstractions of popular databases that implements the interface.
I've been able to add the abstraction for aerospike. Impls for other databases as contributions are welcome.
The following are the CRUD ops in the Store interface (pretty self-explanatory)
void create(final T item);
void update(final T item);
void delete(final String id);
Optional<T> get(final String id);
Map<String, T> get(final List<String> ids);
List<T> list();
An extension to this has been added (since 1.2.5) ReferenceExtendedStore, to support fetch by references through indexes if a Store is able to support it.
void create(final T item, final List<String> refIds);
List<T> getByRefId(final String refId);
Wraps your store with a Caffine in-memory cache. Use this to quickly have a cache on top of your store
Usage:
Store<MyData> store=new CachingStore(
myAerospikeStore,
1000, // maxsize of cache
10, // expire after write in seconds
5, // refresh after write in seconds
);
This impl provides crud for your data by storing it in a default set (data
), hides details of
serialization/de-serserialization, provides hook for proper error handling.
It also supports indexing on references, as it implements a ReferenceExtendedStore. So if you have data that needs to be retrieved through some reference ids, you can do so in an optimal manner. Internally, a LIST s-index is created, and an Aerospike query on the index is fired during retrieval
Usage:
public class MyAerospikeStore extends AerospikeStore<TestData> {
protected MyAerospikeStore(final IAerospikeClient client,
final NamespaceSet namespaceSet,
final ObjectMapper mapper,
final Class<TestData> clazz,
final ErrorHandler<TestData> errorHandler) {
super(client, namespaceSet, mapper, clazz, errorHandler);
}
@Override
protected boolean isValidDataItem(final TestData userData) {
return true; // you may do additional checks here
}
}
Your TestData class can look something like this
@Builder
public record TestData(
String id,
String name,
int age) implements Id {
}
That is it, you should be good to go to do the following
public class Logic {
private AerospikeStore<TestData> store
= new MyAerospikeStore(
AerospikeClientHelpers.aerospikeClient(AerospikeConfiguration.builder()
.hosts("...") // set the rest
.build()), new NamespaceSet("test", "test-set"),
mapper,
TestData.class,
new DefaultErrorHandler<>());
void myOperations() {
store.create(new TestData("Id001", "Rick", 47));
store.create(new TestData("Id001", "Rick", 47), List.of("animated"));
store.update(new TestData("Id001", "Rick Sanchez", 48));
Optional<TestData> result = store.get("Id001");
List<TestData> result = store.getByRefId("animated");
List<TestData> result = store.get(List.of("Id001", "Id002"));
List<TestData> result = store.list();
store.delete("Id001");
}
}
The following can be added in your dependencies, for the aerospike crud-store.
<dependency>
<groupId>com.livetheoogway.crudstore</groupId>
<artifactId>aerospike-crud-store</artifactId>
<version>${crudstore.version}</version> <!--look for the latest version on top-->
</dependency>
- Java 17
- Aerospike (any provided version should do)
Please raise Issues, Bugs or any feature requests at Github Issues
.
If you plan on contributing to the code, fork the repository and raise a Pull Request back here.