Replace SortDirection with SortOrder, SortDirection is being removed.
This commit is contained in:
parent
4e1e462dbe
commit
c27e9c266c
|
@ -18,7 +18,6 @@ import {
|
|||
SqlQuery,
|
||||
RelationshipsJson,
|
||||
SearchFilters,
|
||||
SortDirection,
|
||||
SqlQueryBinding,
|
||||
Table,
|
||||
TableSourceType,
|
||||
|
@ -27,6 +26,7 @@ import {
|
|||
QueryOptions,
|
||||
JsonTypes,
|
||||
prefixed,
|
||||
SortOrder,
|
||||
} from "@budibase/types"
|
||||
import environment from "../environment"
|
||||
import { helpers } from "@budibase/shared-core"
|
||||
|
@ -420,11 +420,11 @@ class InternalBuilder {
|
|||
if (sort && Object.keys(sort || {}).length > 0) {
|
||||
for (let [key, value] of Object.entries(sort)) {
|
||||
const direction =
|
||||
value.direction === SortDirection.ASCENDING ? "asc" : "desc"
|
||||
value.direction === SortOrder.ASCENDING ? "asc" : "desc"
|
||||
let nulls
|
||||
if (this.client === SqlClient.POSTGRES) {
|
||||
// All other clients already sort this as expected by default, and adding this to the rest of the clients is causing issues
|
||||
nulls = value.direction === SortDirection.ASCENDING ? "first" : "last"
|
||||
nulls = value.direction === SortOrder.ASCENDING ? "first" : "last"
|
||||
}
|
||||
|
||||
query = query.orderBy(`${aliased}.${key}`, direction, nulls)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 85b4fc9ea01472bf69840d046733ad596ef893e2
|
||||
Subproject commit e093f49a9d0f548fe8cf7b981d1e88eb0fcc394a
|
|
@ -566,7 +566,7 @@ class GoogleSheetsIntegration implements DatasourcePlus {
|
|||
query.filters.equal[`_${GOOGLE_SHEETS_PRIMARY_KEY}`] = id
|
||||
}
|
||||
}
|
||||
let filtered = dataFilters.runQuery(rows, query.filters)
|
||||
let filtered = dataFilters.runQuery(rows, query.filters || {})
|
||||
if (hasFilters && query.paginate) {
|
||||
filtered = filtered.slice(offset, offset + limit)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import {
|
||||
SortJson,
|
||||
SortDirection,
|
||||
Operation,
|
||||
PaginationJson,
|
||||
IncludeRelationship,
|
||||
|
@ -9,6 +8,7 @@ import {
|
|||
RowSearchParams,
|
||||
SearchResponse,
|
||||
Table,
|
||||
SortOrder,
|
||||
} from "@budibase/types"
|
||||
import * as exporters from "../../../../api/controllers/view/exporters"
|
||||
import { handleRequest } from "../../../../api/controllers/row/external"
|
||||
|
@ -52,8 +52,8 @@ export async function search(
|
|||
if (params.sort) {
|
||||
const direction =
|
||||
params.sortOrder === "descending"
|
||||
? SortDirection.DESCENDING
|
||||
: SortDirection.ASCENDING
|
||||
? SortOrder.DESCENDING
|
||||
: SortOrder.ASCENDING
|
||||
sort = {
|
||||
[params.sort]: { direction },
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import {
|
|||
RowSearchParams,
|
||||
SearchFilters,
|
||||
SearchResponse,
|
||||
SortDirection,
|
||||
SortOrder,
|
||||
SortType,
|
||||
SqlClient,
|
||||
|
@ -170,8 +169,8 @@ export async function search(
|
|||
sortField.type === FieldType.NUMBER ? SortType.NUMBER : SortType.STRING
|
||||
const sortDirection =
|
||||
params.sortOrder === SortOrder.ASCENDING
|
||||
? SortDirection.ASCENDING
|
||||
: SortDirection.DESCENDING
|
||||
? SortOrder.ASCENDING
|
||||
: SortOrder.DESCENDING
|
||||
request.sort = {
|
||||
[sortField.name]: {
|
||||
direction: sortDirection,
|
||||
|
|
|
@ -1,415 +0,0 @@
|
|||
import {
|
||||
SearchFilters,
|
||||
SearchFilterOperator,
|
||||
FieldType,
|
||||
SearchFilter,
|
||||
} from "@budibase/types"
|
||||
import { buildQuery, runQuery } from "../filters"
|
||||
|
||||
describe("runQuery", () => {
|
||||
const docs = [
|
||||
{
|
||||
order_id: 1,
|
||||
customer_id: 259,
|
||||
order_status: 4,
|
||||
order_date: "2016-01-01T00:00:00.000Z",
|
||||
required_date: "2016-01-03T00:00:00.000Z",
|
||||
shipped_date: "2016-01-03T00:00:00.000Z",
|
||||
store_id: 1,
|
||||
staff_id: 2,
|
||||
description: "Large box",
|
||||
label: undefined,
|
||||
},
|
||||
{
|
||||
order_id: 2,
|
||||
customer_id: 1212,
|
||||
order_status: 4,
|
||||
order_date: "2016-01-05T00:00:00.000Z",
|
||||
required_date: "2016-01-04T00:00:00.000Z",
|
||||
shipped_date: "2016-01-03T00:00:00.000Z",
|
||||
store_id: 2,
|
||||
staff_id: 6,
|
||||
description: "Small box",
|
||||
label: "FRAGILE",
|
||||
},
|
||||
{
|
||||
order_id: 3,
|
||||
customer_id: 523,
|
||||
order_status: 5,
|
||||
order_date: "2016-01-12T00:00:00.000Z",
|
||||
required_date: "2016-01-05T00:00:00.000Z",
|
||||
shipped_date: "2016-01-03T00:00:00.000Z",
|
||||
store_id: 2,
|
||||
staff_id: 7,
|
||||
description: "Heavy box",
|
||||
label: "HEAVY",
|
||||
},
|
||||
]
|
||||
|
||||
function buildQuery(filters: { [filterKey: string]: any }): SearchFilters {
|
||||
const query: SearchFilters = {
|
||||
string: {},
|
||||
fuzzy: {},
|
||||
range: {},
|
||||
equal: {},
|
||||
notEqual: {},
|
||||
empty: {},
|
||||
notEmpty: {},
|
||||
contains: {},
|
||||
notContains: {},
|
||||
oneOf: {},
|
||||
containsAny: {},
|
||||
allOr: false,
|
||||
}
|
||||
|
||||
for (const filterKey in filters) {
|
||||
query[filterKey as SearchFilterOperator] = filters[filterKey]
|
||||
}
|
||||
|
||||
return query
|
||||
}
|
||||
|
||||
it("should return input docs if no search query is provided", () => {
|
||||
expect(runQuery(docs)).toBe(docs)
|
||||
})
|
||||
|
||||
it("should return matching rows for equal filter", () => {
|
||||
const query = buildQuery({
|
||||
equal: { order_status: 4 },
|
||||
})
|
||||
expect(runQuery(docs, query).map(row => row.order_id)).toEqual([1, 2])
|
||||
})
|
||||
|
||||
it("should return matching row for notEqual filter", () => {
|
||||
const query = buildQuery({
|
||||
notEqual: { order_status: 4 },
|
||||
})
|
||||
|
||||
expect(runQuery(docs, query).map(row => row.order_id)).toEqual([3])
|
||||
})
|
||||
|
||||
it("should return starts with matching rows for fuzzy and string filters", () => {
|
||||
expect(
|
||||
runQuery(
|
||||
docs,
|
||||
buildQuery({
|
||||
fuzzy: { description: "sm" },
|
||||
})
|
||||
).map(row => row.description)
|
||||
).toEqual(["Small box"])
|
||||
expect(
|
||||
runQuery(
|
||||
docs,
|
||||
buildQuery({
|
||||
string: { description: "SM" },
|
||||
})
|
||||
).map(row => row.description)
|
||||
).toEqual(["Small box"])
|
||||
})
|
||||
|
||||
it("should return rows within a range filter", () => {
|
||||
const query = buildQuery({
|
||||
range: {
|
||||
customer_id: {
|
||||
low: 500,
|
||||
high: 1000,
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(runQuery(docs, query).map(row => row.order_id)).toEqual([3])
|
||||
})
|
||||
|
||||
it("should return rows with numeric strings within a range filter", () => {
|
||||
const query = buildQuery({
|
||||
range: {
|
||||
customer_id: {
|
||||
low: "500",
|
||||
high: "1000",
|
||||
},
|
||||
},
|
||||
})
|
||||
expect(runQuery(docs, query).map(row => row.order_id)).toEqual([3])
|
||||
})
|
||||
|
||||
it("should return rows with ISO date strings within a range filter", () => {
|
||||
const query = buildQuery({
|
||||
range: {
|
||||
order_date: {
|
||||
low: "2016-01-04T00:00:00.000Z",
|
||||
high: "2016-01-11T00:00:00.000Z",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(runQuery(docs, query).map(row => row.order_id)).toEqual([2])
|
||||
})
|
||||
|
||||
it("should return return all docs if an invalid doc value is passed into a range filter", async () => {
|
||||
const docs = [
|
||||
{
|
||||
order_id: 4,
|
||||
customer_id: 1758,
|
||||
order_status: 5,
|
||||
order_date: "{{ Binding.INVALID }}",
|
||||
required_date: "2017-03-05T00:00:00.000Z",
|
||||
shipped_date: "2017-03-03T00:00:00.000Z",
|
||||
store_id: 2,
|
||||
staff_id: 7,
|
||||
description: undefined,
|
||||
label: "",
|
||||
},
|
||||
]
|
||||
|
||||
const query = buildQuery({
|
||||
range: {
|
||||
order_date: {
|
||||
low: "2016-01-04T00:00:00.000Z",
|
||||
high: "2016-01-11T00:00:00.000Z",
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
expect(runQuery(docs, query)).toEqual(docs)
|
||||
})
|
||||
|
||||
it("should return rows with matches on empty filter", () => {
|
||||
const query = buildQuery({
|
||||
empty: {
|
||||
label: null,
|
||||
},
|
||||
})
|
||||
|
||||
expect(runQuery(docs, query).map(row => row.order_id)).toEqual([1])
|
||||
})
|
||||
|
||||
it("should return rows with matches on notEmpty filter", () => {
|
||||
const query = buildQuery({
|
||||
notEmpty: {
|
||||
label: null,
|
||||
},
|
||||
})
|
||||
|
||||
expect(runQuery(docs, query).map(row => row.order_id)).toEqual([2, 3])
|
||||
})
|
||||
|
||||
it.each([[523, 259], "523,259"])(
|
||||
"should return rows with matches on numeric oneOf filter",
|
||||
input => {
|
||||
const query = buildQuery({
|
||||
oneOf: {
|
||||
customer_id: input,
|
||||
},
|
||||
})
|
||||
|
||||
expect(runQuery(docs, query).map(row => row.customer_id)).toEqual([
|
||||
259, 523,
|
||||
])
|
||||
}
|
||||
)
|
||||
|
||||
it.each([
|
||||
[false, []],
|
||||
[true, [1, 2, 3]],
|
||||
])("should return %s if allOr is %s ", (allOr, expectedResult) => {
|
||||
const query = buildQuery({
|
||||
allOr,
|
||||
oneOf: { staff_id: [10] },
|
||||
contains: { description: ["box"] },
|
||||
})
|
||||
|
||||
expect(runQuery(docs, query).map(row => row.order_id)).toEqual(
|
||||
expectedResult
|
||||
)
|
||||
})
|
||||
|
||||
it("should return matching results if allOr is true and only one filter matches with different operands", () => {
|
||||
const query = buildQuery({
|
||||
allOr: true,
|
||||
equal: { order_status: 4 },
|
||||
oneOf: { label: ["FRAGILE"] },
|
||||
})
|
||||
|
||||
expect(runQuery(docs, query).map(row => row.order_id)).toEqual([1, 2])
|
||||
})
|
||||
|
||||
it("should handle when a value is null or undefined", () => {
|
||||
const query = buildQuery({
|
||||
allOr: true,
|
||||
equal: { order_status: null },
|
||||
oneOf: { label: ["FRAGILE"] },
|
||||
})
|
||||
|
||||
expect(runQuery(docs, query).map(row => row.order_id)).toEqual([2])
|
||||
})
|
||||
})
|
||||
|
||||
describe("buildQuery", () => {
|
||||
it("should return a basic search query template if the input is not an array", () => {
|
||||
const filter: any = "NOT_AN_ARRAY"
|
||||
expect(buildQuery(filter)).toEqual({
|
||||
string: {},
|
||||
fuzzy: {},
|
||||
range: {},
|
||||
equal: {},
|
||||
notEqual: {},
|
||||
empty: {},
|
||||
notEmpty: {},
|
||||
contains: {},
|
||||
notContains: {},
|
||||
oneOf: {},
|
||||
containsAny: {},
|
||||
})
|
||||
})
|
||||
|
||||
it("should parseFloat if the type is a number, but the value is a numeric string", () => {
|
||||
const filter: SearchFilter[] = [
|
||||
{
|
||||
operator: SearchFilterOperator.EQUAL,
|
||||
field: "customer_id",
|
||||
type: FieldType.NUMBER,
|
||||
value: "1212",
|
||||
},
|
||||
{
|
||||
operator: SearchFilterOperator.ONE_OF,
|
||||
field: "customer_id",
|
||||
type: FieldType.NUMBER,
|
||||
value: "1000,1212,3400",
|
||||
},
|
||||
]
|
||||
expect(buildQuery(filter)).toEqual({
|
||||
string: {},
|
||||
fuzzy: {},
|
||||
range: {},
|
||||
equal: {
|
||||
customer_id: 1212,
|
||||
},
|
||||
notEqual: {},
|
||||
empty: {},
|
||||
notEmpty: {},
|
||||
contains: {},
|
||||
notContains: {},
|
||||
oneOf: {
|
||||
customer_id: [1000, 1212, 3400],
|
||||
},
|
||||
containsAny: {},
|
||||
})
|
||||
})
|
||||
|
||||
it("should not parseFloat if the type is a number, but the value is a handlebars binding string", () => {
|
||||
const filter: SearchFilter[] = [
|
||||
{
|
||||
operator: SearchFilterOperator.EQUAL,
|
||||
field: "customer_id",
|
||||
type: FieldType.NUMBER,
|
||||
value: "{{ customer_id }}",
|
||||
},
|
||||
{
|
||||
operator: SearchFilterOperator.ONE_OF,
|
||||
field: "customer_id",
|
||||
type: FieldType.NUMBER,
|
||||
value: "{{ list_of_customer_ids }}",
|
||||
},
|
||||
]
|
||||
expect(buildQuery(filter)).toEqual({
|
||||
string: {},
|
||||
fuzzy: {},
|
||||
range: {},
|
||||
equal: {
|
||||
customer_id: "{{ customer_id }}",
|
||||
},
|
||||
notEqual: {},
|
||||
empty: {},
|
||||
notEmpty: {},
|
||||
contains: {},
|
||||
notContains: {},
|
||||
oneOf: {
|
||||
customer_id: "{{ list_of_customer_ids }}",
|
||||
},
|
||||
containsAny: {},
|
||||
})
|
||||
})
|
||||
|
||||
it("should cast string to boolean if the type is boolean", () => {
|
||||
const filter: SearchFilter[] = [
|
||||
{
|
||||
operator: SearchFilterOperator.EQUAL,
|
||||
field: "a",
|
||||
type: FieldType.BOOLEAN,
|
||||
value: "not_true",
|
||||
},
|
||||
{
|
||||
operator: SearchFilterOperator.NOT_EQUAL,
|
||||
field: "b",
|
||||
type: FieldType.BOOLEAN,
|
||||
value: "not_true",
|
||||
},
|
||||
{
|
||||
operator: SearchFilterOperator.EQUAL,
|
||||
field: "c",
|
||||
type: FieldType.BOOLEAN,
|
||||
value: "true",
|
||||
},
|
||||
]
|
||||
expect(buildQuery(filter)).toEqual({
|
||||
string: {},
|
||||
fuzzy: {},
|
||||
range: {},
|
||||
equal: {
|
||||
b: true,
|
||||
c: true,
|
||||
},
|
||||
notEqual: {
|
||||
a: true,
|
||||
},
|
||||
empty: {},
|
||||
notEmpty: {},
|
||||
contains: {},
|
||||
notContains: {},
|
||||
oneOf: {},
|
||||
containsAny: {},
|
||||
})
|
||||
})
|
||||
|
||||
it("should split the string for contains operators", () => {
|
||||
const filter: SearchFilter[] = [
|
||||
{
|
||||
operator: SearchFilterOperator.CONTAINS,
|
||||
field: "description",
|
||||
type: FieldType.ARRAY,
|
||||
value: "Large box,Heavy box,Small box",
|
||||
},
|
||||
{
|
||||
operator: SearchFilterOperator.NOT_CONTAINS,
|
||||
field: "description",
|
||||
type: FieldType.ARRAY,
|
||||
value: "Large box,Heavy box,Small box",
|
||||
},
|
||||
{
|
||||
operator: SearchFilterOperator.CONTAINS_ANY,
|
||||
field: "description",
|
||||
type: FieldType.ARRAY,
|
||||
value: "Large box,Heavy box,Small box",
|
||||
},
|
||||
]
|
||||
expect(buildQuery(filter)).toEqual({
|
||||
string: {},
|
||||
fuzzy: {},
|
||||
range: {},
|
||||
equal: {},
|
||||
notEqual: {},
|
||||
empty: {},
|
||||
notEmpty: {},
|
||||
contains: {
|
||||
description: ["Large box", "Heavy box", "Small box"],
|
||||
},
|
||||
notContains: {
|
||||
description: ["Large box", "Heavy box", "Small box"],
|
||||
},
|
||||
oneOf: {},
|
||||
containsAny: {
|
||||
description: ["Large box", "Heavy box", "Small box"],
|
||||
},
|
||||
})
|
||||
})
|
||||
})
|
|
@ -22,11 +22,6 @@ export const RowOperations = [
|
|||
Operation.BULK_CREATE,
|
||||
]
|
||||
|
||||
export enum SortDirection {
|
||||
ASCENDING = "ASCENDING",
|
||||
DESCENDING = "DESCENDING",
|
||||
}
|
||||
|
||||
export enum QueryType {
|
||||
SQL = "sql",
|
||||
JSON = "json",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { Operation, SortDirection } from "./datasources"
|
||||
import { Operation } from "./datasources"
|
||||
import { Row, Table, DocumentType } from "../documents"
|
||||
import { SortType } from "../api"
|
||||
import { SortOrder, SortType } from "../api"
|
||||
import { Knex } from "knex"
|
||||
|
||||
export enum SearchFilterOperator {
|
||||
|
@ -77,7 +77,7 @@ export type SearchQueryFields = Omit<SearchFilters, "allOr" | "onEmptyFilter">
|
|||
|
||||
export interface SortJson {
|
||||
[key: string]: {
|
||||
direction: SortDirection
|
||||
direction: SortOrder
|
||||
type?: SortType
|
||||
}
|
||||
}
|
||||
|
|
24
yarn.lock
24
yarn.lock
|
@ -3495,10 +3495,10 @@
|
|||
dependencies:
|
||||
lodash "^4.17.21"
|
||||
|
||||
"@koa/cors@^3.1.0":
|
||||
version "3.4.3"
|
||||
resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-3.4.3.tgz#d669ee6e8d6e4f0ec4a7a7b0a17e7a3ed3752ebb"
|
||||
integrity sha512-WPXQUaAeAMVaLTEFpoq3T2O1C+FstkjJnDQqy95Ck1UdILajsRhu6mhJ8H2f4NFPRBoCNN+qywTJfq/gGki5mw==
|
||||
"@koa/cors@^5.0.0":
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-5.0.0.tgz#0029b5f057fa0d0ae0e37dd2c89ece315a0daffd"
|
||||
integrity sha512-x/iUDjcS90W69PryLDIMgFyV21YLTnG9zOpPXS7Bkt2b8AsY3zZsIpOLBkYr9fBcF3HbkKaER5hOBZLfpLgYNw==
|
||||
dependencies:
|
||||
vary "^1.1.2"
|
||||
|
||||
|
@ -5817,10 +5817,10 @@
|
|||
"@types/koa-compose" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/koa__cors@^3.1.1":
|
||||
version "3.3.1"
|
||||
resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-3.3.1.tgz#0ec7543c4c620fd23451bfdd3e21b9a6aadedccd"
|
||||
integrity sha512-aFGYhTFW7651KhmZZ05VG0QZJre7QxBxDj2LF1lf6GA/wSXEfKVAJxiQQWzRV4ZoMzQIO8vJBXKsUcRuvYK9qw==
|
||||
"@types/koa__cors@^5.0.0":
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/koa__cors/-/koa__cors-5.0.0.tgz#74567a045b599266e2cd3940cef96cedecc2ef1f"
|
||||
integrity sha512-LCk/n25Obq5qlernGOK/2LUwa/2YJb2lxHUkkvYFDOpLXlVI6tKcdfCHRBQnOY4LwH6el5WOLs6PD/a8Uzau6g==
|
||||
dependencies:
|
||||
"@types/koa" "*"
|
||||
|
||||
|
@ -16343,10 +16343,10 @@ node-source-walk@^5.0.0:
|
|||
dependencies:
|
||||
"@babel/parser" "^7.0.0"
|
||||
|
||||
nodemailer@6.7.2:
|
||||
version "6.7.2"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.7.2.tgz#44b2ad5f7ed71b7067f7a21c4fedabaec62b85e0"
|
||||
integrity sha512-Dz7zVwlef4k5R71fdmxwR8Q39fiboGbu3xgswkzGwczUfjp873rVxt1O46+Fh0j1ORnAC6L9+heI8uUpO6DT7Q==
|
||||
nodemailer@6.9.13:
|
||||
version "6.9.13"
|
||||
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.13.tgz#5b292bf1e92645f4852ca872c56a6ba6c4a3d3d6"
|
||||
integrity sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==
|
||||
|
||||
nodemailer@6.9.9:
|
||||
version "6.9.9"
|
||||
|
|
Loading…
Reference in New Issue