1
0
Fork 0
mirror of synced 2024-07-08 15:56:23 +12:00

Improving typing around search, there was duplicates of SearchParams and SearchResponse - which were a little different, bring all of this together under the types library.

This commit is contained in:
mike12345567 2024-03-28 17:57:37 +00:00
parent 12c168e6eb
commit 4c755b3af3
20 changed files with 166 additions and 167 deletions

View file

@ -1,28 +1,16 @@
import fetch from "node-fetch" import fetch from "node-fetch"
import { getCouchInfo } from "./couch" import { getCouchInfo } from "./couch"
import { SearchFilters, Row, EmptyFilterOption } from "@budibase/types" import {
SearchFilters,
Row,
EmptyFilterOption,
SearchResponse,
SearchParams,
WithRequired,
} from "@budibase/types"
const QUERY_START_REGEX = /\d[0-9]*:/g const QUERY_START_REGEX = /\d[0-9]*:/g
interface SearchResponse<T> {
rows: T[] | any[]
bookmark?: string
totalRows: number
}
export type SearchParams<T> = {
tableId?: string
sort?: string
sortOrder?: string
sortType?: string
limit?: number
bookmark?: string
version?: string
indexer?: () => Promise<any>
disableEscaping?: boolean
rows?: T | Row[]
}
export function removeKeyNumbering(key: any): string { export function removeKeyNumbering(key: any): string {
if (typeof key === "string" && key.match(QUERY_START_REGEX) != null) { if (typeof key === "string" && key.match(QUERY_START_REGEX) != null) {
const parts = key.split(":") const parts = key.split(":")
@ -44,7 +32,7 @@ export class QueryBuilder<T> {
#query: SearchFilters #query: SearchFilters
#limit: number #limit: number
#sort?: string #sort?: string
#bookmark?: string #bookmark?: string | number
#sortOrder: string #sortOrder: string
#sortType: string #sortType: string
#includeDocs: boolean #includeDocs: boolean
@ -130,7 +118,7 @@ export class QueryBuilder<T> {
return this return this
} }
setBookmark(bookmark?: string) { setBookmark(bookmark?: string | number) {
if (bookmark != null) { if (bookmark != null) {
this.#bookmark = bookmark this.#bookmark = bookmark
} }
@ -226,14 +214,20 @@ export class QueryBuilder<T> {
} }
} }
/** preprocess(
* Preprocesses a value before going into a lucene search. value: any,
* Transforms strings to lowercase and wraps strings and bools in quotes. {
* @param value The value to process escape,
* @param options The preprocess options lowercase,
* @returns {string|*} wrap,
*/ type,
preprocess(value: any, { escape, lowercase, wrap, type }: any = {}) { }: {
escape?: boolean
lowercase?: boolean
wrap?: boolean
type?: string
} = {}
): string | any {
const hasVersion = !!this.#version const hasVersion = !!this.#version
// Determine if type needs wrapped // Determine if type needs wrapped
const originalType = typeof value const originalType = typeof value
@ -561,7 +555,7 @@ async function runQuery<T>(
url: string, url: string,
body: any, body: any,
cookie: string cookie: string
): Promise<SearchResponse<T>> { ): Promise<WithRequired<SearchResponse<T>, "totalRows">> {
const response = await fetch(url, { const response = await fetch(url, {
body: JSON.stringify(body), body: JSON.stringify(body),
method: "POST", method: "POST",
@ -575,7 +569,7 @@ async function runQuery<T>(
} }
const json = await response.json() const json = await response.json()
let output: SearchResponse<T> = { let output: WithRequired<SearchResponse<T>, "totalRows"> = {
rows: [], rows: [],
totalRows: 0, totalRows: 0,
} }
@ -613,63 +607,51 @@ async function recursiveSearch<T>(
dbName: string, dbName: string,
index: string, index: string,
query: any, query: any,
params: any params: SearchParams
): Promise<any> { ): Promise<any> {
const bookmark = params.bookmark const bookmark = params.bookmark
const rows = params.rows || [] const rows = params.rows || []
if (rows.length >= params.limit) { if (params.limit && rows.length >= params.limit) {
return rows return rows
} }
let pageSize = QueryBuilder.maxLimit let pageSize = QueryBuilder.maxLimit
if (rows.length > params.limit - QueryBuilder.maxLimit) { if (params.limit && rows.length > params.limit - QueryBuilder.maxLimit) {
pageSize = params.limit - rows.length pageSize = params.limit - rows.length
} }
const page = await new QueryBuilder<T>(dbName, index, query) const queryBuilder = new QueryBuilder<T>(dbName, index, query)
queryBuilder
.setVersion(params.version) .setVersion(params.version)
.setTable(params.tableId)
.setBookmark(bookmark) .setBookmark(bookmark)
.setLimit(pageSize) .setLimit(pageSize)
.setSort(params.sort) .setSort(params.sort)
.setSortOrder(params.sortOrder) .setSortOrder(params.sortOrder)
.setSortType(params.sortType) .setSortType(params.sortType)
.run()
if (params.tableId) {
queryBuilder.setTable(params.tableId)
}
const page = await queryBuilder.run()
if (!page.rows.length) { if (!page.rows.length) {
return rows return rows
} }
if (page.rows.length < QueryBuilder.maxLimit) { if (page.rows.length < QueryBuilder.maxLimit) {
return [...rows, ...page.rows] return [...rows, ...page.rows]
} }
const newParams = { const newParams: SearchParams = {
...params, ...params,
bookmark: page.bookmark, bookmark: page.bookmark,
rows: [...rows, ...page.rows], rows: [...rows, ...page.rows] as Row[],
} }
return await recursiveSearch(dbName, index, query, newParams) return await recursiveSearch(dbName, index, query, newParams)
} }
/**
* Performs a paginated search. A bookmark will be returned to allow the next
* page to be fetched. There is a max limit off 200 results per page in a
* paginated search.
* @param dbName Which database to run a lucene query on
* @param index Which search index to utilise
* @param query The JSON query structure
* @param params The search params including:
* tableId {string} The table ID to search
* sort {string} The sort column
* sortOrder {string} The sort order ("ascending" or "descending")
* sortType {string} Whether to treat sortable values as strings or
* numbers. ("string" or "number")
* limit {number} The desired page size
* bookmark {string} The bookmark to resume from
* @returns {Promise<{hasNextPage: boolean, rows: *[]}>}
*/
export async function paginatedSearch<T>( export async function paginatedSearch<T>(
dbName: string, dbName: string,
index: string, index: string,
query: SearchFilters, query: SearchFilters,
params: SearchParams<T> params: SearchParams
) { ): Promise<SearchResponse<T>> {
let limit = params.limit let limit = params.limit
if (limit == null || isNaN(limit) || limit < 0) { if (limit == null || isNaN(limit) || limit < 0) {
limit = 50 limit = 50
@ -713,29 +695,12 @@ export async function paginatedSearch<T>(
} }
} }
/**
* Performs a full search, fetching multiple pages if required to return the
* desired amount of results. There is a limit of 1000 results to avoid
* heavy performance hits, and to avoid client components breaking from
* handling too much data.
* @param dbName Which database to run a lucene query on
* @param index Which search index to utilise
* @param query The JSON query structure
* @param params The search params including:
* tableId {string} The table ID to search
* sort {string} The sort column
* sortOrder {string} The sort order ("ascending" or "descending")
* sortType {string} Whether to treat sortable values as strings or
* numbers. ("string" or "number")
* limit {number} The desired number of results
* @returns {Promise<{rows: *}>}
*/
export async function fullSearch<T>( export async function fullSearch<T>(
dbName: string, dbName: string,
index: string, index: string,
query: SearchFilters, query: SearchFilters,
params: SearchParams<T> params: SearchParams
) { ): Promise<{ rows: Row[] }> {
let limit = params.limit let limit = params.limit
if (limit == null || isNaN(limit) || limit < 0) { if (limit == null || isNaN(limit) || limit < 0) {
limit = 1000 limit = 1000

View file

@ -1,9 +1,15 @@
import { newid } from "../../docIds/newid" import { newid } from "../../docIds/newid"
import { getDB } from "../db" import { getDB } from "../db"
import { Database, EmptyFilterOption } from "@budibase/types" import {
import { QueryBuilder, paginatedSearch, fullSearch } from "../lucene" Database,
EmptyFilterOption,
SortOrder,
SortType,
} from "@budibase/types"
import { fullSearch, paginatedSearch, QueryBuilder } from "../lucene"
const INDEX_NAME = "main" const INDEX_NAME = "main"
const TABLE_ID = ""
const index = `function(doc) { const index = `function(doc) {
let props = ["property", "number", "array"] let props = ["property", "number", "array"]
@ -25,8 +31,16 @@ describe("lucene", () => {
dbName = `db-${newid()}` dbName = `db-${newid()}`
// create the DB for testing // create the DB for testing
db = getDB(dbName) db = getDB(dbName)
await db.put({ _id: newid(), property: "word", array: ["1", "4"] }) await db.put({
await db.put({ _id: newid(), property: "word2", array: ["3", "1"] }) _id: newid(),
property: "word",
array: ["1", "4"],
})
await db.put({
_id: newid(),
property: "word2",
array: ["3", "1"],
})
await db.put({ await db.put({
_id: newid(), _id: newid(),
property: "word3", property: "word3",
@ -338,10 +352,11 @@ describe("lucene", () => {
}, },
}, },
{ {
tableId: TABLE_ID,
limit: 1, limit: 1,
sort: "property", sort: "property",
sortType: "string", sortType: SortType.STRING,
sortOrder: "desc", sortOrder: SortOrder.DESCENDING,
} }
) )
expect(page.rows.length).toBe(1) expect(page.rows.length).toBe(1)
@ -360,7 +375,10 @@ describe("lucene", () => {
property: "wo", property: "wo",
}, },
}, },
{} {
tableId: TABLE_ID,
query: {},
}
) )
expect(page.rows.length).toBe(3) expect(page.rows.length).toBe(3)
}) })

View file

@ -32,7 +32,6 @@ export { default as env } from "./environment"
export * as blacklist from "./blacklist" export * as blacklist from "./blacklist"
export * as docUpdates from "./docUpdates" export * as docUpdates from "./docUpdates"
export * from "./utils/Duration" export * from "./utils/Duration"
export { SearchParams } from "./db"
export * as docIds from "./docIds" export * as docIds from "./docIds"
export * as security from "./security" export * as security from "./security"
// Add context to tenancy for backwards compatibility // Add context to tenancy for backwards compatibility

View file

@ -13,7 +13,7 @@ import {
PatchRowRequest, PatchRowRequest,
PatchRowResponse, PatchRowResponse,
Row, Row,
SearchParams, RowSearchParams,
SearchRowRequest, SearchRowRequest,
SearchRowResponse, SearchRowResponse,
UserCtx, UserCtx,
@ -192,7 +192,7 @@ export async function destroy(ctx: UserCtx<DeleteRowRequest>) {
export async function search(ctx: Ctx<SearchRowRequest, SearchRowResponse>) { export async function search(ctx: Ctx<SearchRowRequest, SearchRowResponse>) {
const tableId = utils.getTableId(ctx) const tableId = utils.getTableId(ctx)
const searchParams: SearchParams = { const searchParams: RowSearchParams = {
...ctx.request.body, ...ctx.request.body,
tableId, tableId,
} }

View file

@ -4,8 +4,8 @@ import {
SearchRowResponse, SearchRowResponse,
SearchViewRowRequest, SearchViewRowRequest,
RequiredKeys, RequiredKeys,
SearchParams,
SearchFilters, SearchFilters,
RowSearchParams,
} from "@budibase/types" } from "@budibase/types"
import { dataFilters } from "@budibase/shared-core" import { dataFilters } from "@budibase/shared-core"
import sdk from "../../../sdk" import sdk from "../../../sdk"
@ -57,7 +57,7 @@ export async function searchView(
} }
const searchOptions: RequiredKeys<SearchViewRowRequest> & const searchOptions: RequiredKeys<SearchViewRowRequest> &
RequiredKeys<Pick<SearchParams, "tableId" | "query" | "fields">> = { RequiredKeys<Pick<RowSearchParams, "tableId" | "query" | "fields">> = {
tableId: view.tableId, tableId: view.tableId,
query, query,
fields: viewFields, fields: viewFields,

View file

@ -1,18 +1,18 @@
const nodeFetch = require("node-fetch") const nodeFetch = require("node-fetch")
nodeFetch.mockSearch() nodeFetch.mockSearch()
import { SearchParams } from "@budibase/backend-core" import * as search from "../../../sdk/app/rows/search/utils"
import * as search from "../../../sdk/app/rows/search/internalSearch" import { RowSearchParams, SortOrder, SortType } from "@budibase/types"
import { Row } from "@budibase/types"
// this will be mocked out for _search endpoint // this will be mocked out for _search endpoint
const PARAMS: SearchParams<Row> = { const PARAMS: RowSearchParams = {
query: {},
tableId: "ta_12345679abcdef", tableId: "ta_12345679abcdef",
version: "1", version: "1",
bookmark: undefined, bookmark: undefined,
sort: undefined, sort: undefined,
sortOrder: "ascending", sortOrder: SortOrder.ASCENDING,
sortType: "string", sortType: SortType.STRING,
} }
function checkLucene(resp: any, expected: any, params = PARAMS) { function checkLucene(resp: any, expected: any, params = PARAMS) {

View file

@ -1,7 +1,7 @@
import { import {
Row, Row,
RowSearchParams,
SearchFilters, SearchFilters,
SearchParams,
SearchResponse, SearchResponse,
} from "@budibase/types" } from "@budibase/types"
import { isExternalTableID } from "../../../integrations/utils" import { isExternalTableID } from "../../../integrations/utils"
@ -56,7 +56,9 @@ export function removeEmptyFilters(filters: SearchFilters) {
return filters return filters
} }
export async function search(options: SearchParams): Promise<SearchResponse> { export async function search(
options: RowSearchParams
): Promise<SearchResponse<Row>> {
const isExternalTable = isExternalTableID(options.tableId) const isExternalTable = isExternalTableID(options.tableId)
if (isExternalTable) { if (isExternalTable) {
return external.search(options) return external.search(options)

View file

@ -6,7 +6,7 @@ import {
IncludeRelationship, IncludeRelationship,
Row, Row,
SearchFilters, SearchFilters,
SearchParams, RowSearchParams,
SearchResponse, SearchResponse,
} from "@budibase/types" } from "@budibase/types"
import * as exporters from "../../../../api/controllers/view/exporters" import * as exporters from "../../../../api/controllers/view/exporters"
@ -23,11 +23,14 @@ import pick from "lodash/pick"
import { outputProcessing } from "../../../../utilities/rowProcessor" import { outputProcessing } from "../../../../utilities/rowProcessor"
import sdk from "../../../" import sdk from "../../../"
export async function search(options: SearchParams): Promise<SearchResponse> { export async function search(
options: RowSearchParams
): Promise<SearchResponse<Row>> {
const { tableId } = options const { tableId } = options
const { paginate, query, ...params } = options const { paginate, query, ...params } = options
const { limit } = params const { limit } = params
let bookmark = (params.bookmark && parseInt(params.bookmark)) || undefined let bookmark =
(params.bookmark && parseInt(params.bookmark as string)) || undefined
if (paginate && !bookmark) { if (paginate && !bookmark) {
bookmark = 1 bookmark = 1
} }
@ -92,7 +95,7 @@ export async function search(options: SearchParams): Promise<SearchResponse> {
rows = rows.map((r: any) => pick(r, fields)) rows = rows.map((r: any) => pick(r, fields))
} }
rows = await outputProcessing(table, rows, { rows = await outputProcessing<Row[]>(table, rows, {
preserveLinks: true, preserveLinks: true,
squash: true, squash: true,
}) })

View file

@ -1,19 +1,16 @@
import { import { context, db, HTTPError } from "@budibase/backend-core"
context,
db,
HTTPError,
SearchParams as InternalSearchParams,
} from "@budibase/backend-core"
import env from "../../../../environment" import env from "../../../../environment"
import { fullSearch, paginatedSearch } from "./internalSearch" import { fullSearch, paginatedSearch, searchInputMapping } from "./utils"
import { getRowParams, InternalTables } from "../../../../db/utils" import { getRowParams, InternalTables } from "../../../../db/utils"
import { import {
Database, Database,
Row,
Table,
SearchParams,
SearchResponse,
DocumentType, DocumentType,
Row,
RowSearchParams,
SearchResponse,
SortType,
Table,
User,
} from "@budibase/types" } from "@budibase/types"
import { getGlobalUsersFromMetadata } from "../../../../utilities/global" import { getGlobalUsersFromMetadata } from "../../../../utilities/global"
import { outputProcessing } from "../../../../utilities/rowProcessor" import { outputProcessing } from "../../../../utilities/rowProcessor"
@ -32,16 +29,17 @@ import {
} from "../../../../api/controllers/view/utils" } from "../../../../api/controllers/view/utils"
import sdk from "../../../../sdk" import sdk from "../../../../sdk"
import { ExportRowsParams, ExportRowsResult } from "./types" import { ExportRowsParams, ExportRowsResult } from "./types"
import { searchInputMapping } from "./utils"
import pick from "lodash/pick" import pick from "lodash/pick"
import { breakRowIdField } from "../../../../integrations/utils" import { breakRowIdField } from "../../../../integrations/utils"
export async function search(options: SearchParams): Promise<SearchResponse> { export async function search(
options: RowSearchParams
): Promise<SearchResponse<Row>> {
const { tableId } = options const { tableId } = options
const { paginate, query } = options const { paginate, query } = options
const params: InternalSearchParams<any> = { const params: RowSearchParams = {
tableId: options.tableId, tableId: options.tableId,
sort: options.sort, sort: options.sort,
sortOrder: options.sortOrder, sortOrder: options.sortOrder,
@ -50,6 +48,7 @@ export async function search(options: SearchParams): Promise<SearchResponse> {
bookmark: options.bookmark, bookmark: options.bookmark,
version: options.version, version: options.version,
disableEscaping: options.disableEscaping, disableEscaping: options.disableEscaping,
query: {},
} }
let table = await sdk.tables.getTable(tableId) let table = await sdk.tables.getTable(tableId)
@ -57,7 +56,8 @@ export async function search(options: SearchParams): Promise<SearchResponse> {
if (params.sort && !params.sortType) { if (params.sort && !params.sortType) {
const schema = table.schema const schema = table.schema
const sortField = schema[params.sort] const sortField = schema[params.sort]
params.sortType = sortField.type === "number" ? "number" : "string" params.sortType =
sortField.type === "number" ? SortType.NUMBER : SortType.STRING
} }
let response let response
@ -71,7 +71,7 @@ export async function search(options: SearchParams): Promise<SearchResponse> {
if (response.rows && response.rows.length) { if (response.rows && response.rows.length) {
// enrich with global users if from users table // enrich with global users if from users table
if (tableId === InternalTables.USER_METADATA) { if (tableId === InternalTables.USER_METADATA) {
response.rows = await getGlobalUsersFromMetadata(response.rows) response.rows = await getGlobalUsersFromMetadata(response.rows as User[])
} }
if (options.fields) { if (options.fields) {

View file

@ -1,18 +0,0 @@
import { db as dbCore, context, SearchParams } from "@budibase/backend-core"
import { SearchFilters, Row, SearchIndex } from "@budibase/types"
export async function paginatedSearch(
query: SearchFilters,
params: SearchParams<Row>
) {
const appId = context.getAppId()
return dbCore.paginatedSearch(appId!, SearchIndex.ROWS, query, params)
}
export async function fullSearch(
query: SearchFilters,
params: SearchParams<Row>
) {
const appId = context.getAppId()
return dbCore.fullSearch(appId!, SearchIndex.ROWS, query, params)
}

View file

@ -5,7 +5,7 @@ import {
RelationshipFieldMetadata, RelationshipFieldMetadata,
Row, Row,
SearchFilters, SearchFilters,
SearchParams, RowSearchParams,
SearchResponse, SearchResponse,
SortDirection, SortDirection,
SortOrder, SortOrder,
@ -93,7 +93,9 @@ function buildTableMap(tables: Table[]) {
return tableMap return tableMap
} }
export async function search(options: SearchParams): Promise<SearchResponse> { export async function search(
options: RowSearchParams
): Promise<SearchResponse<Row>> {
const { tableId, paginate, query, ...params } = options const { tableId, paginate, query, ...params } = options
const builder = new SqlQueryBuilder(SqlClient.SQL_LITE) const builder = new SqlQueryBuilder(SqlClient.SQL_LITE)

View file

@ -6,7 +6,7 @@ import {
Row, Row,
SourceName, SourceName,
Table, Table,
SearchParams, RowSearchParams,
TableSourceType, TableSourceType,
} from "@budibase/types" } from "@budibase/types"
@ -110,7 +110,7 @@ describe("external search", () => {
await config.doInContext(config.appId, async () => { await config.doInContext(config.appId, async () => {
const tableId = config.table!._id! const tableId = config.table!._id!
const searchParams: SearchParams = { const searchParams: RowSearchParams = {
tableId, tableId,
query: {}, query: {},
} }
@ -127,7 +127,7 @@ describe("external search", () => {
await config.doInContext(config.appId, async () => { await config.doInContext(config.appId, async () => {
const tableId = config.table!._id! const tableId = config.table!._id!
const searchParams: SearchParams = { const searchParams: RowSearchParams = {
tableId, tableId,
query: {}, query: {},
fields: ["name", "age"], fields: ["name", "age"],
@ -151,7 +151,7 @@ describe("external search", () => {
await config.doInContext(config.appId, async () => { await config.doInContext(config.appId, async () => {
const tableId = config.table!._id! const tableId = config.table!._id!
const searchParams: SearchParams = { const searchParams: RowSearchParams = {
tableId, tableId,
query: { query: {
oneOf: { oneOf: {

View file

@ -2,7 +2,7 @@ import {
FieldType, FieldType,
Row, Row,
Table, Table,
SearchParams, RowSearchParams,
INTERNAL_TABLE_SOURCE_ID, INTERNAL_TABLE_SOURCE_ID,
TableSourceType, TableSourceType,
} from "@budibase/types" } from "@budibase/types"
@ -77,7 +77,7 @@ describe("internal", () => {
await config.doInContext(config.appId, async () => { await config.doInContext(config.appId, async () => {
const tableId = config.table!._id! const tableId = config.table!._id!
const searchParams: SearchParams = { const searchParams: RowSearchParams = {
tableId, tableId,
query: {}, query: {},
} }
@ -94,7 +94,7 @@ describe("internal", () => {
await config.doInContext(config.appId, async () => { await config.doInContext(config.appId, async () => {
const tableId = config.table!._id! const tableId = config.table!._id!
const searchParams: SearchParams = { const searchParams: RowSearchParams = {
tableId, tableId,
query: {}, query: {},
fields: ["name", "age"], fields: ["name", "age"],

View file

@ -4,7 +4,7 @@ import {
FieldType, FieldType,
FieldTypeSubtypes, FieldTypeSubtypes,
INTERNAL_TABLE_SOURCE_ID, INTERNAL_TABLE_SOURCE_ID,
SearchParams, RowSearchParams,
Table, Table,
TableSourceType, TableSourceType,
} from "@budibase/types" } from "@budibase/types"
@ -47,7 +47,7 @@ describe.each([tableWithUserCol, tableWithUsersCol])(
const userMedataId = dbCore.generateUserMetadataID(globalUserId) const userMedataId = dbCore.generateUserMetadataID(globalUserId)
it("should be able to map ro_ to global user IDs", () => { it("should be able to map ro_ to global user IDs", () => {
const params: SearchParams = { const params: RowSearchParams = {
tableId, tableId,
query: { query: {
equal: { equal: {
@ -60,7 +60,7 @@ describe.each([tableWithUserCol, tableWithUsersCol])(
}) })
it("should handle array of user IDs", () => { it("should handle array of user IDs", () => {
const params: SearchParams = { const params: RowSearchParams = {
tableId, tableId,
query: { query: {
oneOf: { oneOf: {
@ -77,7 +77,7 @@ describe.each([tableWithUserCol, tableWithUsersCol])(
it("shouldn't change any other input", () => { it("shouldn't change any other input", () => {
const email = "test@example.com" const email = "test@example.com"
const params: SearchParams = { const params: RowSearchParams = {
tableId, tableId,
query: { query: {
equal: { equal: {

View file

@ -1,17 +1,37 @@
import { import {
FieldType, FieldType,
SearchParams,
Table, Table,
DocumentType, DocumentType,
SEPARATOR, SEPARATOR,
FieldSubtype, FieldSubtype,
SearchFilters,
SearchIndex,
SearchResponse,
Row,
RowSearchParams,
} from "@budibase/types" } from "@budibase/types"
import { db as dbCore } from "@budibase/backend-core" import { db as dbCore, context } from "@budibase/backend-core"
import { utils } from "@budibase/shared-core" import { utils } from "@budibase/shared-core"
export async function paginatedSearch(
query: SearchFilters,
params: RowSearchParams
): Promise<SearchResponse<Row>> {
const appId = context.getAppId()
return dbCore.paginatedSearch(appId!, SearchIndex.ROWS, query, params)
}
export async function fullSearch(
query: SearchFilters,
params: RowSearchParams
): Promise<{ rows: Row[] }> {
const appId = context.getAppId()
return dbCore.fullSearch(appId!, SearchIndex.ROWS, query, params)
}
function findColumnInQueries( function findColumnInQueries(
column: string, column: string,
options: SearchParams, options: RowSearchParams,
callback: (filter: any) => any callback: (filter: any) => any
) { ) {
if (!options.query) { if (!options.query) {
@ -29,7 +49,7 @@ function findColumnInQueries(
} }
} }
function userColumnMapping(column: string, options: SearchParams) { function userColumnMapping(column: string, options: RowSearchParams) {
findColumnInQueries(column, options, (filterValue: any): any => { findColumnInQueries(column, options, (filterValue: any): any => {
const isArray = Array.isArray(filterValue), const isArray = Array.isArray(filterValue),
isString = typeof filterValue === "string" isString = typeof filterValue === "string"
@ -60,7 +80,7 @@ function userColumnMapping(column: string, options: SearchParams) {
// maps through the search parameters to check if any of the inputs are invalid // maps through the search parameters to check if any of the inputs are invalid
// based on the table schema, converts them to something that is valid. // based on the table schema, converts them to something that is valid.
export function searchInputMapping(table: Table, options: SearchParams) { export function searchInputMapping(table: Table, options: RowSearchParams) {
if (!table?.schema) { if (!table?.schema) {
return options return options
} }

View file

@ -58,7 +58,7 @@ import {
RelationshipType, RelationshipType,
Row, Row,
Screen, Screen,
SearchParams, RowSearchParams,
SourceName, SourceName,
Table, Table,
TableSourceType, TableSourceType,
@ -733,7 +733,7 @@ export default class TestConfiguration {
return this.api.row.fetch(tableId) return this.api.row.fetch(tableId)
} }
async searchRows(tableId: string, searchParams?: SearchParams) { async searchRows(tableId: string, searchParams?: RowSearchParams) {
if (!tableId && this.table) { if (!tableId && this.table) {
tableId = this.table._id! tableId = this.table._id!
} }

View file

@ -7,7 +7,7 @@ import {
BulkImportRequest, BulkImportRequest,
BulkImportResponse, BulkImportResponse,
SearchRowResponse, SearchRowResponse,
SearchParams, RowSearchParams,
DeleteRows, DeleteRows,
DeleteRow, DeleteRow,
} from "@budibase/types" } from "@budibase/types"
@ -135,7 +135,7 @@ export class RowAPI extends TestAPI {
search = async ( search = async (
sourceId: string, sourceId: string,
params?: SearchParams, params?: RowSearchParams,
expectations?: Expectations expectations?: Expectations
): Promise<SearchRowResponse> => { ): Promise<SearchRowResponse> => {
return await this._post<SearchRowResponse>(`/api/${sourceId}/search`, { return await this._post<SearchRowResponse>(`/api/${sourceId}/search`, {

View file

@ -1,4 +1,4 @@
import { SearchFilters, SearchParams } from "../../../sdk" import { SearchFilters, RowSearchParams } from "../../../sdk"
import { Row } from "../../../documents" import { Row } from "../../../documents"
import { PaginationResponse, SortOrder } from "../../../api" import { PaginationResponse, SortOrder } from "../../../api"
import { ReadStream } from "fs" import { ReadStream } from "fs"
@ -13,7 +13,7 @@ export interface PatchRowRequest extends Row {
export interface PatchRowResponse extends Row {} export interface PatchRowResponse extends Row {}
export interface SearchRowRequest extends Omit<SearchParams, "tableId"> {} export interface SearchRowRequest extends Omit<RowSearchParams, "tableId"> {}
export interface SearchViewRowRequest export interface SearchViewRowRequest
extends Pick< extends Pick<

View file

@ -22,6 +22,6 @@ export interface PaginationRequest extends BasicPaginationRequest {
} }
export interface PaginationResponse { export interface PaginationResponse {
bookmark: string | undefined bookmark: string | number | undefined
hasNextPage: boolean hasNextPage?: boolean
} }

View file

@ -1,12 +1,13 @@
import { SortOrder, SortType } from "../api" import { SortOrder, SortType } from "../api"
import { SearchFilters } from "./search" import { SearchFilters } from "./search"
import { Row } from "../documents" import { Row } from "../documents"
import { WithRequired } from "../shared"
export interface SearchParams { export interface SearchParams {
tableId: string tableId?: string
query?: SearchFilters
paginate?: boolean paginate?: boolean
query: SearchFilters bookmark?: string | number
bookmark?: string
limit?: number limit?: number
sort?: string sort?: string
sortOrder?: SortOrder sortOrder?: SortOrder
@ -14,10 +15,17 @@ export interface SearchParams {
version?: string version?: string
disableEscaping?: boolean disableEscaping?: boolean
fields?: string[] fields?: string[]
indexer?: () => Promise<any>
rows?: Row[]
} }
export interface SearchResponse { // when searching for rows we want a more extensive search type that requires certain properties
rows: Row[] export interface RowSearchParams
extends WithRequired<SearchParams, "tableId" | "query"> {}
export interface SearchResponse<T> {
rows: T[]
hasNextPage?: boolean hasNextPage?: boolean
bookmark?: string | number bookmark?: string | number
totalRows?: number
} }