Alarm Query performance improvements
This commit is contained in:
		
							parent
							
								
									a8dad4c6e0
								
							
						
					
					
						commit
						d3c20b2e57
					
				
							
								
								
									
										29
									
								
								application/src/main/data/upgrade/3.3.2/schema_update.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								application/src/main/data/upgrade/3.3.2/schema_update.sql
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
--
 | 
			
		||||
-- Copyright © 2016-2021 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.
 | 
			
		||||
--
 | 
			
		||||
 | 
			
		||||
CREATE TABLE IF NOT EXISTS entity_alarm (
 | 
			
		||||
    tenant_id uuid NOT NULL,
 | 
			
		||||
    entity_id uuid NOT NULL,
 | 
			
		||||
    created_time bigint NOT NULL,
 | 
			
		||||
    type varchar(255) NOT NULL,
 | 
			
		||||
    customer_id uuid,
 | 
			
		||||
    alarm_id uuid
 | 
			
		||||
    CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id),
 | 
			
		||||
    CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX IF NOT EXISTS idx_alarm_tenant_status_created_time ON alarm(tenant_id, status, created_time DESC);
 | 
			
		||||
CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC);
 | 
			
		||||
@ -210,6 +210,10 @@ public class ThingsboardInstallService {
 | 
			
		||||
                            log.info("Upgrading ThingsBoard from version 3.3.0 to 3.3.1 ...");
 | 
			
		||||
                        case "3.3.1":
 | 
			
		||||
                            log.info("Upgrading ThingsBoard from version 3.3.1 to 3.3.2 ...");
 | 
			
		||||
                            break;
 | 
			
		||||
                        case "3.3.2":
 | 
			
		||||
                            log.info("Upgrading ThingsBoard from version 3.3.2 to 3.3.3 ...");
 | 
			
		||||
                            databaseEntitiesUpgradeService.upgradeDatabase("3.3.2");
 | 
			
		||||
                            log.info("Updating system data...");
 | 
			
		||||
                            systemDataLoaderService.updateSystemWidgets();
 | 
			
		||||
                            break;
 | 
			
		||||
 | 
			
		||||
@ -469,6 +469,28 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService
 | 
			
		||||
                    log.error("Failed updating schema!!!", e);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            case "3.3.2":
 | 
			
		||||
                try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) {
 | 
			
		||||
                    log.info("Updating schema ...");
 | 
			
		||||
                    schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.2", SCHEMA_UPDATE_SQL);
 | 
			
		||||
                    loadSql(schemaUpdateFile, conn);
 | 
			
		||||
                    try {
 | 
			
		||||
                        conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id, status, severity)" +
 | 
			
		||||
                                " select tenant_id, originator_id, created_time, type, customer_id, id, status, severity from alarm;");
 | 
			
		||||
                        conn.createStatement().execute("insert into entity_alarm(tenant_id, entity_id, created_time, type, customer_id, alarm_id, status, severity)" +
 | 
			
		||||
                                " select a.tenant_id, r.from_id, created_time, type, customer_id, id, status, severity" +
 | 
			
		||||
                                " from alarm a inner join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id ON CONFLICT DO NOTHING;");
 | 
			
		||||
                        conn.createStatement().execute("delete from relation r where r.relation_type_group = 'ALARM';");
 | 
			
		||||
                    } catch (Exception e) {
 | 
			
		||||
                        log.error("Failed to update alarm relations!!!", e);
 | 
			
		||||
                    }
 | 
			
		||||
                    log.info("Updating schema settings...");
 | 
			
		||||
                    conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3003003;");
 | 
			
		||||
                    log.info("Schema updated.");
 | 
			
		||||
                } catch (Exception e) {
 | 
			
		||||
                    log.error("Failed updating schema!!!", e);
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                throw new RuntimeException("Unable to upgrade SQL database, unsupported fromVersion: " + fromVersion);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,40 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2021 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.common.data.alarm;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import org.thingsboard.server.common.data.HasTenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.AlarmId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.CustomerId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
public class EntityAlarm implements HasTenantId {
 | 
			
		||||
 | 
			
		||||
    private TenantId tenantId;
 | 
			
		||||
    private EntityId entityId;
 | 
			
		||||
    private long createdTime;
 | 
			
		||||
    private String alarmType;
 | 
			
		||||
 | 
			
		||||
    private CustomerId customerId;
 | 
			
		||||
    private AlarmId alarmId;
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -18,7 +18,6 @@ package org.thingsboard.server.common.data.relation;
 | 
			
		||||
public enum RelationTypeGroup {
 | 
			
		||||
 | 
			
		||||
    COMMON,
 | 
			
		||||
    ALARM,
 | 
			
		||||
    DASHBOARD,
 | 
			
		||||
    RULE_CHAIN,
 | 
			
		||||
    RULE_NODE,
 | 
			
		||||
 | 
			
		||||
@ -21,6 +21,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmQuery;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmStatus;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.EntityAlarm;
 | 
			
		||||
import org.thingsboard.server.common.data.id.AlarmId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.CustomerId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
@ -32,6 +33,7 @@ import org.thingsboard.server.common.data.query.AlarmDataQuery;
 | 
			
		||||
import org.thingsboard.server.dao.Dao;
 | 
			
		||||
 | 
			
		||||
import java.util.Collection;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Set;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
@ -59,4 +61,7 @@ public interface AlarmDao extends Dao<Alarm> {
 | 
			
		||||
 | 
			
		||||
    PageData<AlarmId> findAlarmsIdsByEndTsBeforeAndTenantId(Long time, TenantId tenantId, PageLink pageLink);
 | 
			
		||||
 | 
			
		||||
    void createEntityAlarmRecord(EntityAlarm entityAlarm);
 | 
			
		||||
 | 
			
		||||
    List<EntityAlarm> findEntityAlarmRecords(TenantId tenantId, AlarmId id);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -34,6 +34,7 @@ import org.thingsboard.server.common.data.alarm.AlarmQuery;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmSearchStatus;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmStatus;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.EntityAlarm;
 | 
			
		||||
import org.thingsboard.server.common.data.exception.ApiUsageLimitsExceededException;
 | 
			
		||||
import org.thingsboard.server.common.data.id.AlarmId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.CustomerId;
 | 
			
		||||
@ -166,23 +167,24 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
 | 
			
		||||
    private AlarmOperationResult createAlarm(Alarm alarm) throws InterruptedException, ExecutionException {
 | 
			
		||||
        log.debug("New Alarm : {}", alarm);
 | 
			
		||||
        Alarm saved = alarmDao.save(alarm.getTenantId(), alarm);
 | 
			
		||||
        List<EntityId> propagatedEntitiesList = createAlarmRelations(saved);
 | 
			
		||||
        List<EntityId> propagatedEntitiesList = createEntityAlarmRecords(saved);
 | 
			
		||||
        return new AlarmOperationResult(saved, true, true, propagatedEntitiesList);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private List<EntityId> createAlarmRelations(Alarm alarm) throws InterruptedException, ExecutionException {
 | 
			
		||||
    private List<EntityId> createEntityAlarmRecords(Alarm alarm) throws InterruptedException, ExecutionException {
 | 
			
		||||
        List<EntityId> propagatedEntitiesList;
 | 
			
		||||
        if (alarm.isPropagate()) {
 | 
			
		||||
            Set<EntityId> parentEntities = getParentEntities(alarm);
 | 
			
		||||
            propagatedEntitiesList = new ArrayList<>(parentEntities.size() + 1);
 | 
			
		||||
            for (EntityId parentId : parentEntities) {
 | 
			
		||||
                propagatedEntitiesList.add(parentId);
 | 
			
		||||
                createAlarmRelation(alarm.getTenantId(), parentId, alarm.getId());
 | 
			
		||||
                createEntityAlarmRecord(alarm.getTenantId(), parentId, alarm);
 | 
			
		||||
            }
 | 
			
		||||
            propagatedEntitiesList.add(alarm.getOriginator());
 | 
			
		||||
        } else {
 | 
			
		||||
            propagatedEntitiesList = Collections.singletonList(alarm.getOriginator());
 | 
			
		||||
        }
 | 
			
		||||
        createEntityAlarmRecord(alarm.getTenantId(), alarm.getOriginator(), alarm);
 | 
			
		||||
        return propagatedEntitiesList;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -221,7 +223,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
 | 
			
		||||
        List<EntityId> propagatedEntitiesList;
 | 
			
		||||
        if (!oldPropagate && newPropagate) {
 | 
			
		||||
            try {
 | 
			
		||||
                propagatedEntitiesList = createAlarmRelations(result);
 | 
			
		||||
                propagatedEntitiesList = createEntityAlarmRecords(result);
 | 
			
		||||
            } catch (InterruptedException | ExecutionException e) {
 | 
			
		||||
                log.warn("Failed to update alarm relations [{}]", result, e);
 | 
			
		||||
                throw new RuntimeException(e);
 | 
			
		||||
@ -382,17 +384,20 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
 | 
			
		||||
 | 
			
		||||
    private Set<EntityId> getPropagationEntityIds(Alarm alarm) {
 | 
			
		||||
        if (alarm.isPropagate()) {
 | 
			
		||||
            List<EntityRelation> relations = relationService.findByTo(alarm.getTenantId(), alarm.getId(), RelationTypeGroup.ALARM);
 | 
			
		||||
            Set<EntityId> propagationEntityIds = relations.stream().map(EntityRelation::getFrom).collect(Collectors.toSet());
 | 
			
		||||
            propagationEntityIds.add(alarm.getOriginator());
 | 
			
		||||
            return propagationEntityIds;
 | 
			
		||||
            List<EntityAlarm> entityAlarms = alarmDao.findEntityAlarmRecords(alarm.getTenantId(), alarm.getId());
 | 
			
		||||
            return entityAlarms.stream().map(EntityAlarm::getEntityId).collect(Collectors.toSet());
 | 
			
		||||
        } else {
 | 
			
		||||
            return Collections.singleton(alarm.getOriginator());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void createAlarmRelation(TenantId tenantId, EntityId entityId, EntityId alarmId) {
 | 
			
		||||
        createRelation(tenantId, new EntityRelation(entityId, alarmId, AlarmSearchStatus.ANY.name(), RelationTypeGroup.ALARM));
 | 
			
		||||
    private void createEntityAlarmRecord(TenantId tenantId, EntityId entityId, Alarm alarm) {
 | 
			
		||||
        EntityAlarm entityAlarm = new EntityAlarm(tenantId, entityId, alarm.getCreatedTime(), alarm.getType(), alarm.getCustomerId(), alarm.getId());
 | 
			
		||||
        try {
 | 
			
		||||
            alarmDao.createEntityAlarmRecord(entityAlarm);
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            log.warn("[{}] Failed to create entity alarm record: {}", tenantId, entityAlarm, e);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private <T> ListenableFuture<T> getAndUpdate(TenantId tenantId, AlarmId alarmId, Function<Alarm, T> function) {
 | 
			
		||||
@ -402,7 +407,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private DataValidator<Alarm> alarmDataValidator =
 | 
			
		||||
            new DataValidator<Alarm>() {
 | 
			
		||||
            new DataValidator<>() {
 | 
			
		||||
 | 
			
		||||
                @Override
 | 
			
		||||
                protected void validateDataImpl(TenantId tenantId, Alarm alarm) {
 | 
			
		||||
 | 
			
		||||
@ -44,7 +44,6 @@ import org.thingsboard.server.common.data.id.EntityViewId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageData;
 | 
			
		||||
import org.thingsboard.server.common.data.page.PageLink;
 | 
			
		||||
import org.thingsboard.server.common.data.page.TimePageLink;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntityRelation;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.EntitySearchDirection;
 | 
			
		||||
import org.thingsboard.server.common.data.relation.RelationTypeGroup;
 | 
			
		||||
 | 
			
		||||
@ -257,6 +257,7 @@ public class ModelConstants {
 | 
			
		||||
    /**
 | 
			
		||||
     * Cassandra alarm constants.
 | 
			
		||||
     */
 | 
			
		||||
    public static final String ENTITY_ALARM_COLUMN_FAMILY_NAME = "entity_alarm";
 | 
			
		||||
    public static final String ALARM_COLUMN_FAMILY_NAME = "alarm";
 | 
			
		||||
    public static final String ALARM_TENANT_ID_PROPERTY = TENANT_ID_PROPERTY;
 | 
			
		||||
    public static final String ALARM_CUSTOMER_ID_PROPERTY = CUSTOMER_ID_PROPERTY;
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,42 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2021 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.model.sql;
 | 
			
		||||
 | 
			
		||||
import lombok.AllArgsConstructor;
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import lombok.NoArgsConstructor;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.EntityAlarm;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.Transient;
 | 
			
		||||
import java.io.Serializable;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
@NoArgsConstructor
 | 
			
		||||
@AllArgsConstructor
 | 
			
		||||
@Data
 | 
			
		||||
public class EntityAlarmCompositeKey implements Serializable {
 | 
			
		||||
 | 
			
		||||
    @Transient
 | 
			
		||||
    private static final long serialVersionUID = -245388185894468450L;
 | 
			
		||||
 | 
			
		||||
    private UUID entityId;
 | 
			
		||||
    private UUID alarmId;
 | 
			
		||||
 | 
			
		||||
    public EntityAlarmCompositeKey(EntityAlarm entityAlarm) {
 | 
			
		||||
        this.entityId = entityAlarm.getEntityId().getId();
 | 
			
		||||
        this.alarmId = entityAlarm.getAlarmId().getId();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,99 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2021 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.model.sql;
 | 
			
		||||
 | 
			
		||||
import lombok.Data;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.EntityAlarm;
 | 
			
		||||
import org.thingsboard.server.common.data.id.AlarmId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.CustomerId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityIdFactory;
 | 
			
		||||
import org.thingsboard.server.common.data.id.TenantId;
 | 
			
		||||
import org.thingsboard.server.dao.model.ToData;
 | 
			
		||||
 | 
			
		||||
import javax.persistence.Column;
 | 
			
		||||
import javax.persistence.Entity;
 | 
			
		||||
import javax.persistence.Id;
 | 
			
		||||
import javax.persistence.IdClass;
 | 
			
		||||
import javax.persistence.Table;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
import static org.thingsboard.server.dao.model.ModelConstants.CREATED_TIME_PROPERTY;
 | 
			
		||||
import static org.thingsboard.server.dao.model.ModelConstants.CUSTOMER_ID_PROPERTY;
 | 
			
		||||
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ALARM_COLUMN_FAMILY_NAME;
 | 
			
		||||
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_ID_COLUMN;
 | 
			
		||||
import static org.thingsboard.server.dao.model.ModelConstants.ENTITY_TYPE_COLUMN;
 | 
			
		||||
import static org.thingsboard.server.dao.model.ModelConstants.TENANT_ID_COLUMN;
 | 
			
		||||
 | 
			
		||||
@Data
 | 
			
		||||
@Entity
 | 
			
		||||
@Table(name = ENTITY_ALARM_COLUMN_FAMILY_NAME)
 | 
			
		||||
@IdClass(EntityAlarmCompositeKey.class)
 | 
			
		||||
public final class EntityAlarmEntity implements ToData<EntityAlarm> {
 | 
			
		||||
 | 
			
		||||
    @Column(name = TENANT_ID_COLUMN, columnDefinition = "uuid")
 | 
			
		||||
    private UUID tenantId;
 | 
			
		||||
 | 
			
		||||
    @Column(name = ENTITY_TYPE_COLUMN)
 | 
			
		||||
    private String entityType;
 | 
			
		||||
 | 
			
		||||
    @Id
 | 
			
		||||
    @Column(name = ENTITY_ID_COLUMN, columnDefinition = "uuid")
 | 
			
		||||
    private UUID entityId;
 | 
			
		||||
 | 
			
		||||
    @Id
 | 
			
		||||
    @Column(name = "alarm_id", columnDefinition = "uuid")
 | 
			
		||||
    private UUID alarmId;
 | 
			
		||||
 | 
			
		||||
    @Column(name = CREATED_TIME_PROPERTY)
 | 
			
		||||
    private long createdTime;
 | 
			
		||||
 | 
			
		||||
    @Column(name = "alarm_type")
 | 
			
		||||
    private String alarmType;
 | 
			
		||||
 | 
			
		||||
    @Column(name = CUSTOMER_ID_PROPERTY, columnDefinition = "uuid")
 | 
			
		||||
    private UUID customerId;
 | 
			
		||||
 | 
			
		||||
    public EntityAlarmEntity() {
 | 
			
		||||
        super();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public EntityAlarmEntity(EntityAlarm entityAlarm) {
 | 
			
		||||
        tenantId = entityAlarm.getTenantId().getId();
 | 
			
		||||
        entityId = entityAlarm.getEntityId().getId();
 | 
			
		||||
        entityType = entityAlarm.getEntityId().getEntityType().name();
 | 
			
		||||
        alarmId = entityAlarm.getAlarmId().getId();
 | 
			
		||||
        alarmType = entityAlarm.getAlarmType();
 | 
			
		||||
        createdTime = entityAlarm.getCreatedTime();
 | 
			
		||||
        if (entityAlarm.getCustomerId() != null) {
 | 
			
		||||
            customerId = entityAlarm.getCustomerId().getId();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public EntityAlarm toData() {
 | 
			
		||||
        EntityAlarm result = new EntityAlarm();
 | 
			
		||||
        result.setTenantId(new TenantId(tenantId));
 | 
			
		||||
        result.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId));
 | 
			
		||||
        result.setAlarmId(new AlarmId(alarmId));
 | 
			
		||||
        result.setAlarmType(alarmType);
 | 
			
		||||
        result.setCreatedTime(createdTime);
 | 
			
		||||
        if (customerId != null) {
 | 
			
		||||
            result.setCustomerId(new CustomerId(customerId));
 | 
			
		||||
        }
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -42,47 +42,28 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, UUID> {
 | 
			
		||||
                                                    Pageable pageable);
 | 
			
		||||
 | 
			
		||||
    @Query(value = "SELECT new org.thingsboard.server.dao.model.sql.AlarmInfoEntity(a) FROM AlarmEntity a " +
 | 
			
		||||
            "LEFT JOIN RelationEntity re ON a.id = re.toId " +
 | 
			
		||||
            "AND re.relationTypeGroup = 'ALARM' " +
 | 
			
		||||
            "AND re.toType = 'ALARM' " +
 | 
			
		||||
            "AND re.fromId = :affectedEntityId " +
 | 
			
		||||
            "AND re.fromType = :affectedEntityType " +
 | 
			
		||||
            "LEFT JOIN EntityAlarmEntity ea ON a.id = ea.alarmId " +
 | 
			
		||||
            "WHERE a.tenantId = :tenantId " +
 | 
			
		||||
            "AND (a.originatorId = :affectedEntityId or re.fromId IS NOT NULL) " +
 | 
			
		||||
            "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
 | 
			
		||||
            "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
 | 
			
		||||
            "AND ea.tenantId = :tenantId " +
 | 
			
		||||
            "AND ea.entityId = :affectedEntityId " +
 | 
			
		||||
            "AND ea.entityType = :affectedEntityType " +
 | 
			
		||||
            "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " +
 | 
			
		||||
            "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " +
 | 
			
		||||
            "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " +
 | 
			
		||||
            "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
 | 
			
		||||
            "  OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
 | 
			
		||||
            "  OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) "
 | 
			
		||||
            ,
 | 
			
		||||
            countQuery = "" +
 | 
			
		||||
                    "SELECT count(a) + " + //alarms with relations only
 | 
			
		||||
                    " (SELECT count(a) FROM AlarmEntity a " + //alarms WITHOUT any relations
 | 
			
		||||
                    "    LEFT JOIN RelationEntity re ON a.id = re.toId " +
 | 
			
		||||
                    "    AND re.relationTypeGroup = 'ALARM' " +
 | 
			
		||||
                    "    AND re.toType = 'ALARM' " +
 | 
			
		||||
                    "    AND re.fromId = :affectedEntityId " +
 | 
			
		||||
                    "    AND re.fromType = :affectedEntityType " +
 | 
			
		||||
                    "    WHERE a.tenantId = :tenantId " +
 | 
			
		||||
                    "    AND (a.originatorId = :affectedEntityId) " +
 | 
			
		||||
                    "    AND (re.fromId IS NULL) " + //anti join
 | 
			
		||||
                    "    AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
 | 
			
		||||
                    "    AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
 | 
			
		||||
                    "    AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " +
 | 
			
		||||
                    "    AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
 | 
			
		||||
                    "    OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
 | 
			
		||||
                    "    OR LOWER(a.status) LIKE LOWER(CONCAT('%', :searchText, '%'))) " +
 | 
			
		||||
                    " )" +
 | 
			
		||||
                    "SELECT count(a) " + //alarms with relations only
 | 
			
		||||
                    "FROM AlarmEntity a " +
 | 
			
		||||
                    "INNER JOIN RelationEntity re ON a.id = re.toId " +
 | 
			
		||||
                    "AND re.relationTypeGroup = 'ALARM' " +
 | 
			
		||||
                    "AND re.toType = 'ALARM' " +
 | 
			
		||||
                    "AND re.fromId = :affectedEntityId " +
 | 
			
		||||
                    "AND re.fromType = :affectedEntityType " +
 | 
			
		||||
                    "LEFT JOIN EntityAlarmEntity ea ON a.id = ea.alarmId " +
 | 
			
		||||
                    "WHERE a.tenantId = :tenantId " +
 | 
			
		||||
                    "AND (:startTime IS NULL OR a.createdTime >= :startTime) " +
 | 
			
		||||
                    "AND (:endTime IS NULL OR a.createdTime <= :endTime) " +
 | 
			
		||||
                    "AND ea.tenantId = :tenantId " +
 | 
			
		||||
                    "AND ea.entityId = :affectedEntityId " +
 | 
			
		||||
                    "AND ea.entityType = :affectedEntityType " +
 | 
			
		||||
                    "AND (:startTime IS NULL OR (a.createdTime >= :startTime AND ea.createdTime >= :startTime)) " +
 | 
			
		||||
                    "AND (:endTime IS NULL OR (a.createdTime <= :endTime AND ea.createdTime <= :endTime)) " +
 | 
			
		||||
                    "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses)) " +
 | 
			
		||||
                    "AND (LOWER(a.type) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
 | 
			
		||||
                    "  OR LOWER(a.severity) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
 | 
			
		||||
@ -149,13 +130,11 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, UUID> {
 | 
			
		||||
                                             Pageable pageable);
 | 
			
		||||
 | 
			
		||||
    @Query(value = "SELECT a.severity FROM AlarmEntity a " +
 | 
			
		||||
            "LEFT JOIN RelationEntity re ON a.id = re.toId " +
 | 
			
		||||
            "AND re.relationTypeGroup = 'ALARM' " +
 | 
			
		||||
            "AND re.toType = 'ALARM' " +
 | 
			
		||||
            "AND re.fromId = :affectedEntityId " +
 | 
			
		||||
            "AND re.fromType = :affectedEntityType " +
 | 
			
		||||
            "LEFT JOIN EntityAlarmEntity ea ON a.id = ea.alarmId " +
 | 
			
		||||
            "WHERE a.tenantId = :tenantId " +
 | 
			
		||||
            "AND (a.originatorId = :affectedEntityId or re.fromId IS NOT NULL) " +
 | 
			
		||||
            "AND ea.tenantId = :tenantId " +
 | 
			
		||||
            "AND ea.entityId = :affectedEntityId " +
 | 
			
		||||
            "AND ea.entityType = :affectedEntityType " +
 | 
			
		||||
            "AND ((:alarmStatuses) IS NULL OR a.status in (:alarmStatuses))")
 | 
			
		||||
    Set<AlarmSeverity> findAlarmSeverities(@Param("tenantId") UUID tenantId,
 | 
			
		||||
                                           @Param("affectedEntityId") UUID affectedEntityId,
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,29 @@
 | 
			
		||||
/**
 | 
			
		||||
 * Copyright © 2016-2021 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.alarm;
 | 
			
		||||
 | 
			
		||||
import org.springframework.data.repository.CrudRepository;
 | 
			
		||||
import org.thingsboard.server.dao.model.sql.EntityAlarmCompositeKey;
 | 
			
		||||
import org.thingsboard.server.dao.model.sql.EntityAlarmEntity;
 | 
			
		||||
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.UUID;
 | 
			
		||||
 | 
			
		||||
public interface EntityAlarmRepository extends CrudRepository<EntityAlarmEntity, EntityAlarmCompositeKey> {
 | 
			
		||||
 | 
			
		||||
    List<EntityAlarmEntity> findAllByAlarmId(UUID alarmId);
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.alarm.AlarmInfo;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmQuery;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmSeverity;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.AlarmStatus;
 | 
			
		||||
import org.thingsboard.server.common.data.alarm.EntityAlarm;
 | 
			
		||||
import org.thingsboard.server.common.data.id.AlarmId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.CustomerId;
 | 
			
		||||
import org.thingsboard.server.common.data.id.EntityId;
 | 
			
		||||
@ -37,6 +38,7 @@ import org.thingsboard.server.common.data.query.AlarmDataQuery;
 | 
			
		||||
import org.thingsboard.server.dao.DaoUtil;
 | 
			
		||||
import org.thingsboard.server.dao.alarm.AlarmDao;
 | 
			
		||||
import org.thingsboard.server.dao.model.sql.AlarmEntity;
 | 
			
		||||
import org.thingsboard.server.dao.model.sql.EntityAlarmEntity;
 | 
			
		||||
import org.thingsboard.server.dao.relation.RelationDao;
 | 
			
		||||
import org.thingsboard.server.dao.sql.JpaAbstractDao;
 | 
			
		||||
import org.thingsboard.server.dao.sql.query.AlarmQueryRepository;
 | 
			
		||||
@ -62,7 +64,7 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
 | 
			
		||||
    private AlarmQueryRepository alarmQueryRepository;
 | 
			
		||||
 | 
			
		||||
    @Autowired
 | 
			
		||||
    private RelationDao relationDao;
 | 
			
		||||
    private EntityAlarmRepository entityAlarmRepository;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected Class<AlarmEntity> getEntityClass() {
 | 
			
		||||
@ -169,4 +171,16 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
 | 
			
		||||
        return DaoUtil.pageToPageData(alarmRepository.findAlarmsIdsByEndTsBeforeAndTenantId(time, tenantId.getId(), DaoUtil.toPageable(pageLink)))
 | 
			
		||||
                .mapData(AlarmId::new);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void createEntityAlarmRecord(EntityAlarm entityAlarm) {
 | 
			
		||||
        log.debug("Saving entity {}", entityAlarm);
 | 
			
		||||
        entityAlarmRepository.save(new EntityAlarmEntity(entityAlarm));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public List<EntityAlarm> findEntityAlarmRecords(TenantId tenantId, AlarmId id) {
 | 
			
		||||
        log.trace("[{}] Try to find entity alarm records using [{}]", tenantId, id);
 | 
			
		||||
        return DaoUtil.convertDataList(entityAlarmRepository.findAllByAlarmId(id.getId()));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -105,7 +105,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
 | 
			
		||||
            " a.propagate_relation_types as propagate_relation_types, " +
 | 
			
		||||
            " a.type as type," + SELECT_ORIGINATOR_NAME + ", ";
 | 
			
		||||
 | 
			
		||||
    private static final String JOIN_RELATIONS = "left join relation r on r.relation_type_group = 'ALARM' and r.relation_type = 'ANY' and a.id = r.to_id and r.from_id in (:entity_ids)";
 | 
			
		||||
    private static final String JOIN_ENTITY_ALARMS = "inner join entity_alarm ea on a.id = ea.alarm_id";
 | 
			
		||||
 | 
			
		||||
    protected final NamedParameterJdbcTemplate jdbcTemplate;
 | 
			
		||||
    private final TransactionTemplate transactionTemplate;
 | 
			
		||||
@ -132,8 +132,8 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
 | 
			
		||||
            StringBuilder joinPart = new StringBuilder();
 | 
			
		||||
            boolean addAnd = false;
 | 
			
		||||
            if (pageLink.isSearchPropagatedAlarms()) {
 | 
			
		||||
                selectPart.append(" CASE WHEN r.from_id IS NULL THEN a.originator_id ELSE r.from_id END as entity_id ");
 | 
			
		||||
                fromPart.append(JOIN_RELATIONS);
 | 
			
		||||
                selectPart.append(" ea.entity_id as entity_id ");
 | 
			
		||||
                fromPart.append(JOIN_ENTITY_ALARMS);
 | 
			
		||||
                wherePart.append(buildPermissionsQuery(tenantId, customerId, ctx));
 | 
			
		||||
                addAnd = true;
 | 
			
		||||
            } else {
 | 
			
		||||
@ -145,7 +145,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
 | 
			
		||||
                sortPart.append(alarmFieldColumnMap.getOrDefault(sortOrderKey, sortOrderKey))
 | 
			
		||||
                        .append(" ").append(sortOrder.getDirection().name());
 | 
			
		||||
                if (pageLink.isSearchPropagatedAlarms()) {
 | 
			
		||||
                    wherePart.append(" and (a.originator_id in (:entity_ids) or r.from_id IS NOT NULL)");
 | 
			
		||||
                    wherePart.append(" and ea.entity_id in (:entity_ids)");
 | 
			
		||||
                } else {
 | 
			
		||||
                    addAndIfNeeded(wherePart, addAnd);
 | 
			
		||||
                    addAnd = true;
 | 
			
		||||
@ -166,7 +166,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
 | 
			
		||||
                }
 | 
			
		||||
                joinPart.append(" as e(id, priority)) e ");
 | 
			
		||||
                if (pageLink.isSearchPropagatedAlarms()) {
 | 
			
		||||
                    joinPart.append("on (r.from_id IS NULL and a.originator_id = e.id) or (r.from_id IS NOT NULL and r.from_id = e.id)");
 | 
			
		||||
                    joinPart.append("on ea.entity_id = e.id");
 | 
			
		||||
                } else {
 | 
			
		||||
                    joinPart.append("on a.originator_id = e.id");
 | 
			
		||||
                }
 | 
			
		||||
@ -188,6 +188,9 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
 | 
			
		||||
                addAnd = true;
 | 
			
		||||
                ctx.addLongParameter("startTime", startTs);
 | 
			
		||||
                wherePart.append("a.created_time >= :startTime");
 | 
			
		||||
                if (pageLink.isSearchPropagatedAlarms()) {
 | 
			
		||||
                    wherePart.append(" and ea.created_time >= :startTime");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (endTs > 0) {
 | 
			
		||||
@ -195,6 +198,9 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
 | 
			
		||||
                addAnd = true;
 | 
			
		||||
                ctx.addLongParameter("endTime", endTs);
 | 
			
		||||
                wherePart.append("a.created_time <= :endTime");
 | 
			
		||||
                if (pageLink.isSearchPropagatedAlarms()) {
 | 
			
		||||
                    wherePart.append(" and ea.created_time <= :endTime");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (pageLink.getTypeList() != null && !pageLink.getTypeList().isEmpty()) {
 | 
			
		||||
@ -202,6 +208,9 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
 | 
			
		||||
                addAnd = true;
 | 
			
		||||
                ctx.addStringListParameter("alarmTypes", pageLink.getTypeList());
 | 
			
		||||
                wherePart.append("a.type in (:alarmTypes)");
 | 
			
		||||
                if (pageLink.isSearchPropagatedAlarms()) {
 | 
			
		||||
                    wherePart.append(" and ea.alarm_type in (:alarmTypes)");
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (pageLink.getSeverityList() != null && !pageLink.getSeverityList().isEmpty()) {
 | 
			
		||||
@ -279,7 +288,7 @@ public class DefaultAlarmQueryRepository implements AlarmQueryRepository {
 | 
			
		||||
    private String buildPermissionsQuery(TenantId tenantId, CustomerId customerId, QueryContext ctx) {
 | 
			
		||||
        StringBuilder permissionsQuery = new StringBuilder();
 | 
			
		||||
        ctx.addUuidParameter("permissions_tenant_id", tenantId.getId());
 | 
			
		||||
        permissionsQuery.append(" a.tenant_id = :permissions_tenant_id ");
 | 
			
		||||
        permissionsQuery.append(" a.tenant_id = :permissions_tenant_id and ea.tenant_id = :permissions_tenant_id ");
 | 
			
		||||
/*
 | 
			
		||||
      No need to check the customer id, because we already use entity id list that passed security check when we were evaluating the data query.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
@ -33,7 +33,7 @@ public class DefaultQueryLogComponent implements QueryLogComponent {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void logQuery(QueryContext ctx, String query, long duration) {
 | 
			
		||||
        if (logSqlQueries && duration > logQueriesThreshold) {
 | 
			
		||||
            log.info("QUERY: {} took {}ms", query, duration);
 | 
			
		||||
            log.info("QUERY: {} took {} ms", query, duration);
 | 
			
		||||
            Arrays.asList(ctx.getParameterNames()).forEach(param -> log.info("QUERY PARAM: {} -> {}", param, ctx.getValue(param)));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -43,6 +43,18 @@ CREATE TABLE IF NOT EXISTS alarm (
 | 
			
		||||
    type varchar(255)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE IF NOT EXISTS entity_alarm (
 | 
			
		||||
    tenant_id uuid NOT NULL,
 | 
			
		||||
    entity_type varchar(32),
 | 
			
		||||
    entity_id uuid NOT NULL,
 | 
			
		||||
    created_time bigint NOT NULL,
 | 
			
		||||
    alarm_type varchar(255) NOT NULL,
 | 
			
		||||
    customer_id uuid,
 | 
			
		||||
    alarm_id uuid,
 | 
			
		||||
    CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id),
 | 
			
		||||
    CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE IF NOT EXISTS asset (
 | 
			
		||||
    id uuid NOT NULL CONSTRAINT asset_pkey PRIMARY KEY,
 | 
			
		||||
    created_time bigint NOT NULL,
 | 
			
		||||
 | 
			
		||||
@ -20,8 +20,12 @@ CREATE INDEX IF NOT EXISTS idx_alarm_originator_created_time ON alarm(originator
 | 
			
		||||
 | 
			
		||||
CREATE INDEX IF NOT EXISTS idx_alarm_tenant_created_time ON alarm(tenant_id, created_time DESC);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX IF NOT EXISTS idx_alarm_tenant_status_created_time ON alarm(tenant_id, status, created_time DESC);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX IF NOT EXISTS idx_alarm_tenant_alarm_type_created_time ON alarm(tenant_id, type, created_time DESC);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX IF NOT EXISTS idx_entity_alarm_created_time ON entity_alarm(tenant_id, entity_id, created_time DESC);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX IF NOT EXISTS idx_relation_to_id ON relation(relation_type_group, to_type, to_id);
 | 
			
		||||
 | 
			
		||||
CREATE INDEX IF NOT EXISTS idx_relation_from_id ON relation(relation_type_group, from_type, from_id);
 | 
			
		||||
 | 
			
		||||
@ -58,6 +58,18 @@ CREATE TABLE IF NOT EXISTS alarm (
 | 
			
		||||
    type varchar(255)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE IF NOT EXISTS entity_alarm (
 | 
			
		||||
    tenant_id uuid NOT NULL,
 | 
			
		||||
    entity_type varchar(32),
 | 
			
		||||
    entity_id uuid NOT NULL,
 | 
			
		||||
    created_time bigint NOT NULL,
 | 
			
		||||
    alarm_type varchar(255) NOT NULL,
 | 
			
		||||
    customer_id uuid,
 | 
			
		||||
    alarm_id uuid,
 | 
			
		||||
    CONSTRAINT entity_alarm_pkey PRIMARY KEY(entity_id, alarm_id),
 | 
			
		||||
    CONSTRAINT fk_entity_alarm_id FOREIGN KEY (alarm_id) REFERENCES alarm(id) ON DELETE CASCADE
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
CREATE TABLE IF NOT EXISTS asset (
 | 
			
		||||
    id uuid NOT NULL CONSTRAINT asset_pkey PRIMARY KEY,
 | 
			
		||||
    created_time bigint NOT NULL,
 | 
			
		||||
 | 
			
		||||
@ -612,16 +612,6 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest {
 | 
			
		||||
        Assert.assertEquals(1, alarms.getData().size());
 | 
			
		||||
        Assert.assertEquals(created, alarms.getData().get(0));
 | 
			
		||||
 | 
			
		||||
        List<EntityRelation> toAlarmRelations = relationService.findByTo(tenantId, created.getId(), RelationTypeGroup.ALARM);
 | 
			
		||||
        Assert.assertEquals(1, toAlarmRelations.size());
 | 
			
		||||
 | 
			
		||||
        List<EntityRelation> fromChildRelations = relationService.findByFrom(tenantId, childId, RelationTypeGroup.ALARM);
 | 
			
		||||
        Assert.assertEquals(0, fromChildRelations.size());
 | 
			
		||||
 | 
			
		||||
        List<EntityRelation> fromParentRelations = relationService.findByFrom(tenantId, parentId, RelationTypeGroup.ALARM);
 | 
			
		||||
        Assert.assertEquals(1, fromParentRelations.size());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        Assert.assertTrue("Alarm was not deleted when expected", alarmService.deleteAlarm(tenantId, created.getId()).isSuccessful());
 | 
			
		||||
 | 
			
		||||
        Alarm fetched = alarmService.findAlarmByIdAsync(tenantId, created.getId()).get();
 | 
			
		||||
@ -647,14 +637,5 @@ public abstract class BaseAlarmServiceTest extends AbstractServiceTest {
 | 
			
		||||
        Assert.assertNotNull(alarms.getData());
 | 
			
		||||
        Assert.assertEquals(0, alarms.getData().size());
 | 
			
		||||
 | 
			
		||||
        toAlarmRelations = relationService.findByTo(tenantId, created.getId(), RelationTypeGroup.ALARM);
 | 
			
		||||
        Assert.assertEquals(0, toAlarmRelations.size());
 | 
			
		||||
 | 
			
		||||
        fromChildRelations = relationService.findByFrom(tenantId, childId, RelationTypeGroup.ALARM);
 | 
			
		||||
        Assert.assertEquals(0, fromChildRelations.size());
 | 
			
		||||
 | 
			
		||||
        fromParentRelations = relationService.findByFrom(tenantId, childId, RelationTypeGroup.ALARM);
 | 
			
		||||
        Assert.assertEquals(0, fromParentRelations.size());
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
DROP TABLE IF EXISTS admin_settings;
 | 
			
		||||
DROP TABLE IF EXISTS entity_alarm;
 | 
			
		||||
DROP TABLE IF EXISTS alarm;
 | 
			
		||||
DROP TABLE IF EXISTS asset;
 | 
			
		||||
DROP TABLE IF EXISTS audit_log;
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
DROP TABLE IF EXISTS admin_settings;
 | 
			
		||||
DROP TABLE IF EXISTS entity_alarm;
 | 
			
		||||
DROP TABLE IF EXISTS alarm;
 | 
			
		||||
DROP TABLE IF EXISTS asset;
 | 
			
		||||
DROP TABLE IF EXISTS audit_log;
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
DROP TABLE IF EXISTS admin_settings;
 | 
			
		||||
DROP TABLE IF EXISTS entity_alarm;
 | 
			
		||||
DROP TABLE IF EXISTS alarm;
 | 
			
		||||
DROP TABLE IF EXISTS asset;
 | 
			
		||||
DROP TABLE IF EXISTS audit_log;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user