Device info view improvements
This commit is contained in:
		
							parent
							
								
									dcbc4c5c7d
								
							
						
					
					
						commit
						9e589c8044
					
				@ -16,16 +16,27 @@
 | 
			
		||||
 | 
			
		||||
-- DEVICE INFO VIEW START
 | 
			
		||||
 | 
			
		||||
DROP VIEW IF EXISTS device_info_view CASCADE;
 | 
			
		||||
CREATE OR REPLACE VIEW device_info_view as
 | 
			
		||||
DROP VIEW IF EXISTS device_info_active_attribute_view CASCADE;
 | 
			
		||||
CREATE OR REPLACE VIEW device_info_active_attribute_view AS
 | 
			
		||||
SELECT d.*
 | 
			
		||||
       , c.title as customer_title
 | 
			
		||||
       , c.additional_info::json->>'isPublic' as customer_is_public
 | 
			
		||||
       , COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public
 | 
			
		||||
       , d.type as device_profile_name
 | 
			
		||||
       , (select bool_v from attribute_kv da where da.entity_id = d.id and da.attribute_key = 'active') as attribute_active
 | 
			
		||||
       , (select bool_v from ts_kv_latest dt where dt.entity_id = d.id and dt.key = (select key_id from ts_kv_dictionary where key = 'active')) as ts_active
 | 
			
		||||
       , COALESCE(da.bool_v, FALSE) as active
 | 
			
		||||
FROM device d
 | 
			
		||||
         LEFT JOIN customer c ON c.id = d.customer_id;
 | 
			
		||||
         LEFT JOIN customer c ON c.id = d.customer_id
 | 
			
		||||
         LEFT JOIN attribute_kv da ON da.entity_id = d.id and da.attribute_key = 'active';
 | 
			
		||||
 | 
			
		||||
DROP VIEW IF EXISTS device_info_active_ts_view CASCADE;
 | 
			
		||||
CREATE OR REPLACE VIEW device_info_active_ts_view AS
 | 
			
		||||
SELECT d.*
 | 
			
		||||
       , c.title as customer_title
 | 
			
		||||
       , COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public
 | 
			
		||||
       , d.type as device_profile_name
 | 
			
		||||
       , COALESCE(dt.bool_v, FALSE) as active
 | 
			
		||||
FROM device d
 | 
			
		||||
         LEFT JOIN customer c ON c.id = d.customer_id
 | 
			
		||||
         LEFT JOIN ts_kv_latest dt ON dt.entity_id = d.id and dt.key = (select key_id from ts_kv_dictionary where key = 'active');
 | 
			
		||||
 | 
			
		||||
-- DEVICE INFO VIEW END
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -53,6 +53,9 @@ public class ThingsboardInstallService {
 | 
			
		||||
    @Value("${install.load_demo:false}")
 | 
			
		||||
    private Boolean loadDemo;
 | 
			
		||||
 | 
			
		||||
    @Value("${state.persistToTelemetry:false}")
 | 
			
		||||
    private boolean persistToTelemetry;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private EntityDatabaseSchemaService entityDatabaseSchemaService;
 | 
			
		||||
 | 
			
		||||
@ -247,6 +250,7 @@ public class ThingsboardInstallService {
 | 
			
		||||
                        case "3.4.4":
 | 
			
		||||
                            log.info("Upgrading ThingsBoard from version 3.4.4 to 3.5.0 ...");
 | 
			
		||||
                            databaseEntitiesUpgradeService.upgradeDatabase("3.4.4");
 | 
			
		||||
                            entityDatabaseSchemaService.createOrUpdateDeviceInfoView(persistToTelemetry);
 | 
			
		||||
                            log.info("Updating system data...");
 | 
			
		||||
                            systemDataLoaderService.updateSystemWidgets();
 | 
			
		||||
                            if (!getEnv("SKIP_DEFAULT_NOTIFICATION_CONFIGS_CREATION", false)) {
 | 
			
		||||
@ -272,6 +276,8 @@ public class ThingsboardInstallService {
 | 
			
		||||
 | 
			
		||||
                entityDatabaseSchemaService.createDatabaseSchema();
 | 
			
		||||
 | 
			
		||||
                entityDatabaseSchemaService.createOrUpdateDeviceInfoView(persistToTelemetry);
 | 
			
		||||
 | 
			
		||||
                log.info("Installing DataBase schema for timeseries...");
 | 
			
		||||
 | 
			
		||||
                if (noSqlKeyspaceService != null) {
 | 
			
		||||
 | 
			
		||||
@ -16,4 +16,7 @@
 | 
			
		||||
package org.thingsboard.server.service.install;
 | 
			
		||||
 | 
			
		||||
public interface EntityDatabaseSchemaService extends DatabaseSchemaService {
 | 
			
		||||
 | 
			
		||||
    void createOrUpdateDeviceInfoView(boolean activityStateInTelemetry);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -39,4 +39,10 @@ public class SqlEntityDatabaseSchemaService extends SqlAbstractDatabaseSchemaSer
 | 
			
		||||
        executeQueryFromFile(SCHEMA_ENTITIES_IDX_PSQL_ADDON_SQL);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void createOrUpdateDeviceInfoView(boolean activityStateInTelemetry) {
 | 
			
		||||
        String sourceViewName = activityStateInTelemetry ? "device_info_active_ts_view" : "device_info_active_attribute_view";
 | 
			
		||||
        executeQuery("DROP VIEW IF EXISTS device_info_view CASCADE;");
 | 
			
		||||
        executeQuery("CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM " + sourceViewName + ";");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -645,6 +645,10 @@ state:
 | 
			
		||||
  # Should be greater then transport.sessions.report_timeout
 | 
			
		||||
  defaultInactivityTimeoutInSec: "${DEFAULT_INACTIVITY_TIMEOUT:600}"
 | 
			
		||||
  defaultStateCheckIntervalInSec: "${DEFAULT_STATE_CHECK_INTERVAL:60}"
 | 
			
		||||
  # Controls whether we store device 'active' flag in attributes (default) or telemetry.
 | 
			
		||||
  # If you device to change this parameter, you should re-create the device info view as one of the following:
 | 
			
		||||
  # If 'persistToTelemetry' is changed from 'false' to 'true': 'CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM device_info_active_ts_view;'
 | 
			
		||||
  # If 'persistToTelemetry' is changed from 'true' to 'false': 'CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM device_info_active_attribute_view;'
 | 
			
		||||
  persistToTelemetry: "${PERSIST_STATE_TO_TELEMETRY:false}"
 | 
			
		||||
 | 
			
		||||
tbel:
 | 
			
		||||
 | 
			
		||||
@ -46,12 +46,6 @@ public abstract class DaoUtil {
 | 
			
		||||
        return new PageData<>(data, page.getTotalPages(), page.getTotalElements(), page.hasNext());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static <T> PageData<T> toPageData(Page<? extends ToData<T>> page, Object... params) {
 | 
			
		||||
        List<T> data = convertDataList(page.getContent(), params);
 | 
			
		||||
        return new PageData<>(data, page.getTotalPages(), page.getTotalElements(), page.hasNext());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public static <T> PageData<T> pageToPageData(Page<T> page) {
 | 
			
		||||
        return new PageData<>(page.getContent(), page.getTotalPages(), page.getTotalElements(), page.hasNext());
 | 
			
		||||
    }
 | 
			
		||||
@ -85,19 +79,6 @@ public abstract class DaoUtil {
 | 
			
		||||
        return list;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static <T> List<T> convertDataList(Collection<? extends ToData<T>> toDataList, Object... params) {
 | 
			
		||||
        List<T> list = Collections.emptyList();
 | 
			
		||||
        if (toDataList != null && !toDataList.isEmpty()) {
 | 
			
		||||
            list = new ArrayList<>();
 | 
			
		||||
            for (ToData<T> object : toDataList) {
 | 
			
		||||
                if (object != null) {
 | 
			
		||||
                    list.add(object.toData(params));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return list;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static <T> T getData(ToData<T> data) {
 | 
			
		||||
        T object = null;
 | 
			
		||||
        if (data != null) {
 | 
			
		||||
@ -106,15 +87,6 @@ public abstract class DaoUtil {
 | 
			
		||||
        return object;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static <T> T getData(ToData<T> data, Object... params) {
 | 
			
		||||
        T object = null;
 | 
			
		||||
        if (data != null) {
 | 
			
		||||
            object = data.toData(params);
 | 
			
		||||
        }
 | 
			
		||||
        return object;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    public static <T> T getData(Optional<? extends ToData<T>> data) {
 | 
			
		||||
        T object = null;
 | 
			
		||||
        if (data.isPresent()) {
 | 
			
		||||
 | 
			
		||||
@ -172,8 +172,7 @@ public class ModelConstants {
 | 
			
		||||
    public static final String DEVICE_CUSTOMER_TITLE_PROPERTY = "customer_title";
 | 
			
		||||
    public static final String DEVICE_CUSTOMER_IS_PUBLIC_PROPERTY = "customer_is_public";
 | 
			
		||||
    public static final String DEVICE_DEVICE_PROFILE_NAME_PROPERTY = "device_profile_name";
 | 
			
		||||
    public static final String DEVICE_ATTR_ACTIVE_PROPERTY = "attribute_active";
 | 
			
		||||
    public static final String DEVICE_TS_ACTIVE_PROPERTY = "ts_active";
 | 
			
		||||
    public static final String DEVICE_ACTIVE_PROPERTY = "active";
 | 
			
		||||
 | 
			
		||||
    public static final String DEVICE_BY_TENANT_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_and_search_text";
 | 
			
		||||
    public static final String DEVICE_BY_TENANT_BY_TYPE_AND_SEARCH_TEXT_COLUMN_FAMILY_NAME = "device_by_tenant_by_type_and_search_text";
 | 
			
		||||
 | 
			
		||||
@ -29,7 +29,4 @@ public interface ToData<T> {
 | 
			
		||||
     */
 | 
			
		||||
    T toData();
 | 
			
		||||
 | 
			
		||||
    default T toData(Object... params) {
 | 
			
		||||
        return toData();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -24,8 +24,6 @@ import org.thingsboard.server.dao.model.ModelConstants;
 | 
			
		||||
import javax.persistence.Column;
 | 
			
		||||
import javax.persistence.Entity;
 | 
			
		||||
import javax.persistence.Table;
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@EqualsAndHashCode(callSuper = true)
 | 
			
		||||
@ -34,23 +32,14 @@ import java.util.Map;
 | 
			
		||||
@Table(name = ModelConstants.DEVICE_INFO_VIEW_COLUMN_FAMILY_NAME)
 | 
			
		||||
public class DeviceInfoEntity extends AbstractDeviceEntity<DeviceInfo> {
 | 
			
		||||
 | 
			
		||||
    public static final Map<String, String> attrActiveColumnMap = new HashMap<>();
 | 
			
		||||
    public static final Map<String, String> tsActiveColumnMap = new HashMap<>();
 | 
			
		||||
    static {
 | 
			
		||||
        attrActiveColumnMap.put("active", "attributeActive");
 | 
			
		||||
        tsActiveColumnMap.put("active", "tsActive");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Column(name = ModelConstants.DEVICE_CUSTOMER_TITLE_PROPERTY)
 | 
			
		||||
    private String customerTitle;
 | 
			
		||||
    @Column(name = ModelConstants.DEVICE_CUSTOMER_IS_PUBLIC_PROPERTY)
 | 
			
		||||
    private Boolean customerIsPublic;
 | 
			
		||||
    private boolean customerIsPublic;
 | 
			
		||||
    @Column(name = ModelConstants.DEVICE_DEVICE_PROFILE_NAME_PROPERTY)
 | 
			
		||||
    private String deviceProfileName;
 | 
			
		||||
    @Column(name = ModelConstants.DEVICE_ATTR_ACTIVE_PROPERTY)
 | 
			
		||||
    private Boolean attributeActive;
 | 
			
		||||
    @Column(name = ModelConstants.DEVICE_TS_ACTIVE_PROPERTY)
 | 
			
		||||
    private Boolean tsActive;
 | 
			
		||||
    @Column(name = ModelConstants.DEVICE_ACTIVE_PROPERTY)
 | 
			
		||||
    private boolean active;
 | 
			
		||||
 | 
			
		||||
    public DeviceInfoEntity() {
 | 
			
		||||
        super();
 | 
			
		||||
@ -59,13 +48,7 @@ public class DeviceInfoEntity extends AbstractDeviceEntity<DeviceInfo> {
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public DeviceInfo toData() {
 | 
			
		||||
        return toData(false);
 | 
			
		||||
        return new DeviceInfo(super.toDevice(), customerTitle, customerIsPublic, deviceProfileName, active);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public DeviceInfo toData(Object... persistToTelemetry) {
 | 
			
		||||
        boolean attr = persistToTelemetry.length == 0 || !(Boolean) persistToTelemetry[0];
 | 
			
		||||
        return new DeviceInfo(super.toDevice(), customerTitle, Boolean.TRUE.equals(customerIsPublic), deviceProfileName,
 | 
			
		||||
                attr ? Boolean.TRUE.equals(attributeActive) : Boolean.TRUE.equals(tsActive));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -21,10 +21,6 @@ import org.springframework.data.jpa.repository.JpaRepository;
 | 
			
		||||
import org.springframework.data.jpa.repository.Query;
 | 
			
		||||
import org.springframework.data.repository.query.Param;
 | 
			
		||||
import org.thingsboard.server.common.data.DeviceTransportType;
 | 
			
		||||
import org.thingsboard.server.common.data.DeviceIdInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.id.CustomerId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.DeviceProfileId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.dao.ExportableEntityRepository;
 | 
			
		||||
import org.thingsboard.server.dao.model.sql.DeviceEntity;
 | 
			
		||||
import org.thingsboard.server.dao.model.sql.DeviceInfoEntity;
 | 
			
		||||
@ -125,7 +121,7 @@ public interface DeviceRepository extends JpaRepository<DeviceEntity, UUID>, Exp
 | 
			
		||||
            "AND (:customerId IS NULL OR d.customerId = uuid(:customerId)) " +
 | 
			
		||||
            "AND ((:deviceType) IS NULL OR d.type = :deviceType) " +
 | 
			
		||||
            "AND (:deviceProfileId IS NULL OR d.deviceProfileId = uuid(:deviceProfileId)) " +
 | 
			
		||||
            "AND ((:filterByActive) IS FALSE OR (((:persistToTelemetry) IS TRUE AND d.tsActive = :deviceActive) OR ((:persistToTelemetry) IS FALSE AND d.attributeActive = :deviceActive))) " +
 | 
			
		||||
            "AND ((:filterByActive) IS FALSE OR d.active = :deviceActive) " +
 | 
			
		||||
            "AND (LOWER(d.searchText) LIKE LOWER(CONCAT('%', :textSearch, '%')) " +
 | 
			
		||||
            "OR LOWER(d.label) LIKE LOWER(CONCAT('%', :textSearch, '%')) " +
 | 
			
		||||
            "OR LOWER(d.type) LIKE LOWER(CONCAT('%', :textSearch, '%')) " +
 | 
			
		||||
@ -135,7 +131,6 @@ public interface DeviceRepository extends JpaRepository<DeviceEntity, UUID>, Exp
 | 
			
		||||
                                                   @Param("deviceType") String type,
 | 
			
		||||
                                                   @Param("deviceProfileId") String deviceProfileId,
 | 
			
		||||
                                                   @Param("filterByActive") boolean filterByActive,
 | 
			
		||||
                                                   @Param("persistToTelemetry") boolean persistToTelemetry,
 | 
			
		||||
                                                   @Param("deviceActive") boolean active,
 | 
			
		||||
                                                   @Param("textSearch") String textSearch,
 | 
			
		||||
                                                   Pageable pageable);
 | 
			
		||||
@ -178,7 +173,7 @@ public interface DeviceRepository extends JpaRepository<DeviceEntity, UUID>, Exp
 | 
			
		||||
    /**
 | 
			
		||||
     * Count devices by tenantId.
 | 
			
		||||
     * Custom query applied because default QueryDSL produces slow count(id).
 | 
			
		||||
     * <p>
 | 
			
		||||
     *
 | 
			
		||||
     * There is two way to count devices.
 | 
			
		||||
     * OPTIMAL: count(*)
 | 
			
		||||
     * - returns _row_count_ and use index-only scan (super fast).
 | 
			
		||||
 | 
			
		||||
@ -64,11 +64,6 @@ import java.util.UUID;
 | 
			
		||||
@Slf4j
 | 
			
		||||
public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device> implements DeviceDao {
 | 
			
		||||
 | 
			
		||||
    @Value("${state.persistToTelemetry:false}")
 | 
			
		||||
    private boolean persistToTelemetry;
 | 
			
		||||
 | 
			
		||||
    private Map<String, String> activeColumnMap;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private DeviceRepository deviceRepository;
 | 
			
		||||
 | 
			
		||||
@ -85,14 +80,9 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
 | 
			
		||||
        return deviceRepository;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @PostConstruct
 | 
			
		||||
    public void init() {
 | 
			
		||||
        activeColumnMap = persistToTelemetry ? DeviceInfoEntity.tsActiveColumnMap : DeviceInfoEntity.attrActiveColumnMap;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public DeviceInfo findDeviceInfoById(TenantId tenantId, UUID deviceId) {
 | 
			
		||||
        return DaoUtil.getData(deviceRepository.findDeviceInfoById(deviceId), persistToTelemetry);
 | 
			
		||||
        return DaoUtil.getData(deviceRepository.findDeviceInfoById(deviceId));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
@ -128,10 +118,9 @@ public class JpaDeviceDao extends JpaAbstractSearchTextDao<DeviceEntity, Device>
 | 
			
		||||
                        filter.getType(),
 | 
			
		||||
                        DaoUtil.getStringId(filter.getDeviceProfileId()),
 | 
			
		||||
                        filter.getActive() != null,
 | 
			
		||||
                        persistToTelemetry,
 | 
			
		||||
                        Boolean.TRUE.equals(filter.getActive()),
 | 
			
		||||
                        Objects.toString(pageLink.getTextSearch(), ""),
 | 
			
		||||
                        DaoUtil.toPageable(pageLink, activeColumnMap)), persistToTelemetry);
 | 
			
		||||
                        DaoUtil.toPageable(pageLink)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
 | 
			
		||||
@ -859,15 +859,27 @@ CREATE TABLE IF NOT EXISTS user_settings (
 | 
			
		||||
    CONSTRAINT user_settings_pkey PRIMARY KEY (user_id, type)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE OR REPLACE VIEW device_info_view as
 | 
			
		||||
DROP VIEW IF EXISTS device_info_active_attribute_view CASCADE;
 | 
			
		||||
CREATE OR REPLACE VIEW device_info_active_attribute_view AS
 | 
			
		||||
SELECT d.*
 | 
			
		||||
       , c.title as customer_title
 | 
			
		||||
       , c.additional_info::json->>'isPublic' as customer_is_public
 | 
			
		||||
       , COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public
 | 
			
		||||
       , d.type as device_profile_name
 | 
			
		||||
       , (select bool_v from attribute_kv da where da.entity_id = d.id and da.attribute_key = 'active') as attribute_active
 | 
			
		||||
       , (select bool_v from ts_kv_latest dt where dt.entity_id = d.id and dt.key = (select key_id from ts_kv_dictionary where key = 'active')) as ts_active
 | 
			
		||||
       , COALESCE(da.bool_v, FALSE) as active
 | 
			
		||||
FROM device d
 | 
			
		||||
         LEFT JOIN customer c ON c.id = d.customer_id;
 | 
			
		||||
         LEFT JOIN customer c ON c.id = d.customer_id
 | 
			
		||||
         LEFT JOIN attribute_kv da ON da.entity_id = d.id and da.attribute_key = 'active';
 | 
			
		||||
 | 
			
		||||
DROP VIEW IF EXISTS device_info_active_ts_view CASCADE;
 | 
			
		||||
CREATE OR REPLACE VIEW device_info_active_ts_view AS
 | 
			
		||||
SELECT d.*
 | 
			
		||||
       , c.title as customer_title
 | 
			
		||||
       , COALESCE((c.additional_info::json->>'isPublic')::bool, FALSE) as customer_is_public
 | 
			
		||||
       , d.type as device_profile_name
 | 
			
		||||
       , COALESCE(dt.bool_v, FALSE) as active
 | 
			
		||||
FROM device d
 | 
			
		||||
         LEFT JOIN customer c ON c.id = d.customer_id
 | 
			
		||||
         LEFT JOIN ts_kv_latest dt ON dt.entity_id = d.id and dt.key = (select key_id from ts_kv_dictionary where key = 'active');
 | 
			
		||||
 | 
			
		||||
DROP VIEW IF EXISTS alarm_info CASCADE;
 | 
			
		||||
CREATE VIEW alarm_info AS
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user