Merge pull request #14257 from Budibase/fix/search-by-row-id
Fix for searching by row ID (with a limit) when the row has many related rows
This commit is contained in:
commit
ba3f69ead9
|
@ -5,12 +5,12 @@ import {
|
|||
knexClient,
|
||||
} from "../../../integrations/tests/utils"
|
||||
import {
|
||||
db as dbCore,
|
||||
context,
|
||||
db as dbCore,
|
||||
MAX_VALID_DATE,
|
||||
MIN_VALID_DATE,
|
||||
utils,
|
||||
SQLITE_DESIGN_DOC_ID,
|
||||
utils,
|
||||
} from "@budibase/backend-core"
|
||||
|
||||
import * as setup from "./utilities"
|
||||
|
@ -2560,4 +2560,48 @@ describe.each([
|
|||
}).toContainExactly([{ name: "foo" }])
|
||||
})
|
||||
})
|
||||
|
||||
!isInMemory &&
|
||||
describe("search by _id", () => {
|
||||
let row: Row
|
||||
|
||||
beforeAll(async () => {
|
||||
const toRelateTable = await createTable({
|
||||
name: {
|
||||
name: "name",
|
||||
type: FieldType.STRING,
|
||||
},
|
||||
})
|
||||
table = await createTable({
|
||||
name: {
|
||||
name: "name",
|
||||
type: FieldType.STRING,
|
||||
},
|
||||
rel: {
|
||||
name: "rel",
|
||||
type: FieldType.LINK,
|
||||
relationshipType: RelationshipType.MANY_TO_MANY,
|
||||
tableId: toRelateTable._id!,
|
||||
fieldName: "rel",
|
||||
},
|
||||
})
|
||||
const [row1, row2] = await Promise.all([
|
||||
config.api.row.save(toRelateTable._id!, { name: "tag 1" }),
|
||||
config.api.row.save(toRelateTable._id!, { name: "tag 2" }),
|
||||
])
|
||||
row = await config.api.row.save(table._id!, {
|
||||
name: "product 1",
|
||||
rel: [row1._id, row2._id],
|
||||
})
|
||||
})
|
||||
|
||||
it("can filter by the row ID with limit 1", async () => {
|
||||
await expectSearch({
|
||||
query: {
|
||||
equal: { _id: row._id },
|
||||
},
|
||||
limit: 1,
|
||||
}).toContainExactly([row])
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -22,21 +22,21 @@ import { HTTPError } from "@budibase/backend-core"
|
|||
import pick from "lodash/pick"
|
||||
import { outputProcessing } from "../../../../utilities/rowProcessor"
|
||||
import sdk from "../../../"
|
||||
import { isSearchingByRowID } from "./utils"
|
||||
|
||||
export async function search(
|
||||
options: RowSearchParams,
|
||||
table: Table
|
||||
): Promise<SearchResponse<Row>> {
|
||||
const { tableId } = options
|
||||
const { countRows, paginate, query, ...params } = options
|
||||
const { limit } = params
|
||||
let bookmark =
|
||||
(params.bookmark && parseInt(params.bookmark as string)) || undefined
|
||||
if (paginate && !bookmark) {
|
||||
bookmark = 0
|
||||
}
|
||||
function getPaginationAndLimitParameters(
|
||||
filters: SearchFilters,
|
||||
paginate: boolean | undefined,
|
||||
bookmark: number | undefined,
|
||||
limit: number | undefined
|
||||
): PaginationJson | undefined {
|
||||
let paginateObj: PaginationJson | undefined
|
||||
|
||||
// only try set limits/pagination if we aren't doing a row ID search
|
||||
if (isSearchingByRowID(filters)) {
|
||||
return
|
||||
}
|
||||
|
||||
if (paginate && !limit) {
|
||||
throw new Error("Cannot paginate query without a limit")
|
||||
}
|
||||
|
@ -49,11 +49,35 @@ export async function search(
|
|||
if (bookmark) {
|
||||
paginateObj.offset = limit * bookmark
|
||||
}
|
||||
} else if (params && limit) {
|
||||
} else if (limit) {
|
||||
paginateObj = {
|
||||
limit: limit,
|
||||
}
|
||||
}
|
||||
|
||||
return paginateObj
|
||||
}
|
||||
|
||||
export async function search(
|
||||
options: RowSearchParams,
|
||||
table: Table
|
||||
): Promise<SearchResponse<Row>> {
|
||||
const { tableId } = options
|
||||
const { countRows, paginate, query, ...params } = options
|
||||
const { limit } = params
|
||||
let bookmark =
|
||||
(params.bookmark && parseInt(params.bookmark as string)) || undefined
|
||||
if (paginate && !bookmark) {
|
||||
bookmark = 0
|
||||
}
|
||||
|
||||
let paginateObj = getPaginationAndLimitParameters(
|
||||
query,
|
||||
paginate,
|
||||
bookmark,
|
||||
limit
|
||||
)
|
||||
|
||||
let sort: SortJson | undefined
|
||||
if (params.sort) {
|
||||
const direction =
|
||||
|
|
|
@ -42,6 +42,7 @@ import {
|
|||
getTableIDList,
|
||||
} from "./filters"
|
||||
import { dataFilters, PROTECTED_INTERNAL_COLUMNS } from "@budibase/shared-core"
|
||||
import { isSearchingByRowID } from "./utils"
|
||||
|
||||
const builder = new sql.Sql(SqlClient.SQL_LITE)
|
||||
const MISSING_COLUMN_REGEX = new RegExp(`no such column: .+`)
|
||||
|
@ -264,6 +265,10 @@ export async function search(
|
|||
|
||||
const relationships = buildInternalRelationships(table)
|
||||
|
||||
const searchFilters: SearchFilters = {
|
||||
...cleanupFilters(query, table, allTables),
|
||||
documentType: DocumentType.ROW,
|
||||
}
|
||||
const request: QueryJson = {
|
||||
endpoint: {
|
||||
// not important, we query ourselves
|
||||
|
@ -271,10 +276,7 @@ export async function search(
|
|||
entityId: table._id!,
|
||||
operation: Operation.READ,
|
||||
},
|
||||
filters: {
|
||||
...cleanupFilters(query, table, allTables),
|
||||
documentType: DocumentType.ROW,
|
||||
},
|
||||
filters: searchFilters,
|
||||
table,
|
||||
meta: {
|
||||
table,
|
||||
|
@ -304,7 +306,8 @@ export async function search(
|
|||
}
|
||||
|
||||
const bookmark: number = (params.bookmark as number) || 0
|
||||
if (params.limit) {
|
||||
// limits don't apply if we doing a row ID search
|
||||
if (!isSearchingByRowID(searchFilters) && params.limit) {
|
||||
paginate = true
|
||||
request.paginate = {
|
||||
limit: params.limit + 1,
|
||||
|
|
|
@ -108,3 +108,18 @@ export function searchInputMapping(table: Table, options: RowSearchParams) {
|
|||
}
|
||||
return options
|
||||
}
|
||||
|
||||
export function isSearchingByRowID(query: SearchFilters): boolean {
|
||||
for (let searchField of Object.values(query)) {
|
||||
if (typeof searchField !== "object") {
|
||||
continue
|
||||
}
|
||||
const hasId = Object.keys(searchField).find(
|
||||
key => dbCore.removeKeyNumbering(key) === "_id" && searchField[key]
|
||||
)
|
||||
if (hasId) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue