Skip to content

Commit

Permalink
Merge branch 'develop' into fix/clone-preload
Browse files Browse the repository at this point in the history
  • Loading branch information
RomainLanz authored Aug 31, 2024
2 parents bb935f4 + 2fd32fc commit fba8791
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 47 deletions.
33 changes: 18 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@adonisjs/lucid",
"description": "SQL ORM built on top of Active Record pattern",
"version": "21.1.0",
"version": "21.2.0",
"engines": {
"node": ">=18.16.0"
},
Expand Down Expand Up @@ -60,44 +60,44 @@
},
"devDependencies": {
"@adonisjs/assembler": "^7.7.0",
"@adonisjs/core": "^6.11.0",
"@adonisjs/core": "^6.12.1",
"@adonisjs/eslint-config": "^1.3.0",
"@adonisjs/prettier-config": "^1.3.0",
"@adonisjs/tsconfig": "^1.3.0",
"@commitlint/cli": "^19.3.0",
"@commitlint/cli": "^19.4.0",
"@commitlint/config-conventional": "^19.2.2",
"@japa/assert": "^3.0.0",
"@japa/file-system": "^2.3.0",
"@japa/runner": "^3.1.4",
"@libsql/sqlite3": "^0.3.1",
"@swc/core": "^1.6.1",
"@swc/core": "^1.7.6",
"@types/chance": "^1.1.6",
"@types/luxon": "^3.4.2",
"@types/node": "^20.14.5",
"@types/node": "^22.1.0",
"@types/pretty-hrtime": "^1.0.3",
"@types/qs": "^6.9.15",
"@vinejs/vine": "^2.1.0",
"better-sqlite3": "^11.0.0",
"better-sqlite3": "^11.1.2",
"c8": "^10.1.2",
"chance": "^1.1.11",
"chance": "^1.1.12",
"copyfiles": "^2.4.1",
"cross-env": "^7.0.3",
"del-cli": "^5.1.0",
"dotenv": "^16.4.5",
"eslint": "^8.57.0",
"fs-extra": "^11.2.0",
"github-label-sync": "^2.3.1",
"husky": "^9.0.11",
"luxon": "^3.4.4",
"mysql2": "^3.10.1",
"np": "^10.0.6",
"husky": "^9.1.4",
"luxon": "^3.5.0",
"mysql2": "^3.11.0",
"np": "^10.0.7",
"pg": "^8.12.0",
"prettier": "^3.3.2",
"prettier": "^3.3.3",
"reflect-metadata": "^0.2.2",
"sqlite3": "^5.1.7",
"tedious": "^18.2.0",
"tedious": "^18.3.0",
"ts-node": "^10.9.2",
"typescript": "^5.4.5"
"typescript": "^5.5.4"
},
"dependencies": {
"@adonisjs/presets": "^2.6.1",
Expand All @@ -111,7 +111,7 @@
"knex": "^3.1.0",
"knex-dynamic-connection": "^3.2.0",
"pretty-hrtime": "^1.0.3",
"qs": "^6.12.1",
"qs": "^6.13.0",
"slash": "^5.1.0",
"tarn": "^3.0.2"
},
Expand All @@ -138,6 +138,9 @@
"bugs": {
"url": "https://github.com/adonisjs/lucid/issues"
},
"overrides": {
"strtok3": "8.0.1"
},
"eslintConfig": {
"extends": "@adonisjs/eslint-config/package"
},
Expand Down
20 changes: 15 additions & 5 deletions src/connection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,23 @@ export class Connection extends EventEmitter implements ConnectionContract {
}

/**
* Cleanup references
* Cleans up reference for the write client and also the
* read client when not using replicas
*/
private cleanup(): void {
private cleanupWriteClient() {
if (this.client === this.readClient) {
this.cleanupReadClient()
}
this.client = undefined
}

/**
* Cleans up reference for the read client
*/
private cleanupReadClient() {
this.roundRobinCounter = 0
this.readClient = undefined
this.readReplicas = []
this.roundRobinCounter = 0
}

/**
Expand All @@ -127,15 +137,15 @@ export class Connection extends EventEmitter implements ConnectionContract {
*/
this.pool!.on('poolDestroySuccess', () => {
this.logger.trace({ connection: this.name }, 'pool destroyed, cleaning up resource')
this.cleanup()
this.cleanupWriteClient()
this.emit('disconnect', this)
this.removeAllListeners()
})

if (this.readPool !== this.pool) {
this.readPool!.on('poolDestroySuccess', () => {
this.logger.trace({ connection: this.name }, 'pool destroyed, cleaning up resource')
this.cleanup()
this.cleanupReadClient()
this.emit('disconnect', this)
this.removeAllListeners()
})
Expand Down
11 changes: 9 additions & 2 deletions src/database/query_builder/chainable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,8 +231,7 @@ export abstract class Chainable extends Macroable implements ChainableContract {
*/
protected transformValue(value: any) {
if (value instanceof Chainable) {
value.applyWhere()
return value.knexQuery
return value.toKnex()
}

if (value instanceof ReferenceBuilder) {
Expand Down Expand Up @@ -2074,4 +2073,12 @@ export abstract class Chainable extends Macroable implements ChainableContract {

return this
}

/**
* Applies statements and returns knex query
*/
toKnex() {
this.applyWhere()
return this.knexQuery
}
}
8 changes: 8 additions & 0 deletions src/orm/relations/base/query_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,14 @@ export abstract class BaseQueryBuilder
return this
}

/**
* Return knex query
*/
toKnex() {
this.applyConstraints()
return super.toKnex()
}

/**
* Get query sql
*/
Expand Down
35 changes: 35 additions & 0 deletions test/connection/connection.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,41 @@ test.group('Connection | setup', (group) => {

await connection.disconnect()
}).waitForDone()

test('cleanup read/write clients when connection is closed', async ({ assert }) => {
let disconnectEmitsCount = 0

const config = getConfig()
config.replicas! = {
write: {
connection: {
host: '10.0.0.1',
},
},
read: {
connection: [
{
host: '10.0.0.1',
},
],
},
}

const connection = new Connection('primary', config, logger)
connection.connect()
connection.readPool?.on('poolDestroySuccess', () => {
disconnectEmitsCount++
})
connection.pool?.on('poolDestroySuccess', () => {
disconnectEmitsCount++
})

await connection.disconnect()

assert.equal(disconnectEmitsCount, 2)
assert.isUndefined(connection.client)
assert.isUndefined(connection.readClient)
}).skip(['sqlite', 'better_sqlite', 'libsql'].includes(process.env.DB!))
})

if (process.env.DB === 'mysql') {
Expand Down
17 changes: 10 additions & 7 deletions test/database/db_check.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,27 @@ test.group('Db connection check', (group) => {
await cleanup()
})

test('perform health check for a connection', async ({ assert }) => {
test('perform health check for a connection', async ({ assert, cleanup: teardown }) => {
const config = {
connection: 'primary',
connections: { primary: getConfig() },
}

const db = new Database(config, logger, createEmitter())
teardown(async () => {
await db.manager.closeAll()
})

const healthCheck = new DbCheck(db.connection())
const result = await healthCheck.run()
assert.containsSubset(result, {
message: 'Successfully connected to the database server',
status: 'ok',
meta: { connection: { name: 'primary', dialect: config.connections.primary.client } },
meta: { connection: { name: 'primary', dialect: db.connection().dialect.name } },
})

await db.manager.closeAll()
})

test('report error when unable to connect', async ({ assert }) => {
test('report error when unable to connect', async ({ assert, cleanup: teardown }) => {
const config = {
connection: 'primary',
connections: {
Expand All @@ -56,16 +57,18 @@ test.group('Db connection check', (group) => {
}

const db = new Database(config, logger, createEmitter())
teardown(async () => {
await db.manager.closeAll()
})

const healthCheck = new DbCheck(db.connection())
const result = await healthCheck.run()

assert.containsSubset(result, {
message: 'Connection failed',
status: 'error',
meta: { connection: { name: 'primary', dialect: 'mysql' } },
})
assert.equal(result.meta?.error.code, 'ECONNREFUSED')

await db.manager.closeAll()
})
})
52 changes: 34 additions & 18 deletions test/database/db_connection_count_check.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,21 @@ test.group('Db connection count check', (group) => {
await cleanup()
})

test('return error when failure threshold has been crossed', async ({ assert }) => {
test('return error when failure threshold has been crossed', async ({
assert,
cleanup: teardown,
}) => {
const config = {
connection: 'primary',
connections: { primary: getConfig() },
}

const db = new Database(config, logger, createEmitter())
const client = db.connection()
teardown(async () => {
await db.manager.closeAll()
})

const client = db.connection()
const healthCheck = new DbConnectionCountCheck(client).compute(async () => {
return 20
})
Expand All @@ -48,19 +54,23 @@ test.group('Db connection count check', (group) => {
},
},
})

await db.manager.closeAll()
})

test('return warning when warning threshold has been crossed', async ({ assert }) => {
test('return warning when warning threshold has been crossed', async ({
assert,
cleanup: teardown,
}) => {
const config = {
connection: 'primary',
connections: { primary: getConfig() },
}

const db = new Database(config, logger, createEmitter())
const client = db.connection()
teardown(async () => {
await db.manager.closeAll()
})

const client = db.connection()
const healthCheck = new DbConnectionCountCheck(client).compute(async () => {
return 12
})
Expand All @@ -78,17 +88,22 @@ test.group('Db connection count check', (group) => {
},
},
})

await db.manager.closeAll()
})

test('return success when unable to compute connections count', async ({ assert }) => {
test('return success when unable to compute connections count', async ({
assert,
cleanup: teardown,
}) => {
const config = {
connection: 'primary',
connections: { primary: getConfig() },
}

const db = new Database(config, logger, createEmitter())
teardown(async () => {
await db.manager.closeAll()
})

const client = db.connection()

const healthCheck = new DbConnectionCountCheck(client).compute(async () => {
Expand All @@ -103,17 +118,19 @@ test.group('Db connection count check', (group) => {
connection: { name: 'primary', dialect: client.dialect.name },
},
})

await db.manager.closeAll()
})

test('get PostgreSQL connections count', async ({ assert }) => {
test('get PostgreSQL connections count', async ({ assert, cleanup: teardown }) => {
const config = {
connection: 'primary',
connections: { primary: getConfig() },
}

const db = new Database(config, logger, createEmitter())
teardown(async () => {
await db.manager.closeAll()
})

const client = db.connection()

const healthCheck = new DbConnectionCountCheck(client)
Expand All @@ -133,19 +150,20 @@ test.group('Db connection count check', (group) => {
},
},
})

await db.manager.closeAll()
}).skip(process.env.DB !== 'pg', 'Only for PostgreSQL')

test('get MySQL connections count', async ({ assert }) => {
test('get MySQL connections count', async ({ assert, cleanup: teardown }) => {
const config = {
connection: 'primary',
connections: { primary: getConfig() },
}

const db = new Database(config, logger, createEmitter())
const client = db.connection()
teardown(async () => {
await db.manager.closeAll()
})

const client = db.connection()
const healthCheck = new DbConnectionCountCheck(client)

const result = await healthCheck.run()
Expand All @@ -163,7 +181,5 @@ test.group('Db connection count check', (group) => {
},
},
})

await db.manager.closeAll()
}).skip(!['mysql', 'mysql_legacy'].includes(process.env.DB!), 'Only for MySQL')
})
Loading

0 comments on commit fba8791

Please sign in to comment.