added calculated field entity, dao and controller

This commit is contained in:
IrynaMatveieva 2024-10-31 16:42:28 +02:00
parent 32b5aaebc0
commit 32bbd83541
17 changed files with 615 additions and 15 deletions

View File

@ -67,6 +67,7 @@ import org.thingsboard.server.common.data.asset.Asset;
import org.thingsboard.server.common.data.asset.AssetInfo; import org.thingsboard.server.common.data.asset.AssetInfo;
import org.thingsboard.server.common.data.asset.AssetProfile; import org.thingsboard.server.common.data.asset.AssetProfile;
import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.audit.ActionType;
import org.thingsboard.server.common.data.calculated_field.CalculatedField;
import org.thingsboard.server.common.data.domain.Domain; import org.thingsboard.server.common.data.domain.Domain;
import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.Edge;
import org.thingsboard.server.common.data.edge.EdgeInfo; import org.thingsboard.server.common.data.edge.EdgeInfo;
@ -77,6 +78,7 @@ import org.thingsboard.server.common.data.id.AlarmCommentId;
import org.thingsboard.server.common.data.id.AlarmId; import org.thingsboard.server.common.data.id.AlarmId;
import org.thingsboard.server.common.data.id.AssetId; import org.thingsboard.server.common.data.id.AssetId;
import org.thingsboard.server.common.data.id.AssetProfileId; import org.thingsboard.server.common.data.id.AssetProfileId;
import org.thingsboard.server.common.data.id.CalculatedFieldId;
import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.CustomerId;
import org.thingsboard.server.common.data.id.DashboardId; import org.thingsboard.server.common.data.id.DashboardId;
import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.DeviceId;
@ -124,6 +126,7 @@ import org.thingsboard.server.dao.asset.AssetProfileService;
import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.asset.AssetService;
import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.attributes.AttributesService;
import org.thingsboard.server.dao.audit.AuditLogService; import org.thingsboard.server.dao.audit.AuditLogService;
import org.thingsboard.server.dao.calculated_field.CalculatedFieldService;
import org.thingsboard.server.dao.customer.CustomerService; import org.thingsboard.server.dao.customer.CustomerService;
import org.thingsboard.server.dao.dashboard.DashboardService; import org.thingsboard.server.dao.dashboard.DashboardService;
import org.thingsboard.server.dao.device.ClaimDevicesService; import org.thingsboard.server.dao.device.ClaimDevicesService;
@ -343,6 +346,9 @@ public abstract class BaseController {
@Autowired @Autowired
protected TbServiceInfoProvider serviceInfoProvider; protected TbServiceInfoProvider serviceInfoProvider;
@Autowired
protected CalculatedFieldService calculatedFieldService;
@Value("${server.log_controller_error_stack_trace}") @Value("${server.log_controller_error_stack_trace}")
@Getter @Getter
private boolean logControllerErrorStackTrace; private boolean logControllerErrorStackTrace;
@ -645,6 +651,8 @@ public abstract class BaseController {
case MOBILE_APP: case MOBILE_APP:
checkMobileAppId(new MobileAppId(entityId.getId()), operation); checkMobileAppId(new MobileAppId(entityId.getId()), operation);
return; return;
case CALCULATED_FIELD:
checkCalculatedFieldId(new CalculatedFieldId(entityId.getId()), operation);
default: default:
checkEntityId(entityId, entitiesService::findEntityByTenantIdAndId, operation); checkEntityId(entityId, entitiesService::findEntityByTenantIdAndId, operation);
} }
@ -915,6 +923,10 @@ public abstract class BaseController {
} }
} }
protected CalculatedField checkCalculatedFieldId(CalculatedFieldId calculatedFieldId, Operation operation) throws ThingsboardException {
return checkEntityId(calculatedFieldId, calculatedFieldService::findById, operation);
}
protected MediaType parseMediaType(String contentType) { protected MediaType parseMediaType(String contentType) {
try { try {
return MediaType.parseMediaType(contentType); return MediaType.parseMediaType(contentType);

View File

@ -0,0 +1,95 @@
/**
* Copyright © 2016-2024 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.controller;
import io.swagger.v3.oas.annotations.Parameter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import org.thingsboard.server.common.data.calculated_field.CalculatedField;
import org.thingsboard.server.common.data.exception.ThingsboardException;
import org.thingsboard.server.common.data.id.CalculatedFieldId;
import org.thingsboard.server.config.annotations.ApiOperation;
import org.thingsboard.server.dao.calculated_field.CalculatedFieldService;
import org.thingsboard.server.queue.util.TbCoreComponent;
import org.thingsboard.server.service.security.permission.Operation;
import org.thingsboard.server.service.security.permission.Resource;
import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH;
import static org.thingsboard.server.controller.ControllerConstants.UUID_WIKI_LINK;
@RestController
@TbCoreComponent
@RequestMapping("/api")
@RequiredArgsConstructor
@Slf4j
public class CalculatedFieldController extends BaseController{
private final CalculatedFieldService calculatedFieldService;
public static final String CALCULATED_FIELD_ID = "calculatedFieldId";
@ApiOperation(value = "Create Or Update Calculated Field (saveCalculatedField)",
notes = "Creates or Updates the Calculated Field. When creating calculated field, platform generates Calculated Field Id as " + UUID_WIKI_LINK +
"The newly created Calculated Field Id will be present in the response. " +
"Specify existing Calculated Field Id to update the calculated field. " +
"Referencing non-existing Calculated Field Id will cause 'Not Found' error. " +
"Remove 'id', 'tenantId' from the request body example (below) to create new Calculated Field entity. "
+ TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/calculatedField", method = RequestMethod.POST)
@ResponseBody
public CalculatedField saveCalculatedField(@io.swagger.v3.oas.annotations.parameters.RequestBody(description = "A JSON value representing the calculated field.")
@RequestBody CalculatedField calculatedField) throws Exception {
calculatedField.setTenantId(getTenantId());
checkEntity(calculatedField.getId(), calculatedField, Resource.CALCULATED_FIELD);
return calculatedFieldService.save(calculatedField);
}
@ApiOperation(value = "Get Calculated Field (getCalculatedFieldById)",
notes = "Fetch the Calculated Field object based on the provided Calculated Field Id."
)
@PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
@RequestMapping(value = "/calculatedField/{calculatedFieldId}", method = RequestMethod.GET)
@ResponseBody
public CalculatedField getCalculatedFieldById(@Parameter @PathVariable(CALCULATED_FIELD_ID) String strCalculatedFieldId) throws ThingsboardException {
checkParameter(CALCULATED_FIELD_ID, strCalculatedFieldId);
CalculatedFieldId calculatedFieldId = new CalculatedFieldId(toUUID(strCalculatedFieldId));
return checkCalculatedFieldId(calculatedFieldId, Operation.READ);
}
@ApiOperation(value = "Delete Calculated Field (deleteCalculatedField)",
notes = "Deletes the calculated field. Referencing non-existing Calculated Field Id will cause an error." + TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH)
@PreAuthorize("hasAuthority('TENANT_ADMIN')")
@RequestMapping(value = "/calculatedField/{calculatedFieldId}", method = RequestMethod.DELETE)
@ResponseStatus(value = HttpStatus.OK)
public void deleteCalculatedField(@PathVariable(CALCULATED_FIELD_ID) String strCalculatedField) throws Exception {
checkParameter(CALCULATED_FIELD_ID, strCalculatedField);
CalculatedFieldId calculatedFieldId = new CalculatedFieldId(toUUID(strCalculatedField));
checkCalculatedFieldId(calculatedFieldId, Operation.DELETE);
calculatedFieldService.deleteCalculatedField(getTenantId(), calculatedFieldId);
}
}

View File

@ -49,7 +49,9 @@ public enum Resource {
VERSION_CONTROL, VERSION_CONTROL,
NOTIFICATION(EntityType.NOTIFICATION_TARGET, EntityType.NOTIFICATION_TEMPLATE, NOTIFICATION(EntityType.NOTIFICATION_TARGET, EntityType.NOTIFICATION_TEMPLATE,
EntityType.NOTIFICATION_REQUEST, EntityType.NOTIFICATION_RULE), EntityType.NOTIFICATION_REQUEST, EntityType.NOTIFICATION_RULE),
MOBILE_APP_SETTINGS; MOBILE_APP_SETTINGS,
CALCULATED_FIELD(EntityType.CALCULATED_FIELD);
private final Set<EntityType> entityTypes; private final Set<EntityType> entityTypes;
Resource() { Resource() {

View File

@ -51,6 +51,7 @@ public class TenantAdminPermissions extends AbstractPermissions {
put(Resource.VERSION_CONTROL, PermissionChecker.allowAllPermissionChecker); put(Resource.VERSION_CONTROL, PermissionChecker.allowAllPermissionChecker);
put(Resource.NOTIFICATION, tenantEntityPermissionChecker); put(Resource.NOTIFICATION, tenantEntityPermissionChecker);
put(Resource.MOBILE_APP_SETTINGS, new PermissionChecker.GenericPermissionChecker(Operation.READ)); put(Resource.MOBILE_APP_SETTINGS, new PermissionChecker.GenericPermissionChecker(Operation.READ));
put(Resource.CALCULATED_FIELD, tenantEntityPermissionChecker);
} }
public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker() { public static final PermissionChecker tenantEntityPermissionChecker = new PermissionChecker() {

View File

@ -0,0 +1,31 @@
/**
* Copyright © 2016-2024 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.calculated_field;
import org.thingsboard.server.common.data.calculated_field.CalculatedField;
import org.thingsboard.server.common.data.id.CalculatedFieldId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.entity.EntityDaoService;
public interface CalculatedFieldService extends EntityDaoService {
CalculatedField save(CalculatedField calculatedField);
CalculatedField findById(TenantId tenantId, CalculatedFieldId calculatedFieldId);
void deleteCalculatedField(TenantId tenantId, CalculatedFieldId calculatedFieldId);
}

View File

@ -60,7 +60,8 @@ public enum EntityType {
QUEUE_STATS(34), QUEUE_STATS(34),
OAUTH2_CLIENT(35), OAUTH2_CLIENT(35),
DOMAIN(36), DOMAIN(36),
MOBILE_APP(37); MOBILE_APP(37),
CALCULATED_FIELD(38);
@Getter @Getter
private final int protoNumber; // Corresponds to EntityTypeProto private final int protoNumber; // Corresponds to EntityTypeProto

View File

@ -0,0 +1,94 @@
/**
* Copyright © 2016-2024 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.calculated_field;
import com.fasterxml.jackson.databind.JsonNode;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import org.thingsboard.server.common.data.BaseData;
import org.thingsboard.server.common.data.HasName;
import org.thingsboard.server.common.data.HasTenantId;
import org.thingsboard.server.common.data.HasVersion;
import org.thingsboard.server.common.data.id.CalculatedFieldId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.common.data.validation.Length;
import org.thingsboard.server.common.data.validation.NoXss;
@Schema
@Data
@EqualsAndHashCode(callSuper = true)
public class CalculatedField extends BaseData<CalculatedFieldId> implements HasName, HasTenantId, HasVersion {
private static final long serialVersionUID = 4491966747773381420L;
private TenantId tenantId;
private EntityId entityId;
@NoXss
@Length(fieldName = "type")
private String type;
@NoXss
@Length(fieldName = "name")
@Schema(description = "User defined name of the calculated field.")
private String name;
@Schema(description = "Version of calculated field configuration.", example = "0")
private int configurationVersion;
@Schema(description = "JSON with the calculated field configuration.", implementation = com.fasterxml.jackson.databind.JsonNode.class)
private transient JsonNode configuration;
@Getter
@Setter
private Long version;
@Getter
@Setter
private CalculatedFieldId externalId;
public CalculatedField() {
super();
}
public CalculatedField(CalculatedFieldId id) {
super(id);
}
public CalculatedField(TenantId tenantId, EntityId entityId, String type, String name, int configurationVersion, JsonNode configuration, Long version, CalculatedFieldId externalId) {
super();
this.tenantId = tenantId;
this.entityId = entityId;
this.type = type;
this.name = name;
this.configurationVersion = configurationVersion;
this.configuration = configuration;
this.version = version;
this.externalId = externalId;
}
@Schema(description = "JSON object with the Calculated Field Id. Referencing non-existing Calculated Field Id will cause error.")
@Override
public CalculatedFieldId getId() {
return super.getId();
}
@Schema(description = "Timestamp of the calculated field creation, in milliseconds", example = "1609459200000", accessMode = Schema.AccessMode.READ_ONLY)
@Override
public long getCreatedTime() {
return super.getCreatedTime();
}
}

View File

@ -0,0 +1,44 @@
/**
* Copyright © 2016-2024 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.id;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import org.thingsboard.server.common.data.EntityType;
import java.util.UUID;
@Schema
public class CalculatedFieldId extends UUIDBased implements EntityId {
private static final long serialVersionUID = 1L;
@JsonCreator
public CalculatedFieldId(@JsonProperty("id") UUID id) {
super(id);
}
public static CalculatedFieldId fromString(String calculatedFieldId) {
return new CalculatedFieldId(UUID.fromString(calculatedFieldId));
}
@Schema(requiredMode = Schema.RequiredMode.REQUIRED, description = "string", example = "CALCULATED_FIELD", allowableValues = "CALCULATED_FIELD")
@Override
public EntityType getEntityType() {
return EntityType.CALCULATED_FIELD;
}
}

View File

@ -111,6 +111,8 @@ public class EntityIdFactory {
return new MobileAppId(uuid); return new MobileAppId(uuid);
case DOMAIN: case DOMAIN:
return new DomainId(uuid); return new DomainId(uuid);
case CALCULATED_FIELD:
return new CalculatedFieldId(uuid);
} }
throw new IllegalArgumentException("EntityType " + type + " is not supported!"); throw new IllegalArgumentException("EntityType " + type + " is not supported!");
} }

View File

@ -58,6 +58,7 @@ enum EntityTypeProto {
OAUTH2_CLIENT = 35; OAUTH2_CLIENT = 35;
DOMAIN = 36; DOMAIN = 36;
MOBILE_APP = 37; MOBILE_APP = 37;
CALCULATED_FIELD = 38;
} }
/** /**

View File

@ -0,0 +1,75 @@
/**
* Copyright © 2016-2024 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.calculated_field;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.calculated_field.CalculatedField;
import org.thingsboard.server.common.data.id.CalculatedFieldId;
import org.thingsboard.server.common.data.id.EntityId;
import org.thingsboard.server.common.data.id.HasId;
import org.thingsboard.server.common.data.id.TenantId;
import java.util.Optional;
import static org.thingsboard.server.dao.service.Validator.validateId;
@Service("CalculatedFieldDaoService")
@Slf4j
@RequiredArgsConstructor
public class BaseCalculatedFieldService implements CalculatedFieldService {
public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
public static final String INCORRECT_CALCULATED_FIELD_ID = "Incorrect calculatedFieldId ";
private final CalculatedFieldDao calculatedFieldDao;
@Override
public CalculatedField save(CalculatedField calculatedField) {
log.trace("Executing save, [{}]", calculatedField);
return calculatedFieldDao.save(calculatedField.getTenantId(), calculatedField);
}
@Override
public CalculatedField findById(TenantId tenantId, CalculatedFieldId calculatedFieldId) {
log.trace("Executing findById, tenantId [{}], rpcId [{}]", tenantId, calculatedFieldId);
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(calculatedFieldId, id -> INCORRECT_CALCULATED_FIELD_ID + id);
return calculatedFieldDao.findById(tenantId, calculatedFieldId.getId());
}
@Override
public void deleteCalculatedField(TenantId tenantId, CalculatedFieldId calculatedFieldId) {
log.trace("Executing deleteRpc, tenantId [{}], rpcId [{}]", tenantId, calculatedFieldId);
validateId(tenantId, id -> INCORRECT_TENANT_ID + id);
validateId(calculatedFieldId, id -> INCORRECT_CALCULATED_FIELD_ID + id);
calculatedFieldDao.removeById(tenantId, calculatedFieldId.getId());
}
@Override
public Optional<HasId<?>> findEntity(TenantId tenantId, EntityId entityId) {
return Optional.ofNullable(findById(tenantId, new CalculatedFieldId(entityId.getId())));
}
@Override
public EntityType getEntityType() {
return EntityType.CALCULATED_FIELD;
}
}

View File

@ -0,0 +1,22 @@
/**
* Copyright © 2016-2024 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.calculated_field;
import org.thingsboard.server.common.data.calculated_field.CalculatedField;
import org.thingsboard.server.dao.Dao;
public interface CalculatedFieldDao extends Dao<CalculatedField> {
}

View File

@ -691,6 +691,20 @@ public class ModelConstants {
public static final String MOBILE_APP_SETTINGS_IOS_CONFIG_PROPERTY = "ios_config"; public static final String MOBILE_APP_SETTINGS_IOS_CONFIG_PROPERTY = "ios_config";
public static final String MOBILE_APP_SETTINGS_QR_CODE_CONFIG_PROPERTY = "qr_code_config"; public static final String MOBILE_APP_SETTINGS_QR_CODE_CONFIG_PROPERTY = "qr_code_config";
/**
* Calculated fields constants.
*/
public static final String CALCULATED_FIELD_TABLE_NAME = "calculated_field";
public static final String CALCULATED_FIELD_TENANT_ID_COLUMN = TENANT_ID_COLUMN;
public static final String CALCULATED_FIELD_ENTITY_TYPE = ENTITY_TYPE_COLUMN;
public static final String CALCULATED_FIELD_ENTITY_ID = ENTITY_ID_COLUMN;
public static final String CALCULATED_FIELD_TYPE = "type";
public static final String CALCULATED_FIELD_NAME = "name";
public static final String CALCULATED_FIELD_CONFIGURATION_VERSION = "configuration_version";
public static final String CALCULATED_FIELD_CONFIGURATION = "configuration";
public static final String CALCULATED_FIELD_VERSION = "version";
public static final String CALCULATED_FIELD_EXTERNAL_ID = "external_id";
protected static final String[] NONE_AGGREGATION_COLUMNS = new String[]{LONG_VALUE_COLUMN, DOUBLE_VALUE_COLUMN, BOOLEAN_VALUE_COLUMN, STRING_VALUE_COLUMN, JSON_VALUE_COLUMN, KEY_COLUMN, TS_COLUMN}; protected static final String[] NONE_AGGREGATION_COLUMNS = new String[]{LONG_VALUE_COLUMN, DOUBLE_VALUE_COLUMN, BOOLEAN_VALUE_COLUMN, STRING_VALUE_COLUMN, JSON_VALUE_COLUMN, KEY_COLUMN, TS_COLUMN};
protected static final String[] COUNT_AGGREGATION_COLUMNS = new String[]{count(LONG_VALUE_COLUMN), count(DOUBLE_VALUE_COLUMN), count(BOOLEAN_VALUE_COLUMN), count(STRING_VALUE_COLUMN), count(JSON_VALUE_COLUMN), max(TS_COLUMN)}; protected static final String[] COUNT_AGGREGATION_COLUMNS = new String[]{count(LONG_VALUE_COLUMN), count(DOUBLE_VALUE_COLUMN), count(BOOLEAN_VALUE_COLUMN), count(STRING_VALUE_COLUMN), count(JSON_VALUE_COLUMN), max(TS_COLUMN)};

View File

@ -0,0 +1,118 @@
/**
* Copyright © 2016-2024 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 com.fasterxml.jackson.databind.JsonNode;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.thingsboard.server.common.data.EntityType;
import org.thingsboard.server.common.data.calculated_field.CalculatedField;
import org.thingsboard.server.common.data.id.CalculatedFieldId;
import org.thingsboard.server.common.data.id.EntityIdFactory;
import org.thingsboard.server.common.data.id.TenantId;
import org.thingsboard.server.dao.model.BaseEntity;
import org.thingsboard.server.dao.model.BaseSqlEntity;
import org.thingsboard.server.dao.util.mapping.JsonConverter;
import java.util.UUID;
import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_CONFIGURATION;
import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_CONFIGURATION_VERSION;
import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_ENTITY_ID;
import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_ENTITY_TYPE;
import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_EXTERNAL_ID;
import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_TABLE_NAME;
import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_TENANT_ID_COLUMN;
import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_TYPE;
import static org.thingsboard.server.dao.model.ModelConstants.CALCULATED_FIELD_VERSION;
@Data
@EqualsAndHashCode(callSuper = true)
@Entity
@Table(name = CALCULATED_FIELD_TABLE_NAME)
public class CalculatedFieldEntity extends BaseSqlEntity<CalculatedField> implements BaseEntity<CalculatedField> {
@Column(name = CALCULATED_FIELD_TENANT_ID_COLUMN)
private UUID tenantId;
@Column(name = CALCULATED_FIELD_ENTITY_TYPE)
private EntityType entityType;
@Column(name = CALCULATED_FIELD_ENTITY_ID)
private UUID entityId;
@Column(name = CALCULATED_FIELD_TYPE)
private String type;
@Column(name = CALCULATED_FIELD_NAME)
private String name;
@Column(name = CALCULATED_FIELD_CONFIGURATION_VERSION)
private int configurationVersion;
@Convert(converter = JsonConverter.class)
@Column(name = CALCULATED_FIELD_CONFIGURATION)
private JsonNode configuration;
@Column(name = CALCULATED_FIELD_VERSION)
private Long version;
@Column(name = CALCULATED_FIELD_EXTERNAL_ID)
private UUID externalId;
public CalculatedFieldEntity() {
super();
}
public CalculatedFieldEntity(CalculatedField calculatedField) {
this.setUuid(calculatedField.getUuidId());
this.createdTime = calculatedField.getCreatedTime();
this.tenantId = calculatedField.getTenantId().getId();
this.entityType = calculatedField.getEntityId().getEntityType();
this.entityId = calculatedField.getEntityId().getId();
this.type = calculatedField.getType();
this.name = calculatedField.getName();
this.configurationVersion = calculatedField.getConfigurationVersion();
this.configuration = calculatedField.getConfiguration();
this.version = calculatedField.getVersion();
if (calculatedField.getExternalId() != null) {
this.externalId = calculatedField.getExternalId().getId();
}
}
@Override
public CalculatedField toData() {
CalculatedField calculatedField = new CalculatedField(new CalculatedFieldId(id));
calculatedField.setCreatedTime(createdTime);
calculatedField.setTenantId(TenantId.fromUUID(tenantId));
calculatedField.setEntityId(EntityIdFactory.getByTypeAndUuid(entityType, entityId));
calculatedField.setType(type);
calculatedField.setName(name);
calculatedField.setConfigurationVersion(configurationVersion);
calculatedField.setConfiguration(configuration);
calculatedField.setVersion(version);
if (externalId != null) {
calculatedField.setExternalId(new CalculatedFieldId(externalId));
}
return calculatedField;
}
}

View File

@ -0,0 +1,24 @@
/**
* Copyright © 2016-2024 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.calculated_field;
import org.springframework.data.jpa.repository.JpaRepository;
import org.thingsboard.server.dao.model.sql.CalculatedFieldEntity;
import java.util.UUID;
public interface CalculatedFieldRepository extends JpaRepository<CalculatedFieldEntity, UUID> {
}

View File

@ -0,0 +1,47 @@
/**
* Copyright © 2016-2024 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.calculated_field;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Component;
import org.thingsboard.server.common.data.calculated_field.CalculatedField;
import org.thingsboard.server.dao.calculated_field.CalculatedFieldDao;
import org.thingsboard.server.dao.model.sql.CalculatedFieldEntity;
import org.thingsboard.server.dao.sql.JpaAbstractDao;
import org.thingsboard.server.dao.util.SqlDao;
import java.util.UUID;
@Slf4j
@Component
@AllArgsConstructor
@SqlDao
public class JpaCalculatedFieldDao extends JpaAbstractDao<CalculatedFieldEntity, CalculatedField> implements CalculatedFieldDao {
private final CalculatedFieldRepository calculatedFieldRepository;
@Override
protected Class<CalculatedFieldEntity> getEntityClass() {
return CalculatedFieldEntity.class;
}
@Override
protected JpaRepository<CalculatedFieldEntity, UUID> getRepository() {
return calculatedFieldRepository;
}
}

View File

@ -1,3 +1,19 @@
--
-- Copyright © 2016-2024 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.
--
-- --
-- ThingsBoard, Inc. ("COMPANY") CONFIDENTIAL -- ThingsBoard, Inc. ("COMPANY") CONFIDENTIAL
-- --
@ -891,6 +907,7 @@ CREATE TABLE IF NOT EXISTS calculated_field (
id uuid NOT NULL CONSTRAINT calculated_field_pkey PRIMARY KEY, id uuid NOT NULL CONSTRAINT calculated_field_pkey PRIMARY KEY,
created_time bigint NOT NULL, created_time bigint NOT NULL,
tenant_id uuid NOT NULL, tenant_id uuid NOT NULL,
entity_type VARCHAR(32),
entity_id uuid NOT NULL, entity_id uuid NOT NULL,
type varchar(32) NOT NULL, type varchar(32) NOT NULL,
name varchar(255) NOT NULL, name varchar(255) NOT NULL,
@ -899,18 +916,18 @@ CREATE TABLE IF NOT EXISTS calculated_field (
version BIGINT DEFAULT 1, version BIGINT DEFAULT 1,
external_id UUID, external_id UUID,
CONSTRAINT calculated_field_unq_key UNIQUE (entity_id, name), CONSTRAINT calculated_field_unq_key UNIQUE (entity_id, name),
CONSTRAINT device_external_id_unq_key UNIQUE (tenant_id, external_id) CONSTRAINT calculated_field_external_id_unq_key UNIQUE (tenant_id, external_id)
); );
CREATE TABLE IF NOT EXISTS calculated_field_link ( -- CREATE TABLE IF NOT EXISTS calculated_field_link (
id uuid NOT NULL CONSTRAINT calculated_field_pkey PRIMARY KEY, -- id uuid NOT NULL CONSTRAINT calculated_field_pkey PRIMARY KEY,
created_time bigint NOT NULL, -- created_time bigint NOT NULL,
tenant_id uuid NOT NULL, -- tenant_id uuid NOT NULL,
entity_id uuid NOT NULL, -- entity_id uuid NOT NULL,
-- target_id uuid NOT NULL, -- -- target_id uuid NOT NULL,
calculated_field_id uuid NOT NULL, -- calculated_field_id uuid NOT NULL,
configuration varchar(10000), -- configuration varchar(10000),
CONSTRAINT calculated_field_link_unq_key UNIQUE (entity_id, calculated_field_id), -- CONSTRAINT calculated_field_link_unq_key UNIQUE (entity_id, calculated_field_id),
CONSTRAINT device_external_id_unq_key UNIQUE (tenant_id, external_id), -- CONSTRAINT calculated_field_external_id_unq_key UNIQUE (tenant_id, external_id),
CONSTRAINT fk_calculated_field_id FOREIGN KEY (calculated_field_id) REFERENCES calculated_field(id) ON DELETE CASCADE -- CONSTRAINT fk_calculated_field_id FOREIGN KEY (calculated_field_id) REFERENCES calculated_field(id) ON DELETE CASCADE
); -- );