+
+
+
+
@for (query of selectionModel.queries; track query; let i = $index) {
-
+
+
+
+
+
+ @switch (query.operator) {
+ @case ('exists') {
+
+ }
+ @default {
+
+ }
+ }
+
+
+
+
+
+
diff --git a/src-ui/src/app/components/common/custom-fields-lookup-dropdown/custom-fields-lookup-dropdown.component.ts b/src-ui/src/app/components/common/custom-fields-lookup-dropdown/custom-fields-lookup-dropdown.component.ts
index 9af356aa8..3b872b5c2 100644
--- a/src-ui/src/app/components/common/custom-fields-lookup-dropdown/custom-fields-lookup-dropdown.component.ts
+++ b/src-ui/src/app/components/common/custom-fields-lookup-dropdown/custom-fields-lookup-dropdown.component.ts
@@ -3,19 +3,29 @@ import { Subject, first, takeUntil } from 'rxjs'
import { CustomField } from 'src/app/data/custom-field'
import { CustomFieldsService } from 'src/app/services/rest/custom-fields.service'
-export class CustomFieldQuery {
- public changed = new Subject
()
+export enum CustomFieldQueryLogicalOperator {
+ And = 'AND',
+ Or = 'OR',
+ Not = 'NOT',
+}
- private _field: string
- set field(value: string) {
- this._field = value
- this.changed.next(this)
- }
- get field(): string {
- return this._field
+export enum CustomFieldQueryComponentType {
+ Atom = 'Atom',
+ Expression = 'Expression',
+}
+
+export class CustomFieldQueryComponent {
+ public readonly type: CustomFieldQueryComponentType
+ public changed: Subject
+
+ constructor(type: CustomFieldQueryComponentType) {
+ this.type = type
+ this.changed = new Subject()
}
- private _operator: string
+ public serialize() {}
+
+ protected _operator: string
set operator(value: string) {
this._operator = value
this.changed.next(this)
@@ -24,31 +34,75 @@ export class CustomFieldQuery {
return this._operator
}
- private _value: string
- set value(value: string) {
+ protected _value: string | CustomFieldQueryAtom[] | CustomFieldQueryExpression
+ set value(
+ value: string | CustomFieldQueryAtom[] | CustomFieldQueryExpression
+ ) {
this._value = value
this.changed.next(this)
}
- get value(): string {
+ get value(): string | CustomFieldQueryAtom[] | CustomFieldQueryExpression {
return this._value
}
+}
+export class CustomFieldQueryAtom extends CustomFieldQueryComponent {
+ protected _field: string
+ set field(value: string) {
+ this._field = value
+ this.changed.next(this)
+ }
+ get field(): string {
+ return this._field
+ }
+
+ constructor(queryArray: [string, string, string] = [null, null, null]) {
+ super(CustomFieldQueryComponentType.Atom)
+ ;[this._field, this._operator, this._value] = queryArray
+ }
+
+ public serialize() {
+ return [this._field, this._operator, this._value]
+ }
+}
+
+export class CustomFieldQueryExpression extends CustomFieldQueryComponent {
constructor(
- field: string = null,
- operator: string = null,
- value: string = null
+ expressionArray: [
+ CustomFieldQueryLogicalOperator,
+ (
+ | [string, string, string][]
+ | [CustomFieldQueryLogicalOperator, [string, string, string][]]
+ ),
+ ] = [CustomFieldQueryLogicalOperator.And, null]
) {
- this.field = field
- this.operator = operator
- this.value = value
+ super(CustomFieldQueryComponentType.Expression)
+ ;[this._operator] = expressionArray
+ let values = expressionArray[1]
+ if (!values) {
+ this._value = []
+ } else if (values?.length > 0 && values[0] instanceof Array) {
+ this._value = values.map((value) => new CustomFieldQueryAtom(value))
+ } else {
+ this._value = new CustomFieldQueryExpression(values as any)
+ }
+ }
+
+ public serialize() {
+ let value
+ if (this._value instanceof Array) {
+ value = this._value.map((atom) => atom.serialize())
+ } else {
+ value = value.serialize()
+ }
+ return [this._operator, value]
}
}
export class CustomFieldQueriesModel {
- // matchingModel: MatchingModel
- queries: CustomFieldQuery[] = []
+ public queries: Array = []
- changed = new Subject()
+ public readonly changed = new Subject()
public clear(fireEvent = true) {
this.queries = []
@@ -57,8 +111,14 @@ export class CustomFieldQueriesModel {
}
}
- public addQuery(query: CustomFieldQuery = new CustomFieldQuery()) {
- this.queries.push(query)
+ public addQuery(query: CustomFieldQueryAtom = new CustomFieldQueryAtom()) {
+ if (this.queries.length > 0) {
+ if (this.queries[0].type === CustomFieldQueryComponentType.Expression) {
+ ;(this.queries[0].value as Array).push(query)
+ }
+ } else {
+ this.queries.push(query)
+ }
query.changed.subscribe(() => {
if (query.field && query.operator && query.value) {
this.changed.next(this)
@@ -71,6 +131,21 @@ export class CustomFieldQueriesModel {
query.changed.complete()
this.changed.next(this)
}
+
+ public addExpression(
+ expression: CustomFieldQueryExpression = new CustomFieldQueryExpression()
+ ) {
+ if (this.queries.length > 0) {
+ if (this.queries[0].type === CustomFieldQueryComponentType.Atom) {
+ expression.value = this.queries as CustomFieldQueryAtom[]
+ this.queries = []
+ }
+ }
+ this.queries.push(expression)
+ expression.changed.subscribe(() => {
+ this.changed.next(this)
+ })
+ }
}
@Component({
@@ -79,6 +154,8 @@ export class CustomFieldQueriesModel {
styleUrls: ['./custom-fields-lookup-dropdown.component.scss'],
})
export class CustomFieldsLookupDropdownComponent {
+ public CustomFieldQueryComponentType = CustomFieldQueryComponentType
+
@Input()
title: string
@@ -143,10 +220,14 @@ export class CustomFieldsLookupDropdownComponent {
})
}
- public addQuery() {
+ public addAtom() {
this.selectionModel.addQuery()
}
+ public addExpression() {
+ this.selectionModel.addExpression()
+ }
+
public removeQuery(index: number) {
this.selectionModel.removeQuery(index)
}
diff --git a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts
index f51862b7e..133dc636c 100644
--- a/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts
+++ b/src-ui/src/app/components/document-list/filter-editor/filter-editor.component.ts
@@ -95,7 +95,8 @@ import { CustomField } from 'src/app/data/custom-field'
import { SearchService } from 'src/app/services/rest/search.service'
import {
CustomFieldQueriesModel,
- CustomFieldQuery,
+ CustomFieldQueryAtom,
+ CustomFieldQueryExpression,
} from '../../common/custom-fields-lookup-dropdown/custom-fields-lookup-dropdown.component'
const TEXT_FILTER_TARGET_TITLE = 'title'
@@ -523,11 +524,24 @@ export class FilterEditorComponent
)
break
case FILTER_CUSTOM_FIELDS_LOOKUP:
- // TODO: fully implement
- const query = JSON.parse(rule.value)
- this.customFieldQueriesModel.addQuery(
- new CustomFieldQuery(query[0], query[1], query[2])
- )
+ try {
+ const query = JSON.parse(rule.value)
+ if (Array.isArray(query)) {
+ if (query.length === 2) {
+ // expression
+ this.customFieldQueriesModel.addExpression(
+ new CustomFieldQueryExpression(query as any)
+ )
+ } else if (query.length === 3) {
+ // atom
+ this.customFieldQueriesModel.addQuery(
+ new CustomFieldQueryAtom(query as any)
+ )
+ }
+ }
+ } catch (e) {
+ // TODO: handle error?
+ }
break
case FILTER_HAS_CUSTOM_FIELDS_ALL:
console.log('FILTER_HAS_CUSTOM_FIELDS_ALL', rule.value)
@@ -752,8 +766,8 @@ export class FilterEditorComponent
})
}
let queries = this.customFieldQueriesModel.queries
- .filter((query) => query.field && query.operator)
- .map((query) => [query.field, query.operator, query.value])
+ .filter((query) => query.value && query.operator)
+ .map((query) => query.serialize())
console.log(
'this.customFieldQueriesModel.queries',
this.customFieldQueriesModel.queries
@@ -762,10 +776,7 @@ export class FilterEditorComponent
if (queries.length > 0) {
filterRules.push({
rule_type: FILTER_CUSTOM_FIELDS_LOOKUP,
- value:
- queries.length === 1
- ? JSON.stringify(queries[0])
- : JSON.stringify(queries),
+ value: JSON.stringify(queries[0]),
})
}
// TODO: fully implement custom fields