From df84a397346dbe5116554eb471e5befdd1629533 Mon Sep 17 00:00:00 2001 From: Karsten Ludwig Hauser Date: Fri, 22 Feb 2019 13:31:21 +0100 Subject: [PATCH] added JPAInsertClause --- .../com/querydsl/jpa/JPQLQueryFactory.java | 9 + .../java/com/querydsl/jpa/JPQLSerializer.java | 21 +++ .../jpa/hibernate/HibernateInsertClause.java | 163 ++++++++++++++++++ .../jpa/hibernate/HibernateQueryFactory.java | 5 + .../querydsl/jpa/impl/JPAInsertClause.java | 150 ++++++++++++++++ .../querydsl/jpa/impl/JPAQueryFactory.java | 9 + .../com/querydsl/jpa/JPAQueryFactoryTest.java | 30 ++++ 7 files changed, 387 insertions(+) create mode 100644 querydsl-jpa/src/main/java/com/querydsl/jpa/hibernate/HibernateInsertClause.java create mode 100644 querydsl-jpa/src/main/java/com/querydsl/jpa/impl/JPAInsertClause.java diff --git a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPQLQueryFactory.java b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPQLQueryFactory.java index ca4d19500..4c18b87da 100644 --- a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPQLQueryFactory.java +++ b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPQLQueryFactory.java @@ -16,6 +16,7 @@ package com.querydsl.jpa; import com.querydsl.core.QueryFactory; import com.querydsl.core.Tuple; import com.querydsl.core.dml.DeleteClause; +import com.querydsl.core.dml.InsertClause; import com.querydsl.core.dml.UpdateClause; import com.querydsl.core.types.EntityPath; import com.querydsl.core.types.Expression; @@ -117,4 +118,12 @@ public interface JPQLQueryFactory extends QueryFactory> { */ UpdateClause update(EntityPath path); + /** + * Create a new INSERT clause + * + * @param path entity to insert to + * @return insert clause + */ + InsertClause insert(EntityPath path); + } \ No newline at end of file diff --git a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPQLSerializer.java b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPQLSerializer.java index 748b9835d..0c202d3f3 100644 --- a/querydsl-jpa/src/main/java/com/querydsl/jpa/JPQLSerializer.java +++ b/querydsl-jpa/src/main/java/com/querydsl/jpa/JPQLSerializer.java @@ -69,6 +69,8 @@ public class JPQLSerializer extends SerializerBase { private static final String UPDATE = "update "; + private static final String INSERT = "insert into "; + private static final String WHERE = "\nwhere "; private static final String WITH = " with "; @@ -258,6 +260,25 @@ public class JPQLSerializer extends SerializerBase { } } + public void serializeForInsert(QueryMetadata md, List> columns, SubQueryExpression query) { + append(INSERT); + JoinExpression je = md.getJoins().get(0); + final EntityPath pe = (EntityPath) je.getTarget(); + append(pe.toString()); + //handleJoinTarget(je); + append(" ("); + boolean first = true; + for (Path path : columns) { + if (!first) { + append(", "); + } + handle(path); + first = false; + } + append(")\n"); + serialize(query.getMetadata(), false, null); + } + public void serializeForUpdate(QueryMetadata md, Map, Expression> updates) { append(UPDATE); handleJoinTarget(md.getJoins().get(0)); diff --git a/querydsl-jpa/src/main/java/com/querydsl/jpa/hibernate/HibernateInsertClause.java b/querydsl-jpa/src/main/java/com/querydsl/jpa/hibernate/HibernateInsertClause.java new file mode 100644 index 000000000..08a8a6d39 --- /dev/null +++ b/querydsl-jpa/src/main/java/com/querydsl/jpa/hibernate/HibernateInsertClause.java @@ -0,0 +1,163 @@ +/* + * Copyright 2015, The Querydsl Team (http://www.querydsl.com/team) + * + * 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.querydsl.jpa.hibernate; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.hibernate.LockMode; +import org.hibernate.Query; +import org.hibernate.Session; +import org.hibernate.StatelessSession; + +import com.google.common.collect.Maps; +import com.querydsl.core.JoinType; +import com.querydsl.core.dml.InsertClause; +import com.querydsl.core.dml.UpdateClause; +import com.querydsl.core.support.QueryMixin; +import com.querydsl.core.types.EntityPath; +import com.querydsl.core.types.Expression; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.Predicate; +import com.querydsl.core.types.SubQueryExpression; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.jpa.HQLTemplates; +import com.querydsl.jpa.JPAQueryMixin; +import com.querydsl.jpa.JPQLSerializer; +import com.querydsl.jpa.JPQLTemplates; +import com.querydsl.jpa.impl.JPAInsertClause; + +/** + * UpdateClause implementation for Hibernate + * + * @author tiwe + * + */ +public class HibernateInsertClause implements + InsertClause { + + private final QueryMixin queryMixin = new JPAQueryMixin(); + + private final List> columns = new ArrayList>(); + + private SubQueryExpression subQuery; + + private final SessionHolder session; + + private final JPQLTemplates templates; + + private final Map,LockMode> lockModes = new HashMap,LockMode>(); + + public HibernateInsertClause(Session session, EntityPath entity) { + this(new DefaultSessionHolder(session), entity, HQLTemplates.DEFAULT); + } + + public HibernateInsertClause(StatelessSession session, EntityPath entity) { + this(new StatelessSessionHolder(session), entity, HQLTemplates.DEFAULT); + } + + public HibernateInsertClause(Session session, EntityPath entity, JPQLTemplates templates) { + this(new DefaultSessionHolder(session), entity, templates); + } + + public HibernateInsertClause(SessionHolder session, EntityPath entity, + JPQLTemplates templates) { + this.session = session; + this.templates = templates; + queryMixin.addJoin(JoinType.DEFAULT, entity); + } + + @Override + public long execute() { + JPQLSerializer serializer = new JPQLSerializer(templates, null); + serializer.serializeForInsert(queryMixin.getMetadata(), columns, subQuery); + Map constants = serializer.getConstantToLabel(); + + Query query = session.createQuery(serializer.toString()); + for (Map.Entry, LockMode> entry : lockModes.entrySet()) { + query.setLockMode(entry.getKey().toString(), entry.getValue()); + } + HibernateUtil.setConstants(query, constants, queryMixin.getMetadata().getParams()); + return query.executeUpdate(); + } + + @Override + public HibernateInsertClause columns(Path... columns) + { + this.columns.addAll(Arrays.asList(columns)); + return this; + } + + @Override + public HibernateInsertClause select(SubQueryExpression sq) + { + subQuery = sq; + return this; + } + + /** + * Set the lock mode for the given path. + * @return the current object + */ + @SuppressWarnings("unchecked") + public HibernateInsertClause setLockMode(Path path, LockMode lockMode) { + lockModes.put(path, lockMode); + return this; + } + + @Override + public String toString() { + JPQLSerializer serializer = new JPQLSerializer(templates, null); + serializer.serializeForInsert(queryMixin.getMetadata(), columns, subQuery); + return serializer.toString(); + } + + @Override + public boolean isEmpty() { + return columns.isEmpty(); + } + + @Override + public HibernateInsertClause set(Path path, T value) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public HibernateInsertClause set(Path path, Expression expression) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public HibernateInsertClause setNull(Path path) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public HibernateInsertClause values(Object... v) + { + // TODO Auto-generated method stub + return null; + } + + +} diff --git a/querydsl-jpa/src/main/java/com/querydsl/jpa/hibernate/HibernateQueryFactory.java b/querydsl-jpa/src/main/java/com/querydsl/jpa/hibernate/HibernateQueryFactory.java index afc4808c6..f9d6cbc2d 100644 --- a/querydsl-jpa/src/main/java/com/querydsl/jpa/hibernate/HibernateQueryFactory.java +++ b/querydsl-jpa/src/main/java/com/querydsl/jpa/hibernate/HibernateQueryFactory.java @@ -114,6 +114,11 @@ public class HibernateQueryFactory implements JPQLQueryFactory { public HibernateUpdateClause update(EntityPath path) { return new HibernateUpdateClause(session.get(), path, templates); } + + @Override + public HibernateInsertClause insert(EntityPath path) { + return new HibernateInsertClause(session.get(), path, templates); + } @Override public HibernateQuery query() { diff --git a/querydsl-jpa/src/main/java/com/querydsl/jpa/impl/JPAInsertClause.java b/querydsl-jpa/src/main/java/com/querydsl/jpa/impl/JPAInsertClause.java new file mode 100644 index 000000000..cffcce37d --- /dev/null +++ b/querydsl-jpa/src/main/java/com/querydsl/jpa/impl/JPAInsertClause.java @@ -0,0 +1,150 @@ +/* + * Copyright 2015, The Querydsl Team (http://www.querydsl.com/team) + * + * 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.querydsl.jpa.impl; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import javax.annotation.Nullable; +import javax.persistence.EntityManager; +import javax.persistence.LockModeType; +import javax.persistence.Query; + +import com.google.common.collect.Maps; +import com.querydsl.core.JoinType; +import com.querydsl.core.dml.InsertClause; +import com.querydsl.core.dml.UpdateClause; +import com.querydsl.core.support.QueryMixin; +import com.querydsl.core.types.EntityPath; +import com.querydsl.core.types.Expression; +import com.querydsl.core.types.ParamExpression; +import com.querydsl.core.types.Path; +import com.querydsl.core.types.Predicate; +import com.querydsl.core.types.SubQueryExpression; +import com.querydsl.core.types.dsl.Expressions; +import com.querydsl.jpa.JPAQueryMixin; +import com.querydsl.jpa.JPQLSerializer; +import com.querydsl.jpa.JPQLTemplates; + +/** + * UpdateClause implementation for JPA + * + * @author tiwe + * + */ +public class JPAInsertClause implements InsertClause { + + private final QueryMixin queryMixin = new JPAQueryMixin(); + + private final List> columns = new ArrayList>(); + + private final List> values = new ArrayList>(); + + private final EntityManager entityManager; + + private final JPQLTemplates templates; + + private SubQueryExpression subQuery; + + @Nullable + private LockModeType lockMode; + + public JPAInsertClause(EntityManager em, EntityPath entity) { + this(em, entity, JPAProvider.getTemplates(em)); + } + + public JPAInsertClause(EntityManager em, EntityPath entity, JPQLTemplates templates) { + this.entityManager = em; + this.templates = templates; + queryMixin.addJoin(JoinType.DEFAULT, entity); + } + + @Override + public long execute() { + JPQLSerializer serializer = new JPQLSerializer(templates, entityManager); + serializer.serializeForInsert(queryMixin.getMetadata(), columns, subQuery); + Map constants = serializer.getConstantToLabel(); + + Query query = entityManager.createQuery(serializer.toString()); + if (lockMode != null) { + query.setLockMode(lockMode); + } + JPAUtil.setConstants(query, constants, queryMixin.getMetadata().getParams()); + return query.executeUpdate(); + } + + public JPAInsertClause setLockMode(LockModeType lockMode) { + this.lockMode = lockMode; + return this; + } + + @Override + public String toString() { + JPQLSerializer serializer = new JPQLSerializer(templates, entityManager); + serializer.serializeForInsert(queryMixin.getMetadata(), columns, subQuery); + return serializer.toString(); + } + + @Override + public JPAInsertClause columns(Path... columns) + { + this.columns.addAll(Arrays.asList(columns)); + return this; + } + + @Override + public JPAInsertClause select(SubQueryExpression sq) + { + subQuery = sq; + return this; + } + + @Override + public JPAInsertClause values(Object... v) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isEmpty() + { + // TODO Auto-generated method stub + return false; + } + + @Override + public JPAInsertClause set(Path path, T value) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public JPAInsertClause set(Path path, Expression expression) + { + // TODO Auto-generated method stub + return null; + } + + @Override + public JPAInsertClause setNull(Path path) + { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/querydsl-jpa/src/main/java/com/querydsl/jpa/impl/JPAQueryFactory.java b/querydsl-jpa/src/main/java/com/querydsl/jpa/impl/JPAQueryFactory.java index a78f15786..9b71b82be 100644 --- a/querydsl-jpa/src/main/java/com/querydsl/jpa/impl/JPAQueryFactory.java +++ b/querydsl-jpa/src/main/java/com/querydsl/jpa/impl/JPAQueryFactory.java @@ -130,6 +130,15 @@ public class JPAQueryFactory implements JPQLQueryFactory { } } + @Override + public JPAInsertClause insert(EntityPath path) { + if (templates != null) { + return new JPAInsertClause(entityManager.get(), path, templates); + } else { + return new JPAInsertClause(entityManager.get(), path); + } + } + @Override public JPAQuery query() { if (templates != null) { diff --git a/querydsl-jpa/src/test/java/com/querydsl/jpa/JPAQueryFactoryTest.java b/querydsl-jpa/src/test/java/com/querydsl/jpa/JPAQueryFactoryTest.java index 5a9b44f86..6af8f9a98 100644 --- a/querydsl-jpa/src/test/java/com/querydsl/jpa/JPAQueryFactoryTest.java +++ b/querydsl-jpa/src/test/java/com/querydsl/jpa/JPAQueryFactoryTest.java @@ -29,6 +29,7 @@ import org.junit.Test; import com.google.common.collect.Maps; import com.querydsl.jpa.domain.QAnimal; import com.querydsl.jpa.impl.JPAQueryFactory; +import com.querydsl.sql.SQLExpressions; public class JPAQueryFactoryTest { @@ -135,4 +136,33 @@ public class JPAQueryFactoryTest { EasyMock.verify(mock, factoryMock); } + @Test + public void insert() { + assertNotNull(queryFactory.insert(QAnimal.animal)); + } + + @Test + public void insert2() { + queryFactory2.insert(QAnimal.animal) + .set(QAnimal.animal.birthdate, new Date()); + } + + @Test + public void insert3() { + EasyMock.expect(mock.getEntityManagerFactory()).andReturn(factoryMock); + EasyMock.expect(factoryMock.getProperties()).andReturn(properties); + EasyMock.expect(mock.getDelegate()).andReturn(mock).atLeastOnce(); + EasyMock.replay(mock, factoryMock); + + assertNotNull(queryFactory3.insert(QAnimal.animal)); + + EasyMock.verify(mock, factoryMock); + } + + @Test + public void insert4() { + queryFactory.insert(QAnimal.animal).columns(QAnimal.animal.id, QAnimal.animal.birthdate) + .select(SQLExpressions.select(QAnimal.animal.id, QAnimal.animal.birthdate).from(QAnimal.animal)); + } + }