Commit 3acae2fbf2c6ac17297999671af60267d1540864

Authored by Igor Kulikov
1 parent 45479a79

Entity data query - query builder

Showing 46 changed files with 1745 additions and 20 deletions
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.controller;
  17 +
  18 +import org.springframework.beans.factory.annotation.Autowired;
  19 +import org.springframework.security.access.prepost.PreAuthorize;
  20 +import org.springframework.web.bind.annotation.RequestBody;
  21 +import org.springframework.web.bind.annotation.RequestMapping;
  22 +import org.springframework.web.bind.annotation.RequestMethod;
  23 +import org.springframework.web.bind.annotation.ResponseBody;
  24 +import org.springframework.web.bind.annotation.RestController;
  25 +import org.thingsboard.server.common.data.exception.ThingsboardException;
  26 +import org.thingsboard.server.common.data.page.PageData;
  27 +import org.thingsboard.server.common.data.query.EntityCountQuery;
  28 +import org.thingsboard.server.common.data.query.EntityData;
  29 +import org.thingsboard.server.common.data.query.EntityDataQuery;
  30 +import org.thingsboard.server.queue.util.TbCoreComponent;
  31 +import org.thingsboard.server.service.query.EntityQueryService;
  32 +
  33 +@RestController
  34 +@TbCoreComponent
  35 +@RequestMapping("/api")
  36 +public class EntityQueryController extends BaseController {
  37 +
  38 + @Autowired
  39 + private EntityQueryService entityQueryService;
  40 +
  41 +
  42 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  43 + @RequestMapping(value = "/entitiesQuery/count", method = RequestMethod.POST)
  44 + @ResponseBody
  45 + public long countEntitiesByQuery(@RequestBody EntityCountQuery query) throws ThingsboardException {
  46 + checkNotNull(query);
  47 + try {
  48 + return this.entityQueryService.countEntitiesByQuery(getCurrentUser(), query);
  49 + } catch (Exception e) {
  50 + throw handleException(e);
  51 + }
  52 + }
  53 +
  54 + @PreAuthorize("hasAnyAuthority('TENANT_ADMIN', 'CUSTOMER_USER')")
  55 + @RequestMapping(value = "/entitiesQuery/find", method = RequestMethod.POST)
  56 + @ResponseBody
  57 + public PageData<EntityData> findEntityDataByQuery(@RequestBody EntityDataQuery query) throws ThingsboardException {
  58 + checkNotNull(query);
  59 + try {
  60 + return this.entityQueryService.findEntityDataByQuery(getCurrentUser(), query);
  61 + } catch (Exception e) {
  62 + throw handleException(e);
  63 + }
  64 + }
  65 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.query;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.springframework.beans.factory.annotation.Autowired;
  20 +import org.springframework.stereotype.Service;
  21 +import org.thingsboard.server.common.data.page.PageData;
  22 +import org.thingsboard.server.common.data.query.EntityCountQuery;
  23 +import org.thingsboard.server.common.data.query.EntityData;
  24 +import org.thingsboard.server.common.data.query.EntityDataQuery;
  25 +import org.thingsboard.server.dao.entity.EntityService;
  26 +import org.thingsboard.server.queue.util.TbCoreComponent;
  27 +import org.thingsboard.server.service.security.model.SecurityUser;
  28 +
  29 +@Service
  30 +@Slf4j
  31 +@TbCoreComponent
  32 +public class DefaultEntityQueryService implements EntityQueryService {
  33 +
  34 + @Autowired
  35 + private EntityService entityService;
  36 +
  37 + @Override
  38 + public long countEntitiesByQuery(SecurityUser securityUser, EntityCountQuery query) {
  39 + return entityService.countEntitiesByQuery(securityUser.getTenantId(), securityUser.getCustomerId(), query);
  40 + }
  41 +
  42 + @Override
  43 + public PageData<EntityData> findEntityDataByQuery(SecurityUser securityUser, EntityDataQuery query) {
  44 + return entityService.findEntityDataByQuery(securityUser.getTenantId(), securityUser.getCustomerId(), query);
  45 + }
  46 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.service.query;
  17 +
  18 +import org.thingsboard.server.common.data.page.PageData;
  19 +import org.thingsboard.server.common.data.query.EntityCountQuery;
  20 +import org.thingsboard.server.common.data.query.EntityData;
  21 +import org.thingsboard.server.common.data.query.EntityDataQuery;
  22 +import org.thingsboard.server.service.security.model.SecurityUser;
  23 +
  24 +public interface EntityQueryService {
  25 +
  26 + long countEntitiesByQuery(SecurityUser securityUser, EntityCountQuery query);
  27 +
  28 + PageData<EntityData> findEntityDataByQuery(SecurityUser securityUser, EntityDataQuery query);
  29 +
  30 +}
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at 6 * You may obtain a copy of the License at
7 * 7 *
8 - * http://www.apache.org/licenses/LICENSE-2.0 8 + * http://www.apache.org/licenses/LICENSE-2.0
9 * 9 *
10 * Unless required by applicable law or agreed to in writing, software 10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, 11 * distributed under the License is distributed on an "AS IS" BASIS,
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.service.telemetry.cmd.v2; 16 package org.thingsboard.server.service.telemetry.cmd.v2;
2 17
3 import lombok.Data; 18 import lombok.Data;
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.service.telemetry.cmd.v2; 16 package org.thingsboard.server.service.telemetry.cmd.v2;
2 17
3 import lombok.Data; 18 import lombok.Data;
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.service.telemetry.cmd.v2; 16 package org.thingsboard.server.service.telemetry.cmd.v2;
2 17
3 import lombok.Data; 18 import lombok.Data;
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.service.telemetry.cmd.v2; 16 package org.thingsboard.server.service.telemetry.cmd.v2;
2 17
3 import org.thingsboard.server.common.data.kv.Aggregation; 18 import org.thingsboard.server.common.data.kv.Aggregation;
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.service.telemetry.cmd.v2; 16 package org.thingsboard.server.service.telemetry.cmd.v2;
2 17
3 import org.thingsboard.server.common.data.query.EntityKey; 18 import org.thingsboard.server.common.data.query.EntityKey;
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.service.telemetry.cmd.v2; 16 package org.thingsboard.server.service.telemetry.cmd.v2;
2 17
3 import java.util.List; 18 import java.util.List;
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 * you may not use this file except in compliance with the License. 5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at 6 * You may obtain a copy of the License at
7 * 7 *
8 - * http://www.apache.org/licenses/LICENSE-2.0 8 + * http://www.apache.org/licenses/LICENSE-2.0
9 * 9 *
10 * Unless required by applicable law or agreed to in writing, software 10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, 11 * distributed under the License is distributed on an "AS IS" BASIS,
@@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
16 package org.thingsboard.server.dao.entity; 16 package org.thingsboard.server.dao.entity;
17 17
18 import com.google.common.util.concurrent.ListenableFuture; 18 import com.google.common.util.concurrent.ListenableFuture;
  19 +import org.thingsboard.server.common.data.id.CustomerId;
19 import org.thingsboard.server.common.data.id.EntityId; 20 import org.thingsboard.server.common.data.id.EntityId;
20 import org.thingsboard.server.common.data.id.TenantId; 21 import org.thingsboard.server.common.data.id.TenantId;
21 import org.thingsboard.server.common.data.page.PageData; 22 import org.thingsboard.server.common.data.page.PageData;
@@ -29,8 +30,8 @@ public interface EntityService { @@ -29,8 +30,8 @@ public interface EntityService {
29 30
30 void deleteEntityRelations(TenantId tenantId, EntityId entityId); 31 void deleteEntityRelations(TenantId tenantId, EntityId entityId);
31 32
32 - long countEntitiesByQuery(TenantId tenantId, EntityCountQuery query); 33 + long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query);
33 34
34 - PageData<EntityData> findEntityDataByQuery(TenantId tenantId, EntityDataQuery query); 35 + PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query);
35 36
36 } 37 }
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +import java.util.List;
  21 +
  22 +@Data
  23 +public class AssetSearchQueryFilter extends EntitySearchQueryFilter {
  24 +
  25 + @Override
  26 + public EntityFilterType getType() {
  27 + return EntityFilterType.ASSET_SEARCH_QUERY;
  28 + }
  29 +
  30 + private List<String> assetTypes;
  31 +
  32 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class AssetTypeFilter implements EntityFilter {
  22 +
  23 + @Override
  24 + public EntityFilterType getType() {
  25 + return EntityFilterType.ASSET_TYPE;
  26 + }
  27 +
  28 + private String assetType;
  29 +
  30 + private String assetNameFilter;
  31 +
  32 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class BooleanFilterPredicate implements KeyFilterPredicate {
  22 +
  23 + private BooleanOperation operation;
  24 + private boolean value;
  25 +
  26 + @Override
  27 + public FilterPredicateType getType() {
  28 + return FilterPredicateType.BOOLEAN;
  29 + }
  30 +
  31 + public enum BooleanOperation {
  32 + EQUAL,
  33 + NOT_EQUAL
  34 + }
  35 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +import java.util.List;
  21 +
  22 +@Data
  23 +public class ComplexFilterPredicate implements KeyFilterPredicate {
  24 +
  25 + private ComplexOperation operation;
  26 + private List<KeyFilterPredicate> predicates;
  27 +
  28 + @Override
  29 + public FilterPredicateType getType() {
  30 + return FilterPredicateType.COMPLEX;
  31 + }
  32 +
  33 + public enum ComplexOperation {
  34 + AND,
  35 + OR
  36 + }
  37 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +import java.util.List;
  21 +
  22 +@Data
  23 +public class DeviceSearchQueryFilter extends EntitySearchQueryFilter {
  24 +
  25 + @Override
  26 + public EntityFilterType getType() {
  27 + return EntityFilterType.DEVICE_SEARCH_QUERY;
  28 + }
  29 +
  30 + private List<String> deviceTypes;
  31 +
  32 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class DeviceTypeFilter implements EntityFilter {
  22 +
  23 + @Override
  24 + public EntityFilterType getType() {
  25 + return EntityFilterType.DEVICE_TYPE;
  26 + }
  27 +
  28 + private String deviceType;
  29 +
  30 + private String deviceNameFilter;
  31 +
  32 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.common.data.query; 16 package org.thingsboard.server.common.data.query;
2 17
3 import lombok.Getter; 18 import lombok.Getter;
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.common.data.query; 16 package org.thingsboard.server.common.data.query;
2 17
3 import lombok.Data; 18 import lombok.Data;
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.common.data.query; 16 package org.thingsboard.server.common.data.query;
2 17
3 import lombok.Data; 18 import lombok.Data;
4 -import org.thingsboard.server.common.data.page.SortOrder;  
5 19
6 @Data 20 @Data
7 public class EntityDataPageLink { 21 public class EntityDataPageLink {
8 22
9 private final int pageSize; 23 private final int pageSize;
10 private final int page; 24 private final int page;
11 - private final SortOrder sortOrder; 25 + private final EntityDataSortOrder sortOrder;
12 26
13 } 27 }
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.common.data.query; 16 package org.thingsboard.server.common.data.query;
2 17
3 import lombok.Getter; 18 import lombok.Getter;
@@ -12,11 +27,18 @@ public class EntityDataQuery extends EntityCountQuery { @@ -12,11 +27,18 @@ public class EntityDataQuery extends EntityCountQuery {
12 private final List<EntityKey> entityFields; 27 private final List<EntityKey> entityFields;
13 @Getter 28 @Getter
14 private final List<EntityKey> latestValues; 29 private final List<EntityKey> latestValues;
  30 + @Getter
  31 + private final List<KeyFilter> keyFilters;
15 32
16 - public EntityDataQuery(EntityFilter entityFilter, EntityDataPageLink pageLink, List<EntityKey> entityFields, List<EntityKey> latestValues) { 33 + public EntityDataQuery(EntityFilter entityFilter,
  34 + EntityDataPageLink pageLink,
  35 + List<EntityKey> entityFields,
  36 + List<EntityKey> latestValues,
  37 + List<KeyFilter> keyFilters) {
17 super(entityFilter); 38 super(entityFilter);
18 this.pageLink = pageLink; 39 this.pageLink = pageLink;
19 this.entityFields = entityFields; 40 this.entityFields = entityFields;
20 this.latestValues = latestValues; 41 this.latestValues = latestValues;
  42 + this.keyFilters = keyFilters;
21 } 43 }
22 } 44 }
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class EntityDataSortOrder {
  22 +
  23 + private final EntityKey key;
  24 + private final Direction direction;
  25 +
  26 + public EntityDataSortOrder(EntityKey key) {
  27 + this(key, Direction.ASC);
  28 + }
  29 +
  30 + public EntityDataSortOrder(EntityKey key, Direction direction) {
  31 + this.key = key;
  32 + this.direction = direction;
  33 + }
  34 +
  35 + public enum Direction {
  36 + ASC, DESC
  37 + }
  38 +
  39 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.common.data.query; 16 package org.thingsboard.server.common.data.query;
2 17
3 public interface EntityFilter { 18 public interface EntityFilter {
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.common.data.query; 16 package org.thingsboard.server.common.data.query;
2 17
3 public enum EntityFilterType { 18 public enum EntityFilterType {
4 SINGLE_ENTITY("singleEntity"), 19 SINGLE_ENTITY("singleEntity"),
5 ENTITY_LIST("entityList"), 20 ENTITY_LIST("entityList"),
6 - ENTITY_NAME("entityName");  
7 -// stateEntity = 'stateEntity',  
8 -// assetType = 'assetType',  
9 -// deviceType = 'deviceType',  
10 -// entityViewType = 'entityViewType',  
11 -// relationsQuery = 'relationsQuery',  
12 -// assetSearchQuery = 'assetSearchQuery',  
13 -// deviceSearchQuery = 'deviceSearchQuery',  
14 -// entityViewSearchQuery = 'entityViewSearchQuery' 21 + ENTITY_NAME("entityName"),
  22 + ASSET_TYPE("assetType"),
  23 + DEVICE_TYPE("deviceType"),
  24 + ENTITY_VIEW_TYPE("entityViewType"),
  25 + RELATIONS_QUERY("relationsQuery"),
  26 + ASSET_SEARCH_QUERY("assetSearchQuery"),
  27 + DEVICE_SEARCH_QUERY("deviceSearchQuery"),
  28 + ENTITY_VIEW_SEARCH_QUERY("entityViewSearchQuery");
15 29
16 private final String label; 30 private final String label;
17 31
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.common.data.query; 16 package org.thingsboard.server.common.data.query;
2 17
  18 +import lombok.Data;
  19 +
  20 +@Data
3 public class EntityKey { 21 public class EntityKey {
4 private EntityKeyType type; 22 private EntityKeyType type;
5 private String key; 23 private String key;
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.common.data.query; 16 package org.thingsboard.server.common.data.query;
2 17
3 public enum EntityKeyType { 18 public enum EntityKeyType {
  19 + ATTRIBUTE,
4 CLIENT_ATTRIBUTE, 20 CLIENT_ATTRIBUTE,
5 SHARED_ATTRIBUTE, 21 SHARED_ATTRIBUTE,
6 SERVER_ATTRIBUTE, 22 SERVER_ATTRIBUTE,
7 - TIMESERIES, 23 + TIME_SERIES,
8 ENTITY_FIELD; 24 ENTITY_FIELD;
9 } 25 }
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.EntityType;
  20 +import org.thingsboard.server.common.data.id.EntityId;
  21 +
  22 +import java.util.List;
  23 +
  24 +@Data
  25 +public class EntityListFilter implements EntityFilter {
  26 + @Override
  27 + public EntityFilterType getType() {
  28 + return EntityFilterType.ENTITY_LIST;
  29 + }
  30 +
  31 + private EntityType entityType;
  32 +
  33 + private List<String> entityList;
  34 +
  35 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.EntityType;
  20 +
  21 +@Data
  22 +public class EntityNameFilter implements EntityFilter {
  23 + @Override
  24 + public EntityFilterType getType() {
  25 + return EntityFilterType.ENTITY_NAME;
  26 + }
  27 +
  28 + private EntityType entityType;
  29 +
  30 + private String entityNameFilter;
  31 +
  32 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.id.EntityId;
  20 +import org.thingsboard.server.common.data.relation.EntitySearchDirection;
  21 +
  22 +@Data
  23 +public abstract class EntitySearchQueryFilter implements EntityFilter {
  24 +
  25 + private EntityId rootEntity;
  26 + private String relationType;
  27 + private EntitySearchDirection direction;
  28 + private int maxLevel;
  29 + private boolean fetchLastLevelOnly;
  30 +
  31 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +import java.util.List;
  21 +
  22 +@Data
  23 +public class EntityViewSearchQueryFilter extends EntitySearchQueryFilter {
  24 +
  25 + @Override
  26 + public EntityFilterType getType() {
  27 + return EntityFilterType.ENTITY_VIEW_SEARCH_QUERY;
  28 + }
  29 +
  30 + private List<String> entityViewTypes;
  31 +
  32 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class EntityViewTypeFilter implements EntityFilter {
  22 +
  23 + @Override
  24 + public EntityFilterType getType() {
  25 + return EntityFilterType.ENTITY_VIEW_TYPE;
  26 + }
  27 +
  28 + private String entityViewType;
  29 +
  30 + private String entityViewNameFilter;
  31 +
  32 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +public enum FilterPredicateType {
  19 + STRING,
  20 + NUMERIC,
  21 + BOOLEAN,
  22 + COMPLEX
  23 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class KeyFilter {
  22 +
  23 + private EntityKey key;
  24 + private KeyFilterPredicate predicate;
  25 +
  26 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +public interface KeyFilterPredicate {
  19 +
  20 + FilterPredicateType getType();
  21 +
  22 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class NumericFilterPredicate implements KeyFilterPredicate {
  22 +
  23 + private NumericOperation operation;
  24 + private double value;
  25 +
  26 + @Override
  27 + public FilterPredicateType getType() {
  28 + return FilterPredicateType.NUMERIC;
  29 + }
  30 +
  31 + public enum NumericOperation {
  32 + EQUAL,
  33 + NOT_EQUAL,
  34 + GREATER,
  35 + LESS,
  36 + GREATER_OR_EQUAL,
  37 + LESS_OR_EQUAL
  38 + }
  39 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.id.EntityId;
  20 +import org.thingsboard.server.common.data.relation.EntitySearchDirection;
  21 +import org.thingsboard.server.common.data.relation.EntityTypeFilter;
  22 +
  23 +import java.util.List;
  24 +
  25 +@Data
  26 +public class RelationsQueryFilter implements EntityFilter {
  27 +
  28 + @Override
  29 + public EntityFilterType getType() {
  30 + return EntityFilterType.RELATIONS_QUERY;
  31 + }
  32 +
  33 + private EntityId rootEntity;
  34 + private EntitySearchDirection direction;
  35 + private List<EntityTypeFilter> filters;
  36 + private int maxLevel;
  37 + private boolean fetchLastLevelOnly;
  38 +
  39 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.common.data.query; 16 package org.thingsboard.server.common.data.query;
2 17
3 import lombok.Data; 18 import lombok.Data;
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.common.data.query;
  17 +
  18 +import lombok.Data;
  19 +
  20 +@Data
  21 +public class StringFilterPredicate implements KeyFilterPredicate {
  22 +
  23 + private StringOperation operation;
  24 + private String value;
  25 + private boolean ignoreCase;
  26 +
  27 + @Override
  28 + public FilterPredicateType getType() {
  29 + return FilterPredicateType.STRING;
  30 + }
  31 +
  32 + public enum StringOperation {
  33 + EQUAL,
  34 + NOT_EQUAL,
  35 + STARTS_WITH,
  36 + ENDS_WITH,
  37 + CONTAINS,
  38 + NOT_CONTAINS
  39 + }
  40 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
1 package org.thingsboard.server.common.data.query; 16 package org.thingsboard.server.common.data.query;
2 17
3 import lombok.Data; 18 import lombok.Data;
@@ -33,6 +33,10 @@ import org.thingsboard.server.common.data.id.EntityViewId; @@ -33,6 +33,10 @@ import org.thingsboard.server.common.data.id.EntityViewId;
33 import org.thingsboard.server.common.data.id.RuleChainId; 33 import org.thingsboard.server.common.data.id.RuleChainId;
34 import org.thingsboard.server.common.data.id.TenantId; 34 import org.thingsboard.server.common.data.id.TenantId;
35 import org.thingsboard.server.common.data.id.UserId; 35 import org.thingsboard.server.common.data.id.UserId;
  36 +import org.thingsboard.server.common.data.page.PageData;
  37 +import org.thingsboard.server.common.data.query.EntityCountQuery;
  38 +import org.thingsboard.server.common.data.query.EntityData;
  39 +import org.thingsboard.server.common.data.query.EntityDataPageLink;
36 import org.thingsboard.server.common.data.query.EntityDataQuery; 40 import org.thingsboard.server.common.data.query.EntityDataQuery;
37 import org.thingsboard.server.dao.alarm.AlarmService; 41 import org.thingsboard.server.dao.alarm.AlarmService;
38 import org.thingsboard.server.dao.asset.AssetService; 42 import org.thingsboard.server.dao.asset.AssetService;
@@ -40,10 +44,13 @@ import org.thingsboard.server.dao.customer.CustomerService; @@ -40,10 +44,13 @@ import org.thingsboard.server.dao.customer.CustomerService;
40 import org.thingsboard.server.dao.dashboard.DashboardService; 44 import org.thingsboard.server.dao.dashboard.DashboardService;
41 import org.thingsboard.server.dao.device.DeviceService; 45 import org.thingsboard.server.dao.device.DeviceService;
42 import org.thingsboard.server.dao.entityview.EntityViewService; 46 import org.thingsboard.server.dao.entityview.EntityViewService;
  47 +import org.thingsboard.server.dao.exception.IncorrectParameterException;
43 import org.thingsboard.server.dao.rule.RuleChainService; 48 import org.thingsboard.server.dao.rule.RuleChainService;
44 import org.thingsboard.server.dao.tenant.TenantService; 49 import org.thingsboard.server.dao.tenant.TenantService;
45 import org.thingsboard.server.dao.user.UserService; 50 import org.thingsboard.server.dao.user.UserService;
46 51
  52 +import static org.thingsboard.server.dao.service.Validator.validateId;
  53 +
47 /** 54 /**
48 * Created by ashvayka on 04.05.17. 55 * Created by ashvayka on 04.05.17.
49 */ 56 */
@@ -51,6 +58,9 @@ import org.thingsboard.server.dao.user.UserService; @@ -51,6 +58,9 @@ import org.thingsboard.server.dao.user.UserService;
51 @Slf4j 58 @Slf4j
52 public class BaseEntityService extends AbstractEntityService implements EntityService { 59 public class BaseEntityService extends AbstractEntityService implements EntityService {
53 60
  61 + public static final String INCORRECT_TENANT_ID = "Incorrect tenantId ";
  62 + public static final String INCORRECT_CUSTOMER_ID = "Incorrect customerId ";
  63 +
54 @Autowired 64 @Autowired
55 private AssetService assetService; 65 private AssetService assetService;
56 66
@@ -78,14 +88,30 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe @@ -78,14 +88,30 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
78 @Autowired 88 @Autowired
79 private RuleChainService ruleChainService; 89 private RuleChainService ruleChainService;
80 90
  91 + @Autowired
  92 + private EntityQueryDao entityQueryDao;
  93 +
81 @Override 94 @Override
82 public void deleteEntityRelations(TenantId tenantId, EntityId entityId) { 95 public void deleteEntityRelations(TenantId tenantId, EntityId entityId) {
83 super.deleteEntityRelations(tenantId, entityId); 96 super.deleteEntityRelations(tenantId, entityId);
84 } 97 }
85 98
86 @Override 99 @Override
87 - public long countEntitiesByQuery(TenantId tenantId, EntityDataQuery query) {  
88 - return 0; 100 + public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) {
  101 + log.trace("Executing countEntitiesByQuery, tenantId [{}], customerId [{}], query [{}]", tenantId, customerId, query);
  102 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  103 + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
  104 + validateEntityCountQuery(query);
  105 + return this.entityQueryDao.countEntitiesByQuery(tenantId, customerId, query);
  106 + }
  107 +
  108 + @Override
  109 + public PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) {
  110 + log.trace("Executing findEntityDataByQuery, tenantId [{}], customerId [{}], query [{}]", tenantId, customerId, query);
  111 + validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
  112 + validateId(customerId, INCORRECT_CUSTOMER_ID + customerId);
  113 + validateEntityDataQuery(query);
  114 + return this.entityQueryDao.findEntityDataByQuery(tenantId, customerId, query);
89 } 115 }
90 116
91 @Override 117 @Override
@@ -128,4 +154,29 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe @@ -128,4 +154,29 @@ public class BaseEntityService extends AbstractEntityService implements EntitySe
128 return entityName; 154 return entityName;
129 } 155 }
130 156
  157 + private static void validateEntityCountQuery(EntityCountQuery query) {
  158 + if (query == null) {
  159 + throw new IncorrectParameterException("Query must be specified.");
  160 + } else if (query.getEntityFilter() == null) {
  161 + throw new IncorrectParameterException("Query entity filter must be specified.");
  162 + } else if (query.getEntityFilter().getType() == null) {
  163 + throw new IncorrectParameterException("Query entity filter type must be specified.");
  164 + }
  165 + }
  166 +
  167 + private static void validateEntityDataQuery(EntityDataQuery query) {
  168 + validateEntityCountQuery(query);
  169 + validateEntityDataPageLink(query.getPageLink());
  170 + }
  171 +
  172 + private static void validateEntityDataPageLink(EntityDataPageLink pageLink) {
  173 + if (pageLink == null) {
  174 + throw new IncorrectParameterException("Entity Data Page link must be specified.");
  175 + } else if (pageLink.getPageSize() < 1) {
  176 + throw new IncorrectParameterException("Incorrect entity data page link page size '"+pageLink.getPageSize()+"'. Page size must be greater than zero.");
  177 + } else if (pageLink.getPage() < 0) {
  178 + throw new IncorrectParameterException("Incorrect entity data page link page '"+pageLink.getPage()+"'. Page must be positive integer.");
  179 + }
  180 + }
  181 +
131 } 182 }
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.entity;
  17 +
  18 +import org.thingsboard.server.common.data.id.CustomerId;
  19 +import org.thingsboard.server.common.data.id.TenantId;
  20 +import org.thingsboard.server.common.data.page.PageData;
  21 +import org.thingsboard.server.common.data.query.EntityCountQuery;
  22 +import org.thingsboard.server.common.data.query.EntityData;
  23 +import org.thingsboard.server.common.data.query.EntityDataQuery;
  24 +
  25 +public interface EntityQueryDao {
  26 +
  27 + long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query);
  28 +
  29 + PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query);
  30 +
  31 +}
@@ -114,7 +114,6 @@ public class Validator { @@ -114,7 +114,6 @@ public class Validator {
114 * <code>IncorrectParameterException</code> exception 114 * <code>IncorrectParameterException</code> exception
115 * 115 *
116 * @param pageLink the page link 116 * @param pageLink the page link
117 - * @param errorMessage the error message for exception  
118 */ 117 */
119 public static void validatePageLink(PageLink pageLink) { 118 public static void validatePageLink(PageLink pageLink) {
120 if (pageLink == null) { 119 if (pageLink == null) {
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.sql.query;
  17 +
  18 +import lombok.extern.slf4j.Slf4j;
  19 +import org.apache.commons.lang3.StringUtils;
  20 +import org.springframework.stereotype.Repository;
  21 +import org.thingsboard.server.common.data.DataConstants;
  22 +import org.thingsboard.server.common.data.EntityType;
  23 +import org.thingsboard.server.common.data.UUIDConverter;
  24 +import org.thingsboard.server.common.data.id.CustomerId;
  25 +import org.thingsboard.server.common.data.id.EntityId;
  26 +import org.thingsboard.server.common.data.id.EntityIdFactory;
  27 +import org.thingsboard.server.common.data.id.TenantId;
  28 +import org.thingsboard.server.common.data.page.PageData;
  29 +import org.thingsboard.server.common.data.query.AssetTypeFilter;
  30 +import org.thingsboard.server.common.data.query.BooleanFilterPredicate;
  31 +import org.thingsboard.server.common.data.query.ComplexFilterPredicate;
  32 +import org.thingsboard.server.common.data.query.DeviceTypeFilter;
  33 +import org.thingsboard.server.common.data.query.EntityCountQuery;
  34 +import org.thingsboard.server.common.data.query.EntityData;
  35 +import org.thingsboard.server.common.data.query.EntityDataPageLink;
  36 +import org.thingsboard.server.common.data.query.EntityDataQuery;
  37 +import org.thingsboard.server.common.data.query.EntityFilter;
  38 +import org.thingsboard.server.common.data.query.EntityKey;
  39 +import org.thingsboard.server.common.data.query.EntityKeyType;
  40 +import org.thingsboard.server.common.data.query.EntityListFilter;
  41 +import org.thingsboard.server.common.data.query.EntityNameFilter;
  42 +import org.thingsboard.server.common.data.query.EntityViewTypeFilter;
  43 +import org.thingsboard.server.common.data.query.FilterPredicateType;
  44 +import org.thingsboard.server.common.data.query.KeyFilter;
  45 +import org.thingsboard.server.common.data.query.KeyFilterPredicate;
  46 +import org.thingsboard.server.common.data.query.NumericFilterPredicate;
  47 +import org.thingsboard.server.common.data.query.SingleEntityFilter;
  48 +import org.thingsboard.server.common.data.query.StringFilterPredicate;
  49 +import org.thingsboard.server.common.data.query.TsValue;
  50 +import org.thingsboard.server.dao.util.SqlDao;
  51 +
  52 +import javax.persistence.EntityManager;
  53 +import javax.persistence.PersistenceContext;
  54 +import java.math.BigInteger;
  55 +import java.util.ArrayList;
  56 +import java.util.Collections;
  57 +import java.util.HashMap;
  58 +import java.util.List;
  59 +import java.util.Map;
  60 +import java.util.Set;
  61 +import java.util.UUID;
  62 +import java.util.stream.Collectors;
  63 +
  64 +@SqlDao
  65 +@Repository
  66 +@Slf4j
  67 +public class DefaultEntityQueryRepository implements EntityQueryRepository {
  68 +
  69 + private static final Map<String, String> entityFieldColumnMap = new HashMap<>();
  70 + static {
  71 + entityFieldColumnMap.put("createdTime", "id");
  72 + entityFieldColumnMap.put("name", "name");
  73 + entityFieldColumnMap.put("type", "type");
  74 + entityFieldColumnMap.put("label", "label");
  75 + entityFieldColumnMap.put("firstName", "first_name");
  76 + entityFieldColumnMap.put("lastName", "last_name");
  77 + entityFieldColumnMap.put("email", "email");
  78 + entityFieldColumnMap.put("title", "title");
  79 + entityFieldColumnMap.put("country", "country");
  80 + entityFieldColumnMap.put("state", "state");
  81 + entityFieldColumnMap.put("city", "city");
  82 + entityFieldColumnMap.put("address", "address");
  83 + entityFieldColumnMap.put("address2", "address2");
  84 + entityFieldColumnMap.put("zip", "zip");
  85 + entityFieldColumnMap.put("phone", "phone");
  86 + }
  87 +
  88 + private static final Map<EntityType, String> entityTableMap = new HashMap<>();
  89 + static {
  90 + entityTableMap.put(EntityType.ASSET, "asset");
  91 + entityTableMap.put(EntityType.DEVICE, "device");
  92 + entityTableMap.put(EntityType.ENTITY_VIEW, "entity_view");
  93 + entityTableMap.put(EntityType.DASHBOARD, "dashboard");
  94 + entityTableMap.put(EntityType.CUSTOMER, "customer");
  95 + entityTableMap.put(EntityType.USER, "tb_user");
  96 + entityTableMap.put(EntityType.TENANT, "tenant");
  97 + }
  98 +
  99 + @PersistenceContext
  100 + private EntityManager entityManager;
  101 +
  102 + @Override
  103 + public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) {
  104 + EntityType entityType = resolveEntityType(query.getEntityFilter());
  105 + String countQuery = String.format("select count(e.id) from %s e where %s",
  106 + entityTableMap.get(entityType), this.buildEntityWhere(tenantId, customerId, query.getEntityFilter(),
  107 + Collections.emptyList(), entityType));
  108 + return ((BigInteger)entityManager.createNativeQuery(countQuery)
  109 + .getSingleResult()).longValue();
  110 + }
  111 +
  112 + @Override
  113 + public PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) {
  114 + EntityType entityType = resolveEntityType(query.getEntityFilter());
  115 +
  116 + List<EntityKeyMapping> mappings = prepareKeyMapping(query);
  117 +
  118 + List<EntityKeyMapping> selectionMapping = mappings.stream().filter(mapping -> mapping.isSelection())
  119 + .collect(Collectors.toList());
  120 + List<EntityKeyMapping> entityFieldsSelectionMapping = selectionMapping.stream().filter(mapping -> !mapping.isLatest())
  121 + .collect(Collectors.toList());
  122 + List<EntityKeyMapping> latestSelectionMapping = selectionMapping.stream().filter(mapping -> mapping.isLatest())
  123 + .collect(Collectors.toList());
  124 +
  125 + List<EntityKeyMapping> filterMapping = mappings.stream().filter(mapping -> mapping.hasFilter())
  126 + .collect(Collectors.toList());
  127 + List<EntityKeyMapping> entityFieldsFiltersMapping = filterMapping.stream().filter(mapping -> !mapping.isLatest())
  128 + .collect(Collectors.toList());
  129 + List<EntityKeyMapping> latestFiltersMapping = filterMapping.stream().filter(mapping -> mapping.isLatest())
  130 + .collect(Collectors.toList());
  131 +
  132 + List<EntityKeyMapping> allLatestMappings = mappings.stream().filter(mapping -> mapping.isLatest())
  133 + .collect(Collectors.toList());
  134 +
  135 +
  136 + String entityWhereClause = this.buildEntityWhere(tenantId, customerId, query.getEntityFilter(), entityFieldsFiltersMapping, entityType);
  137 + String latestJoins = this.buildLatestJoins(entityType, allLatestMappings);
  138 + String latestFilters = this.buildLatestQuery(latestFiltersMapping);
  139 +
  140 + String countQuery = String.format("select count(*) from (select e.id from %s e where %s) entities %s",
  141 + entityTableMap.get(entityType), entityWhereClause, latestJoins);
  142 + if (!StringUtils.isEmpty(latestFilters)) {
  143 + countQuery = String.format("%s where %s", countQuery, latestFilters);
  144 + }
  145 + int totalElements = ((BigInteger)entityManager.createNativeQuery(countQuery)
  146 + .getSingleResult()).intValue();
  147 +
  148 + String entityFieldsSelection = this.buildEntityFieldsSelection(entityFieldsSelectionMapping);
  149 + if (!StringUtils.isEmpty(entityFieldsSelection)) {
  150 + entityFieldsSelection = String.format("e.id, %s", entityFieldsSelection);
  151 + } else {
  152 + entityFieldsSelection = "e.id";
  153 + }
  154 + String latestSelection = this.buildLatestSelections(latestSelectionMapping);
  155 + String topSelection = "entities.*";
  156 + if (!StringUtils.isEmpty(latestSelection)) {
  157 + topSelection = topSelection + ", " + latestSelection;
  158 + }
  159 +
  160 + String dataQuery = String.format("select %s from (select %s from %s e where %s) entities %s", topSelection,
  161 + entityFieldsSelection,
  162 + entityTableMap.get(entityType),
  163 + entityWhereClause,
  164 + latestJoins);
  165 +
  166 + if (!StringUtils.isEmpty(latestFilters)) {
  167 + dataQuery = String.format("%s where %s", dataQuery, latestFilters);
  168 + }
  169 +
  170 + EntityDataPageLink pageLink = query.getPageLink();
  171 +
  172 + // TODO: order by
  173 +
  174 + int startIndex = pageLink.getPageSize() * pageLink.getPage();
  175 + if (pageLink.getPageSize() > 0) {
  176 + dataQuery = String.format("%s limit %s offset %s", dataQuery, pageLink.getPageSize(), startIndex);
  177 + }
  178 + List result = entityManager.createNativeQuery(dataQuery).getResultList();
  179 + int totalPages = pageLink.getPageSize() > 0 ? (int)Math.ceil((float)totalElements / pageLink.getPageSize()) : 1;
  180 + boolean hasNext = pageLink.getPageSize() > 0 && totalElements > startIndex + result.size();
  181 + List<EntityData> entitiesData = convertListToEntityData(result, entityType, selectionMapping);
  182 + return new PageData<>(entitiesData, totalPages, totalElements, hasNext);
  183 + }
  184 +
  185 + private List<EntityData> convertListToEntityData(List<Object> result, EntityType entityType, List<EntityKeyMapping> selectionMapping) {
  186 + return result.stream().map(obj -> this.toEntityData(obj, entityType, selectionMapping)).collect(Collectors.toList());
  187 + }
  188 +
  189 + private EntityData toEntityData(Object obj, EntityType entityType, List<EntityKeyMapping> selectionMapping) {
  190 + String id = obj instanceof String ? (String)obj : (String)((Object[]) obj)[0];
  191 + EntityId entityId = EntityIdFactory.getByTypeAndUuid(entityType, UUIDConverter.fromString(id));
  192 + Map<EntityKeyType, Map<String, TsValue>> latest = new HashMap<>();
  193 + Map<String, TsValue[]> timeseries = new HashMap<>();
  194 + EntityData entityData = new EntityData(entityId, latest, timeseries);
  195 + for (EntityKeyMapping mapping: selectionMapping) {
  196 + Object value = ((Object[]) obj)[mapping.getIndex()];
  197 + // TODO:
  198 + }
  199 + return entityData;
  200 + }
  201 +
  202 + private List<EntityKeyMapping> prepareKeyMapping(EntityDataQuery query) {
  203 + List<EntityKey> entityFields = query.getEntityFields() != null ? query.getEntityFields() : Collections.emptyList();
  204 + List<EntityKey> latestValues = query.getLatestValues() != null ? query.getLatestValues() : Collections.emptyList();
  205 + Map<EntityKey, List<KeyFilter>> filters =
  206 + query.getKeyFilters() != null ?
  207 + query.getKeyFilters().stream().collect(Collectors.groupingBy(KeyFilter::getKey)) : Collections.emptyMap();
  208 + int index = 1;
  209 + List<EntityKeyMapping> mappings = new ArrayList<>();
  210 + for (EntityKey entityField : entityFields) {
  211 + EntityKeyMapping mapping = new EntityKeyMapping();
  212 + mapping.setIndex(index);
  213 + mapping.setAlias(String.format("alias%s", index));
  214 + mapping.setKeyFilters(filters.remove(entityField));
  215 + mapping.setLatest(false);
  216 + mapping.setSelection(true);
  217 + mapping.setEntityKey(entityField);
  218 + mappings.add(mapping);
  219 + index++;
  220 + }
  221 + for (EntityKey latestField : latestValues) {
  222 + EntityKeyMapping mapping = new EntityKeyMapping();
  223 + mapping.setIndex(index);
  224 + mapping.setAlias(String.format("alias%s", index));
  225 + mapping.setKeyFilters(filters.remove(latestField));
  226 + mapping.setLatest(true);
  227 + mapping.setSelection(true);
  228 + mapping.setEntityKey(latestField);
  229 + mappings.add(mapping);
  230 + index +=2;
  231 + }
  232 + if (!filters.isEmpty()) {
  233 + for (EntityKey filterField : filters.keySet()) {
  234 + EntityKeyMapping mapping = new EntityKeyMapping();
  235 + mapping.setIndex(index);
  236 + mapping.setAlias(String.format("alias%s", index));
  237 + mapping.setKeyFilters(filters.get(filterField));
  238 + mapping.setLatest(!filterField.getType().equals(EntityKeyType.ENTITY_FIELD));
  239 + mapping.setSelection(false);
  240 + mapping.setEntityKey(filterField);
  241 + mappings.add(mapping);
  242 + index +=1;
  243 + }
  244 + }
  245 + return mappings;
  246 + }
  247 +
  248 + private String buildEntityFieldsSelection(List<EntityKeyMapping> entityFieldsSelectionMapping) {
  249 + return entityFieldsSelectionMapping.stream().map(mapping -> {
  250 + String column = entityFieldColumnMap.get(mapping.getEntityKey().getKey());
  251 + return String.format("e.%s as %s", column, mapping.getAlias());
  252 + }).collect(
  253 + Collectors.joining(", "));
  254 + }
  255 +
  256 + private String buildLatestSelections(List<EntityKeyMapping> latestSelectionMapping) {
  257 + return latestSelectionMapping.stream().map(mapping -> this.buildLatestSelection(mapping))
  258 + .collect(
  259 + Collectors.joining(", "));
  260 + }
  261 +
  262 + private String buildLatestSelection(EntityKeyMapping mapping) {
  263 + if (mapping.getEntityKey().getType().equals(EntityKeyType.TIME_SERIES)) {
  264 + return buildTimeseriesSelection(mapping);
  265 + } else {
  266 + return buildAttributeSelection(mapping);
  267 + }
  268 + }
  269 +
  270 + private String buildAttributeSelection(EntityKeyMapping mapping) {
  271 + String alias = mapping.getAlias();
  272 + String attrValAlias = alias + "_value";
  273 + String attrTsAlias = alias + "_ts";
  274 + String attrTsSelection = String.format("%s.last_update_ts as %s", alias, attrTsAlias);
  275 + String attrValSelection =
  276 + String.format("coalesce(cast(%s.bool_v as varchar), '') || " +
  277 + "coalesce(%s.str_v, '') || " +
  278 + "coalesce(cast(%s.long_v as varchar), '') || " +
  279 + "coalesce(cast(%s.dbl_v as varchar), '') || " +
  280 + "coalesce(cast(%s.json_v as varchar), '')) as %s", alias, alias, alias, alias, alias, attrValAlias);
  281 + return String.join(", ", attrTsSelection, attrValSelection);
  282 + }
  283 +
  284 + private String buildTimeseriesSelection(EntityKeyMapping mapping) {
  285 + // TODO:
  286 + String alias = mapping.getAlias();
  287 + String attrValAlias = alias + "_value";
  288 + String attrTsAlias = alias + "_ts";
  289 + return String.format("(select 1) as %s, (select '') as %s", attrTsAlias, attrValAlias);
  290 + }
  291 +
  292 + private String buildLatestJoins(EntityType entityType, List<EntityKeyMapping> latestMappings) {
  293 + return latestMappings.stream().map(mapping -> this.buildLatestJoin(entityType, mapping)).collect(
  294 + Collectors.joining(" "));
  295 + }
  296 +
  297 + private String buildLatestJoin(EntityType entityType, EntityKeyMapping mapping) {
  298 + String join = mapping.hasFilter() ? "left join" : "left outer join";
  299 + if (mapping.getEntityKey().getType().equals(EntityKeyType.TIME_SERIES)) {
  300 + // TODO:
  301 + throw new RuntimeException("Not implemented!");
  302 + } else {
  303 + String alias = mapping.getAlias();
  304 + String query = String.format("%s attribute_kv %s ON %s.entity_id=entities.id AND %s.entity_type='%s' AND %s.attribute_key='%s'",
  305 + join, alias, alias, alias, entityType.name(), alias, mapping.getEntityKey().getKey());
  306 + if (!mapping.getEntityKey().getType().equals(EntityKeyType.ATTRIBUTE)) {
  307 + String scope;
  308 + if (mapping.getEntityKey().getType().equals(EntityKeyType.CLIENT_ATTRIBUTE)) {
  309 + scope = DataConstants.CLIENT_SCOPE;
  310 + } else if (mapping.getEntityKey().getType().equals(EntityKeyType.SHARED_ATTRIBUTE)) {
  311 + scope = DataConstants.SHARED_SCOPE;
  312 + } else {
  313 + scope = DataConstants.SERVER_SCOPE;
  314 + }
  315 + query = String.format("%s AND %s.attribute_type=%s", query, alias, scope);
  316 + }
  317 + return query;
  318 + }
  319 + }
  320 +
  321 + private String buildEntityWhere(TenantId tenantId,
  322 + CustomerId customerId,
  323 + EntityFilter entityFilter,
  324 + List<EntityKeyMapping> entityFieldsFilters,
  325 + EntityType entityType) {
  326 + String permissionQuery = this.buildPermissionQuery(tenantId, customerId, entityType);
  327 + String entityFilterQuery = this.buildEntityFilterQuery(entityFilter);
  328 + if (!entityFieldsFilters.isEmpty()) {
  329 + String entityFieldsQuery = this.buildEntityFieldsQuery(entityFieldsFilters);
  330 + return String.join(" and ", permissionQuery, entityFilterQuery, entityFieldsQuery);
  331 + } else {
  332 + return String.join(" and ", permissionQuery, entityFilterQuery);
  333 + }
  334 + }
  335 +
  336 + private String buildPermissionQuery(TenantId tenantId, CustomerId customerId, EntityType entityType) {
  337 + String permissionQuery = String.format("e.tenant_id=%s", UUIDConverter.fromTimeUUID(tenantId.getId()));
  338 + if (entityType != EntityType.TENANT && entityType != EntityType.CUSTOMER) {
  339 + permissionQuery = String.format("%s and e.customerId=%s", permissionQuery, UUIDConverter.fromTimeUUID(customerId.getId()));
  340 + }
  341 + return permissionQuery;
  342 + }
  343 +
  344 + private String buildEntityFilterQuery(EntityFilter entityFilter) {
  345 + switch (entityFilter.getType()) {
  346 + case SINGLE_ENTITY:
  347 + return this.singleEntityQuery((SingleEntityFilter) entityFilter);
  348 + case ENTITY_LIST:
  349 + return this.entityListQuery((EntityListFilter) entityFilter);
  350 + case ENTITY_NAME:
  351 + return this.entityNameQuery((EntityNameFilter) entityFilter);
  352 + case ASSET_TYPE:
  353 + case DEVICE_TYPE:
  354 + case ENTITY_VIEW_TYPE:
  355 + return this.typeQuery(entityFilter);
  356 + default:
  357 + throw new RuntimeException("Not implemented!");
  358 + }
  359 + }
  360 +
  361 + private String buildLatestQuery(List<EntityKeyMapping> latestFilters) {
  362 + List<String> latestQueries = new ArrayList<>();
  363 + for (EntityKeyMapping mapping: latestFilters) {
  364 + latestQueries.addAll(mapping.getKeyFilters().stream().map(keyFilter ->
  365 + this.buildKeyQuery(mapping.getAlias(), keyFilter))
  366 + .collect(Collectors.toList()));
  367 + }
  368 + return latestQueries.stream().collect(Collectors.joining(" AND "));
  369 + }
  370 +
  371 + private String buildEntityFieldsQuery(List<EntityKeyMapping> entityFieldsFilters) {
  372 + return entityFieldsFilters.stream().flatMap(mapping -> mapping.getKeyFilters().stream())
  373 + .map(keyFilter -> this.buildKeyQuery("e", keyFilter)).collect(
  374 + Collectors.joining(" AND ")
  375 + );
  376 + }
  377 +
  378 + private String buildKeyQuery(String alias, KeyFilter keyFilter) {
  379 + return this.buildPredicateQuery(alias, keyFilter.getKey(), keyFilter.getPredicate());
  380 + }
  381 +
  382 + private String buildPredicateQuery(String alias, EntityKey key, KeyFilterPredicate predicate) {
  383 + if (predicate.getType().equals(FilterPredicateType.COMPLEX)) {
  384 + return this.buildComplexPredicateQuery(alias, key, (ComplexFilterPredicate)predicate);
  385 + } else {
  386 + return this.buildSimplePredicateQuery(alias, key, predicate);
  387 + }
  388 + }
  389 +
  390 + private String buildComplexPredicateQuery(String alias, EntityKey key, ComplexFilterPredicate predicate) {
  391 + return predicate.getPredicates().stream()
  392 + .map(keyFilterPredicate -> this.buildPredicateQuery(alias, key, keyFilterPredicate)).collect(Collectors.joining(
  393 + " " + predicate.getOperation().name() + " "
  394 + ));
  395 + }
  396 +
  397 + private String buildSimplePredicateQuery(String alias, EntityKey key, KeyFilterPredicate predicate) {
  398 + if (predicate.getType().equals(FilterPredicateType.NUMERIC)) {
  399 + if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) {
  400 + String column = entityFieldColumnMap.get(key.getKey());
  401 + return this.buildNumericPredicateQuery(alias + "." + column, (NumericFilterPredicate)predicate);
  402 + } else {
  403 + String longQuery = this.buildNumericPredicateQuery(alias + ".long_v", (NumericFilterPredicate)predicate);
  404 + String doubleQuery = this.buildNumericPredicateQuery(alias + ".dbl_v", (NumericFilterPredicate)predicate);
  405 + return String.format("(%s or %s)", longQuery, doubleQuery);
  406 + }
  407 + } else {
  408 + String column;
  409 + if (key.getType().equals(EntityKeyType.ENTITY_FIELD)) {
  410 + column = entityFieldColumnMap.get(key.getKey());
  411 + } else {
  412 + column = predicate.getType().equals(FilterPredicateType.STRING) ? "str_v" : "bool_v";
  413 + }
  414 + String field = alias + "." + column;
  415 + if (predicate.getType().equals(FilterPredicateType.STRING)) {
  416 + return this.buildStringPredicateQuery(field, (StringFilterPredicate)predicate);
  417 + } else {
  418 + return this.buildBooleanPredicateQuery(field, (BooleanFilterPredicate)predicate);
  419 + }
  420 + }
  421 + }
  422 +
  423 + private String buildStringPredicateQuery(String field, StringFilterPredicate stringFilterPredicate) {
  424 + String operationField = field;
  425 + String value = stringFilterPredicate.getValue();
  426 + String stringOperationQuery = "";
  427 + if (stringFilterPredicate.isIgnoreCase()) {
  428 + value.toLowerCase();
  429 + operationField = String.format("lower(%s)", operationField);
  430 + }
  431 + switch (stringFilterPredicate.getOperation()) {
  432 + case EQUAL:
  433 + stringOperationQuery = String.format("%s = '%s'", operationField, value);
  434 + break;
  435 + case NOT_EQUAL:
  436 + stringOperationQuery = String.format("%s != '%s'", operationField, value);
  437 + break;
  438 + case STARTS_WITH:
  439 + stringOperationQuery = String.format("%s like '%s%'", operationField, value);
  440 + break;
  441 + case ENDS_WITH:
  442 + stringOperationQuery = String.format("%s like '%%s'", operationField, value);
  443 + break;
  444 + case CONTAINS:
  445 + stringOperationQuery = String.format("%s like '%%s%'", operationField, value);
  446 + break;
  447 + case NOT_CONTAINS:
  448 + stringOperationQuery = String.format("%s not like '%%s%'", operationField, value);
  449 + break;
  450 + }
  451 + return String.format("(%s is not null and %s)", field, stringOperationQuery);
  452 + }
  453 +
  454 + private String buildNumericPredicateQuery(String field, NumericFilterPredicate numericFilterPredicate) {
  455 + double value = numericFilterPredicate.getValue();
  456 + String numericOperationQuery = "";
  457 + switch (numericFilterPredicate.getOperation()) {
  458 + case EQUAL:
  459 + numericOperationQuery = String.format("%s = %s", field, value);
  460 + break;
  461 + case NOT_EQUAL:
  462 + numericOperationQuery = String.format("%s != '%s'", field, value);
  463 + break;
  464 + case GREATER:
  465 + numericOperationQuery = String.format("%s > %s", field, value);
  466 + break;
  467 + case GREATER_OR_EQUAL:
  468 + numericOperationQuery = String.format("%s >= %s", field, value);
  469 + break;
  470 + case LESS:
  471 + numericOperationQuery = String.format("%s < %s", field, value);
  472 + break;
  473 + case LESS_OR_EQUAL:
  474 + numericOperationQuery = String.format("%s <= %s", field, value);
  475 + break;
  476 + }
  477 + return String.format("(%s is not null and %s)", field, numericOperationQuery);
  478 + }
  479 +
  480 + private String buildBooleanPredicateQuery(String field,
  481 + BooleanFilterPredicate booleanFilterPredicate) {
  482 + boolean value = booleanFilterPredicate.isValue();
  483 + String booleanOperationQuery = "";
  484 + switch (booleanFilterPredicate.getOperation()) {
  485 + case EQUAL:
  486 + booleanOperationQuery = String.format("%s = %s", field, value);
  487 + break;
  488 + case NOT_EQUAL:
  489 + booleanOperationQuery = String.format("%s != %s", field, value);
  490 + break;
  491 + }
  492 + return String.format("(%s is not null and %s)", field, booleanOperationQuery);
  493 + }
  494 +
  495 + private String singleEntityQuery(SingleEntityFilter filter) {
  496 + return String.format("e.id=%s", UUIDConverter.fromTimeUUID(filter.getSingleEntity().getId()));
  497 + }
  498 +
  499 + private String entityListQuery(EntityListFilter filter) {
  500 + return String.format("e.id in (%s)",
  501 + filter.getEntityList().stream().map(UUID::fromString).map(UUIDConverter::fromTimeUUID).collect(Collectors.joining(",")));
  502 + }
  503 +
  504 + private String entityNameQuery(EntityNameFilter filter) {
  505 + return String.format("lower(e.searchText) like lower(concat(%s, '%'))", filter.getEntityNameFilter());
  506 + }
  507 +
  508 + private String typeQuery(EntityFilter filter) {
  509 + String type;
  510 + String name;
  511 + switch (filter.getType()) {
  512 + case ASSET_TYPE:
  513 + type = ((AssetTypeFilter)filter).getAssetType();
  514 + name = ((AssetTypeFilter)filter).getAssetNameFilter();
  515 + break;
  516 + case DEVICE_TYPE:
  517 + type = ((DeviceTypeFilter)filter).getDeviceType();
  518 + name = ((DeviceTypeFilter)filter).getDeviceNameFilter();
  519 + break;
  520 + case ENTITY_VIEW_TYPE:
  521 + type = ((EntityViewTypeFilter)filter).getEntityViewType();
  522 + name = ((EntityViewTypeFilter)filter).getEntityViewNameFilter();
  523 + break;
  524 + default:
  525 + throw new RuntimeException("Not supported!");
  526 + }
  527 + return String.format("e.type = %s and lower(e.searchText) like lower(concat(%s, '%'))", type, name);
  528 + }
  529 +
  530 + private EntityType resolveEntityType(EntityFilter entityFilter) {
  531 + switch (entityFilter.getType()) {
  532 + case SINGLE_ENTITY:
  533 + return ((SingleEntityFilter)entityFilter).getSingleEntity().getEntityType();
  534 + case ENTITY_LIST:
  535 + return ((EntityListFilter)entityFilter).getEntityType();
  536 + case ENTITY_NAME:
  537 + return ((EntityNameFilter)entityFilter).getEntityType();
  538 + case ASSET_TYPE:
  539 + case ASSET_SEARCH_QUERY:
  540 + return EntityType.ASSET;
  541 + case DEVICE_TYPE:
  542 + case DEVICE_SEARCH_QUERY:
  543 + return EntityType.DEVICE;
  544 + case ENTITY_VIEW_TYPE:
  545 + case ENTITY_VIEW_SEARCH_QUERY:
  546 + return EntityType.ENTITY_VIEW;
  547 + default:
  548 + throw new RuntimeException("Not implemented!");
  549 + }
  550 + }
  551 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.sql.query;
  17 +
  18 +import lombok.Data;
  19 +import org.thingsboard.server.common.data.query.EntityKey;
  20 +import org.thingsboard.server.common.data.query.KeyFilter;
  21 +
  22 +import java.util.List;
  23 +
  24 +@Data
  25 +public class EntityKeyMapping {
  26 + private int index;
  27 + private String alias;
  28 + private boolean isLatest;
  29 + private boolean isSelection;
  30 + private List<KeyFilter> keyFilters;
  31 + private EntityKey entityKey;
  32 +
  33 + public boolean hasFilter() {
  34 + return keyFilters != null && !keyFilters.isEmpty();
  35 + }
  36 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.sql.query;
  17 +
  18 +import org.thingsboard.server.common.data.id.CustomerId;
  19 +import org.thingsboard.server.common.data.id.TenantId;
  20 +import org.thingsboard.server.common.data.page.PageData;
  21 +import org.thingsboard.server.common.data.query.EntityCountQuery;
  22 +import org.thingsboard.server.common.data.query.EntityData;
  23 +import org.thingsboard.server.common.data.query.EntityDataQuery;
  24 +
  25 +public interface EntityQueryRepository {
  26 +
  27 + long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query);
  28 +
  29 + PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query);
  30 +
  31 +}
  1 +/**
  2 + * Copyright © 2016-2020 The Thingsboard Authors
  3 + *
  4 + * Licensed under the Apache License, Version 2.0 (the "License");
  5 + * you may not use this file except in compliance with the License.
  6 + * You may obtain a copy of the License at
  7 + *
  8 + * http://www.apache.org/licenses/LICENSE-2.0
  9 + *
  10 + * Unless required by applicable law or agreed to in writing, software
  11 + * distributed under the License is distributed on an "AS IS" BASIS,
  12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13 + * See the License for the specific language governing permissions and
  14 + * limitations under the License.
  15 + */
  16 +package org.thingsboard.server.dao.sql.query;
  17 +
  18 +import org.springframework.beans.factory.annotation.Autowired;
  19 +import org.springframework.stereotype.Component;
  20 +import org.thingsboard.server.common.data.id.CustomerId;
  21 +import org.thingsboard.server.common.data.id.TenantId;
  22 +import org.thingsboard.server.common.data.page.PageData;
  23 +import org.thingsboard.server.common.data.query.EntityCountQuery;
  24 +import org.thingsboard.server.common.data.query.EntityData;
  25 +import org.thingsboard.server.common.data.query.EntityDataQuery;
  26 +import org.thingsboard.server.dao.entity.EntityQueryDao;
  27 +import org.thingsboard.server.dao.util.SqlDao;
  28 +
  29 +@Component
  30 +@SqlDao
  31 +public class JpaEntityQueryDao implements EntityQueryDao {
  32 +
  33 + @Autowired
  34 + private EntityQueryRepository entityQueryRepository;
  35 +
  36 + @Override
  37 + public long countEntitiesByQuery(TenantId tenantId, CustomerId customerId, EntityCountQuery query) {
  38 + return entityQueryRepository.countEntitiesByQuery(tenantId, customerId, query);
  39 + }
  40 +
  41 + @Override
  42 + public PageData<EntityData> findEntityDataByQuery(TenantId tenantId, CustomerId customerId, EntityDataQuery query) {
  43 + return entityQueryRepository.findEntityDataByQuery(tenantId, customerId, query);
  44 + }
  45 +}