com.speedment.runtime.core.manager.Manager Maven / Gradle / Ivy
Show all versions of runtime-deploy Show documentation
/**
*
* Copyright (c) 2006-2017, Speedment, Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); You may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.speedment.runtime.core.manager;
import com.speedment.common.singletonstream.SingletonStream;
import com.speedment.runtime.config.identifier.TableIdentifier;
import com.speedment.runtime.core.exception.SpeedmentException;
import com.speedment.runtime.field.Field;
import com.speedment.runtime.field.trait.HasFinder;
import java.util.function.Function;
import java.util.stream.Stream;
/**
* A Manager is responsible for abstracting away an Entity's data source CRUD
* operations. Entity sources can be RDBMSes, files or other data sources.
*
* A Manager must be thread safe and be able to handle several reading and
* writing threads at the same time.
*
* @param entity type for this Manager
*
* @author Per Minborg
* @author Emil Forslund
* @since 2.0.0
*/
public interface Manager {
/**
* Returns an identifier for the table that this {@code Manager} handles
* entities for.
*
* @return the table identifier
*/
TableIdentifier getTableIdentifier();
/**
* Returns the entity class for this Manager.
*
* @return the entity class
*/
Class getEntityClass();
/**
* Returns a stream of the fields that every entity in this {@code Manager}
* contains.
*
* @return a stream of all fields
*/
Stream> fields();
/**
* Returns a stream of the fields that are included in the primary key of
* the table represented by this {@code Manager}.
*
* @return the primary key fields
*/
Stream> primaryKeyFields();
/**
* Creates and returns a new {@link Stream} over all entities in the
* underlying database. This is the main query API for Speedment.
*
* This is an inexpensive O(1) operation that will complete in
* constant time regardless of the number of entities in the underlying
* database.
*
* The returned stream is aware of its own pipeline and will optimize
* its own pipeline whenever it encounters a Terminal
* Operation so that it will only iterate over a minimum set of
* matching entities.
*
* When a Terminal Operation is eventually called on the {@link Stream},
* that execution time of the Terminal Operation will depend on the
* optimized pipeline and the entities in the underlying database.
*
* The Stream will be automatically
* {@link Stream#onClose(java.lang.Runnable) closed} after the Terminal
* Operation is completed or if an Exception is thrown during the Terminal
* Operation.
*
* Some of the Terminal Operations are:
*
* - {@link Stream#forEach(java.util.function.Consumer) forEach(Consumer)}
*
- {@link Stream#forEachOrdered(java.util.function.Consumer) forEachOrdered(Consumer)}
*
- {@link Stream#toArray() toArray()}
*
- {@link Stream#toArray(java.util.function.IntFunction) toArray(IntFunction)}
*
- {@link Stream#reduce(java.util.function.BinaryOperator) reduce(BinaryOperation}
*
- {@link Stream#reduce(java.lang.Object, java.util.function.BinaryOperator) reduce(Object, BinaryOperator)}
*
- {@link Stream#reduce(java.lang.Object, java.util.function.BiFunction, java.util.function.BinaryOperator) reduce(Object, BiFunction, BinaryOperator)}
*
- {@link Stream#collect(java.util.stream.Collector) collect(Collector)}
*
- {@link Stream#collect(java.util.function.Supplier, java.util.function.BiConsumer, java.util.function.BiConsumer) collect(Supplier, BiConsumer, BiConsumer)}
*
- {@link Stream#min(java.util.Comparator) min(Comparator)}
*
- {@link Stream#max(java.util.Comparator) min(Comparator)}
*
- {@link Stream#count() count()}
*
- {@link Stream#anyMatch(java.util.function.Predicate) anyMatch(Predicate)}
*
- {@link Stream#noneMatch(java.util.function.Predicate) noneMatch(Predicate)}
*
- {@link Stream#findFirst() findFirst()}
*
- {@link Stream#findAny() findAny()}
*
- {@link Stream#iterator() iterator()}
*
*
* Any Terminating Operation may throw a {@link SpeedmentException} if the
* underlying database throws an Exception (e.g. an SqlException)
*
* Because the Stream may short-circuit operations in the Stream pipeline,
* methods having side-effects (like
* {@link Stream#peek(java.util.function.Consumer) peek(Consumer)} will
* potentially be affected by the optimization.
*
* Here are some examples of how the stream optimization might work:
*
* -
*
{@code stream
* .filter(Hare.NAME.equal("Henry")
* .collect(toList());}
* {@code -> select * from hares where name='Henry'}
*
* -
*
{@code stream.count();}
* {@code -> select count(*) from hares}
*
* -
*
{@code stream
* .filter(Hare.NAME.equal("Henry")
* .count();}
* {@code -> select count(*) from hares where
* name='Henry'}
*
*
* -
*
{@code stream
* .filter(Hare.NAME.equal("Henry")
* .filter(Hare.AGE.greaterThan(5)
* .count();}
* {@code -> select count(*) from hares where
* name ='Henry'
* and
* age > 5}
*
*
*
*
* @return a new stream over all entities in this table
* @throws SpeedmentException if an error occurs during a Terminal Operation
* (e.g. an SqlException is thrown by the underlying database)
* @see java.util.stream
* @see Stream
*/
Stream stream();
/**
* Persists the provided entity to the underlying database and returns a
* potentially updated entity. If the persistence fails for any reason, an
* unchecked {@link SpeedmentException} is thrown.
*
* It is unspecified if the returned updated entity is the same provided
* entity instance or another entity instance. It is erroneous to assume
* either, so you should use only the returned entity after the method has
* been called. However, it is guaranteed that the provided entity is
* untouched if an exception is thrown.
*
* The fields of returned entity instance may differ from the provided
* entity fields due to auto generated column(s) or because of any other
* modification that the underlying database imposed on the persisted
* entity.
*
* @param entity to persist
* @return an entity reflecting the result of the persisted entity
* @throws SpeedmentException if the underlying database throws an exception
* (e.g. SQLException)
*/
ENTITY persist(ENTITY entity) throws SpeedmentException;
/**
* Returns a {@link Persister} that when its
* {@link Persister#apply(java.lang.Object) } method is called, will produce
* the same result as {@link #persist(java.lang.Object) }
*
* @return a Persister
*/
Persister persister();
/**
* Updates the provided entity in the underlying database and returns a
* potentially updated entity. If the update fails for any reason, an
* unchecked {@link SpeedmentException} is thrown.
*
* It is unspecified if the returned updated entity is the same provided
* entity instance or another entity instance. It is erroneous to assume
* either, so you should use only the returned entity after the method has
* been called. However, it is guaranteed that the provided entity is
* untouched if an exception is thrown.
*
* The fields of returned entity instance may differ from the provided
* entity fields due to auto generated column(s) or because of any other
* modification that the underlying database imposed on the persisted
* entity.
*
* Entities are uniquely identified by their primary key(s).
*
* @param entity to update
* @return an entity reflecting the result of the updated entity
* @throws SpeedmentException if the underlying database throws an exception
* (e.g. SQLException)
*/
ENTITY update(ENTITY entity) throws SpeedmentException;
/**
* Returns an {@link Updater} that when its
* {@link Persister#apply(java.lang.Object) } method is called, will produce
* the same result as {@link #update(java.lang.Object) }
*
* @return an Updater
*/
Updater updater();
/**
* Removes the provided entity from the underlying database and returns the
* provided entity instance. If the deletion fails for any reason, an
* unchecked {@link SpeedmentException} is thrown.
*
* Entities are uniquely identified by their primary key(s).
*
* @param entity to remove
* @return the provided entity instance
* @throws SpeedmentException if the underlying database throws an exception
* (e.g. SQLException)
*/
ENTITY remove(ENTITY entity) throws SpeedmentException;
/**
* Returns a {@link Remover} that when its
* {@link Persister#apply(java.lang.Object) } method is called, will produce
* the same result as {@link #remove(java.lang.Object) }
*
* @return a Remover
*/
Remover remover();
/**
* Returns a Function that, when it is applied, will produce an equivalent
* result as if {@link #finderByNullable(HasFinder)} was called.
*
* @param the type of the foreign entity
* @param fkField the foreign key field
* @return an Entity (if any) that matches the given a foreign key relation
* (foreign field and entity)
*
* @see #finderByNullable(HasFinder)
*/
default Function finderBy(HasFinder fkField) {
return fkField.finder(getTableIdentifier(), this::stream);
}
/**
* Retrieves and returns an Entity that matches the given a foreign key
* relation (foreign field and entity). For example, if there is an entity
* Carrot with a FK to Hare using the column "hare", then
* hares.find(Carrot.HARE, carrot) will return the Hare that the Carrot.HARE
* field is pointing to.
*
* @param the type of the foreign entity
* @param fkField the foreign key field
* @param fkEntity the foreign key entity
* @return an Entity (if any) that matches the given a foreign key relation
* (foreign field and entity)
*/
default ENTITY findBy(HasFinder fkField, FK_ENTITY fkEntity) {
return finderBy(fkField).apply(fkEntity);
}
/**
* Returns a Function that, when it is applied, will produce an equivalent
* result as if {@link #findByNullable(HasFinder, Object)} was called.
*
* @param the type of the foreign entity
* @param fkField the foreign key field
* @return an Entity (if any) that matches the given a foreign key relation
* (foreign field and entity)
*
* @see #findByNullable(HasFinder, Object)
*/
default Function> finderByNullable(HasFinder fkField) {
return fkEntity -> SingletonStream.ofNullable(finderBy(fkField).apply(fkEntity));
}
/**
* Retrieves and returns a stream of Entities (with one or zero elements)
* that matches the given a foreign key relation (foreign field and entity).
* For example, if there is an entity Carrot with a FK to Hare using the
* column "hare", then hares.find(Carrot.HARE, carrot) will return a stream
* with the Hare that the Carrot.HARE field is pointing to or Stream.empty()
* if the hare column in carrot was null. I.e. The returned Stream will
* contain either zero or one element.
*
* @param the type of the foreign entity
* @param fkField the foreign key field
* @param fkEntity the foreign key entity
* @return an Entity (if any) that matches the given a foreign key relation
* (foreign field and entity)
*/
default Stream findByNullable(HasFinder fkField, FK_ENTITY fkEntity) {
return finderByNullable(fkField).apply(fkEntity);
}
/**
* Returns a Function that, when it is applied, will produce an equivalent
* result as if {@link #findBackwardsBy(HasFinder, Object)} was called.
*
* @param the type of the foreign entity
* @param fkField the foreign key field
* @return an Entity (if any) that matches the given a foreign key relation
* (foreign field and entity)
* @see #findBackwardsBy(HasFinder, Object)
*/
default Function> finderBackwardsBy(HasFinder fkField) {
return fkField.backwardFinder(getTableIdentifier(), this::stream);
}
/**
* Retrieves and returns a stream of matching entities that matches the
* given a foreign key relation (foreign field and entity). For example, if
* there is an entity Carrot with a FK to Hare using the column "hare", then
* carrots.findBackwardsBy(Carrot.HARE, hare) will produce a Stream of all
* the Carrots that points to the given hare using the Carrot.HARE column.
*
* @param the type of the foreign entity
* @param fkField the foreign key field
* @param fkEntity the foreign key entity
* @return an Entity (if any) that matches the given a foreign key relation
* (foreign field and entity)
*/
default Stream findBackwardsBy(HasFinder fkField, FK_ENTITY fkEntity) {
return finderBackwardsBy(fkField).apply(fkEntity);
}
}