A data store is responsible for:
If a data store is unable to fully implement filtering, sorting, or pagination, it can instead rely on the Elide framework to perform these functions in memory. By default however, Elide pushes these responsibilities to the store.
Elide comes bundled with a number of data stores:
Stores can be included through the following artifact dependencies:
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-datastore-jpa</artifactId>
<version>${elide.version}</version>
</dependency>
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-datastore-hibernate5</artifactId>
<version>${elide.version}</version>
</dependency>
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-datastore-inmemorydb</artifactId>
<version>${elide.version}</version>
</dependency>
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-datastore-multiplex</artifactId>
<version>${elide.version}</version>
</dependency>
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-datastore-noop</artifactId>
<version>${elide.version}</version>
</dependency>
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-datastore-search</artifactId>
<version>${elide.version}</version>
</dependency>
<dependency>
<groupId>com.yahoo.elide</groupId>
<artifactId>elide-datastore-aggregation</artifactId>
<version>${elide.version}</version>
</dependency>
Elide Spring Boot is configured by default with the JPA data store.
To change the store, override the DataStore
autoconfigure bean:
@Bean
public DataStore buildDataStore(EntityManagerFactory entityManagerFactory) {
final Consumer<EntityManager> TXCANCEL = (em) -> { em.unwrap(Session.class).cancelQuery(); };
return new JpaDataStore(
() -> { return entityManagerFactory.createEntityManager(); },
(em -> { return new NonJtaTransaction(em, TXCANCEL); }));
}
Elide Standalone is configured by default with the JPA data store.
To change the store, the ElideStandaloneSettings
interface can be overridden to change the function which builds the DataStore
object. One of two possible functions should be overridden depending on whether the AggregationDataStore
is enabled:
/**
* Gets the DataStore for elide when aggregation store is disabled.
* @param entityManagerFactory EntityManagerFactory object.
* @return DataStore object initialized.
*/
default DataStore getDataStore(EntityManagerFactory entityManagerFactory) {
DataStore jpaDataStore = new JpaDataStore(
() -> { return entityManagerFactory.createEntityManager(); },
(em) -> { return new NonJtaTransaction(em, ElideStandaloneSettings.TXCANCEL); });
return jpaDataStore;
}
/**
* Gets the DataStore for elide.
* @param metaDataStore MetaDataStore object.
* @param aggregationDataStore AggregationDataStore object.
* @param entityManagerFactory EntityManagerFactory object.
* @return DataStore object initialized.
*/
default DataStore getDataStore(MetaDataStore metaDataStore, AggregationDataStore aggregationDataStore,
EntityManagerFactory entityManagerFactory) {
DataStore jpaDataStore = new JpaDataStore(
() -> { return entityManagerFactory.createEntityManager(); },
(em) -> { return new NonJtaTransaction(em, ElideStandaloneSettings.TXCANCEL); });
DataStore dataStore = new MultiplexManager(jpaDataStore, metaDataStore, aggregationDataStore);
return dataStore;
}
Custom stores can be written by implementing the DataStore
and DataStoreTransaction
interfaces.
If a Data Store is unable to fully implement sorting, filtering, or pagination, the Elide framework can perform these functions in-memory instead.
The Data Store Transaction can inform Elide of its capabilities (or lack thereof) by returning a DataStoreIterable
for any collection loaded:
/**
* Returns data loaded from a DataStore. Wraps an iterable but also communicates to Elide
* if the framework needs to filter, sort, or paginate the iterable in memory before returning to the client.
* @param <T> The type being iterated over.
*/
public interface DataStoreIterable<T> extends Iterable<T> {
/**
* Returns the underlying iterable.
* @return The underlying iterable.
*/
Iterable<T> getWrappedIterable();
/**
* Whether the iterable should be filtered in memory.
* @return true if the iterable needs sorting in memory. false otherwise.
*/
default boolean needsInMemoryFilter() {
return false;
}
/**
* Whether the iterable should be sorted in memory.
* @return true if the iterable needs sorting in memory. false otherwise.
*/
default boolean needsInMemorySort() {
return false;
}
/**
* Whether the iterable should be paginated in memory.
* @return true if the iterable needs pagination in memory. false otherwise.
*/
default boolean needsInMemoryPagination() {
return false;
}
}
A common pattern in Elide is the need to support multiple data stores. Typically, one data store manages most models, but some models may require a different persistence backend or have other needs to specialize the behavior of the store. The multiplex store (MultiplexManager
) in Elide manages multiple stores - delegating calls to the appropriate store which is responsible for a particular model.
To setup the multiplex store in spring boot, create a DataStore
bean:
@Bean
public DataStore buildDataStore(EntityManagerFactory entityManagerFactory) {
final Consumer<EntityManager> TXCANCEL = (em) -> { em.unwrap(Session.class).cancelQuery(); };
//Store 1 manages Book, Author, and Publisher
DataStore store1 = new JpaDataStore(
entityManagerFactory::createEntityManager,
(em) -> { return new NonJtaTransaction(em, TXCANCEL); },
Book.class, Author.class, Publisher.class
);
//Store 2 is a custom store that manages Manufacturer
DataStore store2 = new MyCustomDataStore(...);
//Return the new multiplex store...
return new MultiplexManager(store1, store2);
}
To setup the multiplex store in Elide standalone, override the getElideSettings function:
/**
* Gets the DataStore for elide when aggregation store is disabled.
* @param entityManagerFactory EntityManagerFactory object.
* @return DataStore object initialized.
*/
default DataStore getDataStore(EntityManagerFactory entityManagerFactory) {
//Store 1 manages Book, Author, and Publisher
DataStore store1 = new JpaDataStore(
() -> { return entityManagerFactory.createEntityManager(); },
(em) -> { return new NonJtaTransaction(em, ElideStandaloneSettings.TXCANCEL); },
Book.class, Author.class, Publisher.class
);
//Store 2 is a custom store that manages Manufacturer
DataStore store2 = new MyCustomDataStore(...);
//Create the new multiplex store...
return new MultiplexManager(store1, store2);
}
}