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 List<RelationEntityTypeFilter> filters;
private int maxLevel; private int maxLevel;
private boolean fetchLastLevelOnly; 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.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.EntityType;
@ -27,13 +26,25 @@ import java.util.List;
* Created by ashvayka on 02.05.17. * Created by ashvayka on 02.05.17.
*/ */
@Data @Data
@AllArgsConstructor
@ApiModel @ApiModel
public class RelationEntityTypeFilter { 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") @ApiModelProperty(position = 1, value = "Type of the relation between root entity and other entity (e.g. 'Contains' or 'Manages').", example = "Contains")
private String relationType; private String relationType;
@ApiModelProperty(position = 2, value = "Array of entity types to filter the related entities (e.g. 'DEVICE', 'ASSET').") @ApiModelProperty(position = 2, value = "Array of entity types to filter the related entities (e.g. 'DEVICE', 'ASSET').")
private List<EntityType> entityTypes; 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(entityFilter.getDirection().equals(EntitySearchDirection.FROM) ? "to" : "from")
.append("_type in (:where_entity_types").append(")"); .append("_type in (:where_entity_types").append(")");
ctx.addStringListParameter("where_entity_types", Arrays.stream(RELATION_QUERY_ENTITY_TYPES).map(EntityType::name).collect(Collectors.toList())); ctx.addStringListParameter("where_entity_types", Arrays.stream(RELATION_QUERY_ENTITY_TYPES).map(EntityType::name).collect(Collectors.toList()));
} } else {
if (!single) {
if (!noConditions && !single) { whereFilter = new StringBuilder()
whereFilter = new StringBuilder().append("(").append(whereFilter).append(")"); .append(entityFilter.isNegate() ? " NOT (" : "(")
.append(whereFilter).append(")");
} else if (entityFilter.isNegate()) {
whereFilter = new StringBuilder()
.append(" NOT ")
.append(whereFilter).append(")");
}
} }
if (entityFilter.isFetchLastLevelOnly()) { if (entityFilter.isFetchLastLevelOnly()) {
@ -743,8 +749,11 @@ public class DefaultEntityQueryRepository implements EntityQueryRepository {
boolean hasRelationType = !StringUtils.isEmpty(relationType); boolean hasRelationType = !StringUtils.isEmpty(relationType);
if (hasRelationType) { if (hasRelationType) {
ctx.addStringParameter("where_relation_type" + entityTypeFilterIdx, relationType); ctx.addStringParameter("where_relation_type" + entityTypeFilterIdx, relationType);
whereFilter if (etf.isNegate()) {
.append("re.relation_type = :where_relation_type").append(entityTypeFilterIdx); 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 (!whereEntityTypes.isEmpty()) {
if (hasRelationType) { if (hasRelationType) {

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

@ -185,6 +185,9 @@
formControlName="maxLevel"> formControlName="maxLevel">
</mat-form-field> </mat-form-field>
</div> </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> <div class="mat-caption" style="padding-bottom: 10px; color: rgba(0,0,0,0.57);" translate>relation.relation-filters</div>
<tb-relation-filters <tb-relation-filters
[allowedEntityTypes]="allowedEntityTypes" [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]], rootEntity: [filter ? filter.rootEntity : null, (filter && filter.rootStateEntity) ? [] : [Validators.required]],
direction: [filter ? filter.direction : EntitySearchDirection.FROM, [Validators.required]], direction: [filter ? filter.direction : EntitySearchDirection.FROM, [Validators.required]],
maxLevel: [filter ? filter.maxLevel : 1, []], 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('rootStateEntity').valueChanges.subscribe((rootStateEntity: boolean) => {
this.filterFormGroup.get('rootEntity').setValidators(rootStateEntity ? [] : [Validators.required]); 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" <div class="row" fxFlex fxLayout="row"
fxLayoutAlign="start center" formArrayName="relationFilters" fxLayoutAlign="start center" formArrayName="relationFilters"
*ngFor="let relationFilterControl of relationFiltersFormArray().controls; let $index = index"> *ngFor="let relationFilterControl of relationFiltersFormArray().controls; let $index = index">
<div class="mat-elevation-z1" fxFlex fxLayout="row" fxLayoutAlign="start center"> <div class="mat-elevation-z1" fxFlex fxLayout="column" fxLayoutAlign="space-between start">
<tb-relation-type-autocomplete <div fxFlex fxLayout="row" fxLayoutAlign="start center">
class="cell" style="width: 200px; min-width: 200px;" <tb-relation-type-autocomplete
[formControl]="relationFilterControl.get('relationType')"> class="cell" style="width: 200px; min-width: 200px;"
</tb-relation-type-autocomplete> [formControl]="relationFilterControl.get('relationType')">
<tb-entity-type-list class="cell" fxFlex </tb-relation-type-autocomplete>
[allowedEntityTypes]="allowedEntityTypes" <tb-entity-type-list class="cell" fxFlex
[formControl]="relationFilterControl.get('entityTypes')"> [allowedEntityTypes]="allowedEntityTypes"
</tb-entity-type-list> [formControl]="relationFilterControl.get('entityTypes')">
<button mat-icon-button color="primary" </tb-entity-type-list>
type="button" <button mat-icon-button color="primary"
style="width: 40px; min-width: 40px;" type="button"
(click)="removeFilter($index)" style="width: 40px; min-width: 40px;"
[disabled]="isLoading$ | async" (click)="removeFilter($index)"
matTooltip="{{ 'relation.remove-relation-filter' | translate }}" [disabled]="isLoading$ | async"
matTooltipPosition="above"> matTooltip="{{ 'relation.remove-relation-filter' | translate }}"
<mat-icon>close</mat-icon> matTooltipPosition="above">
</button> <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> </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 relationFiltersFormArray = this.relationFiltersFormGroup.get('relationFilters') as FormArray;
const filter: RelationEntityTypeFilter = { const filter: RelationEntityTypeFilter = {
relationType: null, relationType: null,
entityTypes: [] entityTypes: [],
negate: false
}; };
relationFiltersFormArray.push(this.createRelationFilterFormGroup(filter)); relationFiltersFormArray.push(this.createRelationFilterFormGroup(filter));
} }
@ -112,7 +113,8 @@ export class RelationFiltersComponent extends PageComponent implements ControlVa
private createRelationFilterFormGroup(filter: RelationEntityTypeFilter): AbstractControl { private createRelationFilterFormGroup(filter: RelationEntityTypeFilter): AbstractControl {
return this.fb.group({ return this.fb.group({
relationType: [filter ? filter.relationType : null], 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>; filters?: Array<RelationEntityTypeFilter>;
maxLevel?: number; maxLevel?: number;
fetchLastLevelOnly?: boolean; fetchLastLevelOnly?: boolean;
negate?: boolean;
} }
export interface EntitySearchQueryFilter { 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 { export interface RelationEntityTypeFilter {
relationType: string; relationType: string;
entityTypes: Array<EntityType>; entityTypes: Array<EntityType>;
negate?: boolean;
} }
export interface RelationsSearchParameters { export interface RelationsSearchParameters {

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

@ -2840,7 +2840,9 @@
"relation-filters": "Relation filters", "relation-filters": "Relation filters",
"additional-info": "Additional info (JSON)", "additional-info": "Additional info (JSON)",
"invalid-additional-info": "Unable to parse 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": { "resource": {
"add": "Add Resource", "add": "Add Resource",

Loading…
Cancel
Save