added calculated field entity, dao and controller
This commit is contained in:
parent
32b5aaebc0
commit
32bbd83541
@ -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);
|
||||||
|
|||||||
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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() {
|
||||||
|
|||||||
@ -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() {
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
@ -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
|
||||||
|
|||||||
@ -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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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!");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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> {
|
||||||
|
}
|
||||||
@ -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)};
|
||||||
|
|||||||
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -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> {
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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
|
||||||
);
|
-- );
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user