Making progress.
This commit is contained in:
parent
ae6539161f
commit
22bf0d05ad
|
@ -1706,7 +1706,7 @@ describe.each([
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("contains", () => {
|
describe("contains", () => {
|
||||||
it.only("successfully finds a row", () =>
|
it("successfully finds a row", () =>
|
||||||
expectQuery({ contains: { users: [user1._id] } }).toContainExactly([
|
expectQuery({ contains: { users: [user1._id] } }).toContainExactly([
|
||||||
{ users: [{ _id: user1._id }] },
|
{ users: [{ _id: user1._id }] },
|
||||||
{ users: [{ _id: user1._id }, { _id: user2._id }] },
|
{ users: [{ _id: user1._id }, { _id: user2._id }] },
|
||||||
|
@ -1763,9 +1763,12 @@ describe.each([
|
||||||
|
|
||||||
// This will never work for Lucene.
|
// This will never work for Lucene.
|
||||||
!isLucene &&
|
!isLucene &&
|
||||||
|
// It also can't work for in-memory searching because the related table name
|
||||||
|
// isn't available.
|
||||||
|
!isInMemory &&
|
||||||
describe("relations", () => {
|
describe("relations", () => {
|
||||||
let otherTable: Table
|
let otherTable: Table
|
||||||
let rows: Row[]
|
let otherRows: Row[]
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
otherTable = await createTable({
|
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: "foo" }),
|
||||||
config.api.row.save(otherTable._id!, { one: "bar" }),
|
config.api.row.save(otherTable._id!, { one: "bar" }),
|
||||||
])
|
])
|
||||||
|
@ -1793,18 +1796,22 @@ describe.each([
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
config.api.row.save(table._id!, {
|
config.api.row.save(table._id!, {
|
||||||
two: "foo",
|
two: "foo",
|
||||||
other: [rows[0]._id],
|
other: [otherRows[0]._id],
|
||||||
}),
|
}),
|
||||||
config.api.row.save(table._id!, {
|
config.api.row.save(table._id!, {
|
||||||
two: "bar",
|
two: "bar",
|
||||||
other: [rows[1]._id],
|
other: [otherRows[1]._id],
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
|
||||||
|
rows = await config.api.row.fetch(table._id!)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("can search through relations", () =>
|
it("can search through relations", () =>
|
||||||
expectQuery({
|
expectQuery({
|
||||||
equal: { [`${otherTable.name}.one`]: "foo" },
|
equal: { [`${otherTable.name}.one`]: "foo" },
|
||||||
}).toContainExactly([{ two: "foo", other: [{ _id: rows[0]._id }] }]))
|
}).toContainExactly([
|
||||||
|
{ two: "foo", other: [{ _id: otherRows[0]._id }] },
|
||||||
|
]))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {
|
||||||
import dayjs from "dayjs"
|
import dayjs from "dayjs"
|
||||||
import { OperatorOptions, SqlNumberTypeRangeMap } from "./constants"
|
import { OperatorOptions, SqlNumberTypeRangeMap } from "./constants"
|
||||||
import { deepGet, schema } from "./helpers"
|
import { deepGet, schema } from "./helpers"
|
||||||
|
import _ from "lodash"
|
||||||
|
|
||||||
const HBS_REGEX = /{{([^{].*?)}}/g
|
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 =
|
const not =
|
||||||
<T extends any[]>(f: (...args: T) => boolean) =>
|
<T extends any[]>(f: (...args: T) => boolean) =>
|
||||||
(...args: T): boolean =>
|
(...args: T): boolean =>
|
||||||
!f(...args)
|
!f(...args)
|
||||||
|
|
||||||
const _equal = (docValue: any, testValue: any) => docValue === testValue
|
const equalMatch = match(SearchFilterOperator.EQUAL, _valueMatches)
|
||||||
|
const notEqualMatch = match(
|
||||||
const equalMatch = match(SearchFilterOperator.EQUAL, _equal)
|
SearchFilterOperator.NOT_EQUAL,
|
||||||
const notEqualMatch = match(SearchFilterOperator.NOT_EQUAL, not(_equal))
|
not(_valueMatches)
|
||||||
|
)
|
||||||
|
|
||||||
const _empty = (docValue: any) => {
|
const _empty = (docValue: any) => {
|
||||||
if (typeof docValue === "string") {
|
if (typeof docValue === "string") {
|
||||||
|
@ -379,54 +401,40 @@ export const runQuery = (
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return testValue.includes(docValue)
|
return testValue.some(item => _valueMatches(docValue, item))
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const _contains =
|
||||||
|
(f: "some" | "every") => (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[f](item => _valueMatches(docValue, item))
|
||||||
|
}
|
||||||
|
|
||||||
|
const contains = match(SearchFilterOperator.CONTAINS, _contains("every"))
|
||||||
|
const notContains = match(
|
||||||
|
SearchFilterOperator.NOT_CONTAINS,
|
||||||
|
not(_contains("every"))
|
||||||
|
)
|
||||||
const containsAny = match(
|
const containsAny = match(
|
||||||
SearchFilterOperator.CONTAINS_ANY,
|
SearchFilterOperator.CONTAINS_ANY,
|
||||||
(docValue: any, testValue: any) => {
|
_contains("some")
|
||||||
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.some(item => docValue.includes(item))
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
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 docMatch = (doc: Record<string, any>) => {
|
||||||
const filterFunctions = {
|
const filterFunctions = {
|
||||||
string: stringMatch,
|
string: stringMatch,
|
||||||
|
|
Loading…
Reference in New Issue