Skip to content

Commit

Permalink
Merge pull request #118 from AthennaIO/develop
Browse files Browse the repository at this point in the history
feat(driver): add exists method
  • Loading branch information
jlenon7 authored Dec 29, 2023
2 parents e239315 + eddd32b commit 40ce18e
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 41 deletions.
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": "4.14.1",
"version": "4.14.2",
"description": "The Athenna database handler for SQL/NoSQL.",
"license": "MIT",
"author": "João Lenon <lenon@athenna.io>",
Expand Down
29 changes: 20 additions & 9 deletions src/database/builders/QueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

import type { Operations } from '#src/types/Operations'
import type { Direction, ModelColumns } from '#src/types'
import type { Driver as DriverImpl } from '#src/database/drivers/Driver'
import type { Collection, PaginatedResponse } from '@athenna/common'
import type { Driver as DriverImpl } from '#src/database/drivers/Driver'

export class QueryBuilder<T = any, Driver extends DriverImpl = any> {
/**
Expand Down Expand Up @@ -144,6 +144,13 @@ export class QueryBuilder<T = any, Driver extends DriverImpl = any> {
return this.driver.find()
}

/**
* Find a value in database and return as boolean.
*/
public async exists(): Promise<boolean> {
return this.driver.exists()
}

/**
* Find many values in database.
*/
Expand Down Expand Up @@ -172,29 +179,33 @@ export class QueryBuilder<T = any, Driver extends DriverImpl = any> {
/**
* Create a value in database.
*/
public async create(data?: Partial<T>): Promise<T> {
return this.driver.create(data)
public async create(data?: Partial<T> | ModelColumns<T>): Promise<T> {
return this.driver.create(data as Partial<T>)
}

/**
* Create many values in database.
*/
public async createMany(data?: Partial<T>[]): Promise<T[]> {
return this.driver.createMany(data)
public async createMany(
data?: Partial<T>[] | ModelColumns<T>[]
): Promise<T[]> {
return this.driver.createMany(data as Partial<T>[])
}

/**
* Create data or update if already exists.
*/
public async createOrUpdate(data?: Partial<T>): Promise<T | T[]> {
return this.driver.createOrUpdate(data)
public async createOrUpdate(
data?: Partial<T> | ModelColumns<T>
): Promise<T | T[]> {
return this.driver.createOrUpdate(data as Partial<T>)
}

/**
* Update data in database.
*/
public async update(data: Partial<T>): Promise<T | T[]> {
return this.driver.update(data)
public async update(data: Partial<T> | ModelColumns<T>): Promise<T | T[]> {
return this.driver.update(data as Partial<T>)
}

/**
Expand Down
9 changes: 9 additions & 0 deletions src/database/drivers/Driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,15 @@ export abstract class Driver<Client = any, QB = any> {
*/
public abstract countDistinct(column?: string): Promise<string>

/**
* Find a value in database and return as boolean.
*/
public async exists(): Promise<boolean> {
const data = await this.find()

return !!data
}

/**
* Find a value in database or throw exception if undefined.
*/
Expand Down
7 changes: 7 additions & 0 deletions src/database/drivers/FakeDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,13 @@ export class FakeDriver {
return {}
}

/**
* Find a value in database.
*/
public static async exists(): Promise<boolean> {
return true
}

/**
* Find a value in database or fail.
*/
Expand Down
1 change: 0 additions & 1 deletion src/database/drivers/MongoDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,6 @@ export class MongoDriver extends Driver<Connection, Collection> {
await this.client.dropCollection(table)
} catch (err) {
debug('error happened while dropping table %s in MongoDriver: %o', err)
console.log('error while dropping table ' + table, err)
}
}

Expand Down
8 changes: 4 additions & 4 deletions src/factories/ConnectionFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export class ConnectionFactory {
* Create the connection with a mysql database.
*/
// TODO Don't use connection here. Pass connection
// configs in here instead.
// configs instead.
public static mysql(con: string): Knex {
const client = this.knex(con, 'mysql2')

Expand All @@ -86,7 +86,7 @@ export class ConnectionFactory {
* Create the connection with a mongo database.
*/
// TODO Don't use connection here. Pass connection
// configs in here instead.
// configs instead.
public static mongo(con: string): Connection {
const client = this.mongoose(con)

Expand All @@ -99,7 +99,7 @@ export class ConnectionFactory {
* Create the connection with a sqlite database.
*/
// TODO Don't use connection here. Pass connection
// configs in here instead.
// configs instead.
public static sqlite(con: string): Knex {
const client = this.knex(con, 'better-sqlite3')

Expand All @@ -112,7 +112,7 @@ export class ConnectionFactory {
* Create the connection with a postgres database.
*/
// TODO Don't use connection here. Pass connection
// configs in here instead.
// configs instead.
public static postgres(con: string): Knex {
const client = this.knex(con, 'pg')

Expand Down
50 changes: 33 additions & 17 deletions src/models/BaseModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

import equal from 'fast-deep-equal'
import { Database } from '#src/facades/Database'
import type { ModelRelations } from '#src/types'
import type { ModelColumns, ModelRelations } from '#src/types'
import { faker, type Faker } from '@faker-js/faker'
import { ModelSchema } from '#src/models/schemas/ModelSchema'
import { Collection, Is, Json, String } from '@athenna/common'
Expand Down Expand Up @@ -156,7 +156,7 @@ export class BaseModel {
*/
public static async find<T extends typeof BaseModel>(
this: T,
where?: Partial<InstanceType<T>>
where?: Partial<ModelColumns<T>>
): Promise<InstanceType<T>> {
const query = this.query()

Expand All @@ -167,12 +167,28 @@ export class BaseModel {
return query.find()
}

/**
* Find a value in database.
*/
public static async exists<T extends typeof BaseModel>(
this: T,
where?: Partial<ModelColumns<T>>
): Promise<boolean> {
const query = this.query()

if (where) {
query.where(where)
}

return query.exists()
}

/**
* Find a value in database or throw exception if undefined.
*/
public static async findOrFail<T extends typeof BaseModel>(
this: T,
where?: Partial<InstanceType<T>>
where?: Partial<ModelColumns<T>>
): Promise<InstanceType<T>> {
const query = this.query()

Expand All @@ -189,7 +205,7 @@ export class BaseModel {
*/
public static async findOr<T extends typeof BaseModel>(
this: T,
where: Partial<InstanceType<T>>,
where: Partial<ModelColumns<T>>,
closure: () => any | Promise<any>
): Promise<InstanceType<T> | any> {
const query = this.query()
Expand All @@ -206,7 +222,7 @@ export class BaseModel {
*/
public static async findMany<T extends typeof BaseModel>(
this: T,
where?: Partial<InstanceType<T>>
where?: Partial<ModelColumns<T>>
): Promise<InstanceType<T>[]> {
const query = this.query()

Expand All @@ -223,7 +239,7 @@ export class BaseModel {
*/
public static async collection<T extends typeof BaseModel>(
this: T,
where?: Partial<InstanceType<T>>
where?: Partial<ModelColumns<T>>
): Promise<Collection<InstanceType<T>>> {
const query = this.query()

Expand All @@ -239,61 +255,61 @@ export class BaseModel {
*/
public static async create<T extends typeof BaseModel>(
this: T,
data: Partial<InstanceType<T>> = {}
data: Partial<ModelColumns<T>> = {}
): Promise<InstanceType<T>> {
return this.query().create(data)
return this.query().create(data as any)
}

/**
* Create many values in database.
*/
public static async createMany<T extends typeof BaseModel>(
this: T,
data: Partial<InstanceType<T>>[]
data: Partial<ModelColumns<T>>[]
): Promise<InstanceType<T>[]> {
return this.query().createMany(data)
return this.query().createMany(data as any[])
}

/**
* Create or update a value in database.
*/
public static async createOrUpdate<T extends typeof BaseModel>(
this: T,
where: Partial<InstanceType<T>>,
data: Partial<InstanceType<T>>
where: Partial<ModelColumns<T>>,
data: Partial<ModelColumns<T>>
): Promise<InstanceType<T> | InstanceType<T>[]> {
const query = this.query()

if (where) {
query.where(where)
}

return query.createOrUpdate(data)
return query.createOrUpdate(data as any)
}

/**
* Update a value in database.
*/
public static async update<T extends typeof BaseModel>(
this: T,
where: Partial<InstanceType<T>>,
data: Partial<InstanceType<T>>
where: Partial<ModelColumns<T>>,
data: Partial<ModelColumns<T>>
): Promise<InstanceType<T> | InstanceType<T>[]> {
const query = this.query()

if (where) {
query.where(where)
}

return query.update(data)
return query.update(data as any)
}

/**
* Delete or soft delete a value in database.
*/
public static async delete<T extends typeof BaseModel>(
this: T,
where: Partial<InstanceType<T>>,
where: Partial<ModelColumns<T>>,
force = false
): Promise<void> {
const query = this.query()
Expand Down
16 changes: 8 additions & 8 deletions src/models/builders/ModelQueryBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import type {
ModelRelations
} from '#src/types'
import { Collection, Is } from '@athenna/common'
import type { Driver } from '#src/database/drivers/Driver'
import type { BaseModel } from '#src/models/BaseModel'
import type { Driver } from '#src/database/drivers/Driver'
import { QueryBuilder } from '#src/database/builders/QueryBuilder'
import type { ModelSchema } from '#src/models/schemas/ModelSchema'
import { ModelGenerator } from '#src/models/factories/ModelGenerator'
Expand Down Expand Up @@ -209,7 +209,7 @@ export class ModelQueryBuilder<
/**
* Create a value in database.
*/
public async create(data: Partial<M> = {}) {
public async create(data: ModelColumns<M> = {} as any) {
const created = await this.createMany([data])

return created[0]
Expand All @@ -218,8 +218,8 @@ export class ModelQueryBuilder<
/**
* Create many values in database.
*/
public async createMany(data: Partial<M>[]) {
data = await Promise.all(
public async createMany(data: ModelColumns<M>[]) {
data = (await Promise.all(
data.map(async d => {
const date = new Date()
const createdAt = this.schema.getCreatedAtColumn()
Expand Down Expand Up @@ -249,7 +249,7 @@ export class ModelQueryBuilder<

return parsed
})
)
)) as any[]

const created = await super.createMany(data)

Expand All @@ -268,7 +268,7 @@ export class ModelQueryBuilder<
return this.where(pk, hasValue[pk as any]).update(data)
}

return this.create(data)
return this.create(data as any)
}

/**
Expand Down Expand Up @@ -972,9 +972,9 @@ export class ModelQueryBuilder<
}
}

const isDuplicated = !!(await this.Model.query()
const isDuplicated = await this.Model.query()
.where(column.name as never, value)
.find())
.exists()

if (isDuplicated) {
records[column.property] = value
Expand Down
6 changes: 5 additions & 1 deletion src/models/schemas/ModelSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ export class ModelSchema<M extends BaseModel = any> {
* column names.
*/
public propertiesToColumnNames(
data: Partial<M>,
data: Partial<M> | ModelColumns<M>,
options: { attributes?: Record<string, any>; cleanPersist?: boolean } = {}
) {
options = Options.create(options, {
Expand All @@ -144,6 +144,10 @@ export class ModelSchema<M extends BaseModel = any> {
return
}

if (data[key] === undefined) {
return
}

if (ObjectId.isValidString(data[key])) {
data[key] = new ObjectId(data[key])
}
Expand Down
10 changes: 10 additions & 0 deletions tests/unit/drivers/MongoDriverTest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,16 @@ export default class MongoDriverTest {
assert.containsSubset(result, data)
}

@Test()
public async shouldBeAbleToValidateThatDataExistsUsingDriver({ assert }: Context) {
const data = { _id: '1', name: 'Charles Babbage' }
await this.driver.table('users').create(data)

const result = await this.driver.table('users').exists()

assert.isTrue(result)
}

@Test()
public async shouldReturnUndefinedWhenFindMethodCantFindNothing({ assert }: Context) {
const result = await this.driver.table('users').find()
Expand Down
Loading

0 comments on commit 40ce18e

Please sign in to comment.