Skip to content

Commit 15c4313

Browse files
committed
introduce UpdateSpecification, DeleteSpecification for typesafety
because assign() only makes sense for updates
1 parent 68dd166 commit 15c4313

File tree

7 files changed

+291
-62
lines changed

7 files changed

+291
-62
lines changed
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.query.specification;
6+
7+
import jakarta.persistence.criteria.CriteriaBuilder;
8+
import jakarta.persistence.criteria.CriteriaDelete;
9+
import org.hibernate.Incubating;
10+
import org.hibernate.query.restriction.Restriction;
11+
import org.hibernate.query.specification.internal.DeleteSpecificationImpl;
12+
13+
/**
14+
* Specialization of {@link MutationSpecification} for programmatic customization
15+
* of delete queries.
16+
* <p>
17+
*
18+
* @param <T> The entity type which is the target of the mutation.
19+
*
20+
* @author Gavin King
21+
*
22+
* @since 7.2
23+
*/
24+
@Incubating
25+
public interface DeleteSpecification<T> extends MutationSpecification<T> {
26+
@Override
27+
DeleteSpecification<T> restrict(Restriction<? super T> restriction);
28+
29+
@Override
30+
DeleteSpecification<T> augment(Augmentation<T> augmentation);
31+
32+
@Override
33+
DeleteSpecification<T> validate(CriteriaBuilder builder);
34+
35+
/**
36+
* Returns a specification reference which can be used to programmatically,
37+
* iteratively build a {@linkplain org.hibernate.query.MutationQuery} which
38+
* deletes the given entity type.
39+
*
40+
* @param targetEntityClass The target entity type
41+
*
42+
* @param <T> The root entity type for the mutation (the "target").
43+
*/
44+
static <T> DeleteSpecification<T> create(Class<T> targetEntityClass) {
45+
return new DeleteSpecificationImpl<>( targetEntityClass );
46+
}
47+
48+
/**
49+
* Returns a specification reference which can be used to programmatically,
50+
* iteratively build a {@linkplain org.hibernate.query.MutationQuery} based
51+
* on the given criteria delete, allowing the addition of
52+
* {@linkplain #restrict restrictions}.
53+
*
54+
* @param criteriaDelete The criteria delete query
55+
*
56+
* @param <T> The root entity type for the mutation (the "target").
57+
*/
58+
static <T> DeleteSpecification<T> create(CriteriaDelete<T> criteriaDelete) {
59+
return new DeleteSpecificationImpl<>( criteriaDelete );
60+
}
61+
}

hibernate-core/src/main/java/org/hibernate/query/specification/MutationSpecification.java

Lines changed: 4 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@
1616
import org.hibernate.StatelessSession;
1717
import org.hibernate.query.IllegalMutationQueryException;
1818
import org.hibernate.query.MutationQuery;
19-
import org.hibernate.query.assignment.Assignment;
2019
import org.hibernate.query.specification.internal.MutationSpecificationImpl;
21-
import org.hibernate.query.specification.internal.MutationSpecificationImpl.MutationType;
2220
import org.hibernate.query.restriction.Restriction;
2321

2422
/**
@@ -53,20 +51,6 @@ public interface MutationSpecification<T> extends QuerySpecification<T> {
5351
@Override
5452
MutationSpecification<T> restrict(Restriction<? super T> restriction);
5553

56-
/**
57-
* If this {@code MutationSpecification} represents an {@code update}
58-
* statement, add an assigment to a field or property of the target
59-
* entity.
60-
*
61-
* @param assignment The assignment to add
62-
*
63-
* @return {@code this} for method chaining.
64-
*
65-
* @since 7.2
66-
*/
67-
@Incubating
68-
MutationSpecification<T> assign(Assignment<? super T> assignment);
69-
7054
/**
7155
* A function capable of modifying or augmenting a criteria query.
7256
*
@@ -130,6 +114,8 @@ static <T> MutationSpecification<T> create(Class<T> mutationTarget, String hql)
130114
* @param criteriaUpdate The criteria update query
131115
*
132116
* @param <T> The root entity type for the mutation (the "target").
117+
*
118+
* @see UpdateSpecification#create(CriteriaUpdate)
133119
*/
134120
static <T> MutationSpecification<T> create(CriteriaUpdate<T> criteriaUpdate) {
135121
return new MutationSpecificationImpl<>( criteriaUpdate );
@@ -143,34 +129,10 @@ static <T> MutationSpecification<T> create(CriteriaUpdate<T> criteriaUpdate) {
143129
* @param criteriaDelete The criteria delete query
144130
*
145131
* @param <T> The root entity type for the mutation (the "target").
132+
*
133+
* @see DeleteSpecification#create(CriteriaDelete)
146134
*/
147135
static <T> MutationSpecification<T> create(CriteriaDelete<T> criteriaDelete) {
148136
return new MutationSpecificationImpl<>( criteriaDelete );
149137
}
150-
151-
/**
152-
* Returns a specification reference which can be used to programmatically,
153-
* iteratively build a {@linkplain MutationQuery} which updates the given
154-
* entity type..
155-
*
156-
* @param targetEntityClass The target entity type
157-
*
158-
* @param <T> The root entity type for the mutation (the "target").
159-
*/
160-
static <T> MutationSpecification<T> createUpdate(Class<T> targetEntityClass) {
161-
return new MutationSpecificationImpl<>( MutationType.UPDATE, targetEntityClass );
162-
}
163-
164-
/**
165-
* Returns a specification reference which can be used to programmatically,
166-
* iteratively build a {@linkplain MutationQuery} which deletes the given
167-
* entity type.
168-
*
169-
* @param targetEntityClass The target entity type
170-
*
171-
* @param <T> The root entity type for the mutation (the "target").
172-
*/
173-
static <T> MutationSpecification<T> createDelete(Class<T> targetEntityClass) {
174-
return new MutationSpecificationImpl<>( MutationType.DELETE, targetEntityClass );
175-
}
176138
}
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.query.specification;
6+
7+
import jakarta.persistence.criteria.CriteriaBuilder;
8+
import jakarta.persistence.criteria.CriteriaUpdate;
9+
import org.hibernate.Incubating;
10+
import org.hibernate.query.assignment.Assignment;
11+
import org.hibernate.query.restriction.Restriction;
12+
import org.hibernate.query.specification.internal.UpdateSpecificationImpl;
13+
14+
/**
15+
* Specialization of {@link MutationSpecification} for programmatic customization
16+
* of update queries.
17+
* <p>
18+
* The method {@link #assign(Assignment)} allows application of additional
19+
* {@linkplain Assignment assignments} to the mutated entity. The static factory
20+
* methods of {@link Assignment} are used to express assignments to attributes
21+
* or compound paths.
22+
* <pre>
23+
* UpdateSpecification.create(Book.class)
24+
* .assign(Assignment.set(Book_.title, newTitle))
25+
* .restrict(Restriction.equal(Book_.isbn, isbn))
26+
* .createQuery(session)
27+
* .executeUpdate();
28+
* </pre>
29+
*
30+
* @param <T> The entity type which is the target of the mutation.
31+
*
32+
* @author Gavin King
33+
*
34+
* @since 7.2
35+
*/
36+
@Incubating
37+
public interface UpdateSpecification<T> extends MutationSpecification<T> {
38+
/**
39+
* If this {@code MutationSpecification} represents an {@code update}
40+
* statement, add an assigment to a field or property of the target
41+
* entity.
42+
*
43+
* @param assignment The assignment to add
44+
*
45+
* @return {@code this} for method chaining.
46+
*
47+
* @since 7.2
48+
*/
49+
UpdateSpecification<T> assign(Assignment<? super T> assignment);
50+
51+
@Override
52+
UpdateSpecification<T> restrict(Restriction<? super T> restriction);
53+
54+
@Override
55+
UpdateSpecification<T> augment(Augmentation<T> augmentation);
56+
57+
@Override
58+
UpdateSpecification<T> validate(CriteriaBuilder builder);
59+
60+
/**
61+
* Returns a specification reference which can be used to programmatically,
62+
* iteratively build a {@linkplain org.hibernate.query.MutationQuery} which
63+
* updates the given entity type.
64+
*
65+
* @param targetEntityClass The target entity type
66+
*
67+
* @param <T> The root entity type for the mutation (the "target").
68+
*/
69+
static <T> UpdateSpecification<T> create(Class<T> targetEntityClass) {
70+
return new UpdateSpecificationImpl<>( targetEntityClass );
71+
}
72+
73+
/**
74+
* Returns a specification reference which can be used to programmatically,
75+
* iteratively build a {@linkplain org.hibernate.query.MutationQuery} based
76+
* on the given criteria update, allowing the addition of
77+
* {@linkplain #restrict restrictions} and {@linkplain #assign assignments}.
78+
*
79+
* @param criteriaUpdate The criteria update query
80+
*
81+
* @param <T> The root entity type for the mutation (the "target").
82+
*/
83+
static <T> UpdateSpecification<T> create(CriteriaUpdate<T> criteriaUpdate) {
84+
return new UpdateSpecificationImpl<>( criteriaUpdate );
85+
}
86+
87+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.query.specification.internal;
6+
7+
import jakarta.persistence.criteria.CriteriaBuilder;
8+
import jakarta.persistence.criteria.CriteriaDelete;
9+
import org.hibernate.query.restriction.Restriction;
10+
import org.hibernate.query.specification.DeleteSpecification;
11+
12+
/**
13+
* @author Gavin King
14+
*/
15+
public class DeleteSpecificationImpl<T>
16+
extends MutationSpecificationImpl<T>
17+
implements DeleteSpecification<T> {
18+
19+
public DeleteSpecificationImpl(Class<T> mutationTarget) {
20+
super( MutationType.DELETE, mutationTarget );
21+
}
22+
23+
public DeleteSpecificationImpl(CriteriaDelete<T> criteriaQuery) {
24+
super( criteriaQuery );
25+
}
26+
27+
@Override
28+
public DeleteSpecification<T> restrict(Restriction<? super T> restriction) {
29+
super.restrict( restriction );
30+
return this;
31+
}
32+
33+
@Override
34+
public DeleteSpecification<T> augment(Augmentation<T> augmentation) {
35+
super.augment( augmentation );
36+
return this;
37+
}
38+
39+
@Override
40+
public DeleteSpecification<T> validate(CriteriaBuilder builder) {
41+
super.validate( builder );
42+
return this;
43+
}
44+
}

hibernate-core/src/main/java/org/hibernate/query/specification/internal/MutationSpecificationImpl.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
import org.hibernate.SharedSessionContract;
1717
import org.hibernate.StatelessSession;
1818
import org.hibernate.engine.spi.SharedSessionContractImplementor;
19-
import org.hibernate.query.assignment.Assignment;
2019
import org.hibernate.query.specification.MutationSpecification;
2120
import org.hibernate.query.IllegalMutationQueryException;
2221
import org.hibernate.query.MutationQuery;
@@ -55,7 +54,7 @@ public enum MutationType {
5554
DELETE
5655
}
5756

58-
private final List<BiConsumer<SqmDeleteOrUpdateStatement<T>, SqmRoot<T>>> specifications = new ArrayList<>();
57+
final List<BiConsumer<SqmDeleteOrUpdateStatement<T>, SqmRoot<T>>> specifications = new ArrayList<>();
5958
private final String hql;
6059
private final Class<T> mutationTarget;
6160
private final SqmDeleteOrUpdateStatement<T> deleteOrUpdateStatement;
@@ -120,19 +119,6 @@ public MutationSpecification<T> restrict(Restriction<? super T> restriction) {
120119
return this;
121120
}
122121

123-
@Override
124-
public MutationSpecification<T> assign(Assignment<? super T> assignment) {
125-
specifications.add( (sqmStatement, mutationTargetRoot) -> {
126-
if ( sqmStatement instanceof SqmUpdateStatement<T> sqmUpdateStatement ) {
127-
assignment.apply( sqmUpdateStatement );
128-
}
129-
else {
130-
throw new IllegalStateException( "Delete query cannot perform assignment" );
131-
}
132-
} );
133-
return this;
134-
}
135-
136122
@Override
137123
public MutationSpecification<T> augment(Augmentation<T> augmentation) {
138124
specifications.add( (sqmStatement, mutationTargetRoot) ->
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.query.specification.internal;
6+
7+
import jakarta.persistence.criteria.CriteriaBuilder;
8+
import jakarta.persistence.criteria.CriteriaUpdate;
9+
import org.hibernate.query.assignment.Assignment;
10+
import org.hibernate.query.restriction.Restriction;
11+
import org.hibernate.query.specification.UpdateSpecification;
12+
import org.hibernate.query.sqm.tree.update.SqmUpdateStatement;
13+
14+
/**
15+
* @author Gavin King
16+
*/
17+
public class UpdateSpecificationImpl<T>
18+
extends MutationSpecificationImpl<T>
19+
implements UpdateSpecification<T> {
20+
21+
public UpdateSpecificationImpl(Class<T> mutationTarget) {
22+
super( MutationType.UPDATE, mutationTarget );
23+
}
24+
25+
public UpdateSpecificationImpl(CriteriaUpdate<T> criteriaQuery) {
26+
super( criteriaQuery );
27+
}
28+
29+
@Override
30+
public UpdateSpecification<T> assign(Assignment<? super T> assignment) {
31+
specifications.add( (sqmStatement, mutationTargetRoot) -> {
32+
if ( sqmStatement instanceof SqmUpdateStatement<T> sqmUpdateStatement ) {
33+
assignment.apply( sqmUpdateStatement );
34+
}
35+
else {
36+
throw new IllegalStateException( "Delete query cannot perform assignment" );
37+
}
38+
} );
39+
return this;
40+
}
41+
42+
@Override
43+
public UpdateSpecification<T> restrict(Restriction<? super T> restriction) {
44+
super.restrict( restriction );
45+
return this;
46+
}
47+
48+
@Override
49+
public UpdateSpecification<T> augment(Augmentation<T> augmentation) {
50+
super.augment( augmentation );
51+
return this;
52+
}
53+
54+
@Override
55+
public UpdateSpecification<T> validate(CriteriaBuilder builder) {
56+
super.validate( builder );
57+
return this;
58+
}
59+
}

0 commit comments

Comments
 (0)