10 changed files with 689 additions and 341 deletions
@ -0,0 +1,101 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* 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 org.thingsboard.server.dao.sql.query; |
|||
|
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.UUIDConverter; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.EntityIdFactory; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.query.EntityData; |
|||
import org.thingsboard.server.common.data.query.EntityDataPageLink; |
|||
import org.thingsboard.server.common.data.query.EntityKey; |
|||
import org.thingsboard.server.common.data.query.EntityKeyType; |
|||
import org.thingsboard.server.common.data.query.TsValue; |
|||
|
|||
import java.util.HashMap; |
|||
import java.util.List; |
|||
import java.util.Map; |
|||
import java.util.stream.Collectors; |
|||
|
|||
public class EntityDataAdapter { |
|||
|
|||
public static PageData<EntityData> createEntityData(EntityDataPageLink pageLink, |
|||
List<EntityKeyMapping> selectionMapping, |
|||
List<Object[]> rows, |
|||
int totalElements) { |
|||
int totalPages = pageLink.getPageSize() > 0 ? (int)Math.ceil((float)totalElements / pageLink.getPageSize()) : 1; |
|||
int startIndex = pageLink.getPageSize() * pageLink.getPage(); |
|||
boolean hasNext = pageLink.getPageSize() > 0 && totalElements > startIndex + rows.size(); |
|||
List<EntityData> entitiesData = convertListToEntityData(rows, selectionMapping); |
|||
return new PageData<>(entitiesData, totalPages, totalElements, hasNext); |
|||
} |
|||
|
|||
private static List<EntityData> convertListToEntityData(List<Object[]> result, List<EntityKeyMapping> selectionMapping) { |
|||
return result.stream().map(row -> toEntityData(row, selectionMapping)).collect(Collectors.toList()); |
|||
} |
|||
|
|||
private static EntityData toEntityData(Object[] row, List<EntityKeyMapping> selectionMapping) { |
|||
String id = (String)row[0]; |
|||
EntityType entityType = EntityType.valueOf((String)row[1]); |
|||
EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, UUIDConverter.fromString(id)); |
|||
Map<EntityKeyType, Map<String, TsValue>> latest = new HashMap<>(); |
|||
Map<String, TsValue[]> timeseries = new HashMap<>(); |
|||
EntityData entityData = new EntityData(entityId, latest, timeseries); |
|||
for (EntityKeyMapping mapping: selectionMapping) { |
|||
EntityKey entityKey = mapping.getEntityKey(); |
|||
Object value = row[mapping.getIndex()]; |
|||
String strValue; |
|||
long ts; |
|||
if (entityKey.getType().equals(EntityKeyType.ENTITY_FIELD)) { |
|||
strValue = value != null ? value.toString() : null; |
|||
ts = System.currentTimeMillis(); |
|||
} else { |
|||
strValue = convertValue(value); |
|||
Object tsObject = row[mapping.getIndex()+1]; |
|||
ts = Long.parseLong(tsObject.toString()); |
|||
} |
|||
TsValue tsValue = new TsValue(ts, strValue); |
|||
latest.computeIfAbsent(entityKey.getType(), entityKeyType -> new HashMap<>()).put(entityKey.getKey(), tsValue); |
|||
} |
|||
return entityData; |
|||
} |
|||
|
|||
private static String convertValue(Object value) { |
|||
if (value != null) { |
|||
String strVal = value.toString(); |
|||
// check number
|
|||
if (strVal.length() > 0) { |
|||
try { |
|||
int intVal = Integer.parseInt(strVal); |
|||
return Integer.toString(intVal); |
|||
} catch (NumberFormatException ignored) { |
|||
} |
|||
try { |
|||
double dblVal = Double.parseDouble(strVal); |
|||
if (!Double.isInfinite(dblVal)) { |
|||
return Double.toString(dblVal); |
|||
} |
|||
} catch (NumberFormatException ignored) { |
|||
} |
|||
} |
|||
return strVal; |
|||
} else { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
} |
|||
@ -0,0 +1,166 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* 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 org.thingsboard.server.dao.service; |
|||
|
|||
import org.junit.After; |
|||
import org.junit.Assert; |
|||
import org.junit.Before; |
|||
import org.junit.Test; |
|||
import org.thingsboard.server.common.data.Device; |
|||
import org.thingsboard.server.common.data.EntityType; |
|||
import org.thingsboard.server.common.data.Tenant; |
|||
import org.thingsboard.server.common.data.id.CustomerId; |
|||
import org.thingsboard.server.common.data.id.DeviceId; |
|||
import org.thingsboard.server.common.data.id.EntityId; |
|||
import org.thingsboard.server.common.data.id.TenantId; |
|||
import org.thingsboard.server.common.data.page.PageData; |
|||
import org.thingsboard.server.common.data.query.DeviceTypeFilter; |
|||
import org.thingsboard.server.common.data.query.EntityCountQuery; |
|||
import org.thingsboard.server.common.data.query.EntityData; |
|||
import org.thingsboard.server.common.data.query.EntityDataPageLink; |
|||
import org.thingsboard.server.common.data.query.EntityDataQuery; |
|||
import org.thingsboard.server.common.data.query.EntityDataSortOrder; |
|||
import org.thingsboard.server.common.data.query.EntityFilter; |
|||
import org.thingsboard.server.common.data.query.EntityKey; |
|||
import org.thingsboard.server.common.data.query.EntityKeyType; |
|||
import org.thingsboard.server.common.data.query.EntityListFilter; |
|||
|
|||
import java.util.ArrayList; |
|||
import java.util.Collections; |
|||
import java.util.List; |
|||
import java.util.stream.Collectors; |
|||
|
|||
public abstract class BaseEntityServiceTest extends AbstractServiceTest { |
|||
|
|||
private TenantId tenantId; |
|||
|
|||
@Before |
|||
public void before() { |
|||
Tenant tenant = new Tenant(); |
|||
tenant.setTitle("My tenant"); |
|||
Tenant savedTenant = tenantService.saveTenant(tenant); |
|||
Assert.assertNotNull(savedTenant); |
|||
tenantId = savedTenant.getId(); |
|||
} |
|||
|
|||
@After |
|||
public void after() { |
|||
tenantService.deleteTenant(tenantId); |
|||
} |
|||
|
|||
@Test |
|||
public void testCountEntitiesByQuery() { |
|||
List<Device> devices = new ArrayList<>(); |
|||
for (int i = 0; i < 97; i++) { |
|||
Device device = new Device(); |
|||
device.setTenantId(tenantId); |
|||
device.setName("Device" + i); |
|||
device.setType("default"); |
|||
device.setLabel("testLabel" + (int) (Math.random() * 1000)); |
|||
devices.add(deviceService.saveDevice(device)); |
|||
} |
|||
|
|||
DeviceTypeFilter filter = new DeviceTypeFilter(); |
|||
filter.setDeviceType("default"); |
|||
filter.setDeviceNameFilter(""); |
|||
|
|||
EntityCountQuery countQuery = new EntityCountQuery(filter); |
|||
|
|||
long count = entityService.countEntitiesByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), countQuery); |
|||
Assert.assertEquals(97, count); |
|||
|
|||
filter.setDeviceType("unknown"); |
|||
count = entityService.countEntitiesByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), countQuery); |
|||
Assert.assertEquals(0, count); |
|||
|
|||
filter.setDeviceType("default"); |
|||
filter.setDeviceNameFilter("Device1"); |
|||
count = entityService.countEntitiesByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), countQuery); |
|||
Assert.assertEquals(11, count); |
|||
|
|||
EntityListFilter entityListFilter = new EntityListFilter(); |
|||
entityListFilter.setEntityType(EntityType.DEVICE); |
|||
entityListFilter.setEntityList(devices.stream().map(Device::getId).map(DeviceId::toString).collect(Collectors.toList())); |
|||
|
|||
countQuery = new EntityCountQuery(entityListFilter); |
|||
count = entityService.countEntitiesByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), countQuery); |
|||
Assert.assertEquals(97, count); |
|||
|
|||
deviceService.deleteDevicesByTenantId(tenantId); |
|||
count = entityService.countEntitiesByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), countQuery); |
|||
Assert.assertEquals(0, count); |
|||
} |
|||
|
|||
@Test |
|||
public void testFindEntityDataByQuery() { |
|||
List<Device> devices = new ArrayList<>(); |
|||
for (int i = 0; i < 97; i++) { |
|||
Device device = new Device(); |
|||
device.setTenantId(tenantId); |
|||
device.setName("Device" + i); |
|||
device.setType("default"); |
|||
device.setLabel("testLabel" + (int) (Math.random() * 1000)); |
|||
devices.add(deviceService.saveDevice(device)); |
|||
} |
|||
|
|||
DeviceTypeFilter filter = new DeviceTypeFilter(); |
|||
filter.setDeviceType("default"); |
|||
filter.setDeviceNameFilter(""); |
|||
|
|||
EntityDataSortOrder sortOrder = new EntityDataSortOrder( |
|||
new EntityKey(EntityKeyType.ENTITY_FIELD, "createdTime"), EntityDataSortOrder.Direction.ASC |
|||
); |
|||
EntityDataPageLink pageLink = new EntityDataPageLink(10, 0, null, sortOrder); |
|||
List<EntityKey> entityFields = Collections.singletonList(new EntityKey(EntityKeyType.ENTITY_FIELD, "name")); |
|||
|
|||
EntityDataQuery query = new EntityDataQuery(filter, pageLink, entityFields, null, null); |
|||
PageData<EntityData> data = entityService.findEntityDataByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), query); |
|||
|
|||
Assert.assertEquals(97, data.getTotalElements()); |
|||
Assert.assertEquals(10, data.getTotalPages()); |
|||
Assert.assertTrue(data.hasNext()); |
|||
Assert.assertEquals(10, data.getData().size()); |
|||
|
|||
List<EntityData> loadedEntities = new ArrayList<>(data.getData()); |
|||
while(data.hasNext()) { |
|||
query = query.next(); |
|||
data = entityService.findEntityDataByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), query); |
|||
loadedEntities.addAll(data.getData()); |
|||
} |
|||
Assert.assertEquals(97, loadedEntities.size()); |
|||
|
|||
List<EntityId> loadedIds = loadedEntities.stream().map(EntityData::getEntityId).collect(Collectors.toList()); |
|||
List<EntityId> deviceIds = devices.stream().map(Device::getId).collect(Collectors.toList()); |
|||
|
|||
Assert.assertEquals(deviceIds, loadedIds); |
|||
|
|||
List<String> loadedNames = loadedEntities.stream().map(entityData -> |
|||
entityData.getLatest().get(EntityKeyType.ENTITY_FIELD).get("name").getValue()).collect(Collectors.toList()); |
|||
List<String> deviceNames = devices.stream().map(Device::getName).collect(Collectors.toList()); |
|||
|
|||
Assert.assertEquals(deviceNames, loadedNames); |
|||
|
|||
sortOrder = new EntityDataSortOrder( |
|||
new EntityKey(EntityKeyType.ENTITY_FIELD, "name"), EntityDataSortOrder.Direction.DESC |
|||
); |
|||
|
|||
pageLink = new EntityDataPageLink(10, 0, "device1", sortOrder); |
|||
query = new EntityDataQuery(filter, pageLink, entityFields, null, null); |
|||
data = entityService.findEntityDataByQuery(tenantId, new CustomerId(CustomerId.NULL_UUID), query); |
|||
Assert.assertEquals(11, data.getTotalElements()); |
|||
Assert.assertEquals("Device19", data.getData().get(0).getLatest().get(EntityKeyType.ENTITY_FIELD).get("name").getValue()); |
|||
} |
|||
} |
|||
@ -0,0 +1,23 @@ |
|||
/** |
|||
* Copyright © 2016-2020 The Thingsboard Authors |
|||
* |
|||
* 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 org.thingsboard.server.dao.service.sql; |
|||
|
|||
import org.thingsboard.server.dao.service.BaseEntityServiceTest; |
|||
import org.thingsboard.server.dao.service.DaoSqlTest; |
|||
|
|||
@DaoSqlTest |
|||
public class EntityServiceSqlTest extends BaseEntityServiceTest { |
|||
} |
|||
Loading…
Reference in new issue