Making progress.

This commit is contained in:
Sam Rose 2024-06-12 17:58:13 +01:00
parent ae6539161f
commit 22bf0d05ad
No known key found for this signature in database
2 changed files with 52 additions and 37 deletions

View File

@ -1706,7 +1706,7 @@ describe.each([
})
describe("contains", () => {
it.only("successfully finds a row", () =>
it("successfully finds a row", () =>
expectQuery({ contains: { users: [user1._id] } }).toContainExactly([
{ users: [{ _id: user1._id }] },
{ users: [{ _id: user1._id }, { _id: user2._id }] },
@ -1763,9 +1763,12 @@ describe.each([
// This will never work for Lucene.
!isLucene &&
// It also can't work for in-memory searching because the related table name
// isn't available.
!isInMemory &&
describe("relations", () => {
let otherTable: Table
let rows: Row[]
let otherRows: Row[]
beforeAll(async () => {
otherTable = await createTable({
@ -1785,7 +1788,7 @@ describe.each([
},
})
rows = await Promise.all([
otherRows = await Promise.all([
config.api.row.save(otherTable._id!, { one: "foo" }),
config.api.row.save(otherTable._id!, { one: "bar" }),
])
@ -1793,18 +1796,22 @@ describe.each([
await Promise.all([
config.api.row.save(table._id!, {
two: "foo",
other: [rows[0]._id],
other: [otherRows[0]._id],
}),
config.api.row.save(table._id!, {
two: "bar",
other: [rows[1]._id],
other: [otherRows[1]._id],
}),
])
rows = await config.api.row.fetch(table._id!)
})
it("can search through relations", () =>
expectQuery({
equal: { [`${otherTable.name}.one`]: "foo" },
}).toContainExactly([{ two: "foo", other: [{ _id: rows[0]._id }] }]))
}).toContainExactly([
{ two: "foo", other: [{ _id: otherRows[0]._id }] },
]))
})
})

View File

@ -14,6 +14,7 @@ import {
import dayjs from "dayjs"
import { OperatorOptions, SqlNumberTypeRangeMap } from "./constants"
import { deepGet, schema } from "./helpers"
import _ from "lodash"
const HBS_REGEX = /{{([^{].*?)}}/g
@ -339,15 +340,36 @@ export const runQuery = (
}
)
// This function exists to check that either the docValue is equal to the
// testValue, or if the docValue is an object or array of objects, that the
// _id of the docValue is equal to the testValue.
const _valueMatches = (docValue: any, testValue: any) => {
if (Array.isArray(docValue)) {
for (const item of docValue) {
if (_valueMatches(item, testValue)) {
return true
}
}
return false
}
if (typeof docValue === "object" && typeof testValue === "string") {
return docValue._id === testValue
}
return docValue === testValue
}
const not =
<T extends any[]>(f: (...args: T) => boolean) =>
(...args: T): boolean =>
!f(...args)
const _equal = (docValue: any, testValue: any) => docValue === testValue
const equalMatch = match(SearchFilterOperator.EQUAL, _equal)
const notEqualMatch = match(SearchFilterOperator.NOT_EQUAL, not(_equal))
const equalMatch = match(SearchFilterOperator.EQUAL, _valueMatches)
const notEqualMatch = match(
SearchFilterOperator.NOT_EQUAL,
not(_valueMatches)
)
const _empty = (docValue: any) => {
if (typeof docValue === "string") {
@ -379,13 +401,12 @@ export const runQuery = (
return false
}
return testValue.includes(docValue)
return testValue.some(item => _valueMatches(docValue, item))
}
)
const containsAny = match(
SearchFilterOperator.CONTAINS_ANY,
(docValue: any, testValue: any) => {
const _contains =
(f: "some" | "every") => (docValue: any, testValue: any) => {
if (!Array.isArray(docValue)) {
return false
}
@ -401,31 +422,18 @@ export const runQuery = (
return false
}
return testValue.some(item => docValue.includes(item))
return testValue[f](item => _valueMatches(docValue, item))
}
const contains = match(SearchFilterOperator.CONTAINS, _contains("every"))
const notContains = match(
SearchFilterOperator.NOT_CONTAINS,
not(_contains("every"))
)
const containsAny = match(
SearchFilterOperator.CONTAINS_ANY,
_contains("some")
)
const _contains = (docValue: any, testValue: any) => {
if (!Array.isArray(docValue)) {
return false
}
if (typeof testValue === "string") {
testValue = testValue.split(",")
if (typeof docValue[0] === "number") {
testValue = testValue.map((item: string) => parseFloat(item))
}
}
if (!Array.isArray(testValue)) {
return false
}
return testValue.every(item => docValue.includes(item))
}
const contains = match(SearchFilterOperator.CONTAINS, _contains)
const notContains = match(SearchFilterOperator.NOT_CONTAINS, not(_contains))
const docMatch = (doc: Record<string, any>) => {
const filterFunctions = {