Skip to content

Commit 277cd1e

Browse files
authored
Merge pull request #198 from AthennaIO/develop
feat: add pluck and pluckMany methods
2 parents 65e908b + a1d1f4b commit 277cd1e

File tree

14 files changed

+273
-3
lines changed

14 files changed

+273
-3
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@athenna/database",
3-
"version": "5.19.0",
3+
"version": "5.20.0",
44
"description": "The Athenna database handler for SQL/NoSQL.",
55
"license": "MIT",
66
"author": "João Lenon <lenon@athenna.io>",

src/database/builders/QueryBuilder.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,24 @@ export class QueryBuilder<
146146
return this.driver.findOr(callback)
147147
}
148148

149+
/**
150+
* Find value in database but returns only the value of
151+
* selected column directly.
152+
*/
153+
public async pluck<K extends keyof T = keyof T>(column: K): Promise<T[K]> {
154+
return this.driver.pluck(column)
155+
}
156+
157+
/**
158+
* Find many values in database but returns only the
159+
* values of selected column directly.
160+
*/
161+
public async pluckMany<K extends keyof T = keyof T>(
162+
column: K
163+
): Promise<T[K][]> {
164+
return this.driver.pluckMany(column)
165+
}
166+
149167
/**
150168
* Find a value in database.
151169
*/

src/database/drivers/Driver.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,30 @@ export abstract class Driver<Client = any, QB = any> {
380380
return data
381381
}
382382

383+
/**
384+
* Find value in database but returns only the value of
385+
* selected column directly.
386+
*/
387+
public async pluck<T = any, K extends keyof T = keyof T>(
388+
column: K
389+
): Promise<T[K]> {
390+
const data = await this.find()
391+
392+
return data[column]
393+
}
394+
395+
/**
396+
* Find many values in database but returns only the
397+
* values of selected column directly.
398+
*/
399+
public async pluckMany<T = any, K extends keyof T = keyof T>(
400+
column: K
401+
): Promise<T[K][]> {
402+
const data = await this.findMany()
403+
404+
return data.map(d => d[column])
405+
}
406+
383407
/**
384408
* Find a value in database.
385409
*/

src/database/drivers/FakeDriver.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,22 @@ export class FakeDriver {
323323
return '1'
324324
}
325325

326+
/**
327+
* Find value in database but returns only the value of
328+
* selected column directly.
329+
*/
330+
public static async pluck(): Promise<any> {
331+
return ''
332+
}
333+
334+
/**
335+
* Find many values in database but returns only the
336+
* values of selected column directly.
337+
*/
338+
public static async pluckMany(): Promise<any> {
339+
return ['']
340+
}
341+
326342
/**
327343
* Find a value in database.
328344
*/

src/models/BaseModel.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,48 @@ export class BaseModel {
197197
await Database.connection(this.connection()).truncate(this.table())
198198
}
199199

200+
/**
201+
* Find value in database but returns only the value of
202+
* selected column directly.
203+
*/
204+
public static async pluck<
205+
T extends typeof BaseModel,
206+
K extends keyof InstanceType<T> = keyof InstanceType<T>
207+
>(
208+
this: T,
209+
key: K,
210+
where?: Partial<InstanceType<T>>
211+
): Promise<InstanceType<T>[K]> {
212+
const query = this.query()
213+
214+
if (where) {
215+
query.where(where)
216+
}
217+
218+
return query.pluck(key)
219+
}
220+
221+
/**
222+
* Find many values in database but returns only the
223+
* values of selected column directly.
224+
*/
225+
public static async pluckMany<
226+
T extends typeof BaseModel,
227+
K extends keyof InstanceType<T> = keyof InstanceType<T>
228+
>(
229+
this: T,
230+
key: K,
231+
where?: Partial<InstanceType<T>>
232+
): Promise<InstanceType<T>[K][]> {
233+
const query = this.query()
234+
235+
if (where) {
236+
query.where(where)
237+
}
238+
239+
return query.pluckMany(key)
240+
}
241+
200242
/**
201243
* Find a value in database.
202244
*/

src/models/builders/ModelQueryBuilder.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,34 @@ export class ModelQueryBuilder<
181181
return super.countDistinct(name as any)
182182
}
183183

184+
/**
185+
* Find value in database but returns only the value of
186+
* selected column directly.
187+
*/
188+
public async pluck<K extends keyof M = ModelColumns<M>>(
189+
column: K
190+
): Promise<M[K]> {
191+
this.setInternalQueries()
192+
193+
const columnName: any = this.schema.getColumnNameByProperty(column as any)
194+
195+
return super.pluck(columnName)
196+
}
197+
198+
/**
199+
* Find many values in database but returns only the
200+
* values of selected column directly.
201+
*/
202+
public async pluckMany<K extends keyof M = ModelColumns<M>>(
203+
column: K
204+
): Promise<M[K][]> {
205+
this.setInternalQueries()
206+
207+
const columnName: any = this.schema.getColumnNameByProperty(column as any)
208+
209+
return super.pluckMany(columnName)
210+
}
211+
184212
/**
185213
* Find a value in database.
186214
*/

tests/unit/database/builders/QueryBuilderTest.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,30 @@ export default class QueryBuilderTest {
228228
assert.deepEqual(result, expectedData)
229229
}
230230

231+
@Test()
232+
public async shouldBeAbleToPluckData({ assert }: Context) {
233+
const expectedData = 'John Doe'
234+
Mock.when(FakeDriver, 'pluck').resolve(expectedData)
235+
236+
const queryBuilder = new QueryBuilder(FakeDriver, 'users')
237+
const result = await queryBuilder.pluck('name')
238+
239+
assert.calledOnce(FakeDriver.pluck)
240+
assert.deepEqual(result, 'John Doe')
241+
}
242+
243+
@Test()
244+
public async shouldBeAbleToPluckManyData({ assert }: Context) {
245+
const expectedData = ['John Doe', 'Jane Doe']
246+
Mock.when(FakeDriver, 'pluckMany').resolve(expectedData)
247+
248+
const queryBuilder = new QueryBuilder(FakeDriver, 'users')
249+
const result = await queryBuilder.pluckMany('name')
250+
251+
assert.calledOnce(FakeDriver.pluckMany)
252+
assert.deepEqual(result, ['John Doe', 'Jane Doe'])
253+
}
254+
231255
@Test()
232256
public async shouldBeAbleToFindManyDataUsingCollection({ assert }: Context) {
233257
const expectedData = [

tests/unit/drivers/MongoDriverTest.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -659,6 +659,26 @@ export default class MongoDriverTest {
659659
assert.containsSubset(result, data)
660660
}
661661

662+
@Test()
663+
public async shouldBeAbleToPluckDataUsingDriver({ assert }: Context) {
664+
const data = { _id: '1', name: 'Charles Babbage' }
665+
await this.driver.table('users').create(data)
666+
667+
const result = await this.driver.table('users').pluck('name')
668+
669+
assert.containsSubset(result, 'Charles Babbage')
670+
}
671+
672+
@Test()
673+
public async shouldBeAbleToPluckManyDataUsingDriver({ assert }: Context) {
674+
const data = [{ _id: '1', name: 'Charles Babbage' }]
675+
await this.driver.table('users').createMany(data)
676+
677+
const result = await this.driver.table('users').pluckMany('name')
678+
679+
assert.containsSubset(result, ['Charles Babbage'])
680+
}
681+
662682
@Test()
663683
public async shouldReturnEmptyArrayWhenFindManyMethodCantFindNothing({ assert }: Context) {
664684
const result = await this.driver.table('users').findMany()

tests/unit/drivers/MySqlDriverTest.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,26 @@ export default class MySqlDriverTest {
708708
assert.containsSubset(result, data)
709709
}
710710

711+
@Test()
712+
public async shouldBeAbleToPluckDataUsingDriver({ assert }: Context) {
713+
const data = { id: '1', name: 'Charles Babbage' }
714+
await this.driver.table('users').create(data)
715+
716+
const result = await this.driver.table('users').pluck('name')
717+
718+
assert.containsSubset(result, 'Charles Babbage')
719+
}
720+
721+
@Test()
722+
public async shouldBeAbleToPluckManyDataUsingDriver({ assert }: Context) {
723+
const data = [{ id: '1', name: 'Charles Babbage' }]
724+
await this.driver.table('users').createMany(data)
725+
726+
const result = await this.driver.table('users').pluckMany('name')
727+
728+
assert.containsSubset(result, ['Charles Babbage'])
729+
}
730+
711731
@Test()
712732
public async shouldReturnEmptyArrayWhenFindManyMethodCantFindNothing({ assert }: Context) {
713733
const result = await this.driver.table('users').findMany()

0 commit comments

Comments
 (0)