is.codion.framework.model.EntityEditModel Maven / Gradle / Ivy
/*
* This file is part of Codion.
*
* Codion is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Codion is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Codion. If not, see .
*
* Copyright (c) 2009 - 2024, Björn Darri Sigurðsson.
*/
package is.codion.framework.model;
import is.codion.common.Configuration;
import is.codion.common.db.exception.DatabaseException;
import is.codion.common.event.EventObserver;
import is.codion.common.property.PropertyValue;
import is.codion.common.state.State;
import is.codion.common.state.StateObserver;
import is.codion.common.value.Value;
import is.codion.framework.db.EntityConnection;
import is.codion.framework.db.EntityConnectionProvider;
import is.codion.framework.domain.entity.Entities;
import is.codion.framework.domain.entity.Entity;
import is.codion.framework.domain.entity.EntityDefinition;
import is.codion.framework.domain.entity.EntityType;
import is.codion.framework.domain.entity.EntityValidator;
import is.codion.framework.domain.entity.attribute.Attribute;
import is.codion.framework.domain.entity.attribute.AttributeDefinition;
import is.codion.framework.domain.entity.attribute.ForeignKey;
import is.codion.framework.domain.entity.exception.ValidationException;
import java.util.Collection;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
/**
* Specifies a class for editing {@link Entity} instances.
*/
public interface EntityEditModel {
/**
* Specifies whether writable foreign key values should persist when the model is cleared or set to null
* Value type: Boolean
* Default value: true
*/
PropertyValue PERSIST_FOREIGN_KEYS = Configuration.booleanValue(EntityEditModel.class.getName() + ".persistForeignKeys", true);
/**
* Specifies whether edit models post their insert, update and delete events to {@link EntityEditEvents}
* Value type: Boolean
* Default value: true
* @see #postEditEvents()
* @see EntityTableModel#HANDLE_EDIT_EVENTS
*/
PropertyValue POST_EDIT_EVENTS = Configuration.booleanValue(EntityEditModel.class.getName() + ".postEditEvents", true);
/**
* @return the type of the entity this edit model is based on
*/
EntityType entityType();
/**
* @return the connection provider used by this edit model
*/
EntityConnectionProvider connectionProvider();
/**
* Do not cache or keep the connection returned by this method in a long living field,
* since it may become invalid and thereby unusable.
* @return the connection used by this edit model
*/
EntityConnection connection();
/**
* Populates this edit model with default values for all attributes.
* @see #defaultValue(Attribute)
* @see AttributeDefinition#defaultValue()
*/
void defaults();
/**
* Copies the values from the given {@link Entity} into the underlying
* {@link Entity} being edited by this edit model. If {@code entity} is null
* the effect is the same as calling {@link #defaults()}.
* @param entity the entity
* @see #defaults()
* @see #beforeEntityEvent()
*/
void set(Entity entity);
/**
* Refreshes the active Entity from the database, discarding all changes.
* If the active Entity is new then calling this method has no effect.
*/
void refresh();
/**
* @return an immutable version of the {@link Entity} instance being edited
* @see Entity#immutable()
*/
Entity entity();
/**
* @param attribute the attribute
* @return a {@link StateObserver} indicating whether the value of the given attribute is null
*/
StateObserver isNull(Attribute> attribute);
/**
* @param attribute the attribute
* @return a {@link StateObserver} indicating whether the value of the given attribute is not null
*/
StateObserver isNotNull(Attribute> attribute);
/**
* Reverts all attribute value changes.
*/
void revert();
/**
* @param attribute the attribute to revert
*/
void revert(Attribute attribute);
/**
* @param attribute the attribute
* @return true if this value is allowed to be null in the underlying entity
*/
boolean nullable(Attribute> attribute);
/**
* Sets the given value in the underlying Entity
* @param attribute the attribute to associate the given value with
* @param value the value to associate with the given attribute
* @param the value type
* @return the previous value, if any
*/
T put(Attribute attribute, T value);
/**
* Removes the given value from the underlying Entity
* @param attribute the attribute
* @param the value type
* @return the value, if any
*/
T remove(Attribute attribute);
/**
* Returns the value associated with the given attribute
* @param attribute the attribute
* @param the value type
* @return the value associated with the given attribute
*/
T get(Attribute attribute);
/**
* Returns the value associated with the given attribute
* @param attribute the attribute
* @param the value type
* @return the value associated with the given attribute, an empty Optional in case it is null
*/
Optional optional(Attribute attribute);
/**
* Returns a Value based on {@code attribute} in this edit model, note that
* subsequent calls for the same attribute return the same value instance.
* @param attribute the attribute
* @param the value type
* @return a Value based on the given edit model value
*/
Value value(Attribute attribute);
/**
* @return the underlying domain entities
*/
Entities entities();
/**
* @return the definition of the underlying entity
*/
EntityDefinition entityDefinition();
/**
* Making this edit model read-only prevents any changes from being
* persisted to the database, trying to insert, update or delete will
* cause an exception being thrown, it does not prevent editing.
* Use {@link #insertEnabled()}, {@link #updateEnabled()} and {@link #deleteEnabled()}
* to configure the enabled state of those specific actions.
* @return the State controlling whether this model is read only
*/
State readOnly();
/**
* Disabling insert causes an exception being thrown when inserting.
* @return the state controlling whether inserting is enabled via this edit model
*/
State insertEnabled();
/**
* Disabling update causes an exception being thrown when updating.
* @return the state controlling whether updating is enabled via this edit model
*/
State updateEnabled();
/**
* Disabling updating multiple entities causes an exception being thrown when
* trying to update multiple entities at a time.
* @return the state controlling whether updating multiple entities is enabled
*/
State updateMultipleEnabled();
/**
* Disabling delete causes an exception being thrown when deleting.
* @return the state controlling whether deleting is enabled via this edit model
*/
State deleteEnabled();
/**
* Creates a {@link EntitySearchModel} for looking up entities referenced by the given foreign key,
* using the search attributes defined for that entity type.
* @param foreignKey the foreign key for which to create a {@link EntitySearchModel}
* @return a {@link EntitySearchModel} for looking up entities of the type referenced by the given foreign key attribute,
* @throws IllegalStateException in case no searchable attributes can be found for the entity type referenced by the given foreign key
*/
EntitySearchModel createForeignKeySearchModel(ForeignKey foreignKey);
/**
* @param foreignKey the foreign key for which to retrieve the {@link EntitySearchModel}
* @return the {@link EntitySearchModel} associated with the {@code foreignKey}, if no search model
* has been initialized for the given foreign key, a new one is created, associated with the foreign key and returned.
*/
EntitySearchModel foreignKeySearchModel(ForeignKey foreignKey);
/**
* Returns the {@link Value} instance controlling the default value supplier for the given attribute.
* Used when the underlying value is not persistent. Use {@link #defaults()} or {@link #set(Entity)}
* with a null parameter to populate the model with the default values.
* @param attribute the attribute
* @param the value supplier type
* @param the value type
* @return the {@link Value} instance controlling the default value supplier
* @see #persist(Attribute)
*/
, T> Value defaultValue(Attribute attribute);
/**
* @return a state controlling whether this edit model posts insert, update and delete events
* on the {@link EntityEditEvents} event bus.
* @see #POST_EDIT_EVENTS
*/
State postEditEvents();
/**
* Returns a State controlling whether the last used value for this attribute should persist when the model is cleared.
* @param attribute the attribute
* @return a State controlling whether the given attribute value should persist when the model is cleared
* @see EntityEditModel#PERSIST_FOREIGN_KEYS
*/
State persist(Attribute> attribute);
/**
* Note: This method must be called on the UI thread in case a panel has been based on this model.
* Performs an insert on the active entity, sets the primary key values of the active entity
* according to the primary key of the inserted entity
* @return the inserted entity
* @throws DatabaseException in case of a database exception
* @throws ValidationException in case validation fails
* @throws IllegalStateException in case inserting is not enabled
* @see EntityValidator#validate(Entity)
*/
Entity insert() throws DatabaseException, ValidationException;
/**
* Note: This method must be called on the UI thread in case a panel has been based on this model.
* Performs an insert on the given entities.
* @param entities the entities to insert
* @return a list containing the inserted entities
* @throws DatabaseException in case of a database exception
* @throws ValidationException in case validation fails
* @throws IllegalStateException in case inserting is not enabled
* @see #beforeInsertEvent()
* @see #afterInsertEvent()
* @see EntityValidator#validate(Entity)
*/
Collection insert(Collection entities) throws DatabaseException, ValidationException;
/**
* Note: This method must be called on the UI thread in case a panel has been based on this model.
* Performs an update on the active entity
* @return the updated entity
* @throws DatabaseException in case of a database exception
* @throws is.codion.common.db.exception.RecordModifiedException in case the entity has been modified since it was loaded
* @throws ValidationException in case validation fails
* @throws IllegalStateException in case updating is not enabled
* @throws is.codion.common.db.exception.UpdateException in case the active entity is not modified
* @see EntityValidator#validate(Entity)
*/
Entity update() throws DatabaseException, ValidationException;
/**
* Note: This method must be called on the UI thread in case a panel has been based on this model.
* Updates the given entities.
* @param entities the entities to update
* @return the updated entities
* @throws DatabaseException in case of a database exception
* @throws is.codion.common.db.exception.RecordModifiedException in case an entity has been modified since it was loaded
* @throws ValidationException in case validation fails
* @throws IllegalStateException in case updating is not enabled
* @see #beforeUpdateEvent()
* @see #afterUpdateEvent()
* @see EntityValidator#validate(Entity)
*/
Collection update(Collection entities) throws DatabaseException, ValidationException;
/**
* Note: This method must be called on the UI thread in case a panel has been based on this model.
* @return the deleted entity
* @throws DatabaseException in case of a database exception
* @throws IllegalStateException in case deleting is not enabled
* @see #beforeDeleteEvent()
* @see #afterDeleteEvent()
*/
Entity delete() throws DatabaseException;
/**
* Note: This method must be called on the UI thread in case a panel has been based on this model.
* @param entities the entities to delete
* @return the deleted entities
* @throws DatabaseException in case of a database exception
* @throws IllegalStateException in case deleting is not enabled
* @see #beforeDeleteEvent()
* @see #afterDeleteEvent()
*/
Collection delete(Collection entities) throws DatabaseException;
/**
* Creates a new {@link Insert} instance for inserting the active entity.
* @return a new {@link Insert} instance
* @throws ValidationException in case validation fails
*/
Insert createInsert() throws ValidationException;
/**
* Creates a new {@link Insert} instance for inserting the given entities.
* @param entities the entities to insert
* @return a new {@link Insert} instance
* @throws ValidationException in case validation fails
*/
Insert createInsert(Collection entities) throws ValidationException;
/**
* Creates a new {@link Update} instance for updating the active entity.
* @return a new {@link Update} instance
* @throws IllegalArgumentException in case the active entity is unmodified
* @throws ValidationException in case validation fails
*/
Update createUpdate() throws ValidationException;
/**
* Creates a new {@link Update} instance for updating the given entities.
* @param entities the entities to update
* @return a new {@link Update} instance
* @throws IllegalArgumentException in case any of the given entities are unmodified
* @throws ValidationException in case validation fails
*/
Update createUpdate(Collection entities) throws ValidationException;
/**
* Creates a new {@link Delete} instance for deleting the active entity.
* @return a new {@link Delete} instance
*/
Delete createDelete();
/**
* Creates a new {@link Delete} instance for deleting the given entities.
* @param entities the entities to delete
* @return a new {@link Delete} instance
*/
Delete createDelete(Collection entities);
/**
* Adds the given entities to all foreign key models based on that entity type
* @param foreignKey the foreign key
* @param entities the values
*/
void add(ForeignKey foreignKey, Collection entities);
/**
* Removes the given entities from all foreign key models based on that entity type and clears any foreign
* key values referencing them.
* @param foreignKey the foreign key
* @param entities the values
*/
void remove(ForeignKey foreignKey, Collection entities);
/**
* For every field referencing the given foreign key values, replaces that foreign key instance with
* the corresponding entity from {@code entities}, useful when attribute
* values have been changed in the referenced entity that must be reflected in the edit model.
* @param foreignKey the foreign key
* @param entities the foreign key entities
*/
void replace(ForeignKey foreignKey, Collection entities);
/**
* Validates the value associated with the given attribute, using the underlying validator.
* @param attribute the attribute the value is associated with
* @throws ValidationException if the given value is not valid for the given attribute
*/
void validate(Attribute> attribute) throws ValidationException;
/**
* Validates the current state of the entity
* @throws ValidationException in case the entity is invalid
*/
void validate() throws ValidationException;
/**
* Validates the given entities, using the underlying validator.
* For entities of a type other than this edit model is based on,
* their respective validators are used.
* @param entities the entities to validate
* @throws ValidationException on finding the first invalid entity
* @see EntityDefinition#validator()
*/
void validate(Collection entities) throws ValidationException;
/**
* Validates the given entity, using the underlying validator.
* For entities of a type other than this edit model is based on,
* their respective validators are used.
* @param entity the entity to validate
* @throws ValidationException in case the entity is invalid
* @throws NullPointerException in case the entity is null
*/
void validate(Entity entity) throws ValidationException;
/**
* @return a {@link StateObserver} indicating the valid status of the underlying Entity.
* @see #validate(Attribute)
* @see EntityValidator#validate(Entity)
*/
StateObserver valid();
/**
* @param attribute the attribute
* @return a {@link StateObserver} indicating the valid status of the given attribute.
*/
StateObserver valid(Attribute> attribute);
/**
* Returns a {@link StateObserver} indicating when and if any values in the underlying Entity have been modified.
* @return a {@link StateObserver} indicating the modified state of this edit model
*/
StateObserver modified();
/**
* Returns a {@link StateObserver} instance indicating whether the value of the given attribute has been modified.
* @param attribute the attribute
* @return a {@link StateObserver} indicating the modified state of the value of the given attribute
* @throws IllegalArgumentException in case attribute is not part of the underlying entity
* @see #modified()
*/
StateObserver modified(Attribute> attribute);
/**
* @return a {@link StateObserver} indicating whether the active entity exists in the database
*/
StateObserver exists();
/**
* @return a {@link StateObserver} indicating whether the active entity exists and is modified
* @see #modified()
* @see #exists()
*/
StateObserver editing();
/**
* @return a {@link StateObserver} indicating whether the primary key of the active entity is null
*/
StateObserver primaryKeyNull();
/**
* Returns an observer notified each time the value associated with the given attribute is edited via
* {@link #put(Attribute, Object)} or {@link #remove(Attribute)}, note that this event is only fired
* if the value actually changes.
* @param attribute the attribute which edit observer to return
* @param the value type
* @return an observer for the given attribute value edits
*/
EventObserver editEvent(Attribute attribute);
/**
* Returns an observer notified each time the value associated with the given attribute changes, either
* via editing or when the active entity is set.
* @param attribute the attribute which value observer to return
* @param the value type
* @return an observer for the given attribute value changes
* @see #set(Entity)
*/
EventObserver valueEvent(Attribute attribute);
/**
* @return an observer for attribute value changes
*/
EventObserver> valueEvent();
/**
* @return an observer notified each time the entity is set via {@link #set(Entity)} or {@link #defaults()}.
* @see #set(Entity)
* @see #defaults()
*/
EventObserver entityEvent();
/**
* @return an observer notified each time the active entity is about to be set
* @see #set(Entity)
* @see #defaults()
*/
EventObserver beforeEntityEvent();
/**
* @return an observer notified before an insert is performed
*/
EventObserver> beforeInsertEvent();
/**
* @return an observer notified after an insert is performed
*/
EventObserver> afterInsertEvent();
/**
* @return an observer notified before an update is performed
*/
EventObserver
© 2015 - 2025 Weber Informatics LLC | Privacy Policy