Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -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 <lenon@athenna.io>",
Expand Down
58 changes: 42 additions & 16 deletions src/models/builders/ModelQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,12 @@ export class ModelQueryBuilder<

const data = await super.find()

this.resetCustomSelect()

if (this.hasCustomSelect) {
return data
}

return this.generator.generateOne(data)
}

Expand Down Expand Up @@ -310,6 +316,12 @@ export class ModelQueryBuilder<

const data = await super.findMany()

this.resetCustomSelect()

if (this.hasCustomSelect) {
return data
}

return this.generator.generateMany(data)
}

Expand All @@ -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
Expand Down Expand Up @@ -618,24 +636,20 @@ export class ModelQueryBuilder<
* Set the columns that should be selected on query.
*/
public select(...columns: ModelColumns<M>[]) {
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
}
Expand Down Expand Up @@ -1274,7 +1288,7 @@ export class ModelQueryBuilder<
addSoftDelete: true
})

if (options.addSelect) {
if (options.addSelect && !this.hasCustomSelect) {
super.select(...this.selectColumns)
}

Expand All @@ -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.
Expand Down
56 changes: 56 additions & 0 deletions tests/unit/models/builders/ModelQueryBuilderTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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']
Expand Down
Loading