All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.data.relational.core.conversion.DbAction Maven / Gradle / Ivy

There is a newer version: 3.3.4
Show newest version
/*
 * Copyright 2018-2022 the original author or authors.
 *
 * 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
 *
 *      https://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 org.springframework.data.relational.core.conversion;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.springframework.data.mapping.PersistentPropertyPath;
import org.springframework.data.relational.core.mapping.RelationalPersistentProperty;
import org.springframework.data.util.Pair;
import org.springframework.lang.Nullable;

/**
 * An instance of this interface represents a (conceptual) single interaction with a database, e.g. a single update,
 * used as a step when synchronizing the state of an aggregate with the database.
 *
 * @param  the type of the entity that is affected by this action.
 * @author Jens Schauder
 * @author Mark Paluch
 * @author Tyler Van Gorder
 * @author Myeonghyeon Lee
 */
public interface DbAction {

	Class getEntityType();

	/**
	 * Represents an insert statement for a single entity that is not the root of an aggregate.
	 *
	 * @param  type of the entity for which this represents a database interaction.
	 */
	class Insert implements WithGeneratedId, WithDependingOn {

		private final T entity;
		private final PersistentPropertyPath propertyPath;
		private final WithEntity dependingOn;

		final Map, Object> qualifiers;

		public Insert(T entity, PersistentPropertyPath propertyPath,
				WithEntity dependingOn, Map, Object> qualifiers) {

			this.entity = entity;
			this.propertyPath = propertyPath;
			this.dependingOn = dependingOn;
			this.qualifiers = Collections.unmodifiableMap(new HashMap<>(qualifiers));
		}

		@Override
		public Class getEntityType() {
			return WithDependingOn.super.getEntityType();
		}

		public T getEntity() {
			return this.entity;
		}

		public PersistentPropertyPath getPropertyPath() {
			return this.propertyPath;
		}

		public DbAction.WithEntity getDependingOn() {
			return this.dependingOn;
		}

		public Map, Object> getQualifiers() {
			return this.qualifiers;
		}

		public String toString() {
			return "DbAction.Insert(entity=" + this.getEntity() + ", propertyPath=" + this.getPropertyPath()
					+ ", dependingOn=" + this.getDependingOn() + ", qualifiers=" + this.getQualifiers() + ")";
		}
	}

	/**
	 * Represents an insert statement for the root of an aggregate. Upon a successful insert, the initial version and
	 * generated ids are populated.
	 *
	 * @param  type of the entity for which this represents a database interaction.
	 */
	class InsertRoot implements WithGeneratedId {

		private final T entity;

		public InsertRoot(T entity) {
			this.entity = entity;
		}

		public T getEntity() {
			return this.entity;
		}

		public String toString() {
			return "DbAction.InsertRoot(entity=" + this.getEntity() + ")";
		}
	}

	/**
	 * Represents an update statement for a single entity that is not the root of an aggregate.
	 *
	 * @param  type of the entity for which this represents a database interaction.
	 */
	final class Update implements WithEntity {

		private final T entity;
		private final PersistentPropertyPath propertyPath;

		public Update(T entity, PersistentPropertyPath propertyPath) {
			this.entity = entity;
			this.propertyPath = propertyPath;
		}

		public T getEntity() {
			return this.entity;
		}

		public PersistentPropertyPath getPropertyPath() {
			return this.propertyPath;
		}

		public String toString() {
			return "DbAction.Update(entity=" + this.getEntity() + ", propertyPath=" + this.getPropertyPath() + ")";
		}
	}

	/**
	 * Represents an update statement for the aggregate root.
	 *
	 * @param  type of the entity for which this represents a database interaction.
	 */
	class UpdateRoot implements WithEntity {

		private final T entity;

		public UpdateRoot(T entity) {
			this.entity = entity;
		}

		public T getEntity() {
			return this.entity;
		}

		public String toString() {
			return "DbAction.UpdateRoot(entity=" + this.getEntity() + ")";
		}
	}

	/**
	 * Represents a merge statement for a single entity that is not the root of an aggregate.
	 *
	 * @param  type of the entity for which this represents a database interaction.
	 */
	final class Merge implements WithDependingOn, WithPropertyPath {

		private final T entity;
		private final PersistentPropertyPath propertyPath;
		private final WithEntity dependingOn;

		private final Map, Object> qualifiers = Collections.emptyMap();

		public Merge(T entity, PersistentPropertyPath propertyPath,
				WithEntity dependingOn) {
			this.entity = entity;
			this.propertyPath = propertyPath;
			this.dependingOn = dependingOn;
		}

		public T getEntity() {
			return this.entity;
		}

		public PersistentPropertyPath getPropertyPath() {
			return this.propertyPath;
		}

		public DbAction.WithEntity getDependingOn() {
			return this.dependingOn;
		}

		public Map, Object> getQualifiers() {
			return this.qualifiers;
		}

		public String toString() {
			return "DbAction.Merge(entity=" + this.getEntity() + ", propertyPath=" + this.getPropertyPath() + ", dependingOn="
					+ this.getDependingOn() + ", qualifiers=" + this.getQualifiers() + ")";
		}
	}

	/**
	 * Represents a delete statement for all entities that that a reachable via a give path from the aggregate root.
	 *
	 * @param  type of the entity for which this represents a database interaction.
	 */
	final class Delete implements WithPropertyPath {

		private final Object rootId;

		private final PersistentPropertyPath propertyPath;

		public Delete(Object rootId, PersistentPropertyPath propertyPath) {
			this.rootId = rootId;
			this.propertyPath = propertyPath;
		}

		public Object getRootId() {
			return this.rootId;
		}

		public PersistentPropertyPath getPropertyPath() {
			return this.propertyPath;
		}

		public String toString() {
			return "DbAction.Delete(rootId=" + this.getRootId() + ", propertyPath=" + this.getPropertyPath() + ")";
		}
	}

	/**
	 * Represents a delete statement for a aggregate root when only the ID is known.
	 * 

* Note that deletes for contained entities that reference the root are to be represented by separate * {@link DbAction}s. * * @param type of the entity for which this represents a database interaction. */ final class DeleteRoot implements DbAction { private final Object id; private final Class entityType; @Nullable private final Number previousVersion; public DeleteRoot(Object id, Class entityType, @Nullable Number previousVersion) { this.id = id; this.entityType = entityType; this.previousVersion = previousVersion; } public Object getId() { return this.id; } public Class getEntityType() { return this.entityType; } @Nullable public Number getPreviousVersion() { return this.previousVersion; } public String toString() { return "DbAction.DeleteRoot(id=" + this.getId() + ", entityType=" + this.getEntityType() + ", previousVersion=" + this.getPreviousVersion() + ")"; } } /** * Represents an delete statement for all entities that that a reachable via a give path from any aggregate root of a * given type. * * @param type of the entity for which this represents a database interaction. */ final class DeleteAll implements WithPropertyPath { private final PersistentPropertyPath propertyPath; public DeleteAll(PersistentPropertyPath propertyPath) { this.propertyPath = propertyPath; } public PersistentPropertyPath getPropertyPath() { return this.propertyPath; } public String toString() { return "DbAction.DeleteAll(propertyPath=" + this.getPropertyPath() + ")"; } } /** * Represents a delete statement for all aggregate roots of a given type. *

* Note that deletes for contained entities that reference the root are to be represented by separate * {@link DbAction}s. * * @param type of the entity for which this represents a database interaction. */ final class DeleteAllRoot implements DbAction { private final Class entityType; public DeleteAllRoot(Class entityType) { this.entityType = entityType; } public Class getEntityType() { return this.entityType; } public String toString() { return "DbAction.DeleteAllRoot(entityType=" + this.getEntityType() + ")"; } } /** * Represents an acquire lock statement for a aggregate root when only the ID is known. *

* * @param type of the entity for which this represents a database interaction. */ final class AcquireLockRoot implements DbAction { private final Object id; private final Class entityType; AcquireLockRoot(Object id, Class entityType) { this.id = id; this.entityType = entityType; } public Object getId() { return this.id; } public Class getEntityType() { return this.entityType; } public String toString() { return "DbAction.AcquireLockRoot(id=" + this.getId() + ", entityType=" + this.getEntityType() + ")"; } } /** * Represents an acquire lock statement for all aggregate roots of a given type. * * @param type of the entity for which this represents a database interaction. */ final class AcquireLockAllRoot implements DbAction { private final Class entityType; AcquireLockAllRoot(Class entityType) { this.entityType = entityType; } public Class getEntityType() { return this.entityType; } public String toString() { return "DbAction.AcquireLockAllRoot(entityType=" + this.getEntityType() + ")"; } } /** * An action depending on another action for providing additional information like the id of a parent entity. * * @author Jens Schauder */ interface WithDependingOn extends WithPropertyPath, WithEntity { /** * The {@link DbAction} of a parent entity, possibly the aggregate root. This is used to obtain values needed to * persist the entity, that are not part of the current entity, especially the id of the parent, which might only * become available once the parent entity got persisted. * * @return guaranteed to be not {@code null}. * @see #getQualifiers() */ WithEntity getDependingOn(); /** * Additional values to be set during insert or update statements. *

* Values come from parent entities but one might also add values manually. * * @return guaranteed to be not {@code null}. */ Map, Object> getQualifiers(); // TODO: Encapsulate propertyPath and qualifier in object: PropertyPathWithListIndex, // PropertyPathWithMapIndex, PropertyPathInSet, PropertyPathWithoutQualifier // Probably we need better names. @Nullable default Pair, Object> getQualifier() { Map, Object> qualifiers = getQualifiers(); if (qualifiers.size() == 0) return null; if (qualifiers.size() > 1) { throw new IllegalStateException("Can't handle more then one qualifier"); } Map.Entry, Object> entry = qualifiers.entrySet().iterator() .next(); if (entry.getValue() == null) { return null; } return Pair.of(entry.getKey(), entry.getValue()); } @Override default Class getEntityType() { return WithEntity.super.getEntityType(); } } /** * A {@link DbAction} that stores the information of a single entity in the database. * * @author Jens Schauder */ interface WithEntity extends DbAction { /** * @return the entity to persist. Guaranteed to be not {@code null}. */ T getEntity(); @SuppressWarnings("unchecked") @Override default Class getEntityType() { return (Class) getEntity().getClass(); } } /** * A {@link DbAction} that may "update" its entity. In order to support immutable entities this requires at least * potentially creating a new instance, which this interface makes available. * * @author Jens Schauder */ interface WithGeneratedId extends WithEntity { @SuppressWarnings("unchecked") @Override default Class getEntityType() { return (Class) getEntity().getClass(); } } /** * A {@link DbAction} not operation on the root of an aggregate but on its contained entities. * * @author Jens Schauder */ interface WithPropertyPath extends DbAction { /** * @return the path from the aggregate root to the affected entity */ PersistentPropertyPath getPropertyPath(); @SuppressWarnings("unchecked") @Override default Class getEntityType() { return (Class) getPropertyPath().getRequiredLeafProperty().getActualType(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy