Merge branch 'BUDI-7189-views-v2' into BUDI-7189/return_columns_based_on_schema
This commit is contained in:
commit
c9dc4006a1
|
@ -2,7 +2,13 @@ import { quotas } from "@budibase/pro"
|
||||||
import * as internal from "./internal"
|
import * as internal from "./internal"
|
||||||
import * as external from "./external"
|
import * as external from "./external"
|
||||||
import { isExternalTable } from "../../../integrations/utils"
|
import { isExternalTable } from "../../../integrations/utils"
|
||||||
import { Ctx, SearchResponse } from "@budibase/types"
|
import {
|
||||||
|
Ctx,
|
||||||
|
SearchResponse,
|
||||||
|
SortOrder,
|
||||||
|
SortType,
|
||||||
|
ViewV2,
|
||||||
|
} from "@budibase/types"
|
||||||
import * as utils from "./utils"
|
import * as utils from "./utils"
|
||||||
import { gridSocket } from "../../../websockets"
|
import { gridSocket } from "../../../websockets"
|
||||||
import sdk from "../../../sdk"
|
import sdk from "../../../sdk"
|
||||||
|
@ -146,6 +152,45 @@ export async function search(ctx: any) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getSortOptions(
|
||||||
|
ctx: Ctx,
|
||||||
|
view: ViewV2
|
||||||
|
):
|
||||||
|
| {
|
||||||
|
sort: string
|
||||||
|
sortOrder?: SortOrder
|
||||||
|
sortType?: SortType
|
||||||
|
}
|
||||||
|
| undefined {
|
||||||
|
const { sort_column, sort_order, sort_type } = ctx.query
|
||||||
|
if (Array.isArray(sort_column)) {
|
||||||
|
ctx.throw(400, "sort_column cannot be an array")
|
||||||
|
}
|
||||||
|
if (Array.isArray(sort_order)) {
|
||||||
|
ctx.throw(400, "sort_order cannot be an array")
|
||||||
|
}
|
||||||
|
if (Array.isArray(sort_type)) {
|
||||||
|
ctx.throw(400, "sort_type cannot be an array")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sort_column) {
|
||||||
|
return {
|
||||||
|
sort: sort_column,
|
||||||
|
sortOrder: sort_order as SortOrder,
|
||||||
|
sortType: sort_type as SortType,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (view.sort) {
|
||||||
|
return {
|
||||||
|
sort: view.sort.field,
|
||||||
|
sortOrder: view.sort.order,
|
||||||
|
sortType: view.sort.type,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
export async function searchView(ctx: Ctx<void, SearchResponse>) {
|
export async function searchView(ctx: Ctx<void, SearchResponse>) {
|
||||||
const { viewId } = ctx.params
|
const { viewId } = ctx.params
|
||||||
|
|
||||||
|
@ -172,10 +217,8 @@ export async function searchView(ctx: Ctx<void, SearchResponse>) {
|
||||||
sdk.rows.search({
|
sdk.rows.search({
|
||||||
tableId: view.tableId,
|
tableId: view.tableId,
|
||||||
query: view.query || {},
|
query: view.query || {},
|
||||||
sort: view.sort?.field,
|
|
||||||
sortOrder: view.sort?.order,
|
|
||||||
sortType: view.sort?.type,
|
|
||||||
fields: viewFields,
|
fields: viewFields,
|
||||||
|
...getSortOptions(ctx, view),
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
datasourceId: view.tableId,
|
datasourceId: view.tableId,
|
||||||
|
|
|
@ -755,7 +755,14 @@ describe("/rows", () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it.each([
|
const sortTestOptions: [
|
||||||
|
{
|
||||||
|
field: string
|
||||||
|
order?: SortOrder
|
||||||
|
type?: SortType
|
||||||
|
},
|
||||||
|
string[]
|
||||||
|
][] = [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
field: "name",
|
field: "name",
|
||||||
|
@ -815,32 +822,77 @@ describe("/rows", () => {
|
||||||
},
|
},
|
||||||
["Bob", "Charly", "Alice", "Danny"],
|
["Bob", "Charly", "Alice", "Danny"],
|
||||||
],
|
],
|
||||||
])("allow sorting (%s)", async (sortParams, expected) => {
|
]
|
||||||
await config.createTable(userTable())
|
|
||||||
const users = [
|
it.each(sortTestOptions)(
|
||||||
{ name: "Alice", age: 25 },
|
"allow sorting (%s)",
|
||||||
{ name: "Bob", age: 30 },
|
async (sortParams, expected) => {
|
||||||
{ name: "Charly", age: 27 },
|
await config.createTable(userTable())
|
||||||
{ name: "Danny", age: 15 },
|
const users = [
|
||||||
]
|
{ name: "Alice", age: 25 },
|
||||||
for (const user of users) {
|
{ name: "Bob", age: 30 },
|
||||||
await config.createRow({
|
{ name: "Charly", age: 27 },
|
||||||
tableId: config.table!._id,
|
{ name: "Danny", age: 15 },
|
||||||
...user,
|
]
|
||||||
|
for (const user of users) {
|
||||||
|
await config.createRow({
|
||||||
|
tableId: config.table!._id,
|
||||||
|
...user,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const createViewResponse = await config.api.viewV2.create({
|
||||||
|
sort: sortParams,
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await config.api.viewV2.search(createViewResponse.id)
|
||||||
|
|
||||||
|
expect(response.body.rows).toHaveLength(4)
|
||||||
|
expect(response.body).toEqual({
|
||||||
|
rows: expected.map(name => expect.objectContaining({ name })),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
)
|
||||||
|
|
||||||
const createViewResponse = await config.api.viewV2.create({
|
it.each(sortTestOptions)(
|
||||||
sort: sortParams,
|
"allow override the default view sorting (%s)",
|
||||||
})
|
async (sortParams, expected) => {
|
||||||
|
await config.createTable(userTable())
|
||||||
|
const users = [
|
||||||
|
{ name: "Alice", age: 25 },
|
||||||
|
{ name: "Bob", age: 30 },
|
||||||
|
{ name: "Charly", age: 27 },
|
||||||
|
{ name: "Danny", age: 15 },
|
||||||
|
]
|
||||||
|
for (const user of users) {
|
||||||
|
await config.createRow({
|
||||||
|
tableId: config.table!._id,
|
||||||
|
...user,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const response = await config.api.viewV2.search(createViewResponse.id)
|
const createViewResponse = await config.api.viewV2.create({
|
||||||
|
sort: {
|
||||||
|
field: "name",
|
||||||
|
order: SortOrder.ASCENDING,
|
||||||
|
type: SortType.STRING,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
expect(response.body.rows).toHaveLength(4)
|
const response = await config.api.viewV2.search(createViewResponse.id, {
|
||||||
expect(response.body).toEqual({
|
sort: {
|
||||||
rows: expected.map(name => expect.objectContaining({ name })),
|
column: sortParams.field,
|
||||||
})
|
order: sortParams.order,
|
||||||
})
|
type: sortParams.type,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.body.rows).toHaveLength(4)
|
||||||
|
expect(response.body).toEqual({
|
||||||
|
rows: expected.map(name => expect.objectContaining({ name })),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
it("when schema is defined, no other columns are returned", async () => {
|
it("when schema is defined, no other columns are returned", async () => {
|
||||||
const table = await config.createTable(userTable())
|
const table = await config.createTable(userTable())
|
||||||
|
|
|
@ -186,6 +186,13 @@ export function getDatasourceParams(
|
||||||
return getDocParams(DocumentType.DATASOURCE, datasourceId, otherProps)
|
return getDocParams(DocumentType.DATASOURCE, datasourceId, otherProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getDatasourcePlusParams(
|
||||||
|
datasourceId?: Optional,
|
||||||
|
otherProps?: { include_docs: boolean }
|
||||||
|
) {
|
||||||
|
return getDocParams(DocumentType.DATASOURCE_PLUS, datasourceId, otherProps)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a new query ID.
|
* Generates a new query ID.
|
||||||
* @returns {string} The new query ID which the query doc can be stored under.
|
* @returns {string} The new query ID which the query doc can be stored under.
|
||||||
|
|
|
@ -19,6 +19,7 @@ import _ from "lodash"
|
||||||
import {
|
import {
|
||||||
BudibaseInternalDB,
|
BudibaseInternalDB,
|
||||||
getDatasourceParams,
|
getDatasourceParams,
|
||||||
|
getDatasourcePlusParams,
|
||||||
getTableParams,
|
getTableParams,
|
||||||
} from "../../../db/utils"
|
} from "../../../db/utils"
|
||||||
import sdk from "../../index"
|
import sdk from "../../index"
|
||||||
|
@ -248,7 +249,7 @@ export async function getExternalDatasources(): Promise<Datasource[]> {
|
||||||
const db = context.getAppDB()
|
const db = context.getAppDB()
|
||||||
|
|
||||||
const externalDatasources = await db.allDocs<Datasource>(
|
const externalDatasources = await db.allDocs<Datasource>(
|
||||||
getDatasourceParams("plus", {
|
getDatasourcePlusParams(undefined, {
|
||||||
include_docs: true,
|
include_docs: true,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ViewV2 } from "@budibase/types"
|
import { SortOrder, SortType, ViewV2 } from "@budibase/types"
|
||||||
import TestConfiguration from "../TestConfiguration"
|
import TestConfiguration from "../TestConfiguration"
|
||||||
import { TestAPI } from "./base"
|
import { TestAPI } from "./base"
|
||||||
import { generator } from "@budibase/backend-core/tests"
|
import { generator } from "@budibase/backend-core/tests"
|
||||||
|
@ -38,9 +38,33 @@ export class ViewV2API extends TestAPI {
|
||||||
.expect(expectStatus)
|
.expect(expectStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
search = async (viewId: string, { expectStatus } = { expectStatus: 200 }) => {
|
search = async (
|
||||||
|
viewId: string,
|
||||||
|
options?: {
|
||||||
|
sort: {
|
||||||
|
column: string
|
||||||
|
order?: SortOrder
|
||||||
|
type?: SortType
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ expectStatus } = { expectStatus: 200 }
|
||||||
|
) => {
|
||||||
|
const qs: [string, any][] = []
|
||||||
|
if (options?.sort.column) {
|
||||||
|
qs.push(["sort_column", options.sort.column])
|
||||||
|
}
|
||||||
|
if (options?.sort.order) {
|
||||||
|
qs.push(["sort_order", options.sort.order])
|
||||||
|
}
|
||||||
|
if (options?.sort.type) {
|
||||||
|
qs.push(["sort_type", options.sort.type])
|
||||||
|
}
|
||||||
|
let url = `/api/v2/views/${viewId}/search`
|
||||||
|
if (qs.length) {
|
||||||
|
url += "?" + qs.map(q => q.join("=")).join("&")
|
||||||
|
}
|
||||||
return this.request
|
return this.request
|
||||||
.get(`/api/v2/views/${viewId}/search`)
|
.get(url)
|
||||||
.set(this.config.defaultHeaders())
|
.set(this.config.defaultHeaders())
|
||||||
.expect("Content-Type", /json/)
|
.expect("Content-Type", /json/)
|
||||||
.expect(expectStatus)
|
.expect(expectStatus)
|
||||||
|
|
Loading…
Reference in New Issue