Fix for not contains with all or - variety of changes needed to achieve the actual expected functionality.

This commit is contained in:
mike12345567 2023-03-09 19:00:22 +00:00
parent 1c44a9f0b8
commit 212b93cbe9
1 changed files with 51 additions and 10 deletions

View File

@ -236,6 +236,36 @@ export class QueryBuilder<T> {
return value return value
} }
isMultiCondition() {
let count = 0
for (let filters of Object.values(this.query)) {
// not contains is one massive filter in allOr mode
if (typeof filters === "object") {
count += Object.keys(filters).length
}
}
return count > 1
}
compressFilters(filters: Record<string, string[]>) {
const compressed: typeof filters = {}
for (let key of Object.keys(filters)) {
const finalKey = removeKeyNumbering(key)
if (compressed[finalKey]) {
compressed[finalKey] = compressed[finalKey].concat(filters[key])
} else {
compressed[finalKey] = filters[key]
}
}
// add prefixes back
const final: typeof filters = {}
let count = 1
for (let [key, value] of Object.entries(compressed)) {
final[`${count++}:${key}`] = value
}
return final
}
buildSearchQuery() { buildSearchQuery() {
const builder = this const builder = this
let allOr = this.query && this.query.allOr let allOr = this.query && this.query.allOr
@ -272,9 +302,9 @@ export class QueryBuilder<T> {
} }
const notContains = (key: string, value: any) => { const notContains = (key: string, value: any) => {
// @ts-ignore const allPrefix = allOr ? "*:* AND " : ""
const allPrefix = allOr === "" ? "*:* AND" : "" const mode = allOr ? "AND" : undefined
return allPrefix + "NOT " + contains(key, value) return allPrefix + "NOT " + contains(key, value, mode)
} }
const containsAny = (key: string, value: any) => { const containsAny = (key: string, value: any) => {
@ -299,21 +329,32 @@ export class QueryBuilder<T> {
return `${key}:(${orStatement})` return `${key}:(${orStatement})`
} }
function build(structure: any, queryFn: any) { function build(
structure: any,
queryFn: (key: string, value: any) => string | null,
opts?: { returnBuilt?: boolean; mode?: string }
) {
let built = ""
for (let [key, value] of Object.entries(structure)) { for (let [key, value] of Object.entries(structure)) {
// check for new format - remove numbering if needed // check for new format - remove numbering if needed
key = removeKeyNumbering(key) key = removeKeyNumbering(key)
key = builder.preprocess(builder.handleSpaces(key), { key = builder.preprocess(builder.handleSpaces(key), {
escape: true, escape: true,
}) })
const expression = queryFn(key, value) let expression = queryFn(key, value)
if (expression == null) { if (expression == null) {
continue continue
} }
if (query.length > 0) { if (built.length > 0 || query.length > 0) {
query += ` ${allOr ? "OR" : "AND"} ` const mode = opts?.mode ? opts.mode : allOr ? "OR" : "AND"
built += ` ${mode} `
} }
query += expression built += expression
}
if (opts?.returnBuilt) {
return built
} else {
query += built
} }
} }
@ -384,14 +425,14 @@ export class QueryBuilder<T> {
build(this.query.contains, contains) build(this.query.contains, contains)
} }
if (this.query.notContains) { if (this.query.notContains) {
build(this.query.notContains, notContains) build(this.compressFilters(this.query.notContains), notContains)
} }
if (this.query.containsAny) { if (this.query.containsAny) {
build(this.query.containsAny, containsAny) build(this.query.containsAny, containsAny)
} }
// make sure table ID is always added as an AND // make sure table ID is always added as an AND
if (tableId) { if (tableId) {
query = `(${query})` query = this.isMultiCondition() ? `(${query})` : query
allOr = false allOr = false
build({ tableId }, equal) build({ tableId }, equal)
} }