Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ else if ( method.equals( setIdentifierMethod ) ) {

// otherwise:
return INVOKE_IMPLEMENTATION;

}

private Object getReplacement() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.query.assignment;


import jakarta.persistence.metamodel.SingularAttribute;
import org.hibernate.Incubating;
import org.hibernate.query.restriction.Path;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;

/**
* An assignment to a field or property of an entity or embeddable.
*
* @param <T> The target entity type of the assignment
*
* @since 7.2
*
* @author Gavin King
*/
@Incubating
public interface Assignment<T> {

/**
* An assigment of the given literal value to the given attribute
* of the root entity.
*/
static <T,X> Assignment<T> set(SingularAttribute<T,X> attribute, X value) {
return new AttributeAssignment<>( attribute, value );
}

/**
* An assigment of the given literal value to the entity or embeddable
* field or property identified by the given path from the root entity.
*/
static <T,X> Assignment<T> set(Path<T,X> path, X value) {
return new PathAssignment<>( path, value );
}

/**
* An assigment of the entity or embeddable field or property identified
* by the given path from the root entity to the given attribute of the
* root entity.
*/
static <T,X> Assignment<T> set(SingularAttribute<T,X> attribute, Path<T,X> value) {
return new PathToAttributeAssignment<>( attribute, value );
}

/**
* An assigment of one entity or embeddable field or property to another
* entity or embeddable field or property, each identified by a given path
* from the root entity.
*/
static <T,X> Assignment<T> set(Path<T,X> path, Path<T,X> value) {
return new PathToPathAssignment<>( path, value );
}

void apply(SqmUpdateStatement<? extends T> update);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.query.assignment;

import jakarta.persistence.metamodel.SingularAttribute;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;

/**
* Assignment of a value to an attribute.
*
* @author Gavin King
*/
record AttributeAssignment<T, X>(SingularAttribute<T, X> attribute, X value)
implements Assignment<T> {
@Override
public void apply(SqmUpdateStatement<? extends T> update) {
update.set( attribute, value );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.query.assignment;

import org.hibernate.query.restriction.Path;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;

/**
* Assignment of a value to a path.
*
* @author Gavin King
*/
record PathAssignment<T, X>(Path<T, X> path, X value)
implements Assignment<T> {
@Override
public void apply(SqmUpdateStatement<? extends T> update) {
update.set( path.path( update.getRoot() ), value );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.query.assignment;

import jakarta.persistence.metamodel.SingularAttribute;
import org.hibernate.query.restriction.Path;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;

/**
* Assignment of a path to an attribute.
*
* @author Gavin King
*/
record PathToAttributeAssignment<T, X>(SingularAttribute<T, X> attribute, Path<T,X> value)
implements Assignment<T> {
@Override
public void apply(SqmUpdateStatement<? extends T> update) {
update.set( attribute, value.path( update.getRoot() ) );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.query.assignment;

import org.hibernate.query.restriction.Path;
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;

/**
* * Assignment of a path to a path.
*
* @author Gavin King
*/
record PathToPathAssignment<T, X>(Path<T, X> path, Path<T,X> value)
implements Assignment<T> {
@Override
public void apply(SqmUpdateStatement<? extends T> update) {
update.set( path.path( update.getRoot() ), value.path( update.getRoot() ) );
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* Support for {@linkplain org.hibernate.query.assignment.Assignment assignment}
* with {@link org.hibernate.query.specification.MutationSpecification}.
*
* @since 7.2
*/
@Incubating
package org.hibernate.query.assignment;

import org.hibernate.Incubating;
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.query.specification;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaDelete;
import org.hibernate.Incubating;
import org.hibernate.query.restriction.Restriction;
import org.hibernate.query.specification.internal.DeleteSpecificationImpl;

/**
* Specialization of {@link MutationSpecification} for programmatic customization
* of delete queries.
* <p>
*
* @param <T> The entity type which is the target of the mutation.
*
* @author Gavin King
*
* @since 7.2
*/
@Incubating
public interface DeleteSpecification<T> extends MutationSpecification<T> {
@Override
DeleteSpecification<T> restrict(Restriction<? super T> restriction);

@Override
DeleteSpecification<T> augment(Augmentation<T> augmentation);

@Override
DeleteSpecification<T> validate(CriteriaBuilder builder);

/**
* Returns a specification reference which can be used to programmatically,
* iteratively build a {@linkplain org.hibernate.query.MutationQuery} which
* deletes the given entity type.
*
* @param targetEntityClass The target entity type
*
* @param <T> The root entity type for the mutation (the "target").
*/
static <T> DeleteSpecification<T> create(Class<T> targetEntityClass) {
return new DeleteSpecificationImpl<>( targetEntityClass );
}

/**
* Returns a specification reference which can be used to programmatically,
* iteratively build a {@linkplain org.hibernate.query.MutationQuery} based
* on the given criteria delete, allowing the addition of
* {@linkplain #restrict restrictions}.
*
* @param criteriaDelete The criteria delete query
*
* @param <T> The root entity type for the mutation (the "target").
*/
static <T> DeleteSpecification<T> create(CriteriaDelete<T> criteriaDelete) {
return new DeleteSpecificationImpl<>( criteriaDelete );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ static <T> MutationSpecification<T> create(Class<T> mutationTarget, String hql)
* @param criteriaUpdate The criteria update query
*
* @param <T> The root entity type for the mutation (the "target").
*
* @see UpdateSpecification#create(CriteriaUpdate)
*/
static <T> MutationSpecification<T> create(CriteriaUpdate<T> criteriaUpdate) {
return new MutationSpecificationImpl<>( criteriaUpdate );
Expand All @@ -127,6 +129,8 @@ static <T> MutationSpecification<T> create(CriteriaUpdate<T> criteriaUpdate) {
* @param criteriaDelete The criteria delete query
*
* @param <T> The root entity type for the mutation (the "target").
*
* @see DeleteSpecification#create(CriteriaDelete)
*/
static <T> MutationSpecification<T> create(CriteriaDelete<T> criteriaDelete) {
return new MutationSpecificationImpl<>( criteriaDelete );
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.query.specification;

import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQueryReference;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.metamodel.SingularAttribute;
import org.hibernate.Incubating;
import org.hibernate.Session;
import org.hibernate.StatelessSession;
import org.hibernate.query.SelectionQuery;
import org.hibernate.query.restriction.Path;
import org.hibernate.query.specification.internal.ProjectionSpecificationImpl;

import java.util.function.Function;

/**
* Allows a {@link SelectionSpecification} to be augmented with the specification
* of a projection list.
* <pre>
* var specification =
* SelectionSpecification.create(Book.class)
* .restrict(Restriction.contains(Book_.title, "hibernate", false))
* .sort(Order.desc(Book_.title));
* var projection = ProjectionSpecification.create(specification);
* var bookIsbn = projection.select(Book_.isbn);
* var bookTitle = projection.select(Book_.title);
* var results = projection.createQuery(session).getResultList();
* for (var result : results) {
* var isbn = bookIsbn.in(result);
* var title = bookTitle.in(result);
* ...
* }
* </pre>
* <p>
* A {@code ProjectionSpecification} always results in a query which with result
* type {@code Object[]}. The {@link #select(SingularAttribute) select()} methods
* return {@link Element}, allowing easy and typesafe access to the elements of
* the returned array.
*
* @param <T> The result type of the {@link SelectionSpecification}
*
* @since 7.2
*
* @apiNote This interface marked {@link Incubating} is considered experimental.
* Changes to the API defined here are fully expected in future releases.
*
* @author Gavin King
*/
@Incubating
public interface ProjectionSpecification<T> extends QuerySpecification<Object[]> {

/**
* Create a new {@code ProjectionSpecification} which augments the given
* {@link SelectionSpecification}.
*/
static <T> ProjectionSpecification<T> create(SelectionSpecification<T> selectionSpecification) {
return new ProjectionSpecificationImpl<>( selectionSpecification );
}

/**
* Allows typesafe access to elements of the {@code Object[]}
* arrays returned by the query.
*
* @param <X> The type of the element of the projection list
*/
@FunctionalInterface
interface Element<X> extends Function<Object[],X> {
X in(Object[] tuple);

@Override
default X apply(Object[] tuple) {
return in(tuple);
}
}

/**
* Select the given attribute of the root entity.
*
* @param attribute An attribute of the root entity
* @return An {@link Element} allowing typesafe access to the results
*/
<X> Element<X> select(SingularAttribute<T,X> attribute);

/**
* Select the given field or property identified by the given path
* from of the root entity.
*
* @param path A path from the root entity
* @return An {@link Element} allowing typesafe access to the results
*/
<X> Element<X> select(Path<T,X> path);

@Override
SelectionQuery<Object[]> createQuery(Session session);

@Override
SelectionQuery<Object[]> createQuery(StatelessSession session);

@Override
SelectionQuery<Object[]> createQuery(EntityManager entityManager);

@Override
CriteriaQuery<Object[]> buildCriteria(CriteriaBuilder builder);

@Override
TypedQueryReference<Object[]> reference();

@Override
ProjectionSpecification<T> validate(CriteriaBuilder builder);
}
Loading