Skip to content

Commit

Permalink
REST API does not support entities with composite primary key #49
Browse files Browse the repository at this point in the history
  • Loading branch information
subbotin committed Feb 19, 2021
1 parent e8a9dba commit 486dc5f
Show file tree
Hide file tree
Showing 12 changed files with 277 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
Expand Down Expand Up @@ -652,7 +653,12 @@ private Object getIdFromString(String entityId, MetaClass metaClass) {
} else if (Long.class.isAssignableFrom(idClass)) {
return Long.valueOf(entityId);
} else {
return entityId;
if (metadataTools.hasCompositePrimaryKey(metaClass)) {
String entityIdJson = new String(Base64.getUrlDecoder().decode(entityId), StandardCharsets.UTF_8);
return entitySerializationAPI.entityFromJson(entityIdJson, metadata.getClass(idClass));
} else {
return entityId;
}
}
}
} catch (Exception e) {
Expand Down
7 changes: 7 additions & 0 deletions test/restapi-demo/modules/core/db/init/hsql/10.create-db.sql
Original file line number Diff line number Diff line change
Expand Up @@ -503,3 +503,10 @@ create table REF_PLANT_MODEL_LINK (
primary key (PLANT_ID, MODEL_ID)
)^
-- end REF_PLANT_MODEL_LINK
create table REF_COMPOSITE_KEY (
TENANT integer not null,
ENTITY_ID bigint not null,
NAME varchar(50),
EMAIL varchar(100),
primary key (TENANT, ENTITY_ID)
)^
7 changes: 7 additions & 0 deletions test/restapi-demo/modules/core/db/init/mssql/10.create-db.sql
Original file line number Diff line number Diff line change
Expand Up @@ -513,3 +513,10 @@ create table REF_PLANT_MODEL_LINK (
primary key (PLANT_ID, MODEL_ID)
)^
-- end REF_PLANT_MODEL_LINK
create table REF_COMPOSITE_KEY (
TENANT integer not null,
ENTITY_ID bigint not null,
NAME varchar(50),
EMAIL varchar(100),
primary key (TENANT, ENTITY_ID)
)^
7 changes: 7 additions & 0 deletions test/restapi-demo/modules/core/db/init/mysql/10.create-db.sql
Original file line number Diff line number Diff line change
Expand Up @@ -513,3 +513,10 @@ create table REF_PLANT_MODEL_LINK (
primary key (PLANT_ID, MODEL_ID)
)^
-- end REF_PLANT_MODEL_LINK
create table REF_COMPOSITE_KEY (
TENANT integer not null,
ENTITY_ID bigint not null,
NAME varchar(50),
EMAIL varchar(100),
primary key (TENANT, ENTITY_ID)
)^
Original file line number Diff line number Diff line change
Expand Up @@ -513,3 +513,10 @@ create table REF_PLANT_MODEL_LINK (
primary key (PLANT_ID, MODEL_ID)
)^
-- end REF_PLANT_MODEL_LINK
create table REF_COMPOSITE_KEY (
TENANT integer not null,
ENTITY_ID bigint not null,
NAME varchar(50),
EMAIL varchar(100),
primary key (TENANT, ENTITY_ID)
)^
Original file line number Diff line number Diff line change
Expand Up @@ -513,3 +513,10 @@ create table REF_PLANT_MODEL_LINK (
primary key (PLANT_ID, MODEL_ID)
)^
-- end REF_PLANT_MODEL_LINK
create table REF_COMPOSITE_KEY (
TENANT integer not null,
ENTITY_ID bigint not null,
NAME varchar(50),
EMAIL varchar(100),
primary key (TENANT, ENTITY_ID)
)^
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2008-2016 Haulmont.
*
* 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.haulmont.rest.demo.core.entity;

import com.haulmont.cuba.core.entity.BaseGenericIdEntity;

import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.Table;

@Entity(name = "ref$CompositeKeyEntity")
@Table(name = "REF_COMPOSITE_KEY")
public class CompositeKeyEntity extends BaseGenericIdEntity<EntityKey> {

private static final long serialVersionUID = -2538345720324624741L;

@EmbeddedId
private EntityKey id;

@Column(name = "NAME")
private String name;

@Column(name = "EMAIL")
private String email;

@Override
public void setId(EntityKey id) {
this.id = id;
}

@Override
public EntityKey getId() {
return id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getEmail() {
return email;
}

public void setEmail(String email) {
this.email = email;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* Copyright (c) 2008-2016 Haulmont.
*
* 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.haulmont.rest.demo.core.entity;

import com.haulmont.chile.core.annotations.MetaClass;
import com.haulmont.cuba.core.entity.EmbeddableEntity;

import javax.persistence.Column;
import javax.persistence.Embeddable;
import java.util.Objects;

@Embeddable
@MetaClass(name = "ref$EntityKey")
public class EntityKey extends EmbeddableEntity {

@Column(name = "TENANT")
private Integer tenant;

@Column(name = "ENTITY_ID")
private Long entityId;

public Integer getTenant() {
return tenant;
}

public void setTenant(Integer tenant) {
this.tenant = tenant;
}

public Long getEntityId() {
return entityId;
}

public void setEntityId(Long entityId) {
this.entityId = entityId;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof EntityKey)) return false;
EntityKey entityKey = (EntityKey) o;
return Objects.equals(tenant, entityKey.tenant) &&
Objects.equals(entityId, entityKey.entityId);
}

@Override
public int hashCode() {
return Objects.hash(tenant, entityId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,7 @@
<class>com.haulmont.rest.demo.core.entity.identity.IdentityOrder</class>
<class>com.haulmont.rest.demo.core.entity.identity.IdentityOrderLine</class>
<class>com.haulmont.rest.demo.core.entity.identity.IdentityOrderLineTag</class>
<class>com.haulmont.rest.demo.core.entity.EntityKey</class>
<class>com.haulmont.rest.demo.core.entity.CompositeKeyEntity</class>
</persistence-unit>
</persistence>
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

public class DataSet {

Expand Down Expand Up @@ -40,6 +42,11 @@ public class DataSet {
private Set<UUID> constraintIds = new HashSet<>();
private Set<UUID> plantIds = new HashSet<>();
private Set<String> currencyIds = new HashSet<>();
private Set<Long> compositeKeyEntityIds = new HashSet<>();
private Set<Integer> compositeKeyEntityTenantIds = new HashSet<>();

private AtomicLong compositeKeyEntityIdGen = new AtomicLong();
private AtomicInteger compositeKeyEntityTenantIdGen = new AtomicInteger();

public void addCarId(UUID uuid) {
if (uuid != null)
Expand Down Expand Up @@ -176,6 +183,7 @@ public void cleanup(Connection conn) throws SQLException {
deleteInstances(conn, "SEC_GROUP", groupIds);
deleteInstances(conn, "REF_PLANT", plantIds);
deleteStringInstances(conn, "REF_CURRENCY", "CODE", currencyIds);
deleteCompositeKeyEntities(conn);
}

private void deleteSellers(Connection conn) throws SQLException {
Expand Down Expand Up @@ -394,6 +402,28 @@ private void deleteDriverGroups(Connection conn) throws SQLException {
}
}

private void deleteCompositeKeyEntities(Connection conn) throws SQLException {
PreparedStatement stmt;
stmt = conn.prepareStatement("delete from ref_composite_key where entity_id = ?");
try {
for (Long entityId : compositeKeyEntityIds) {
stmt.setLong(1, entityId);
stmt.executeUpdate();
}
} finally {
stmt.close();
}
stmt = conn.prepareStatement("delete from ref_composite_key where tenant = ?");
try {
for (Integer tenant : compositeKeyEntityTenantIds) {
stmt.setInt(1, tenant);
stmt.executeUpdate();
}
} finally {
stmt.close();
}
}

private void deleteStringInstances(Connection conn, String tableName, String idColumn, Set<String> ids) throws SQLException {
PreparedStatement stmt;
stmt = conn.prepareStatement("delete from " + tableName + " where " + idColumn + " = ?");
Expand Down Expand Up @@ -557,4 +587,16 @@ public UUID createConstraintId() {
addConstraintId(result);
return result;
}

public Long createCompositeKeyEntityId() {
Long result = compositeKeyEntityIdGen.incrementAndGet();
compositeKeyEntityIds.add(result);
return result;
}

public Integer createCompositeKeyEntityTenantId() {
Integer result = compositeKeyEntityTenantIdGen.incrementAndGet();
compositeKeyEntityTenantIds.add(result);
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.junit.*;
import org.junit.rules.ExpectedException;

import java.nio.charset.StandardCharsets;
import java.sql.Date;
import java.sql.*;
import java.text.SimpleDateFormat;
Expand Down Expand Up @@ -49,6 +50,8 @@ public class EntitiesControllerFT {
private String driverUuidString;
private String debtorUuidString;
private String plantUuidString;
private String compositeKeyEntityIdString;
private String compositeKeyEntityTenantIdString;

private String modelName = "Audi A3";
private String model2Name = "BMW X5";
Expand Down Expand Up @@ -105,6 +108,19 @@ public void loadEntityById() throws Exception {
}
}

@Test
public void loadEntityWithCompositeId() throws Exception {
String id = String.format("{tenant : %s, entityId: %s}", compositeKeyEntityTenantIdString,
compositeKeyEntityIdString);
String base64Id = Base64.getUrlEncoder().encodeToString(id.getBytes(StandardCharsets.UTF_8));
String url = "/entities/ref$CompositeKeyEntity/" + base64Id;
try (CloseableHttpResponse response = sendGet(url, oauthToken, null)) {
assertEquals(HttpStatus.SC_OK, statusCode(response));
ReadContext ctx = parseResponse(response);
assertEquals("compositeEntity", ctx.read("$.name"));
}
}

@Test
public void loadEntityWithDynamicAttributes() throws Exception {
String url = "/entities/ref_Car/" + carUuidString;
Expand Down Expand Up @@ -444,7 +460,7 @@ public void loadEntitiesListWithFilterAndCountGet() throws Exception {
}

@Test
public void loadEntitiesFilterIsNull() throws Exception{
public void loadEntitiesFilterIsNull() throws Exception {
String url = "/entities/ref_Car/search";
String json = getFileContent("entitiesFilterIsNull.json", null);
Map<String, String> params = new HashMap<>();
Expand Down Expand Up @@ -949,6 +965,34 @@ public void updateCar() throws Exception {
}
}

@Test
public void updateEntityWithCompositeId() throws Exception {
String id = String.format("{tenant : %s, entityId: %s}", compositeKeyEntityTenantIdString,
compositeKeyEntityIdString);
String base64Id = Base64.getUrlEncoder().encodeToString(id.getBytes(StandardCharsets.UTF_8));
String json = getFileContent("updateEntityWithCompositeId.json", new HashMap<>());

String url = "/entities/ref$CompositeKeyEntity/" + base64Id;

Map<String, String> params = new HashMap<>();

try (CloseableHttpResponse response = sendPut(url, oauthToken, json, params)) {
assertEquals(HttpStatus.SC_OK, statusCode(response));
}

try (PreparedStatement stmt = conn.prepareStatement("select NAME, EMAIL from REF_COMPOSITE_KEY " +
"where ENTITY_ID = ? and TENANT = ?")) {
stmt.setLong(1, Long.valueOf(compositeKeyEntityIdString));
stmt.setInt(2, Integer.valueOf(compositeKeyEntityTenantIdString));
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next());
String name = rs.getString("NAME");
assertEquals("modified name", name);
Object email = rs.getObject("EMAIL");
assertEquals("modified email", email);
}
}

@Test
public void updateCarWithVersion() throws Exception {
Connectors.jmx(WebConfigStorageJmxService.class)
Expand Down Expand Up @@ -1835,7 +1879,16 @@ private void prepareDb() throws Exception {
seatsNumberCategoryAttrId,
"numberOfSeatsAttr",
carUuid,
"10"
);
"10");

Long compositeKeyEntityId = dirtyData.createCompositeKeyEntityId();
Integer compositeKeyEntityTenantId = dirtyData.createCompositeKeyEntityTenantId();
compositeKeyEntityIdString = compositeKeyEntityId.toString();
compositeKeyEntityTenantIdString = compositeKeyEntityTenantId.toString();

executePrepared("insert into ref_composite_key(entity_id, tenant, name) values (?, ?, ?)",
compositeKeyEntityId,
compositeKeyEntityTenantId,
"compositeEntity");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"name" : "modified name",
"email": "modified email"
}

0 comments on commit 486dc5f

Please sign in to comment.