Replace SortDirection with SortOrder, SortDirection is being removed.

This commit is contained in:
Sam Rose 2024-06-14 09:45:30 +01:00
parent 4e1e462dbe
commit c27e9c266c
No known key found for this signature in database
9 changed files with 25 additions and 446 deletions

View File

@ -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

View File

@ -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)
}

View File

@ -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 },
}

View File

@ -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,

View File

@ -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"],
},
})
})
})

View File

@ -22,11 +22,6 @@ export const RowOperations = [
Operation.BULK_CREATE,
]
export enum SortDirection {
ASCENDING = "ASCENDING",
DESCENDING = "DESCENDING",
}
export enum QueryType {
SQL = "sql",
JSON = "json",

View File

@ -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
}
}

View File

@ -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"