Merge pull request #15789 from Budibase/fix/ms-sql-json-columns

MS-SQL JSON column fix
This commit is contained in:
Sam Rose 2025-03-24 10:24:27 +01:00 committed by GitHub
commit d5b1f816bc
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 60 additions and 19 deletions

View File

@ -116,6 +116,15 @@ function stringifyArray(value: any[], quoteStyle = '"'): string {
return `[${value.join(",")}]` return `[${value.join(",")}]`
} }
function isJsonColumn(
field: FieldSchema
): field is JsonFieldMetadata | BBReferenceFieldMetadata {
return (
JsonTypes.includes(field.type) &&
!helpers.schema.isDeprecatedSingleUserColumn(field)
)
}
const allowEmptyRelationships: Record<SearchFilterKey, boolean> = { const allowEmptyRelationships: Record<SearchFilterKey, boolean> = {
[BasicOperator.EQUAL]: false, [BasicOperator.EQUAL]: false,
[BasicOperator.NOT_EQUAL]: true, [BasicOperator.NOT_EQUAL]: true,
@ -179,6 +188,16 @@ class InternalBuilder {
return this.table.schema[column] return this.table.schema[column]
} }
private requiresJsonAsStringClient(): boolean {
const requiresJsonAsString = [
SqlClient.MS_SQL,
SqlClient.MY_SQL,
SqlClient.MARIADB,
SqlClient.ORACLE,
]
return requiresJsonAsString.includes(this.client)
}
private quoteChars(): [string, string] { private quoteChars(): [string, string] {
const wrapped = this.knexClient.wrapIdentifier("foo", {}) const wrapped = this.knexClient.wrapIdentifier("foo", {})
return [wrapped[0], wrapped[wrapped.length - 1]] return [wrapped[0], wrapped[wrapped.length - 1]]
@ -372,6 +391,15 @@ class InternalBuilder {
return null return null
} }
// some database don't allow an object to be passed in
if (
this.requiresJsonAsStringClient() &&
isJsonColumn(schema) &&
typeof input === "object"
) {
return JSON.stringify(input)
}
if ( if (
this.client === SqlClient.ORACLE && this.client === SqlClient.ORACLE &&
schema.type === FieldType.DATETIME && schema.type === FieldType.DATETIME &&
@ -1869,7 +1897,7 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
): T[] { ): T[] {
const tableName = this.getTableName(table, aliases) const tableName = this.getTableName(table, aliases)
for (const [name, field] of Object.entries(table.schema)) { for (const [name, field] of Object.entries(table.schema)) {
if (!this._isJsonColumn(field)) { if (!isJsonColumn(field)) {
continue continue
} }
const fullName = `${tableName}.${name}` as keyof T const fullName = `${tableName}.${name}` as keyof T
@ -1885,15 +1913,6 @@ class SqlQueryBuilder extends SqlTableQueryBuilder {
return results return results
} }
_isJsonColumn(
field: FieldSchema
): field is JsonFieldMetadata | BBReferenceFieldMetadata {
return (
JsonTypes.includes(field.type) &&
!helpers.schema.isDeprecatedSingleUserColumn(field)
)
}
log(query: string, values?: SqlQueryBinding) { log(query: string, values?: SqlQueryBinding) {
sqlLog(this.getSqlClient(), query, values) sqlLog(this.getSqlClient(), query, values)
} }

View File

@ -2196,6 +2196,13 @@ if (descriptions.length) {
}) })
describe("attachments and signatures", () => { describe("attachments and signatures", () => {
function generateAttachment(value: string) {
return {
key: `${config.getAppId()}/attachments/${value}`,
}
}
const newCsv = () => `${uuid.v4()}.csv`
const coreAttachmentEnrichment = async ( const coreAttachmentEnrichment = async (
schema: TableSchema, schema: TableSchema,
field: string, field: string,
@ -2206,18 +2213,13 @@ if (descriptions.length) {
schema, schema,
}) })
) )
const attachmentToStoreKey = (attachmentId: string) => {
return {
key: `${config.getAppId()}/attachments/${attachmentId}`,
}
}
const draftRow = { const draftRow = {
name: "test", name: "test",
description: "test", description: "test",
[field]: [field]:
typeof attachmentCfg === "string" typeof attachmentCfg === "string"
? attachmentToStoreKey(attachmentCfg) ? generateAttachment(attachmentCfg)
: attachmentCfg.map(attachmentToStoreKey), : attachmentCfg.map(generateAttachment),
tableId: testTable._id, tableId: testTable._id,
} }
const row = await config.api.row.save(testTable._id!, draftRow) const row = await config.api.row.save(testTable._id!, draftRow)
@ -2238,6 +2240,7 @@ if (descriptions.length) {
} }
}) })
}) })
return { row, table: testTable }
} }
it("should allow enriching single attachment rows", async () => { it("should allow enriching single attachment rows", async () => {
@ -2250,10 +2253,29 @@ if (descriptions.length) {
}, },
}, },
"attachment", "attachment",
`${uuid.v4()}.csv` newCsv()
) )
}) })
it("should allow updating single attachment row", async () => {
const { row, table } = await coreAttachmentEnrichment(
{
attachment: {
type: FieldType.ATTACHMENT_SINGLE,
name: "attachment",
constraints: { presence: false },
},
},
"attachment",
newCsv()
)
const newAttachment = generateAttachment(newCsv())
row["attachment"] = newAttachment
const updated = await config.api.row.save(table._id!, row)
expect(updated.attachment.key).toBe(newAttachment.key)
})
it("should allow enriching attachment list rows", async () => { it("should allow enriching attachment list rows", async () => {
await coreAttachmentEnrichment( await coreAttachmentEnrichment(
{ {
@ -2264,7 +2286,7 @@ if (descriptions.length) {
}, },
}, },
"attachments", "attachments",
[`${uuid.v4()}.csv`] [newCsv()]
) )
}) })