1
0
Fork 0
mirror of synced 2024-06-30 20:10:54 +12:00

Merge branch 'master' into chore/remove-disabling-nounusedvars

This commit is contained in:
Adria Navarro 2024-04-17 15:49:35 +02:00 committed by GitHub
commit f12e654811
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 101 additions and 140 deletions

View file

@ -17,8 +17,8 @@ import {
ContextUser, ContextUser,
CouchFindOptions, CouchFindOptions,
DatabaseQueryOpts, DatabaseQueryOpts,
SearchQuery, SearchFilters,
SearchQueryOperators, SearchFilterOperator,
SearchUsersRequest, SearchUsersRequest,
User, User,
} from "@budibase/types" } from "@budibase/types"
@ -44,11 +44,11 @@ function removeUserPassword(users: User | User[]) {
return users return users
} }
export function isSupportedUserSearch(query: SearchQuery) { export function isSupportedUserSearch(query: SearchFilters) {
const allowed = [ const allowed = [
{ op: SearchQueryOperators.STRING, key: "email" }, { op: SearchFilterOperator.STRING, key: "email" },
{ op: SearchQueryOperators.EQUAL, key: "_id" }, { op: SearchFilterOperator.EQUAL, key: "_id" },
{ op: SearchQueryOperators.ONE_OF, key: "_id" }, { op: SearchFilterOperator.ONE_OF, key: "_id" },
] ]
for (let [key, operation] of Object.entries(query)) { for (let [key, operation] of Object.entries(query)) {
if (typeof operation !== "object") { if (typeof operation !== "object") {

View file

@ -11,7 +11,7 @@
Label, Label,
Multiselect, Multiselect,
} from "@budibase/bbui" } from "@budibase/bbui"
import { FieldType, SearchQueryOperators } from "@budibase/types" import { FieldType, SearchFilterOperator } from "@budibase/types"
import { generate } from "shortid" import { generate } from "shortid"
import { LuceneUtils, Constants } from "@budibase/frontend-core" import { LuceneUtils, Constants } from "@budibase/frontend-core"
import { getContext } from "svelte" import { getContext } from "svelte"
@ -247,7 +247,7 @@
<slot name="binding" {filter} /> <slot name="binding" {filter} />
{:else if [FieldType.STRING, FieldType.LONGFORM, FieldType.NUMBER, FieldType.BIGINT, FieldType.FORMULA].includes(filter.type)} {:else if [FieldType.STRING, FieldType.LONGFORM, FieldType.NUMBER, FieldType.BIGINT, FieldType.FORMULA].includes(filter.type)}
<Input disabled={filter.noValue} bind:value={filter.value} /> <Input disabled={filter.noValue} bind:value={filter.value} />
{:else if filter.type === FieldType.ARRAY || (filter.type === FieldType.OPTIONS && filter.operator === SearchQueryOperators.ONE_OF)} {:else if filter.type === FieldType.ARRAY || (filter.type === FieldType.OPTIONS && filter.operator === SearchFilterOperator.ONE_OF)}
<Multiselect <Multiselect
disabled={filter.noValue} disabled={filter.noValue}
options={getFieldOptions(filter.field)} options={getFieldOptions(filter.field)}

View file

@ -8,7 +8,7 @@ import {
PermissionLevel, PermissionLevel,
QuotaUsageType, QuotaUsageType,
SaveTableRequest, SaveTableRequest,
SearchQueryOperators, SearchFilterOperator,
SortOrder, SortOrder,
SortType, SortType,
StaticQuotaName, StaticQuotaName,
@ -132,7 +132,7 @@ describe.each([
primaryDisplay: generator.word(), primaryDisplay: generator.word(),
query: [ query: [
{ {
operator: SearchQueryOperators.EQUAL, operator: SearchFilterOperator.EQUAL,
field: "field", field: "field",
value: "value", value: "value",
}, },
@ -236,7 +236,7 @@ describe.each([
...view, ...view,
query: [ query: [
{ {
operator: SearchQueryOperators.EQUAL, operator: SearchFilterOperator.EQUAL,
field: "newField", field: "newField",
value: "thatValue", value: "thatValue",
}, },
@ -263,7 +263,7 @@ describe.each([
primaryDisplay: generator.word(), primaryDisplay: generator.word(),
query: [ query: [
{ {
operator: SearchQueryOperators.EQUAL, operator: SearchFilterOperator.EQUAL,
field: generator.word(), field: generator.word(),
value: generator.word(), value: generator.word(),
}, },
@ -341,7 +341,7 @@ describe.each([
tableId: generator.guid(), tableId: generator.guid(),
query: [ query: [
{ {
operator: SearchQueryOperators.EQUAL, operator: SearchFilterOperator.EQUAL,
field: "newField", field: "newField",
value: "thatValue", value: "thatValue",
}, },
@ -671,7 +671,7 @@ describe.each([
name: generator.guid(), name: generator.guid(),
query: [ query: [
{ {
operator: SearchQueryOperators.EQUAL, operator: SearchFilterOperator.EQUAL,
field: "two", field: "two",
value: "bar2", value: "bar2",
}, },

View file

@ -160,7 +160,7 @@ describe("internal search", () => {
const response = await search.paginatedSearch( const response = await search.paginatedSearch(
{ {
contains: { contains: {
column: "a", column: ["a"],
colArr: [1, 2, 3], colArr: [1, 2, 3],
}, },
}, },
@ -168,7 +168,7 @@ describe("internal search", () => {
) )
checkLucene( checkLucene(
response, response,
`(*:* AND column:a AND colArr:(1 AND 2 AND 3))`, `(*:* AND column:(a) AND colArr:(1 AND 2 AND 3))`,
PARAMS PARAMS
) )
}) })

View file

@ -4,9 +4,9 @@ import {
FieldType, FieldType,
FormulaType, FormulaType,
SearchFilter, SearchFilter,
SearchQuery, SearchFilters,
SearchQueryFields, SearchQueryFields,
SearchQueryOperators, SearchFilterOperator,
SortDirection, SortDirection,
SortType, SortType,
} from "@budibase/types" } from "@budibase/types"
@ -99,18 +99,19 @@ export const NoEmptyFilterStrings = [
* Removes any fields that contain empty strings that would cause inconsistent * Removes any fields that contain empty strings that would cause inconsistent
* behaviour with how backend tables are filtered (no value means no filter). * behaviour with how backend tables are filtered (no value means no filter).
*/ */
const cleanupQuery = (query: SearchQuery) => { const cleanupQuery = (query: SearchFilters) => {
if (!query) { if (!query) {
return query return query
} }
for (let filterField of NoEmptyFilterStrings) { for (let filterField of NoEmptyFilterStrings) {
if (!query[filterField]) { const operator = filterField as SearchFilterOperator
if (!query[operator]) {
continue continue
} }
for (let [key, value] of Object.entries(query[filterField]!)) { for (let [key, value] of Object.entries(query[operator]!)) {
if (value == null || value === "") { if (value == null || value === "") {
delete query[filterField]![key] delete query[operator]![key]
} }
} }
} }
@ -136,7 +137,7 @@ export const removeKeyNumbering = (key: string): string => {
* @param filter the builder filter structure * @param filter the builder filter structure
*/ */
export const buildLuceneQuery = (filter: SearchFilter[]) => { export const buildLuceneQuery = (filter: SearchFilter[]) => {
let query: SearchQuery = { let query: SearchFilters = {
string: {}, string: {},
fuzzy: {}, fuzzy: {},
range: {}, range: {},
@ -157,6 +158,7 @@ export const buildLuceneQuery = (filter: SearchFilter[]) => {
filter.forEach(expression => { filter.forEach(expression => {
let { operator, field, type, value, externalType, onEmptyFilter } = let { operator, field, type, value, externalType, onEmptyFilter } =
expression expression
const queryOperator = operator as SearchFilterOperator
const isHbs = const isHbs =
typeof value === "string" && (value.match(HBS_REGEX) || []).length > 0 typeof value === "string" && (value.match(HBS_REGEX) || []).length > 0
// Parse all values into correct types // Parse all values into correct types
@ -171,8 +173,8 @@ export const buildLuceneQuery = (filter: SearchFilter[]) => {
if ( if (
type === "datetime" && type === "datetime" &&
!isHbs && !isHbs &&
operator !== "empty" && queryOperator !== "empty" &&
operator !== "notEmpty" queryOperator !== "notEmpty"
) { ) {
// Ensure date value is a valid date and parse into correct format // Ensure date value is a valid date and parse into correct format
if (!value) { if (!value) {
@ -185,7 +187,7 @@ export const buildLuceneQuery = (filter: SearchFilter[]) => {
} }
} }
if (type === "number" && typeof value === "string" && !isHbs) { if (type === "number" && typeof value === "string" && !isHbs) {
if (operator === "oneOf") { if (queryOperator === "oneOf") {
value = value.split(",").map(item => parseFloat(item)) value = value.split(",").map(item => parseFloat(item))
} else { } else {
value = parseFloat(value) value = parseFloat(value)
@ -225,24 +227,24 @@ export const buildLuceneQuery = (filter: SearchFilter[]) => {
) { ) {
query.range[field].high = value query.range[field].high = value
} }
} else if (query[operator] && operator !== "onEmptyFilter") { } else if (query[queryOperator] && operator !== "onEmptyFilter") {
if (type === "boolean") { if (type === "boolean") {
// Transform boolean filters to cope with null. // Transform boolean filters to cope with null.
// "equals false" needs to be "not equals true" // "equals false" needs to be "not equals true"
// "not equals false" needs to be "equals true" // "not equals false" needs to be "equals true"
if (operator === "equal" && value === false) { if (queryOperator === "equal" && value === false) {
query.notEqual = query.notEqual || {} query.notEqual = query.notEqual || {}
query.notEqual[field] = true query.notEqual[field] = true
} else if (operator === "notEqual" && value === false) { } else if (queryOperator === "notEqual" && value === false) {
query.equal = query.equal || {} query.equal = query.equal || {}
query.equal[field] = true query.equal[field] = true
} else { } else {
query[operator] = query[operator] || {} query[queryOperator] = query[queryOperator] || {}
query[operator]![field] = value query[queryOperator]![field] = value
} }
} else { } else {
query[operator] = query[operator] || {} query[queryOperator] = query[queryOperator] || {}
query[operator]![field] = value query[queryOperator]![field] = value
} }
} }
}) })
@ -255,7 +257,7 @@ export const buildLuceneQuery = (filter: SearchFilter[]) => {
* @param docs the data * @param docs the data
* @param query the JSON lucene query * @param query the JSON lucene query
*/ */
export const runLuceneQuery = (docs: any[], query?: SearchQuery) => { export const runLuceneQuery = (docs: any[], query?: SearchFilters) => {
if (!docs || !Array.isArray(docs)) { if (!docs || !Array.isArray(docs)) {
return [] return []
} }
@ -269,7 +271,7 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
// Iterates over a set of filters and evaluates a fail function against a doc // Iterates over a set of filters and evaluates a fail function against a doc
const match = const match =
( (
type: keyof SearchQueryFields, type: SearchFilterOperator,
failFn: (docValue: any, testValue: any) => boolean failFn: (docValue: any, testValue: any) => boolean
) => ) =>
(doc: any) => { (doc: any) => {
@ -286,7 +288,7 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
// Process a string match (fails if the value does not start with the string) // Process a string match (fails if the value does not start with the string)
const stringMatch = match( const stringMatch = match(
SearchQueryOperators.STRING, SearchFilterOperator.STRING,
(docValue: string, testValue: string) => { (docValue: string, testValue: string) => {
return ( return (
!docValue || !docValue ||
@ -297,7 +299,7 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
// Process a fuzzy match (treat the same as starts with when running locally) // Process a fuzzy match (treat the same as starts with when running locally)
const fuzzyMatch = match( const fuzzyMatch = match(
SearchQueryOperators.FUZZY, SearchFilterOperator.FUZZY,
(docValue: string, testValue: string) => { (docValue: string, testValue: string) => {
return ( return (
!docValue || !docValue ||
@ -308,7 +310,7 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
// Process a range match // Process a range match
const rangeMatch = match( const rangeMatch = match(
SearchQueryOperators.RANGE, SearchFilterOperator.RANGE,
( (
docValue: string | number | null, docValue: string | number | null,
testValue: { low: number; high: number } testValue: { low: number; high: number }
@ -331,7 +333,7 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
// Process an equal match (fails if the value is different) // Process an equal match (fails if the value is different)
const equalMatch = match( const equalMatch = match(
SearchQueryOperators.EQUAL, SearchFilterOperator.EQUAL,
(docValue: any, testValue: string | null) => { (docValue: any, testValue: string | null) => {
return testValue != null && testValue !== "" && docValue !== testValue return testValue != null && testValue !== "" && docValue !== testValue
} }
@ -339,7 +341,7 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
// Process a not-equal match (fails if the value is the same) // Process a not-equal match (fails if the value is the same)
const notEqualMatch = match( const notEqualMatch = match(
SearchQueryOperators.NOT_EQUAL, SearchFilterOperator.NOT_EQUAL,
(docValue: any, testValue: string | null) => { (docValue: any, testValue: string | null) => {
return testValue != null && testValue !== "" && docValue === testValue return testValue != null && testValue !== "" && docValue === testValue
} }
@ -347,7 +349,7 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
// Process an empty match (fails if the value is not empty) // Process an empty match (fails if the value is not empty)
const emptyMatch = match( const emptyMatch = match(
SearchQueryOperators.EMPTY, SearchFilterOperator.EMPTY,
(docValue: string | null) => { (docValue: string | null) => {
return docValue != null && docValue !== "" return docValue != null && docValue !== ""
} }
@ -355,7 +357,7 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
// Process a not-empty match (fails is the value is empty) // Process a not-empty match (fails is the value is empty)
const notEmptyMatch = match( const notEmptyMatch = match(
SearchQueryOperators.NOT_EMPTY, SearchFilterOperator.NOT_EMPTY,
(docValue: string | null) => { (docValue: string | null) => {
return docValue == null || docValue === "" return docValue == null || docValue === ""
} }
@ -363,7 +365,7 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
// Process an includes match (fails if the value is not included) // Process an includes match (fails if the value is not included)
const oneOf = match( const oneOf = match(
SearchQueryOperators.ONE_OF, SearchFilterOperator.ONE_OF,
(docValue: any, testValue: any) => { (docValue: any, testValue: any) => {
if (typeof testValue === "string") { if (typeof testValue === "string") {
testValue = testValue.split(",") testValue = testValue.split(",")
@ -376,28 +378,28 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
) )
const containsAny = match( const containsAny = match(
SearchQueryOperators.CONTAINS_ANY, SearchFilterOperator.CONTAINS_ANY,
(docValue: any, testValue: any) => { (docValue: any, testValue: any) => {
return !docValue?.includes(...testValue) return !docValue?.includes(...testValue)
} }
) )
const contains = match( const contains = match(
SearchQueryOperators.CONTAINS, SearchFilterOperator.CONTAINS,
(docValue: string | any[], testValue: any[]) => { (docValue: string | any[], testValue: any[]) => {
return !testValue?.every((item: any) => docValue?.includes(item)) return !testValue?.every((item: any) => docValue?.includes(item))
} }
) )
const notContains = match( const notContains = match(
SearchQueryOperators.NOT_CONTAINS, SearchFilterOperator.NOT_CONTAINS,
(docValue: string | any[], testValue: any[]) => { (docValue: string | any[], testValue: any[]) => {
return testValue?.every((item: any) => docValue?.includes(item)) return testValue?.every((item: any) => docValue?.includes(item))
} }
) )
const docMatch = (doc: any) => { const docMatch = (doc: any) => {
const filterFunctions: Record<SearchQueryOperators, (doc: any) => boolean> = const filterFunctions: Record<SearchFilterOperator, (doc: any) => boolean> =
{ {
string: stringMatch, string: stringMatch,
fuzzy: fuzzyMatch, fuzzy: fuzzyMatch,
@ -412,7 +414,7 @@ export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
notContains: notContains, notContains: notContains,
} }
const activeFilterKeys: SearchQueryOperators[] = Object.entries(query || {}) const activeFilterKeys: SearchFilterOperator[] = Object.entries(query || {})
.filter( .filter(
([key, value]: [string, any]) => ([key, value]: [string, any]) =>
!["allOr", "onEmptyFilter"].includes(key) && !["allOr", "onEmptyFilter"].includes(key) &&
@ -480,7 +482,7 @@ export const luceneLimit = (docs: any[], limit: string) => {
return docs.slice(0, numLimit) return docs.slice(0, numLimit)
} }
export const hasFilters = (query?: SearchQuery) => { export const hasFilters = (query?: SearchFilters) => {
if (!query) { if (!query) {
return false return false
} }

View file

@ -1,6 +1,6 @@
import { import {
SearchQuery, SearchFilters,
SearchQueryOperators, SearchFilterOperator,
FieldType, FieldType,
SearchFilter, SearchFilter,
} from "@budibase/types" } from "@budibase/types"
@ -46,8 +46,8 @@ describe("runLuceneQuery", () => {
}, },
] ]
function buildQuery(filters: { [filterKey: string]: any }): SearchQuery { function buildQuery(filters: { [filterKey: string]: any }): SearchFilters {
const query: SearchQuery = { const query: SearchFilters = {
string: {}, string: {},
fuzzy: {}, fuzzy: {},
range: {}, range: {},
@ -63,7 +63,7 @@ describe("runLuceneQuery", () => {
} }
for (const filterKey in filters) { for (const filterKey in filters) {
query[filterKey as SearchQueryOperators] = filters[filterKey] query[filterKey as SearchFilterOperator] = filters[filterKey]
} }
return query return query
@ -265,13 +265,13 @@ describe("buildLuceneQuery", () => {
it("should parseFloat if the type is a number, but the value is a numeric string", () => { it("should parseFloat if the type is a number, but the value is a numeric string", () => {
const filter: SearchFilter[] = [ const filter: SearchFilter[] = [
{ {
operator: SearchQueryOperators.EQUAL, operator: SearchFilterOperator.EQUAL,
field: "customer_id", field: "customer_id",
type: FieldType.NUMBER, type: FieldType.NUMBER,
value: "1212", value: "1212",
}, },
{ {
operator: SearchQueryOperators.ONE_OF, operator: SearchFilterOperator.ONE_OF,
field: "customer_id", field: "customer_id",
type: FieldType.NUMBER, type: FieldType.NUMBER,
value: "1000,1212,3400", value: "1000,1212,3400",
@ -299,13 +299,13 @@ describe("buildLuceneQuery", () => {
it("should not parseFloat if the type is a number, but the value is a handlebars binding string", () => { it("should not parseFloat if the type is a number, but the value is a handlebars binding string", () => {
const filter: SearchFilter[] = [ const filter: SearchFilter[] = [
{ {
operator: SearchQueryOperators.EQUAL, operator: SearchFilterOperator.EQUAL,
field: "customer_id", field: "customer_id",
type: FieldType.NUMBER, type: FieldType.NUMBER,
value: "{{ customer_id }}", value: "{{ customer_id }}",
}, },
{ {
operator: SearchQueryOperators.ONE_OF, operator: SearchFilterOperator.ONE_OF,
field: "customer_id", field: "customer_id",
type: FieldType.NUMBER, type: FieldType.NUMBER,
value: "{{ list_of_customer_ids }}", value: "{{ list_of_customer_ids }}",
@ -333,19 +333,19 @@ describe("buildLuceneQuery", () => {
it("should cast string to boolean if the type is boolean", () => { it("should cast string to boolean if the type is boolean", () => {
const filter: SearchFilter[] = [ const filter: SearchFilter[] = [
{ {
operator: SearchQueryOperators.EQUAL, operator: SearchFilterOperator.EQUAL,
field: "a", field: "a",
type: FieldType.BOOLEAN, type: FieldType.BOOLEAN,
value: "not_true", value: "not_true",
}, },
{ {
operator: SearchQueryOperators.NOT_EQUAL, operator: SearchFilterOperator.NOT_EQUAL,
field: "b", field: "b",
type: FieldType.BOOLEAN, type: FieldType.BOOLEAN,
value: "not_true", value: "not_true",
}, },
{ {
operator: SearchQueryOperators.EQUAL, operator: SearchFilterOperator.EQUAL,
field: "c", field: "c",
type: FieldType.BOOLEAN, type: FieldType.BOOLEAN,
value: "true", value: "true",
@ -374,19 +374,19 @@ describe("buildLuceneQuery", () => {
it("should split the string for contains operators", () => { it("should split the string for contains operators", () => {
const filter: SearchFilter[] = [ const filter: SearchFilter[] = [
{ {
operator: SearchQueryOperators.CONTAINS, operator: SearchFilterOperator.CONTAINS,
field: "description", field: "description",
type: FieldType.ARRAY, type: FieldType.ARRAY,
value: "Large box,Heavy box,Small box", value: "Large box,Heavy box,Small box",
}, },
{ {
operator: SearchQueryOperators.NOT_CONTAINS, operator: SearchFilterOperator.NOT_CONTAINS,
field: "description", field: "description",
type: FieldType.ARRAY, type: FieldType.ARRAY,
value: "Large box,Heavy box,Small box", value: "Large box,Heavy box,Small box",
}, },
{ {
operator: SearchQueryOperators.CONTAINS_ANY, operator: SearchFilterOperator.CONTAINS_ANY,
field: "description", field: "description",
type: FieldType.ARRAY, type: FieldType.ARRAY,
value: "Large box,Heavy box,Small box", value: "Large box,Heavy box,Small box",

View file

@ -1,68 +1,11 @@
import { FieldType } from "../../documents" import { FieldType } from "../../documents"
import { EmptyFilterOption } from "../../sdk" import { EmptyFilterOption, SearchFilters } from "../../sdk"
export type SearchFilter = { export type SearchFilter = {
operator: keyof SearchQuery operator: keyof SearchFilters | "rangeLow" | "rangeHigh"
onEmptyFilter?: EmptyFilterOption onEmptyFilter?: EmptyFilterOption
field: string field: string
type?: FieldType type?: FieldType
value: any value: any
externalType?: string externalType?: string
} }
export enum SearchQueryOperators {
STRING = "string",
FUZZY = "fuzzy",
RANGE = "range",
EQUAL = "equal",
NOT_EQUAL = "notEqual",
EMPTY = "empty",
NOT_EMPTY = "notEmpty",
ONE_OF = "oneOf",
CONTAINS = "contains",
NOT_CONTAINS = "notContains",
CONTAINS_ANY = "containsAny",
}
export type SearchQuery = {
allOr?: boolean
onEmptyFilter?: EmptyFilterOption
[SearchQueryOperators.STRING]?: {
[key: string]: string
}
[SearchQueryOperators.FUZZY]?: {
[key: string]: string
}
[SearchQueryOperators.RANGE]?: {
[key: string]: {
high: number | string
low: number | string
}
}
[SearchQueryOperators.EQUAL]?: {
[key: string]: any
}
[SearchQueryOperators.NOT_EQUAL]?: {
[key: string]: any
}
[SearchQueryOperators.EMPTY]?: {
[key: string]: any
}
[SearchQueryOperators.NOT_EMPTY]?: {
[key: string]: any
}
[SearchQueryOperators.ONE_OF]?: {
[key: string]: any[]
}
[SearchQueryOperators.CONTAINS]?: {
[key: string]: any[]
}
[SearchQueryOperators.NOT_CONTAINS]?: {
[key: string]: any[]
}
[SearchQueryOperators.CONTAINS_ANY]?: {
[key: string]: any[]
}
}
export type SearchQueryFields = Omit<SearchQuery, "allOr" | "onEmptyFilter">

View file

@ -1,5 +1,5 @@
import { User } from "../../documents" import { User } from "../../documents"
import { SearchQuery } from "./searchFilter" import { SearchFilters } from "../../sdk"
export interface SaveUserResponse { export interface SaveUserResponse {
_id: string _id: string
@ -55,7 +55,7 @@ export interface InviteUsersResponse {
export interface SearchUsersRequest { export interface SearchUsersRequest {
bookmark?: string bookmark?: string
query?: SearchQuery query?: SearchFilters
appId?: string appId?: string
limit?: number limit?: number
paginate?: boolean paginate?: boolean

View file

@ -3,47 +3,63 @@ import { Row, Table } from "../documents"
import { SortType } from "../api" import { SortType } from "../api"
import { Knex } from "knex" import { Knex } from "knex"
export enum SearchFilterOperator {
STRING = "string",
FUZZY = "fuzzy",
RANGE = "range",
EQUAL = "equal",
NOT_EQUAL = "notEqual",
EMPTY = "empty",
NOT_EMPTY = "notEmpty",
ONE_OF = "oneOf",
CONTAINS = "contains",
NOT_CONTAINS = "notContains",
CONTAINS_ANY = "containsAny",
}
export interface SearchFilters { export interface SearchFilters {
allOr?: boolean allOr?: boolean
onEmptyFilter?: EmptyFilterOption onEmptyFilter?: EmptyFilterOption
string?: { [SearchFilterOperator.STRING]?: {
[key: string]: string [key: string]: string
} }
fuzzy?: { [SearchFilterOperator.FUZZY]?: {
[key: string]: string [key: string]: string
} }
range?: { [SearchFilterOperator.RANGE]?: {
[key: string]: { [key: string]: {
high: number | string high: number | string
low: number | string low: number | string
} }
} }
equal?: { [SearchFilterOperator.EQUAL]?: {
[key: string]: any [key: string]: any
} }
notEqual?: { [SearchFilterOperator.NOT_EQUAL]?: {
[key: string]: any [key: string]: any
} }
empty?: { [SearchFilterOperator.EMPTY]?: {
[key: string]: any [key: string]: any
} }
notEmpty?: { [SearchFilterOperator.NOT_EMPTY]?: {
[key: string]: any [key: string]: any
} }
oneOf?: { [SearchFilterOperator.ONE_OF]?: {
[key: string]: any[] [key: string]: any[]
} }
contains?: { [SearchFilterOperator.CONTAINS]?: {
[key: string]: any[] | any
}
notContains?: {
[key: string]: any[] [key: string]: any[]
} }
containsAny?: { [SearchFilterOperator.NOT_CONTAINS]?: {
[key: string]: any[]
}
[SearchFilterOperator.CONTAINS_ANY]?: {
[key: string]: any[] [key: string]: any[]
} }
} }
export type SearchQueryFields = Omit<SearchFilters, "allOr" | "onEmptyFilter">
export interface SortJson { export interface SortJson {
[key: string]: { [key: string]: {
direction: SortDirection direction: SortDirection

View file

@ -4,7 +4,7 @@ import {
InviteUsersRequest, InviteUsersRequest,
User, User,
CreateAdminUserRequest, CreateAdminUserRequest,
SearchQuery, SearchFilters,
InviteUsersResponse, InviteUsersResponse,
} from "@budibase/types" } from "@budibase/types"
import structures from "../structures" import structures from "../structures"
@ -150,7 +150,7 @@ export class UserAPI extends TestAPI {
} }
searchUsers = ( searchUsers = (
{ query }: { query?: SearchQuery }, { query }: { query?: SearchFilters },
opts?: { status?: number; noHeaders?: boolean } opts?: { status?: number; noHeaders?: boolean }
) => { ) => {
const req = this.request const req = this.request