diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultUpdateQuery.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultUpdateQuery.java index 20d4ae3a0..897424b8a 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultUpdateQuery.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/DefaultUpdateQuery.java @@ -3,6 +3,9 @@ package io.ebeaninternal.server.querydefn; import io.ebean.ExpressionList; import io.ebean.ProfileLocation; import io.ebean.UpdateQuery; +import io.ebean.core.type.ScalarType; +import io.ebeaninternal.server.deploy.BeanDescriptor; +import io.ebeaninternal.server.deploy.BeanProperty; /** * Default implementation of UpdateQuery. @@ -10,23 +13,30 @@ import io.ebean.UpdateQuery; public class DefaultUpdateQuery implements UpdateQuery { private final OrmUpdateProperties values = new OrmUpdateProperties(); - private final DefaultOrmQuery query; + private final BeanDescriptor descriptor; public DefaultUpdateQuery(DefaultOrmQuery query) { this.query = query; + this.descriptor = query.getBeanDescriptor(); query.setUpdateProperties(values); } @Override public UpdateQuery set(String property, Object value) { - values.set(property, value); + if (value == null) { + values.setNull(property); + } else { + final BeanProperty beanProperty = descriptor.getBeanProperty(property); + final ScalarType scalarType = (beanProperty == null) ? null: beanProperty.getScalarType(); + values.set(property, value, scalarType); + } return this; } @Override public UpdateQuery setNull(String property) { - values.set(property, null); + values.setNull(property); return this; } diff --git a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmUpdateProperties.java b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmUpdateProperties.java index 39a8dc81d..930e653f4 100644 --- a/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmUpdateProperties.java +++ b/ebean-core/src/main/java/io/ebeaninternal/server/querydefn/OrmUpdateProperties.java @@ -1,5 +1,6 @@ package io.ebeaninternal.server.querydefn; +import io.ebean.core.type.ScalarType; import io.ebeaninternal.server.deploy.DeployParser; import io.ebeaninternal.server.persist.Binder; import io.ebeaninternal.server.type.DataBind; @@ -53,9 +54,11 @@ public class OrmUpdateProperties { private static class SimpleValue extends Value { final Object value; + final ScalarType scalarType; - SimpleValue(Object value) { + SimpleValue(Object value, ScalarType scalarType) { this.value = value; + this.scalarType = scalarType; } @Override @@ -70,7 +73,11 @@ public class OrmUpdateProperties { @Override public void bind(Binder binder, DataBind dataBind) throws SQLException { - binder.bindObject(dataBind, value); + if (scalarType != null) { + scalarType.bind(dataBind, value); + } else { + binder.bindObject(dataBind, value); + } dataBind.append(value).append(","); } } @@ -115,16 +122,12 @@ public class OrmUpdateProperties { */ private final LinkedHashMap values = new LinkedHashMap<>(); - /** - * Normal set property. - */ - public void set(String propertyName, Object value) { - if (value == null) { - values.put(propertyName, NULL_VALUE); + public void set(String propertyName, Object value, ScalarType scalarType) { + values.put(propertyName, new SimpleValue(value, scalarType)); + } - } else { - values.put(propertyName, new SimpleValue(value)); - } + public void setNull(String propertyName) { + values.put(propertyName, NULL_VALUE); } /** diff --git a/ebean-core/src/test/java/org/tests/json/TestDbJson_List.java b/ebean-core/src/test/java/org/tests/json/TestDbJson_List.java index 0582818db..28fd78221 100644 --- a/ebean-core/src/test/java/org/tests/json/TestDbJson_List.java +++ b/ebean-core/src/test/java/org/tests/json/TestDbJson_List.java @@ -1,7 +1,7 @@ package org.tests.json; import io.ebean.BaseTestCase; -import io.ebean.Ebean; +import io.ebean.DB; import io.ebean.annotation.ForPlatform; import io.ebean.annotation.Platform; import io.ebean.text.TextException; @@ -25,7 +25,7 @@ import static org.junit.Assert.assertTrue; public class TestDbJson_List extends BaseTestCase { - private EBasicJsonList bean = new EBasicJsonList(); + private final EBasicJsonList bean = new EBasicJsonList(); private EBasicJsonList found; @@ -57,9 +57,9 @@ public class TestDbJson_List extends BaseTestCase { bean.getBeanMap().put("key0", new PlainBean("k0", 90)); bean.getBeanMap().put("key1", new PlainBean("k1", 91)); - Ebean.save(bean); + DB.save(bean); - found = Ebean.find(EBasicJsonList.class, bean.getId()); + found = DB.find(EBasicJsonList.class, bean.getId()); assertThat(found.getTags()).containsExactly("one", "two"); assertTrue(found.getFlags().contains(42L)); @@ -81,7 +81,7 @@ public class TestDbJson_List extends BaseTestCase { //@Test//(dependsOnMethods = "insert") public void json_parse_format() { - String asJson = Ebean.json().toJson(found); + String asJson = DB.json().toJson(found); assertThat(asJson).contains("\"tags\":[\"one\",\"two\"]"); assertThat(asJson).contains("\"flags\":[42,43,44]"); assertThat(asJson).contains("\"plainBean\":{\"name\":\"plain\""); @@ -90,7 +90,7 @@ public class TestDbJson_List extends BaseTestCase { assertThat(asJson).contains("\"beanMap\":{"); assertThat(asJson).contains("\"id\":"); - EBasicJsonList fromJson = Ebean.json().toBean(EBasicJsonList.class, asJson); + EBasicJsonList fromJson = DB.json().toBean(EBasicJsonList.class, asJson); assertEquals(found.getId(), fromJson.getId()); assertEquals(found.getId(), fromJson.getId()); assertEquals(found.getName(), fromJson.getName()); @@ -109,7 +109,7 @@ public class TestDbJson_List extends BaseTestCase { found.setName("mod"); LoggedSqlCollector.start(); - Ebean.save(found); + DB.save(found); List sql = LoggedSqlCollector.stop(); // we don't update the phone numbers (as they are not dirty) @@ -122,7 +122,7 @@ public class TestDbJson_List extends BaseTestCase { found.getTags().add("three"); LoggedSqlCollector.start(); - Ebean.save(found); + DB.save(found); List sql = LoggedSqlCollector.stop(); // we don't update the phone numbers (as they are not dirty) @@ -135,7 +135,7 @@ public class TestDbJson_List extends BaseTestCase { found.getFlags().remove(42L); LoggedSqlCollector.start(); - Ebean.save(found); + DB.save(found); List sql = LoggedSqlCollector.stop(); // we don't update the phone numbers (as they are not dirty) @@ -150,7 +150,7 @@ public class TestDbJson_List extends BaseTestCase { found.getBeanMap().remove("key0"); LoggedSqlCollector.start(); - Ebean.save(found); + DB.save(found); List sql = LoggedSqlCollector.stop(); // we don't update the phone numbers (as they are not dirty) @@ -166,13 +166,13 @@ public class TestDbJson_List extends BaseTestCase { bean.setTags(null); bean.setBeanMap(null); - Ebean.save(bean); + DB.save(bean); - EBasicJsonList found = Ebean.find(EBasicJsonList.class, bean.getId()); + EBasicJsonList found = DB.find(EBasicJsonList.class, bean.getId()); assertNull(found.getPlainBean()); - String asJson = Ebean.json().toJson(found); + String asJson = DB.json().toJson(found); assertNotNull(asJson); } @@ -186,17 +186,16 @@ public class TestDbJson_List extends BaseTestCase { plainBean.setName("Blubb"); bean.getBeanMap().put("bla", plainBean); - Ebean.save(bean); + DB.save(bean); // set some invalid JSON content into DB - Ebean.update(EBasicJsonList.class) - .set("beanMap", "blabla") - .where().eq("id", bean.getId()) - .update(); + DB.sqlUpdate("update ebasic_json_list set bean_map=? where id=?") + .setParameters("blabla", bean.getId()) + .execute(); try { // a normal query fails due to invalid JSON content - Ebean.find(EBasicJsonList.class) + DB.find(EBasicJsonList.class) .setId(bean.getId()) .findOne(); @@ -208,7 +207,7 @@ public class TestDbJson_List extends BaseTestCase { assertThat(e.getMessage()).contains("beanMap"); } - bean = Ebean.find(EBasicJsonList.class) + bean = DB.find(EBasicJsonList.class) .setId(bean.getId()) .setAllowLoadErrors() // allow invalid JSON content .findOne(); @@ -220,6 +219,6 @@ public class TestDbJson_List extends BaseTestCase { .isInstanceOf(TextException.class) .hasMessageContaining("blabla"); - Ebean.delete(bean); + DB.delete(bean); } } diff --git a/ebean-core/src/test/java/org/tests/json/TestJsonMapBasic.java b/ebean-core/src/test/java/org/tests/json/TestJsonMapBasic.java index 2edad3554..01d105760 100644 --- a/ebean-core/src/test/java/org/tests/json/TestJsonMapBasic.java +++ b/ebean-core/src/test/java/org/tests/json/TestJsonMapBasic.java @@ -1,14 +1,16 @@ package org.tests.json; import io.ebean.BaseTestCase; -import io.ebean.Ebean; +import io.ebean.DB; import io.ebean.Query; import io.ebean.text.json.EJson; +import io.ebeantest.LoggedSql; import org.tests.model.json.EBasicJsonMap; import org.junit.Test; import org.tests.model.json.EBasicJsonMapDetail; import java.io.IOException; +import java.util.List; import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; @@ -29,9 +31,9 @@ public class TestJsonMapBasic extends BaseTestCase { bean.getDetails().add(new EBasicJsonMapDetail("detail1")); bean.getDetails().add(new EBasicJsonMapDetail("detail2")); - Ebean.save(bean); + DB.save(bean); - Query query1 = Ebean.find(EBasicJsonMap.class) + Query query1 = DB.find(EBasicJsonMap.class) .fetch("details") .where().startsWith("details.name", "detail") .query(); @@ -40,7 +42,7 @@ public class TestJsonMapBasic extends BaseTestCase { assertThat(query1.getGeneratedSql()).contains("select distinct on (t0.id, t1.id) "); - Query query2 = Ebean.find(EBasicJsonMap.class) + Query query2 = DB.find(EBasicJsonMap.class) .where().startsWith("details.name", "detail") .query(); query2.findList(); @@ -60,9 +62,9 @@ public class TestJsonMapBasic extends BaseTestCase { bean.setName("one"); bean.setContent(content); - Ebean.save(bean); + DB.save(bean); - EBasicJsonMap bean1 = Ebean.find(EBasicJsonMap.class, bean.getId()); + EBasicJsonMap bean1 = DB.find(EBasicJsonMap.class, bean.getId()); assertEquals(bean.getId(), bean1.getId()); assertEquals(bean.getName(), bean1.getName()); @@ -70,16 +72,16 @@ public class TestJsonMapBasic extends BaseTestCase { assertEquals(18L, bean1.getContent().get("docId")); bean1.setName("just change name"); - Ebean.save(bean1); + DB.save(bean1); // content changes detected - dirty state so included in update Map content1 = bean1.getContent(); content1.put("additional", "newValue"); content1.put("docId", 99L); bean1.setName("two"); - Ebean.save(bean1); + DB.save(bean1); - EBasicJsonMap bean2 = Ebean.find(EBasicJsonMap.class, bean.getId()); + EBasicJsonMap bean2 = DB.find(EBasicJsonMap.class, bean.getId()); // name changed and docId changed assertEquals("two", bean2.getName()); @@ -89,12 +91,48 @@ public class TestJsonMapBasic extends BaseTestCase { content1.put("additional", "modValue"); bean1.setName("three"); bean1.setContent(content1); - Ebean.save(bean1); + DB.save(bean1); - EBasicJsonMap bean3 = Ebean.find(EBasicJsonMap.class, bean.getId()); + EBasicJsonMap bean3 = DB.find(EBasicJsonMap.class, bean.getId()); assertEquals("three", bean3.getName()); assertEquals(99L, bean3.getContent().get("docId")); assertEquals("modValue", bean3.getContent().get("additional")); } + + @Test + public void updateQuery_bindingMap() throws IOException { + + String s0 = "{\"docId\":22,\"contentId\":\"initialDoc\"}"; + Map content = EJson.parseObject(s0); + + EBasicJsonMap bean = new EBasicJsonMap(); + bean.setName("one"); + bean.setContent(content); + + DB.save(bean); + + String s1 = "{\"docId\":222,\"contentId\":\"updatedDoc222\"}"; + Map content1 = EJson.parseObject(s1); + + LoggedSql.start(); + + final int rows = DB.update(EBasicJsonMap.class) + .set("content", content1) + .where().eq("id", bean.getId()) + .update(); + + final List sql = LoggedSql.stop(); + + assertThat(sql).hasSize(1); + assertThat(sql.get(0)).contains("update ebasic_json_map set content=? where id = ?"); + assertThat(rows).isEqualTo(1); + + final EBasicJsonMap found = DB.find(EBasicJsonMap.class, bean.getId()); + final Map content2 = found.getContent(); + assertThat(content2.get("contentId")).isEqualTo("updatedDoc222"); + assertThat(content2.get("docId")).isEqualTo(222L); + + DB.delete(found); + } }