Browse Source

Introduce NOT option for relation query.

pull/7514/head
devaskim 4 years ago
parent
commit
8f49f2a021
  1. 1
      common/data/src/main/java/org/thingsboard/server/common/data/query/RelationsQueryFilter.java
  2. 15
      common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationEntityTypeFilter.java
  3. 21
      dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java
  4. 3
      ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html
  5. 3
      ui-ngx/src/app/modules/home/components/entity/entity-filter.component.ts
  6. 41
      ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html
  7. 6
      ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts
  8. 1
      ui-ngx/src/app/shared/models/alias.models.ts
  9. 1
      ui-ngx/src/app/shared/models/relation.models.ts
  10. 4
      ui-ngx/src/assets/locale/locale.constant-en_US.json

1
common/data/src/main/java/org/thingsboard/server/common/data/query/RelationsQueryFilter.java

@ -40,5 +40,6 @@ public class RelationsQueryFilter implements EntityFilter {
private List<RelationEntityTypeFilter> filters;
private int maxLevel;
private boolean fetchLastLevelOnly;
private boolean negate;
}

15
common/data/src/main/java/org/thingsboard/server/common/data/relation/RelationEntityTypeFilter.java

@ -17,7 +17,6 @@ package org.thingsboard.server.common.data.relation;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.thingsboard.server.common.data.EntityType;
@ -27,13 +26,25 @@ import java.util.List;
* Created by ashvayka on 02.05.17.
*/
@Data
@AllArgsConstructor
@ApiModel
public class RelationEntityTypeFilter {
public RelationEntityTypeFilter(String relationType, List<EntityType> entityTypes) {
this(relationType, entityTypes, false);
}
public RelationEntityTypeFilter(String relationType, List<EntityType> entityTypes, boolean negate) {
this.relationType = relationType;
this.entityTypes = entityTypes;
this.negate = negate;
}
@ApiModelProperty(position = 1, value = "Type of the relation between root entity and other entity (e.g. 'Contains' or 'Manages').", example = "Contains")
private String relationType;
@ApiModelProperty(position = 2, value = "Array of entity types to filter the related entities (e.g. 'DEVICE', 'ASSET').")
private List<EntityType> entityTypes;
@ApiModelProperty(position = 3, value = "Negate relation type between root entity and other entity.")
private boolean negate;
}

21
dao/src/main/java/org/thingsboard/server/dao/sql/query/DefaultEntityQueryRepository.java

@ -704,10 +704,16 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
.append(entityFilter.getDirection().equals(EntitySearchDirection.FROM) ? "to" : "from")
.append("_type in (:where_entity_types").append(")");
ctx.addStringListParameter("where_entity_types", Arrays.stream(RELATION_QUERY_ENTITY_TYPES).map(EntityType::name).collect(Collectors.toList()));
}
if (!noConditions && !single) {
whereFilter = new StringBuilder().append("(").append(whereFilter).append(")");
} else {
if (!single) {
whereFilter = new StringBuilder()
.append(entityFilter.isNegate() ? " NOT (" : "(")
.append(whereFilter).append(")");
} else if (entityFilter.isNegate()) {
whereFilter = new StringBuilder()
.append(" NOT ")
.append(whereFilter).append(")");
}
}
if (entityFilter.isFetchLastLevelOnly()) {
@ -743,8 +749,11 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
boolean hasRelationType = !StringUtils.isEmpty(relationType);
if (hasRelationType) {
ctx.addStringParameter("where_relation_type" + entityTypeFilterIdx, relationType);
whereFilter
.append("re.relation_type = :where_relation_type").append(entityTypeFilterIdx);
if (etf.isNegate()) {
whereFilter.append("re.relation_type != :where_relation_type").append(entityTypeFilterIdx);
} else {
whereFilter.append("re.relation_type = :where_relation_type").append(entityTypeFilterIdx);
}
}
if (!whereEntityTypes.isEmpty()) {
if (hasRelationType) {

3
ui-ngx/src/app/modules/home/components/entity/entity-filter.component.html

@ -185,6 +185,9 @@
formControlName="maxLevel">
</mat-form-field>
</div>
<mat-slide-toggle formControlName="negate" *ngIf="this.filterFormGroup.get('filters').value.length > 1">
{{ 'relation.negate-all-relations' | translate }}
</mat-slide-toggle>
<div class="mat-caption" style="padding-bottom: 10px; color: rgba(0,0,0,0.57);" translate>relation.relation-filters</div>
<tb-relation-filters
[allowedEntityTypes]="allowedEntityTypes"

3
ui-ngx/src/app/modules/home/components/entity/entity-filter.component.ts

@ -173,7 +173,8 @@ export class EntityFilterComponent implements ControlValueAccessor, OnInit {
rootEntity: [filter ? filter.rootEntity : null, (filter && filter.rootStateEntity) ? [] : [Validators.required]],
direction: [filter ? filter.direction : EntitySearchDirection.FROM, [Validators.required]],
maxLevel: [filter ? filter.maxLevel : 1, []],
fetchLastLevelOnly: [filter ? filter.fetchLastLevelOnly : false, []]
fetchLastLevelOnly: [filter ? filter.fetchLastLevelOnly : false, []],
negate: [filter ? filter.negate : false, []]
});
this.filterFormGroup.get('rootStateEntity').valueChanges.subscribe((rootStateEntity: boolean) => {
this.filterFormGroup.get('rootEntity').setValidators(rootStateEntity ? [] : [Validators.required]);

41
ui-ngx/src/app/modules/home/components/relation/relation-filters.component.html

@ -28,24 +28,29 @@
<div class="row" fxFlex fxLayout="row"
fxLayoutAlign="start center" formArrayName="relationFilters"
*ngFor="let relationFilterControl of relationFiltersFormArray().controls; let $index = index">
<div class="mat-elevation-z1" fxFlex fxLayout="row" fxLayoutAlign="start center">
<tb-relation-type-autocomplete
class="cell" style="width: 200px; min-width: 200px;"
[formControl]="relationFilterControl.get('relationType')">
</tb-relation-type-autocomplete>
<tb-entity-type-list class="cell" fxFlex
[allowedEntityTypes]="allowedEntityTypes"
[formControl]="relationFilterControl.get('entityTypes')">
</tb-entity-type-list>
<button mat-icon-button color="primary"
type="button"
style="width: 40px; min-width: 40px;"
(click)="removeFilter($index)"
[disabled]="isLoading$ | async"
matTooltip="{{ 'relation.remove-relation-filter' | translate }}"
matTooltipPosition="above">
<mat-icon>close</mat-icon>
</button>
<div class="mat-elevation-z1" fxFlex fxLayout="column" fxLayoutAlign="space-between start">
<div fxFlex fxLayout="row" fxLayoutAlign="start center">
<tb-relation-type-autocomplete
class="cell" style="width: 200px; min-width: 200px;"
[formControl]="relationFilterControl.get('relationType')">
</tb-relation-type-autocomplete>
<tb-entity-type-list class="cell" fxFlex
[allowedEntityTypes]="allowedEntityTypes"
[formControl]="relationFilterControl.get('entityTypes')">
</tb-entity-type-list>
<button mat-icon-button color="primary"
type="button"
style="width: 40px; min-width: 40px;"
(click)="removeFilter($index)"
[disabled]="isLoading$ | async"
matTooltip="{{ 'relation.remove-relation-filter' | translate }}"
matTooltipPosition="above">
<mat-icon>close</mat-icon>
</button>
</div>
<mat-slide-toggle [formControl]="relationFilterControl.get('negate')" style="margin-left: 10px;">
{{ 'relation.negate-relation' | translate }}
</mat-slide-toggle>
</div>
</div>
</div>

6
ui-ngx/src/app/modules/home/components/relation/relation-filters.component.ts

@ -104,7 +104,8 @@ export class RelationFiltersComponent extends PageComponent implements ControlVa
const relationFiltersFormArray = this.relationFiltersFormGroup.get('relationFilters') as FormArray;
const filter: RelationEntityTypeFilter = {
relationType: null,
entityTypes: []
entityTypes: [],
negate: false
};
relationFiltersFormArray.push(this.createRelationFilterFormGroup(filter));
}
@ -112,7 +113,8 @@ export class RelationFiltersComponent extends PageComponent implements ControlVa
private createRelationFilterFormGroup(filter: RelationEntityTypeFilter): AbstractControl {
return this.fb.group({
relationType: [filter ? filter.relationType : null],
entityTypes: [filter ? filter.entityTypes : []]
entityTypes: [filter ? filter.entityTypes : []],
negate: [filter ? filter.negate : false],
});
}

1
ui-ngx/src/app/shared/models/alias.models.ts

@ -114,6 +114,7 @@ export interface RelationsQueryFilter {
filters?: Array<RelationEntityTypeFilter>;
maxLevel?: number;
fetchLastLevelOnly?: boolean;
negate?: boolean;
}
export interface EntitySearchQueryFilter {

1
ui-ngx/src/app/shared/models/relation.models.ts

@ -55,6 +55,7 @@ export const directionTypeTranslations = new Map<EntitySearchDirection, string>(
export interface RelationEntityTypeFilter {
relationType: string;
entityTypes: Array<EntityType>;
negate?: boolean;
}
export interface RelationsSearchParameters {

4
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -2840,7 +2840,9 @@
"relation-filters": "Relation filters",
"additional-info": "Additional info (JSON)",
"invalid-additional-info": "Unable to parse additional info json.",
"no-relations-text": "No relations found"
"no-relations-text": "No relations found",
"negate-all-relations": "Negate all relations (NOT condition)",
"negate-relation": "Negate this relation (NOT condition)"
},
"resource": {
"add": "Add Resource",

Loading…
Cancel
Save