Skip to content

Commit

Permalink
feat(core): transactions, models, criterias and relations
Browse files Browse the repository at this point in the history
  • Loading branch information
jlenon7 committed Aug 23, 2022
1 parent d951c49 commit 8217ff5
Show file tree
Hide file tree
Showing 21 changed files with 2,153 additions and 124 deletions.
13 changes: 7 additions & 6 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
},
"dependencies": {
"@athenna/artisan": "1.3.6",
"@faker-js/faker": "7.4.0",
"@secjs/utils": "1.9.7",
"pg": "8.7.3",
"typeorm": "0.3.7",
Expand Down
167 changes: 125 additions & 42 deletions src/Drivers/PostgresDriver.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
/**
* @athenna/database
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { Table } from 'typeorm'
import { Is } from '@secjs/utils'
import { Exec, Is } from '@secjs/utils'

import { Transaction } from '#src/index'
import { DriverFactory } from '#src/Factories/DriverFactory'
Expand All @@ -15,6 +24,13 @@ export class PostgresDriver {
*/
#isConnected = false

/**
* The TypeORM data source.
*
* @type {import('typeorm').DataSource|null}
*/
#dataSource = null

/**
* The query runner responsible to handle database operations.
*
Expand Down Expand Up @@ -64,6 +80,13 @@ export class PostgresDriver {
*/
#select = []

/**
* The add select queries done to this instance.
*
* @type {string[]}
*/
#addSelect = []

/**
* The skip value done to this instance.
*
Expand All @@ -90,14 +113,26 @@ export class PostgresDriver {
*
* @param {string|any} connection
* @param {any} configs
* @param {import('typeorm').QueryRunner} [client]
* @param {import('typeorm').DataSource} [dataSource]
* @return {Database}
*/
constructor(connection, configs = {}, client = null) {
constructor(connection, configs = {}, dataSource = null) {
this.#configs = configs
this.#connection = connection

this.#client = client
if (dataSource) {
this.#dataSource = dataSource
this.#client = this.#dataSource.createQueryRunner()
}
}

/**
* Return the TypeORM data source.
*
* @return {import('typeorm').DataSource|null}
*/
getDataSource() {
return this.#dataSource
}

/**
Expand All @@ -112,14 +147,14 @@ export class PostgresDriver {
return
}

this.#client = (
await DriverFactory.createConnectionByDriver(
'postgres',
this.#connection,
this.#configs,
saveOnDriver,
)
).createQueryRunner()
this.#dataSource = await DriverFactory.createConnectionByDriver(
'postgres',
this.#connection,
this.#configs,
saveOnDriver,
)

this.#client = this.#dataSource.createQueryRunner()

this.#isConnected = true
}
Expand Down Expand Up @@ -153,23 +188,17 @@ export class PostgresDriver {
}

/** @type {import('typeorm').SelectQueryBuilder} */
let query = null

if (Is.String(this.#table)) {
query = this.#client.manager.createQueryBuilder().from(this.#table)
} else {
query = this.#client.manager.createQueryBuilder(
this.#table,
this.#table.name,
)
}
const query = this.#client.manager
.getRepository(this.#table)
.createQueryBuilder(this.#table)

if (!fullQuery) {
return query
}

this.#setRelationsOnQuery(query)
this.#setSelectOnQuery(query)
this.#setAddSelectOnQuery(query)
this.#setWhereOnQuery(query)
this.#setOrderByOnQuery(query)

Expand All @@ -190,15 +219,9 @@ export class PostgresDriver {
* @return {Promise<Transaction>}
*/
async startTransaction() {
const client = await this.#client.connection.createQueryRunner()

await client.startTransaction()
await this.#client.startTransaction()

const driver = new PostgresDriver(this.#connection, this.#configs, client)

driver.buildTable(this.#table)

return new Transaction(driver)
return new Transaction(this)
}

/**
Expand All @@ -209,6 +232,8 @@ export class PostgresDriver {
async commitTransaction() {
await this.#client.commitTransaction()
await this.#client.release()

this.#client = this.#dataSource.createQueryRunner()
}

/**
Expand All @@ -219,6 +244,8 @@ export class PostgresDriver {
async rollbackTransaction() {
await this.#client.rollbackTransaction()
await this.#client.release()

this.#client = this.#dataSource.createQueryRunner()
}

/**
Expand Down Expand Up @@ -516,9 +543,7 @@ export class PostgresDriver {
* @return {Promise<any>}
*/
async find() {
const data = await this.query(true).take(1).execute()

return data[0]
return this.query(true).getOne()
}

/**
Expand All @@ -527,7 +552,24 @@ export class PostgresDriver {
* @return {Promise<any>}
*/
async findMany() {
return this.query(true).execute()
return this.query(true).getMany()
}

/**
* Find many values in database and return as paginated response.
*
* @param [page] {boolean}
* @param [limit] {boolean}
* @param [resourceUrl] {string}
* @return {Promise<import('@secjs/utils').PaginatedResponse>}
*/
async paginate(page = 0, limit = 10, resourceUrl = '/') {
const [data, count] = await this.query(true)
.take(page)
.limit(limit)
.getManyAndCount()

return Exec.pagination(data, count, { page, limit, resourceUrl })
}

/**
Expand Down Expand Up @@ -593,6 +635,10 @@ export class PostgresDriver {
.returning(select)
.execute()

if (result.raw.length === 1) {
return result.raw[0]
}

return result.raw
}

Expand All @@ -601,21 +647,19 @@ export class PostgresDriver {
*
* @return {Promise<void>}
*/
async delete(soft = false) {
async delete() {
if (!this.#where.size) {
throw new EmptyWhereException('delete')
}

const select = this.#select.length ? [...this.#select] : '*'

if (soft) {
const result = await this.update({ deletedAt: new Date() })
const result = await this.query(true).delete().returning(select).execute()

return result.raw
if (result.raw && result.raw.length === 1) {
return result.raw[0]
}

const result = await this.query(true).delete().returning(select).execute()

return result.raw
}

Expand All @@ -638,11 +682,29 @@ export class PostgresDriver {
* @return {PostgresDriver}
*/
buildSelect(...columns) {
if (columns.find(column => column === '*')) {
this.#select = []

return this
}

columns.forEach(column => this.#select.push(`${this.#table}.${column}`))

return this
}

/**
* Set the columns that should be selected on query.
*
* @param columns {string}
* @return {PostgresDriver}
*/
buildAddSelect(...columns) {
columns.forEach(column => this.#addSelect.push(`${this.#table}.${column}`))

return this
}

/**
* Set a where statement in your query.
*
Expand Down Expand Up @@ -893,6 +955,27 @@ export class PostgresDriver {
this.#select = []
}

/**
* Set add select options in query if exists.
*
* @param query {import('typeorm').SelectQueryBuilder}
*/
#setAddSelectOnQuery(query) {
if (query.returning) {
query.returning(this.#addSelect.length ? this.#addSelect : '*')

return
}

if (!this.#addSelect.length) {
return
}

this.#addSelect.forEach(select => query.addSelect(select))

this.#addSelect = []
}

/**
* Set all where options in query if exists.
*
Expand All @@ -907,12 +990,12 @@ export class PostgresDriver {

for (const [key, value] of iterator) {
if (!value) {
query.where(key)
query.andWhere(key)

continue
}

query.where(key, value)
query.andWhere(key, value)
}

this.#where = new Map()
Expand Down
28 changes: 28 additions & 0 deletions src/Exceptions/NotImplementedDefinitionException.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* @athenna/database
*
* (c) João Lenon <lenon@athenna.io>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { Exception } from '@secjs/utils'

export class NotImplementedDefinitionException extends Exception {
/**
* Creates a new instance of NotImplementedDefinitionException.
*
* @return {NotImplementedDefinitionException}
*/
constructor(modelName) {
const content = `You have not implemented the "static definition()" method inside your ${modelName} model.`

super(
content,
500,
'E_NOT_IMPLEMENTED_DEFINITION_ERROR',
`Open you ${modelName} model and write your "static definition()" method using the "faker" method.`,
)
}
}
Loading

0 comments on commit 8217ff5

Please sign in to comment.