Handle composite keys on exports
This commit is contained in:
parent
85827bbf93
commit
5be8882122
|
@ -172,6 +172,8 @@ function convertBooleans(query: SqlQuery | SqlQuery[]): SqlQuery | SqlQuery[] {
|
||||||
return query
|
return query
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const COMPLEX_ID_OPERATOR = "_complexIdOperator"
|
||||||
|
|
||||||
class InternalBuilder {
|
class InternalBuilder {
|
||||||
private readonly client: string
|
private readonly client: string
|
||||||
|
|
||||||
|
@ -214,7 +216,14 @@ class InternalBuilder {
|
||||||
for (let [key, value] of Object.entries(structure)) {
|
for (let [key, value] of Object.entries(structure)) {
|
||||||
const updatedKey = dbCore.removeKeyNumbering(key)
|
const updatedKey = dbCore.removeKeyNumbering(key)
|
||||||
const isRelationshipField = updatedKey.includes(".")
|
const isRelationshipField = updatedKey.includes(".")
|
||||||
if (!opts.relationship && !isRelationshipField) {
|
|
||||||
|
if (updatedKey === COMPLEX_ID_OPERATOR) {
|
||||||
|
const alias = getTableAlias(tableName)
|
||||||
|
fn(
|
||||||
|
value.id.map((x: string) => (alias ? `${alias}.${x}` : x)),
|
||||||
|
value.values
|
||||||
|
)
|
||||||
|
} else if (!opts.relationship && !isRelationshipField) {
|
||||||
const alias = getTableAlias(tableName)
|
const alias = getTableAlias(tableName)
|
||||||
fn(alias ? `${alias}.${updatedKey}` : updatedKey, value)
|
fn(alias ? `${alias}.${updatedKey}` : updatedKey, value)
|
||||||
} else if (opts.relationship && isRelationshipField) {
|
} else if (opts.relationship && isRelationshipField) {
|
||||||
|
@ -745,6 +754,9 @@ class InternalBuilder {
|
||||||
|
|
||||||
class SqlQueryBuilder extends SqlTableQueryBuilder {
|
class SqlQueryBuilder extends SqlTableQueryBuilder {
|
||||||
private readonly limit: number
|
private readonly limit: number
|
||||||
|
|
||||||
|
public static COMPLEX_ID_OPERATOR = COMPLEX_ID_OPERATOR
|
||||||
|
|
||||||
// pass through client to get flavour of SQL
|
// pass through client to get flavour of SQL
|
||||||
constructor(client: string, limit: number = BASE_LIMIT) {
|
constructor(client: string, limit: number = BASE_LIMIT) {
|
||||||
super(client)
|
super(client)
|
||||||
|
|
|
@ -40,7 +40,7 @@ import {
|
||||||
} from "../../../sdk/app/rows/utils"
|
} from "../../../sdk/app/rows/utils"
|
||||||
import { processObjectSync } from "@budibase/string-templates"
|
import { processObjectSync } from "@budibase/string-templates"
|
||||||
import { cloneDeep } from "lodash/fp"
|
import { cloneDeep } from "lodash/fp"
|
||||||
import { db as dbCore } from "@budibase/backend-core"
|
import { db as dbCore, sql } from "@budibase/backend-core"
|
||||||
import sdk from "../../../sdk"
|
import sdk from "../../../sdk"
|
||||||
import env from "../../../environment"
|
import env from "../../../environment"
|
||||||
import { makeExternalQuery } from "../../../integrations/base/query"
|
import { makeExternalQuery } from "../../../integrations/base/query"
|
||||||
|
@ -193,11 +193,26 @@ export class ExternalRequest<T extends Operation> {
|
||||||
for (let field of Object.keys(operator || {})) {
|
for (let field of Object.keys(operator || {})) {
|
||||||
if (dbCore.removeKeyNumbering(field) === "_id") {
|
if (dbCore.removeKeyNumbering(field) === "_id") {
|
||||||
if (primary) {
|
if (primary) {
|
||||||
const parts = breakRowIdField(operator[field])
|
let idField = operator[field]
|
||||||
for (let field of primary) {
|
try {
|
||||||
operator[`${prefix}:${field}`] = parts.shift()
|
// Make sure _id queries decode the Row IDs
|
||||||
|
idField = JSON.parse(idField)
|
||||||
|
} catch {
|
||||||
|
// It is not a JSON value
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts = breakRowIdField(idField)
|
||||||
|
if (primary.length > 1) {
|
||||||
|
operator[sql.Sql.COMPLEX_ID_OPERATOR] = {
|
||||||
|
id: primary,
|
||||||
|
values: parts,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (let field of primary) {
|
||||||
|
operator[`${prefix}:${field}`] = parts.shift()
|
||||||
|
}
|
||||||
|
prefix++
|
||||||
}
|
}
|
||||||
prefix++
|
|
||||||
}
|
}
|
||||||
// make sure this field doesn't exist on any filter
|
// make sure this field doesn't exist on any filter
|
||||||
delete operator[field]
|
delete operator[field]
|
||||||
|
|
|
@ -1428,22 +1428,6 @@ describe.each([
|
||||||
expect(row._id).toEqual(existing._id)
|
expect(row._id).toEqual(existing._id)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should return an error on composite keys", async () => {
|
|
||||||
const existing = await config.api.row.save(table._id!, {})
|
|
||||||
await config.api.row.exportRows(
|
|
||||||
table._id!,
|
|
||||||
{
|
|
||||||
rows: [`['${existing._id!}']`, "['d001', '10111']"],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
status: 400,
|
|
||||||
body: {
|
|
||||||
message: "Export data does not support composite keys.",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
it("should return an error if no table is found", async () => {
|
it("should return an error if no table is found", async () => {
|
||||||
const existing = await config.api.row.save(table._id!, {})
|
const existing = await config.api.row.save(table._id!, {})
|
||||||
await config.api.row.exportRows(
|
await config.api.row.exportRows(
|
||||||
|
@ -1453,7 +1437,7 @@ describe.each([
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
it("can export rows with composite primary keys", async () => {
|
it("should handle filtering by composite primary keys", async () => {
|
||||||
const tableRequest = saveTableRequest({
|
const tableRequest = saveTableRequest({
|
||||||
primary: ["number", "string"],
|
primary: ["number", "string"],
|
||||||
schema: {
|
schema: {
|
||||||
|
|
|
@ -158,10 +158,7 @@ export async function exportRows(
|
||||||
_id: rowIds.map((row: string) => {
|
_id: rowIds.map((row: string) => {
|
||||||
const ids = breakRowIdField(row)
|
const ids = breakRowIdField(row)
|
||||||
if (ids.length > 1) {
|
if (ids.length > 1) {
|
||||||
throw new HTTPError(
|
return ids
|
||||||
"Export data does not support composite keys.",
|
|
||||||
400
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
return ids[0]
|
return ids[0]
|
||||||
}),
|
}),
|
||||||
|
|
Loading…
Reference in New Issue