1
0
Fork 0
mirror of synced 2024-09-08 05:31:47 +12:00

Merge pull request #11453 from Budibase/BUDI-7189/change_query_format

Change query stored in view2.0
This commit is contained in:
Adria Navarro 2023-08-07 14:41:02 +01:00 committed by GitHub
commit 0d4253b1de
8 changed files with 95 additions and 76 deletions

@ -1 +1 @@
Subproject commit cf3bef2aad9c739111b306fd0712397adc363f81
Subproject commit ecee8071ebe0f98a5bb19646954e373264be210d

View file

@ -7,6 +7,7 @@ import {
RequiredKeys,
SearchParams,
} from "@budibase/types"
import { dataFilters } from "@budibase/shared-core"
import sdk from "../../../sdk"
export async function searchView(
@ -34,11 +35,12 @@ export async function searchView(
ctx.status = 200
const { body } = ctx.request
const query = dataFilters.buildLuceneQuery(view.query || [])
const searchOptions: RequiredKeys<SearchViewRowRequest> &
RequiredKeys<Pick<SearchParams, "tableId" | "query" | "fields">> = {
tableId: view.tableId,
query: view.query || {},
query,
fields: viewFields,
...getSortOptions(body, view),
limit: body.limit,

View file

@ -1072,7 +1072,7 @@ describe("/rows", () => {
)
const createViewResponse = await config.api.viewV2.create({
query: { equal: { age: 40 } },
query: [{ operator: "equal", field: "age", value: 40 }],
})
const response = await config.api.viewV2.search(createViewResponse.id)

View file

@ -62,7 +62,7 @@ describe("/v2/views", () => {
name: generator.name(),
tableId: config.table!._id!,
primaryDisplay: generator.word(),
query: { allOr: false, equal: { field: "value" } },
query: [{ operator: "equal", field: "field", value: "value" }],
sort: {
field: "fieldToSort",
order: SortOrder.DESCENDING,
@ -190,7 +190,7 @@ describe("/v2/views", () => {
const tableId = config.table!._id!
await config.api.viewV2.update({
...view,
query: { equal: { newField: "thatValue" } },
query: [{ operator: "equal", field: "newField", value: "thatValue" }],
})
expect(await config.api.table.get(tableId)).toEqual({
@ -198,7 +198,9 @@ describe("/v2/views", () => {
views: {
[view.name]: {
...view,
query: { equal: { newField: "thatValue" } },
query: [
{ operator: "equal", field: "newField", value: "thatValue" },
],
schema: expect.anything(),
},
},
@ -216,7 +218,13 @@ describe("/v2/views", () => {
tableId,
name: view.name,
primaryDisplay: generator.word(),
query: { equal: { [generator.word()]: generator.word() } },
query: [
{
operator: "equal",
field: generator.word(),
value: generator.word(),
},
],
sort: {
field: generator.word(),
order: SortOrder.DESCENDING,
@ -285,7 +293,7 @@ describe("/v2/views", () => {
{
...view,
tableId: generator.guid(),
query: { equal: { newField: "thatValue" } },
query: [{ operator: "equal", field: "newField", value: "thatValue" }],
},
{ expectStatus: 404 }
)

View file

@ -1,4 +1,12 @@
import { Datasource, FieldType, SortDirection, SortType } from "@budibase/types"
import {
Datasource,
FieldType,
SearchFilter,
SearchQuery,
SearchQueryFields,
SortDirection,
SortType,
} from "@budibase/types"
import { OperatorOptions, SqlNumberTypeRangeMap } from "./constants"
import { deepGet } from "./helpers"
@ -73,13 +81,13 @@ export const NoEmptyFilterStrings = [
OperatorOptions.NotEquals.value,
OperatorOptions.Contains.value,
OperatorOptions.NotContains.value,
] as (keyof QueryFields)[]
] as (keyof SearchQueryFields)[]
/**
* Removes any fields that contain empty strings that would cause inconsistent
* behaviour with how backend tables are filtered (no value means no filter).
*/
const cleanupQuery = (query: Query) => {
const cleanupQuery = (query: SearchQuery) => {
if (!query) {
return query
}
@ -110,66 +118,12 @@ const removeKeyNumbering = (key: string) => {
}
}
type Filter = {
operator: keyof Query
field: string
type: any
value: any
externalType: keyof typeof SqlNumberTypeRangeMap
}
type Query = QueryFields & QueryConfig
type QueryFields = {
string?: {
[key: string]: string
}
fuzzy?: {
[key: string]: string
}
range?: {
[key: string]: {
high: number | string
low: number | string
}
}
equal?: {
[key: string]: any
}
notEqual?: {
[key: string]: any
}
empty?: {
[key: string]: any
}
notEmpty?: {
[key: string]: any
}
oneOf?: {
[key: string]: any[]
}
contains?: {
[key: string]: any[]
}
notContains?: {
[key: string]: any[]
}
containsAny?: {
[key: string]: any[]
}
}
type QueryConfig = {
allOr?: boolean
}
type QueryFieldsType = keyof QueryFields
/**
* Builds a lucene JSON query from the filter structure generated in the builder
* @param filter the builder filter structure
*/
export const buildLuceneQuery = (filter: Filter[]) => {
let query: Query = {
export const buildLuceneQuery = (filter: SearchFilter[]) => {
let query: SearchQuery = {
string: {},
fuzzy: {},
range: {},
@ -227,9 +181,13 @@ export const buildLuceneQuery = (filter: Filter[]) => {
}
if (operator.startsWith("range") && query.range) {
const minint =
SqlNumberTypeRangeMap[externalType]?.min || Number.MIN_SAFE_INTEGER
SqlNumberTypeRangeMap[
externalType as keyof typeof SqlNumberTypeRangeMap
]?.min || Number.MIN_SAFE_INTEGER
const maxint =
SqlNumberTypeRangeMap[externalType]?.max || Number.MAX_SAFE_INTEGER
SqlNumberTypeRangeMap[
externalType as keyof typeof SqlNumberTypeRangeMap
]?.max || Number.MAX_SAFE_INTEGER
if (!query.range[field]) {
query.range[field] = {
low: type === "number" ? minint : "0000-00-00T00:00:00.000Z",
@ -275,7 +233,7 @@ export const buildLuceneQuery = (filter: Filter[]) => {
* @param docs the data
* @param query the JSON lucene query
*/
export const runLuceneQuery = (docs: any[], query?: Query) => {
export const runLuceneQuery = (docs: any[], query?: SearchQuery) => {
if (!docs || !Array.isArray(docs)) {
return []
}
@ -289,7 +247,7 @@ export const runLuceneQuery = (docs: any[], query?: Query) => {
// Iterates over a set of filters and evaluates a fail function against a doc
const match =
(
type: QueryFieldsType,
type: keyof SearchQueryFields,
failFn: (docValue: any, testValue: any) => boolean
) =>
(doc: any) => {
@ -456,7 +414,7 @@ export const luceneLimit = (docs: any[], limit: string) => {
return docs.slice(0, numLimit)
}
export const hasFilters = (query?: Query) => {
export const hasFilters = (query?: SearchQuery) => {
if (!query) {
return false
}

View file

@ -8,3 +8,4 @@ export * from "./system"
export * from "./app"
export * from "./global"
export * from "./pagination"
export * from "./searchFilter"

View file

@ -0,0 +1,51 @@
import { FieldType } from "../../documents"
export type SearchFilter = {
operator: keyof SearchQuery
field: string
type?: FieldType
value: any
externalType?: string
}
export type SearchQuery = {
allOr?: boolean
string?: {
[key: string]: string
}
fuzzy?: {
[key: string]: string
}
range?: {
[key: string]: {
high: number | string
low: number | string
}
}
equal?: {
[key: string]: any
}
notEqual?: {
[key: string]: any
}
empty?: {
[key: string]: any
}
notEmpty?: {
[key: string]: any
}
oneOf?: {
[key: string]: any[]
}
contains?: {
[key: string]: any[]
}
notContains?: {
[key: string]: any[]
}
containsAny?: {
[key: string]: any[]
}
}
export type SearchQueryFields = Omit<SearchQuery, "allOr">

View file

@ -1,6 +1,5 @@
import { SortOrder, SortType } from "../../api"
import { SearchFilters } from "../../sdk"
import { TableSchema, UIFieldMetadata } from "./table"
import { SearchFilter, SortOrder, SortType } from "../../api"
import { UIFieldMetadata } from "./table"
export interface View {
name: string
@ -20,7 +19,7 @@ export interface ViewV2 {
name: string
primaryDisplay?: string
tableId: string
query?: SearchFilters
query?: SearchFilter[]
sort?: {
field: string
order?: SortOrder