diff --git a/packages/backend-core/src/sql/sql.ts b/packages/backend-core/src/sql/sql.ts index 7791ecb28b..937f88c846 100644 --- a/packages/backend-core/src/sql/sql.ts +++ b/packages/backend-core/src/sql/sql.ts @@ -116,6 +116,15 @@ function stringifyArray(value: any[], quoteStyle = '"'): string { return `[${value.join(",")}]` } +function isJsonColumn( + field: FieldSchema +): field is JsonFieldMetadata | BBReferenceFieldMetadata { + return ( + JsonTypes.includes(field.type) && + !helpers.schema.isDeprecatedSingleUserColumn(field) + ) +} + const allowEmptyRelationships: Record = { [BasicOperator.EQUAL]: false, [BasicOperator.NOT_EQUAL]: true, @@ -179,6 +188,16 @@ class InternalBuilder { 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] { const wrapped = this.knexClient.wrapIdentifier("foo", {}) return [wrapped[0], wrapped[wrapped.length - 1]] @@ -372,6 +391,15 @@ class InternalBuilder { 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 ( this.client === SqlClient.ORACLE && schema.type === FieldType.DATETIME && @@ -1869,7 +1897,7 @@ class SqlQueryBuilder extends SqlTableQueryBuilder { ): T[] { const tableName = this.getTableName(table, aliases) for (const [name, field] of Object.entries(table.schema)) { - if (!this._isJsonColumn(field)) { + if (!isJsonColumn(field)) { continue } const fullName = `${tableName}.${name}` as keyof T @@ -1885,15 +1913,6 @@ class SqlQueryBuilder extends SqlTableQueryBuilder { return results } - _isJsonColumn( - field: FieldSchema - ): field is JsonFieldMetadata | BBReferenceFieldMetadata { - return ( - JsonTypes.includes(field.type) && - !helpers.schema.isDeprecatedSingleUserColumn(field) - ) - } - log(query: string, values?: SqlQueryBinding) { sqlLog(this.getSqlClient(), query, values) } diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index e910e5ab55..cf24430f82 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -2196,6 +2196,13 @@ if (descriptions.length) { }) describe("attachments and signatures", () => { + function generateAttachment(value: string) { + return { + key: `${config.getAppId()}/attachments/${value}`, + } + } + const newCsv = () => `${uuid.v4()}.csv` + const coreAttachmentEnrichment = async ( schema: TableSchema, field: string, @@ -2206,18 +2213,13 @@ if (descriptions.length) { schema, }) ) - const attachmentToStoreKey = (attachmentId: string) => { - return { - key: `${config.getAppId()}/attachments/${attachmentId}`, - } - } const draftRow = { name: "test", description: "test", [field]: typeof attachmentCfg === "string" - ? attachmentToStoreKey(attachmentCfg) - : attachmentCfg.map(attachmentToStoreKey), + ? generateAttachment(attachmentCfg) + : attachmentCfg.map(generateAttachment), tableId: testTable._id, } 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 () => { @@ -2250,10 +2253,29 @@ if (descriptions.length) { }, }, "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 () => { await coreAttachmentEnrichment( { @@ -2264,7 +2286,7 @@ if (descriptions.length) { }, }, "attachments", - [`${uuid.v4()}.csv`] + [newCsv()] ) })