Fix bug in oneOf search.
This commit is contained in:
parent
d1f0454831
commit
4c6f7f25c2
|
@ -780,6 +780,32 @@ describe.each([
|
||||||
it("fails to find nonexistent row", async () => {
|
it("fails to find nonexistent row", async () => {
|
||||||
await expectQuery({ oneOf: { name: ["none"] } }).toFindNothing()
|
await expectQuery({ oneOf: { name: ["none"] } }).toFindNothing()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("can have multiple values for same column", async () => {
|
||||||
|
await expectQuery({
|
||||||
|
oneOf: {
|
||||||
|
name: ["foo", "bar"],
|
||||||
|
},
|
||||||
|
}).toContainExactly([{ name: "foo" }, { name: "bar" }])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("splits comma separated strings", async () => {
|
||||||
|
await expectQuery({
|
||||||
|
oneOf: {
|
||||||
|
// @ts-ignore
|
||||||
|
name: "foo,bar",
|
||||||
|
},
|
||||||
|
}).toContainExactly([{ name: "foo" }, { name: "bar" }])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("trims whitespace", async () => {
|
||||||
|
await expectQuery({
|
||||||
|
oneOf: {
|
||||||
|
// @ts-ignore
|
||||||
|
name: "foo, bar",
|
||||||
|
},
|
||||||
|
}).toContainExactly([{ name: "foo" }, { name: "bar" }])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("fuzzy", () => {
|
describe("fuzzy", () => {
|
||||||
|
@ -1002,6 +1028,32 @@ describe.each([
|
||||||
it("fails to find nonexistent row", async () => {
|
it("fails to find nonexistent row", async () => {
|
||||||
await expectQuery({ oneOf: { age: [2] } }).toFindNothing()
|
await expectQuery({ oneOf: { age: [2] } }).toFindNothing()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// I couldn't find a way to make this work in Lucene and given that
|
||||||
|
// we're getting rid of Lucene soon I wasn't inclined to spend time on
|
||||||
|
// it.
|
||||||
|
!isLucene &&
|
||||||
|
it("can convert from a string", async () => {
|
||||||
|
await expectQuery({
|
||||||
|
oneOf: {
|
||||||
|
// @ts-ignore
|
||||||
|
age: "1",
|
||||||
|
},
|
||||||
|
}).toContainExactly([{ age: 1 }])
|
||||||
|
})
|
||||||
|
|
||||||
|
// I couldn't find a way to make this work in Lucene and given that
|
||||||
|
// we're getting rid of Lucene soon I wasn't inclined to spend time on
|
||||||
|
// it.
|
||||||
|
!isLucene &&
|
||||||
|
it("can find multiple values for same column", async () => {
|
||||||
|
await expectQuery({
|
||||||
|
oneOf: {
|
||||||
|
// @ts-ignore
|
||||||
|
age: "1,10",
|
||||||
|
},
|
||||||
|
}).toContainExactly([{ age: 1 }, { age: 10 }])
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("range", () => {
|
describe("range", () => {
|
||||||
|
|
|
@ -66,37 +66,12 @@ export function removeEmptyFilters(filters: SearchFilters) {
|
||||||
return filters
|
return filters
|
||||||
}
|
}
|
||||||
|
|
||||||
// The frontend can send single values for array fields sometimes, so to handle
|
|
||||||
// this we convert them to arrays at the controller level so that nothing below
|
|
||||||
// this has to worry about the non-array values.
|
|
||||||
function fixupFilterArrays(filters: SearchFilters) {
|
|
||||||
const arrayFields = [
|
|
||||||
SearchFilterOperator.ONE_OF,
|
|
||||||
SearchFilterOperator.CONTAINS,
|
|
||||||
SearchFilterOperator.NOT_CONTAINS,
|
|
||||||
SearchFilterOperator.CONTAINS_ANY,
|
|
||||||
]
|
|
||||||
for (const searchField of arrayFields) {
|
|
||||||
const field = filters[searchField]
|
|
||||||
if (field == null) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const key of Object.keys(field)) {
|
|
||||||
if (!Array.isArray(field[key])) {
|
|
||||||
field[key] = [field[key]]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return filters
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function search(
|
export async function search(
|
||||||
options: RowSearchParams
|
options: RowSearchParams
|
||||||
): Promise<SearchResponse<Row>> {
|
): Promise<SearchResponse<Row>> {
|
||||||
const isExternalTable = isExternalTableID(options.tableId)
|
const isExternalTable = isExternalTableID(options.tableId)
|
||||||
options.query = removeEmptyFilters(options.query || {})
|
options.query = removeEmptyFilters(options.query || {})
|
||||||
options.query = fixupFilterArrays(options.query)
|
options.query = dataFilters.fixupFilterArrays(options.query)
|
||||||
if (
|
if (
|
||||||
!dataFilters.hasFilters(options.query) &&
|
!dataFilters.hasFilters(options.query) &&
|
||||||
options.query.onEmptyFilter === EmptyFilterOption.RETURN_NONE
|
options.query.onEmptyFilter === EmptyFilterOption.RETURN_NONE
|
||||||
|
|
|
@ -327,6 +327,35 @@ export const buildQuery = (filter: SearchFilter[]) => {
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The frontend can send single values for array fields sometimes, so to handle
|
||||||
|
// this we convert them to arrays at the controller level so that nothing below
|
||||||
|
// this has to worry about the non-array values.
|
||||||
|
export function fixupFilterArrays(filters: SearchFilters) {
|
||||||
|
const arrayFields = [
|
||||||
|
SearchFilterOperator.ONE_OF,
|
||||||
|
SearchFilterOperator.CONTAINS,
|
||||||
|
SearchFilterOperator.NOT_CONTAINS,
|
||||||
|
SearchFilterOperator.CONTAINS_ANY,
|
||||||
|
]
|
||||||
|
for (const searchField of arrayFields) {
|
||||||
|
const field = filters[searchField]
|
||||||
|
if (field == null) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key of Object.keys(field)) {
|
||||||
|
if (!Array.isArray(field[key])) {
|
||||||
|
if (typeof field[key] !== "string") {
|
||||||
|
field[key] = [field[key]]
|
||||||
|
} else {
|
||||||
|
field[key] = field[key].split(",").map(x => x.trim())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return filters
|
||||||
|
}
|
||||||
|
|
||||||
export const search = (
|
export const search = (
|
||||||
docs: Record<string, any>[],
|
docs: Record<string, any>[],
|
||||||
query: RowSearchParams
|
query: RowSearchParams
|
||||||
|
@ -360,6 +389,7 @@ export const runQuery = (docs: Record<string, any>[], query: SearchFilters) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
query = cleanupQuery(query)
|
query = cleanupQuery(query)
|
||||||
|
query = fixupFilterArrays(query)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!hasFilters(query) &&
|
!hasFilters(query) &&
|
||||||
|
@ -528,9 +558,10 @@ export const runQuery = (docs: Record<string, any>[], query: SearchFilters) => {
|
||||||
(docValue: any, testValue: any) => {
|
(docValue: any, testValue: any) => {
|
||||||
if (typeof testValue === "string") {
|
if (typeof testValue === "string") {
|
||||||
testValue = testValue.split(",")
|
testValue = testValue.split(",")
|
||||||
if (typeof docValue === "number") {
|
}
|
||||||
testValue = testValue.map((item: string) => parseFloat(item))
|
|
||||||
}
|
if (typeof docValue === "number") {
|
||||||
|
testValue = testValue.map((item: string) => parseFloat(item))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Array.isArray(testValue)) {
|
if (!Array.isArray(testValue)) {
|
||||||
|
|
Loading…
Reference in New Issue