From 4592ab895aa13c843c786a3fe7fa56fa2cc0c741 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 24 Jun 2020 20:42:18 +0300 Subject: [PATCH] Implementation of hierarchical query --- .../query/DefaultEntityQueryRepository.java | 230 ++++++++++-------- .../dao/sql/query/EntityKeyMapping.java | 42 +++- 2 files changed, 171 insertions(+), 101 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java index 5c0f5addbe..9f18548682 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -60,6 +60,131 @@ import java.util.stream.Collectors; public class DefaultEntityQueryRepository implements EntityQueryRepository { //TODO: rafactoring to protect from SQL injections; private static final Map entityTableMap = new HashMap<>(); + public static final String SELECT_PHONE = " CASE WHEN entity.entity_type = 'TENANT' THEN (select phone from tenant where id = entity_id)" + + " WHEN entity.entity_type = 'CUSTOMER' THEN (select phone from customer where id = entity_id) END as phone"; + public static final String SELECT_ZIP = " CASE WHEN entity.entity_type = 'TENANT' THEN (select zip from tenant where id = entity_id)" + + " WHEN entity.entity_type = 'CUSTOMER' THEN (select zip from customer where id = entity_id) END as zip"; + public static final String SELECT_ADDRESS_2 = " CASE WHEN entity.entity_type = 'TENANT'" + + " THEN (select address2 from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " + + " THEN (select address2 from customer where id = entity_id) END as address2"; + public static final String SELECT_ADDRESS = " CASE WHEN entity.entity_type = 'TENANT'" + + " THEN (select address from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " + + " THEN (select address from customer where id = entity_id) END as address"; + public static final String SELECT_CITY = " CASE WHEN entity.entity_type = 'TENANT'" + + " THEN (select city from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " + + " THEN (select city from customer where id = entity_id) END as city"; + public static final String SELECT_STATE = " CASE WHEN entity.entity_type = 'TENANT'" + + " THEN (select state from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " + + " THEN (select state from customer where id = entity_id) END as state"; + public static final String SELECT_COUNTRY = " CASE WHEN entity.entity_type = 'TENANT'" + + " THEN (select country from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " + + " THEN (select country from customer where id = entity_id) END as country"; + public static final String SELECT_TITLE = " CASE WHEN entity.entity_type = 'TENANT'" + + " THEN (select title from tenant where id = entity_id) WHEN entity.entity_type = 'CUSTOMER' " + + " THEN (select title from customer where id = entity_id) END as title"; + public static final String SELECT_LAST_NAME = " CASE WHEN entity.entity_type = 'USER'" + + " THEN (select last_name from tb_user where id = entity_id) END as last_name"; + public static final String SELECT_FIRST_NAME = " CASE WHEN entity.entity_type = 'USER'" + + " THEN (select first_name from tb_user where id = entity_id) END as first_name"; + public static final String SELECT_REGION = " CASE WHEN entity.entity_type = 'TENANT'" + + " THEN (select region from tenant where id = entity_id) END as region"; + public static final String SELECT_EMAIL = " CASE" + + " WHEN entity.entity_type = 'TENANT'" + + " THEN (select email from tenant where id = entity_id)" + + " WHEN entity.entity_type = 'CUSTOMER' " + + " THEN (select email from customer where id = entity_id)" + + " WHEN entity.entity_type = 'USER'" + + " THEN (select email from tb_user where id = entity_id)" + + " END as email"; + public static final String SELECT_CUSTOMER_ID = "CASE" + + " WHEN entity.entity_type = 'TENANT'" + + " THEN UUID('" + TenantId.NULL_UUID + "')" + + " WHEN entity.entity_type = 'CUSTOMER' THEN entity_id" + + " WHEN entity.entity_type = 'USER'" + + " THEN (select customer_id from tb_user where id = entity_id)" + + " WHEN entity.entity_type = 'DASHBOARD'" + + //TODO: parse assigned customers or use contains? + " THEN NULL" + + " WHEN entity.entity_type = 'ASSET'" + + " THEN (select customer_id from asset where id = entity_id)" + + " WHEN entity.entity_type = 'DEVICE'" + + " THEN (select customer_id from device where id = entity_id)" + + " WHEN entity.entity_type = 'ENTITY_VIEW'" + + " THEN (select customer_id from entity_view where id = entity_id)" + + " END as customer_id"; + public static final String SELECT_TENANT_ID = "SELECT CASE" + + " WHEN entity.entity_type = 'TENANT' THEN entity_id" + + " WHEN entity.entity_type = 'CUSTOMER'" + + " THEN (select tenant_id from customer where id = entity_id)" + + " WHEN entity.entity_type = 'USER'" + + " THEN (select tenant_id from tb_user where id = entity_id)" + + " WHEN entity.entity_type = 'DASHBOARD'" + + " THEN (select tenant_id from dashboard where id = entity_id)" + + " WHEN entity.entity_type = 'ASSET'" + + " THEN (select tenant_id from asset where id = entity_id)" + + " WHEN entity.entity_type = 'DEVICE'" + + " THEN (select tenant_id from device where id = entity_id)" + + " WHEN entity.entity_type = 'ENTITY_VIEW'" + + " THEN (select tenant_id from entity_view where id = entity_id)" + + " END as tenant_id"; + public static final String SELECT_CREATED_TIME = " CASE" + + " WHEN entity.entity_type = 'TENANT'" + + " THEN (select created_time from tenant where id = entity_id)" + + " WHEN entity.entity_type = 'CUSTOMER' " + + " THEN (select created_time from customer where id = entity_id)" + + " WHEN entity.entity_type = 'USER'" + + " THEN (select created_time from tb_user where id = entity_id)" + + " WHEN entity.entity_type = 'DASHBOARD'" + + " THEN (select created_time from dashboard where id = entity_id)" + + " WHEN entity.entity_type = 'ASSET'" + + " THEN (select created_time from asset where id = entity_id)" + + " WHEN entity.entity_type = 'DEVICE'" + + " THEN (select created_time from device where id = entity_id)" + + " WHEN entity.entity_type = 'ENTITY_VIEW'" + + " THEN (select created_time from entity_view where id = entity_id)" + + " END as created_time"; + public static final String SELECT_NAME = " CASE" + + " WHEN entity.entity_type = 'TENANT'" + + " THEN (select title from tenant where id = entity_id)" + + " WHEN entity.entity_type = 'CUSTOMER' " + + " THEN (select title from customer where id = entity_id)" + + " WHEN entity.entity_type = 'USER'" + + " THEN (select CONCAT (first_name, ' ', last_name) from tb_user where id = entity_id)" + + " WHEN entity.entity_type = 'DASHBOARD'" + + " THEN (select title from dashboard where id = entity_id)" + + " WHEN entity.entity_type = 'ASSET'" + + " THEN (select name from asset where id = entity_id)" + + " WHEN entity.entity_type = 'DEVICE'" + + " THEN (select name from device where id = entity_id)" + + " WHEN entity.entity_type = 'ENTITY_VIEW'" + + " THEN (select name from entity_view where id = entity_id)" + + " END as name"; + public static final String SELECT_TYPE = " CASE" + + " WHEN entity.entity_type = 'USER'" + + " THEN (select authority from tb_user where id = entity_id)" + + " WHEN entity.entity_type = 'ASSET'" + + " THEN (select type from asset where id = entity_id)" + + " WHEN entity.entity_type = 'DEVICE'" + + " THEN (select type from device where id = entity_id)" + + " WHEN entity.entity_type = 'ENTITY_VIEW'" + + " THEN (select type from entity_view where id = entity_id)" + + " ELSE entity.entity_type END as type"; + public static final String SELECT_LABEL = " CASE" + + " WHEN entity.entity_type = 'TENANT'" + + " THEN (select title from tenant where id = entity_id)" + + " WHEN entity.entity_type = 'CUSTOMER' " + + " THEN (select title from customer where id = entity_id)" + + " WHEN entity.entity_type = 'USER'" + + " THEN (select CONCAT (first_name, ' ', last_name) from tb_user where id = entity_id)" + + " WHEN entity.entity_type = 'DASHBOARD'" + + " THEN (select title from dashboard where id = entity_id)" + + " WHEN entity.entity_type = 'ASSET'" + + " THEN (select label from asset where id = entity_id)" + + " WHEN entity.entity_type = 'DEVICE'" + + " THEN (select label from device where id = entity_id)" + + " WHEN entity.entity_type = 'ENTITY_VIEW'" + + " THEN (select name from entity_view where id = entity_id)" + + " END as label"; static { entityTableMap.put(EntityType.ASSET, "asset"); @@ -293,9 +418,14 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { private String relationQuery(EntityQueryContext ctx, RelationsQueryFilter entityFilter) { EntityId rootId = entityFilter.getRootEntity(); String lvlFilter = getLvlFilter(entityFilter.getMaxLevel()); - String selectFields = getSelectCreatedTime() + ", " + getSelectTenantId() + ", " + getSelectCustomerId() + ", " + - " entity.entity_id as id," + getSelectType() + ", " + getSelectName() + ", " + - getSelectLabel() + ", entity.entity_type as entity_type"; + String selectFields = SELECT_TENANT_ID + ", " + SELECT_CUSTOMER_ID + + ", " + SELECT_CREATED_TIME + ", " + + " entity.entity_id as id," + + SELECT_TYPE + ", " + SELECT_NAME + ", " + SELECT_LABEL + ", " + + SELECT_FIRST_NAME + ", " + SELECT_LAST_NAME + ", " + SELECT_EMAIL + ", " + SELECT_REGION + ", " + + SELECT_TITLE + ", " + SELECT_COUNTRY + ", " + SELECT_STATE + ", " + SELECT_CITY + ", " + + SELECT_ADDRESS + ", " + SELECT_ADDRESS_2 + ", " + SELECT_ZIP + ", " + SELECT_PHONE + + ", entity.entity_type as entity_type"; String from = getQueryTemplate(entityFilter.getDirection()); ctx.addUuidParameter("relation_root_id", rootId.getId()); ctx.addStringParameter("relation_root_type", rootId.getEntityType().name()); @@ -347,98 +477,6 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository { return from; } - private String getSelectCreatedTime() { - return "created_time"; - } - - private String getSelectTenantId() { - return "SELECT CASE" + - " WHEN entity.entity_type = 'TENANT' THEN entity_id" + - " WHEN entity.entity_type = 'CUSTOMER'" + - " THEN (select tenant_id from customer where id = entity_id)" + - " WHEN entity.entity_type = 'USER'" + - " THEN (select tenant_id from tb_user where id = entity_id)" + - " WHEN entity.entity_type = 'DASHBOARD'" + - " THEN (select tenant_id from dashboard where id = entity_id)" + - " WHEN entity.entity_type = 'ASSET'" + - " THEN (select tenant_id from asset where id = entity_id)" + - " WHEN entity.entity_type = 'DEVICE'" + - " THEN (select tenant_id from device where id = entity_id)" + - " WHEN entity.entity_type = 'ENTITY_VIEW'" + - " THEN (select tenant_id from entity_view where id = entity_id)" + - " END as tenant_id"; - } - - private String getSelectCustomerId() { - return "CASE" + - " WHEN entity.entity_type = 'TENANT'" + - " THEN UUID('" + TenantId.NULL_UUID + "')" + - " WHEN entity.entity_type = 'CUSTOMER' THEN entity_id" + - " WHEN entity.entity_type = 'USER'" + - " THEN (select customer_id from tb_user where id = entity_id)" + - " WHEN entity.entity_type = 'DASHBOARD'" + - //TODO: parse assigned customers or use contains? - " THEN NULL" + - " WHEN entity.entity_type = 'ASSET'" + - " THEN (select customer_id from asset where id = entity_id)" + - " WHEN entity.entity_type = 'DEVICE'" + - " THEN (select customer_id from device where id = entity_id)" + - " WHEN entity.entity_type = 'ENTITY_VIEW'" + - " THEN (select customer_id from entity_view where id = entity_id)" + - " END as customer_id"; - } - - private String getSelectName() { - return " CASE" + - " WHEN entity.entity_type = 'TENANT'" + - " THEN (select title from tenant where id = entity_id)" + - " WHEN entity.entity_type = 'CUSTOMER' " + - " THEN (select title from customer where id = entity_id)" + - " WHEN entity.entity_type = 'USER'" + - " THEN (select CONCAT (first_name, ' ', last_name) from tb_user where id = entity_id)" + - " WHEN entity.entity_type = 'DASHBOARD'" + - " THEN (select title from dashboard where id = entity_id)" + - " WHEN entity.entity_type = 'ASSET'" + - " THEN (select name from asset where id = entity_id)" + - " WHEN entity.entity_type = 'DEVICE'" + - " THEN (select name from device where id = entity_id)" + - " WHEN entity.entity_type = 'ENTITY_VIEW'" + - " THEN (select name from entity_view where id = entity_id)" + - " END as name"; - } - - private String getSelectType() { - return " CASE" + - " WHEN entity.entity_type = 'USER'" + - " THEN (select authority from tb_user where id = entity_id)" + - " WHEN entity.entity_type = 'ASSET'" + - " THEN (select type from asset where id = entity_id)" + - " WHEN entity.entity_type = 'DEVICE'" + - " THEN (select type from device where id = entity_id)" + - " WHEN entity.entity_type = 'ENTITY_VIEW'" + - " THEN (select type from entity_view where id = entity_id)" + - " ELSE entity.entity_type END as type"; - } - - private String getSelectLabel() { - return " CASE" + - " WHEN entity.entity_type = 'TENANT'" + - " THEN (select title from tenant where id = entity_id)" + - " WHEN entity.entity_type = 'CUSTOMER' " + - " THEN (select title from customer where id = entity_id)" + - " WHEN entity.entity_type = 'USER'" + - " THEN (select CONCAT (first_name, ' ', last_name) from tb_user where id = entity_id)" + - " WHEN entity.entity_type = 'DASHBOARD'" + - " THEN (select title from dashboard where id = entity_id)" + - " WHEN entity.entity_type = 'ASSET'" + - " THEN (select label from asset where id = entity_id)" + - " WHEN entity.entity_type = 'DEVICE'" + - " THEN (select label from device where id = entity_id)" + - " WHEN entity.entity_type = 'ENTITY_VIEW'" + - " THEN (select name from entity_view where id = entity_id)" + - " END as label"; - } - private String buildWhere(EntityQueryContext ctx, List latestFiltersMapping) { String latestFilters = EntityKeyMapping.buildQuery(ctx, latestFiltersMapping); if (!StringUtils.isEmpty(latestFilters)) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java index 74c51723e7..406e6d7607 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/query/EntityKeyMapping.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -50,6 +50,7 @@ public class EntityKeyMapping { private static final Map> allowedEntityFieldMap = new HashMap<>(); private static final Map entityFieldColumnMap = new HashMap<>(); + private static final Map> aliases = new HashMap<>(); private static final String CREATED_TIME = "createdTime"; private static final String ENTITY_TYPE = "entityType"; @@ -71,10 +72,10 @@ public class EntityKeyMapping { public static final List commonEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME); public static final List labeledEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL); - public static final List contactBasedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, EMAIL, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE); + public static final List contactBasedEntityFields = Arrays.asList(CREATED_TIME, ENTITY_TYPE, EMAIL, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE); public static final Set commonEntityFieldsSet = new HashSet<>(commonEntityFields); - public static final Set relationQueryEntityFieldsSet = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL)); + public static final Set relationQueryEntityFieldsSet = new HashSet<>(Arrays.asList(CREATED_TIME, ENTITY_TYPE, NAME, TYPE, LABEL, FIRST_NAME, LAST_NAME, EMAIL, REGION, TITLE, COUNTRY, STATE, CITY, ADDRESS, ADDRESS_2, ZIP, PHONE)); static { allowedEntityFieldMap.put(EntityType.DEVICE, new HashSet<>(labeledEntityFields)); @@ -110,6 +111,25 @@ public class EntityKeyMapping { entityFieldColumnMap.put(ADDRESS_2, ModelConstants.ADDRESS2_PROPERTY); entityFieldColumnMap.put(ZIP, ModelConstants.ZIP_PROPERTY); entityFieldColumnMap.put(PHONE, ModelConstants.PHONE_PROPERTY); + + Map contactBasedAliases = new HashMap<>(); + contactBasedAliases.put(NAME, TITLE); + contactBasedAliases.put(LABEL, TITLE); + aliases.put(EntityType.TENANT, contactBasedAliases); + aliases.put(EntityType.CUSTOMER, contactBasedAliases); + Map commonEntityAliases = new HashMap<>(); + commonEntityAliases.put(TITLE, NAME); + aliases.put(EntityType.DEVICE, commonEntityAliases); + aliases.put(EntityType.ASSET, commonEntityAliases); + aliases.put(EntityType.ENTITY_VIEW, commonEntityAliases); + aliases.put(EntityType.DASHBOARD, commonEntityAliases); + aliases.put(EntityType.WIDGETS_BUNDLE, commonEntityAliases); + + Map userEntityAliases = new HashMap<>(); + userEntityAliases.put(TITLE, EMAIL); + userEntityAliases.put(LABEL, EMAIL); + userEntityAliases.put(NAME, EMAIL); + aliases.put(EntityType.USER, userEntityAliases); } private int index; @@ -141,16 +161,28 @@ public class EntityKeyMapping { public String toSelection(EntityFilterType filterType, EntityType entityType) { if (entityKey.getType().equals(EntityKeyType.ENTITY_FIELD)) { Set existingEntityFields; + String alias; if (filterType.equals(EntityFilterType.RELATIONS_QUERY)) { existingEntityFields = relationQueryEntityFieldsSet; + alias = entityKey.getKey(); } else { existingEntityFields = allowedEntityFieldMap.get(entityType); if (existingEntityFields == null) { existingEntityFields = commonEntityFieldsSet; } + + Map entityAliases = aliases.get(entityType); + if (entityAliases != null) { + alias = entityAliases.get(entityKey.getKey()); + } else { + alias = null; + } + if (alias == null) { + alias = entityKey.getKey(); + } } - if (existingEntityFields.contains(entityKey.getKey())) { - String column = entityFieldColumnMap.get(entityKey.getKey()); + if (existingEntityFields.contains(alias)) { + String column = entityFieldColumnMap.get(alias); return String.format("e.%s as %s", column, getValueAlias()); } else { return String.format("'' as %s", getValueAlias());