diff --git a/packages/backend-core/src/sql/sql.ts b/packages/backend-core/src/sql/sql.ts index 5a6907faa0..334f1efdd4 100644 --- a/packages/backend-core/src/sql/sql.ts +++ b/packages/backend-core/src/sql/sql.ts @@ -1172,20 +1172,22 @@ class InternalBuilder { nulls = value.direction === SortOrder.ASCENDING ? "first" : "last" } + const composite = `${aliased}.${key}` + let identifier + if (this.isAggregateField(key)) { - query = query.orderBy(key, direction, nulls) + identifier = this.rawQuotedIdentifier(key) + } else if (this.client === SqlClient.ORACLE) { + identifier = this.convertClobs(composite) } else { - let composite = `${aliased}.${key}` - if (this.client === SqlClient.ORACLE) { - query = query.orderByRaw(`?? ?? nulls ??`, [ - this.convertClobs(composite), - this.knex.raw(direction), - this.knex.raw(nulls as string), - ]) - } else { - query = query.orderBy(composite, direction, nulls) - } + identifier = this.rawQuotedIdentifier(composite) } + + query = query.orderByRaw(`?? ?? ${nulls ? "nulls ??" : ""}`, [ + identifier, + this.knex.raw(direction), + ...(nulls ? [this.knex.raw(nulls as string)] : []), + ]) } } @@ -1344,14 +1346,16 @@ class InternalBuilder { // add the correlation to the overall query subQuery = subQuery.where( - correlatedTo, + this.rawQuotedIdentifier(correlatedTo), "=", this.rawQuotedIdentifier(correlatedFrom) ) const standardWrap = (select: Knex.Raw): Knex.QueryBuilder => { subQuery = subQuery - .select(relationshipFields) + .select( + relationshipFields.map(field => this.rawQuotedIdentifier(field)) + ) .limit(getRelationshipLimit()) // @ts-ignore - the from alias syntax isn't in Knex typing return knex.select(select).from({ diff --git a/packages/server/src/api/routes/tests/row.spec.ts b/packages/server/src/api/routes/tests/row.spec.ts index db5fcbaebb..576f0bb663 100644 --- a/packages/server/src/api/routes/tests/row.spec.ts +++ b/packages/server/src/api/routes/tests/row.spec.ts @@ -3650,6 +3650,51 @@ if (descriptions.length) { }) }) + if (isInternal || isMSSQL) { + describe("Fields with spaces", () => { + let table: Table + let otherTable: Table + let relatedRow: Row + + beforeAll(async () => { + otherTable = await config.api.table.save(defaultTable()) + table = await config.api.table.save( + saveTableRequest({ + schema: { + links: { + name: "links", + fieldName: "links", + type: FieldType.LINK, + tableId: otherTable._id!, + relationshipType: RelationshipType.ONE_TO_MANY, + }, + "nameWithSpace ": { + name: "nameWithSpace ", + type: FieldType.STRING, + }, + }, + }) + ) + relatedRow = await config.api.row.save(otherTable._id!, { + name: generator.word(), + description: generator.paragraph(), + }) + await config.api.row.save(table._id!, { + "nameWithSpace ": generator.word(), + tableId: table._id!, + links: [relatedRow._id], + }) + }) + + it("Successfully returns rows that have spaces in their field names", async () => { + const { rows } = await config.api.row.search(table._id!) + expect(rows.length).toBe(1) + const row = rows[0] + expect(row["nameWithSpace "]).toBeDefined() + }) + }) + } + if (!isInternal && !isOracle) { describe("bigint ids", () => { let table1: Table, table2: Table diff --git a/packages/server/src/integrations/microsoftSqlServer.ts b/packages/server/src/integrations/microsoftSqlServer.ts index 477813239b..8548d57f15 100644 --- a/packages/server/src/integrations/microsoftSqlServer.ts +++ b/packages/server/src/integrations/microsoftSqlServer.ts @@ -276,6 +276,7 @@ class SqlServerIntegration extends Sql implements DatasourcePlus { encrypt, enableArithAbort: true, requestTimeout: env.QUERY_THREAD_TIMEOUT, + connectTimeout: env.QUERY_THREAD_TIMEOUT, }, } if (encrypt) {