Merge branch 'master' into chore/remove-disabling-nounusedvars
This commit is contained in:
commit
f12e654811
|
@ -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") {
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
|
@ -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",
|
||||||
},
|
},
|
||||||
|
|
|
@ -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
|
||||||
)
|
)
|
||||||
})
|
})
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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">
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue