From 3cda45aee69d3996775a7dba5938e4b39b19f59a Mon Sep 17 00:00:00 2001 From: jlenon7 Date: Thu, 30 Apr 2026 15:49:48 -0300 Subject: [PATCH] fix: stop reseting select on selectRaw --- package-lock.json | 4 +- package.json | 2 +- src/models/builders/ModelQueryBuilder.ts | 58 ++++++++++++++----- .../models/builders/ModelQueryBuilderTest.ts | 56 ++++++++++++++++++ 4 files changed, 101 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index e436b8e..1064ca8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@athenna/database", - "version": "5.47.0", + "version": "5.48.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@athenna/database", - "version": "5.47.0", + "version": "5.48.0", "license": "MIT", "dependencies": { "@faker-js/faker": "^8.4.1" diff --git a/package.json b/package.json index 523e184..8343eb9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@athenna/database", - "version": "5.47.0", + "version": "5.48.0", "description": "The Athenna database handler for SQL/NoSQL.", "license": "MIT", "author": "João Lenon ", diff --git a/src/models/builders/ModelQueryBuilder.ts b/src/models/builders/ModelQueryBuilder.ts index 0b45593..722f67a 100644 --- a/src/models/builders/ModelQueryBuilder.ts +++ b/src/models/builders/ModelQueryBuilder.ts @@ -248,6 +248,12 @@ export class ModelQueryBuilder< const data = await super.find() + this.resetCustomSelect() + + if (this.hasCustomSelect) { + return data + } + return this.generator.generateOne(data) } @@ -310,6 +316,12 @@ export class ModelQueryBuilder< const data = await super.findMany() + this.resetCustomSelect() + + if (this.hasCustomSelect) { + return data + } + return this.generator.generateMany(data) } @@ -325,6 +337,12 @@ export class ModelQueryBuilder< const data = await super.paginate(page, limit, resourceUrl) + this.resetCustomSelect() + + if (this.hasCustomSelect) { + return data + } + data.data = await this.generator.generateMany(data.data) return data @@ -618,24 +636,20 @@ export class ModelQueryBuilder< * Set the columns that should be selected on query. */ public select(...columns: ModelColumns[]) { - if (!this.hasCustomSelect) { - this.hasCustomSelect = true - this.selectColumns = columns.map(c => - this.schema.getColumnNameByProperty(c) - ) + const selectColumns = this.schema.getColumnNamesByProperties(columns) - return this - } - - columns.forEach(column => { - const index = this.selectColumns.indexOf(column) + super.select(...selectColumns) + this.hasCustomSelect = true - if (index) { - return - } + return this + } - this.selectColumns.push(this.schema.getColumnNameByProperty(column)) - }) + /** + * Set the columns that should be selected on query raw. + */ + public selectRaw(sql: string, bindings?: any) { + super.selectRaw(sql, bindings) + this.hasCustomSelect = true return this } @@ -1274,7 +1288,7 @@ export class ModelQueryBuilder< addSoftDelete: true }) - if (options.addSelect) { + if (options.addSelect && !this.hasCustomSelect) { super.select(...this.selectColumns) } @@ -1285,6 +1299,18 @@ export class ModelQueryBuilder< } } + /** + * Reset select state after terminal custom select queries. + */ + private resetCustomSelect() { + if (!this.hasCustomSelect) { + return + } + + this.hasCustomSelect = false + this.selectColumns = this.schema.getAllColumnNames() + } + /** * Verify that columns with `isNullable` property * can be created in database. diff --git a/tests/unit/models/builders/ModelQueryBuilderTest.ts b/tests/unit/models/builders/ModelQueryBuilderTest.ts index 330d203..d2cee41 100644 --- a/tests/unit/models/builders/ModelQueryBuilderTest.ts +++ b/tests/unit/models/builders/ModelQueryBuilderTest.ts @@ -1173,6 +1173,62 @@ export default class ModelQueryBuilderTest { assert.calledOnceWith(Database.driver.selectRaw, sql) } + @Test() + public async shouldReturnRawDataWhenFindingWithCustomSelect({ assert }: Context) { + const expectedData = { name: 'John Doe' } + Mock.when(Database.driver, 'find').resolve(expectedData) + Mock.when(Database.driver, 'select').resolve(undefined) + + const result = await User.query().select('name').find() + + assert.calledOnceWith(Database.driver.select, 'name') + assert.deepEqual(result, expectedData) + } + + @Test() + public async shouldReturnRawDataWhenFindingManyWithCustomSelect({ assert }: Context) { + const expectedData = [{ name: 'John Doe' }, { name: 'Jane Doe' }] + Mock.when(Database.driver, 'findMany').resolve(expectedData) + Mock.when(Database.driver, 'select').resolve(undefined) + + const result = await User.query().select('name').findMany() + + assert.calledOnceWith(Database.driver.select, 'name') + assert.deepEqual(result, expectedData) + } + + @Test() + public async shouldReturnRawDataWhenFindingManyWithRawCustomSelect({ assert }: Context) { + const sql = 'MIN(phone) as phone' + const groupBy = "REGEXP_REPLACE(phone, '[^0-9]', '', 'g')" + const expectedData = [{ phone: '123456789' }] + Mock.when(Database.driver, 'findMany').resolve(expectedData) + Mock.when(Database.driver, 'select').resolve(undefined) + Mock.when(Database.driver, 'selectRaw').resolve(undefined) + Mock.when(Database.driver, 'groupByRaw').resolve(undefined) + Mock.when(Database.driver, 'whereNull').resolve(undefined) + + const result = await User.query().selectRaw(sql).groupByRaw(groupBy).findMany() + + assert.calledOnceWith(Database.driver.selectRaw, sql) + assert.calledOnceWith(Database.driver.groupByRaw, groupBy) + assert.calledOnceWith(Database.driver.whereNull, 'deletedAt') + assert.notCalled(Database.driver.select) + assert.deepEqual(result, expectedData) + } + + @Test() + public async shouldReturnRawPaginatedDataWhenPaginatingWithCustomSelect({ assert }: Context) { + const expectedData = [{ name: 'John Doe' }] + Mock.when(Database.driver, 'findMany').resolve(expectedData) + Mock.when(Database.driver, 'select').resolve(undefined) + + const result = await User.query().select('name').paginate() + + assert.calledOnceWith(Database.driver.select, 'name') + assert.deepEqual(result.data, expectedData) + } + @Test() public async shouldAllowSelectingSpecificColumnsFromTableUsingFrom({ assert }: Context) { const columns: any[] = ['id', 'name']