Skip to content

Commit ed151f7

Browse files
authored
Merge pull request #8 from SecJS/refactor/len-same-connection
refactor: create factories to handle drivers and connections
2 parents 1279802 + 71e609a commit ed151f7

16 files changed

Lines changed: 698 additions & 407 deletions

README.md

Lines changed: 92 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -148,15 +148,90 @@ export default {
148148

149149
> With the config/database file created you can use Database class to start handling operations in your database.
150150
151-
#### Create/drop tables and databases
151+
#### Connecting to database
152152

153153
```ts
154-
import { Knex } from 'knex'
155-
import { Database, TableBuilder } from '@secjs/database'
154+
import { Database } from '@secjs/database'
156155

157156
// Database class will always use the default value set in config/database
158157
// to handle operations, in this case, postgres.
159-
const database = await new Database().connection('postgres').connect()
158+
159+
// If true will force the creation of the connection for that driver
160+
// even if that driver is already connected to database
161+
const force = false // default is false
162+
163+
// If true will save the connection inside DriverFactory and this connection
164+
// will be shared in all Database/Driver instances that use this connection
165+
const saveOnDriver = true // default is true
166+
167+
// You can create the connection for postgres calling connect method
168+
const database = await new Database()
169+
.connection('postgres')
170+
.connect(force, saveOnDriver)
171+
172+
// Now every time that you need postgres connection, you don't need to call connect again
173+
const newDb = new Database().connection('postgres')
174+
// Database/Driver always share the same database connection for each instance!
175+
176+
// We recommend using the static method createConnections in the application startup.
177+
// It will create the connections according to config/database file
178+
await Database.createConnections('postgres', 'mongo')
179+
180+
// Now you don't need to call connect method when changing your connection
181+
database.connection('mongo') // will use mongo driver
182+
```
183+
184+
#### Disconnecting from database
185+
186+
```ts
187+
// There are three ways to disconect from database
188+
189+
// WARN - Becarefull with close if you are using a shared connection,
190+
// it will close the connection for all Database/Driver instances
191+
192+
// 1 - Calling close in the database instance
193+
await database.close()
194+
195+
// 2 - Calling the static closeConnections method
196+
await Database.closeConnections('postgres', 'mongo')
197+
198+
// 3 - Calling the static closeAllDrivers method
199+
await Database.closeAllDrivers() // Close all Drivers connections inside DriverFactory
200+
```
201+
202+
#### Creating a specific connection with database subscribing configs in runtime
203+
204+
```ts
205+
// As you can see above, each Driver class share the same database connection.
206+
// But maybe you need to create a specific connection with runtime configurations,
207+
// without implicating in other Driver connections.
208+
209+
const force = true
210+
const saveOnDriver = false
211+
const runtimeConfigs = { database: 'testing' }
212+
213+
const runtimeDb = new Database()
214+
.connection('postgres', runtimeConfigs)
215+
// You need to set force as true and saveOnDriver as false,
216+
// this way you will force creating a new connection for postgres but
217+
// it will not implicate in other Database/Driver instances connections.
218+
// We can use connect method this way to create a specific connection
219+
// to work on.
220+
.connect(force, saveOnDriver)
221+
222+
// This connection won't be available in static method Database.closeDriver.
223+
// If calling this method it will close the main PostgresDriver connection
224+
await Database.closeDriver('postgres')
225+
226+
// So always remember closing this connection!
227+
await runtimeDb.close()
228+
```
229+
230+
#### Create/drop tables and databases
231+
232+
```ts
233+
import { Knex } from 'knex'
234+
import { Database, TableBuilder } from '@secjs/database'
160235

161236
// All SQL Drivers from Database are using Knex as query builder and for Mongo NoSQL, mongoose.
162237
await database.createTable('products', (tableBuilder: Knex.TableBuilder) => {
@@ -177,7 +252,7 @@ await database.createTable('product_details', (tableBuilder: Knex.TableBuilder)
177252
// but it does not have all the methods from Knex table builder.
178253

179254
// Changing the connection to mongo database
180-
await database.connection('mongo').connect()
255+
database.connection('mongo')
181256

182257
// With mongo connection we do not have to specify the id because
183258
// mongoose auto create the _id property
@@ -200,10 +275,15 @@ await database.createDatabase('testing-database')
200275
// Then you can create a new database instance to connect to this new database
201276
const runtimeConfigurations = { database: 'testing-database' }
202277

203-
const testingDatabase = await new Database(runtimeConfigurations).connection('mongo').connect()
278+
const testingDatabase = await new Database(runtimeConfigurations)
279+
.connection('mongo')
280+
// Force connection and don't save the connection
281+
.connect(true, false)
204282

205-
// Or a more simple way using the same instance, is just calling the connection method again but with runtimeConfigs
206-
await database.connection('mongo', runtimeConfigurations).connect()
283+
// Do operations using testingDatabase....
284+
285+
// Close the connection with testing database
286+
await testingDatabase.close()
207287

208288
// You can drop databases too
209289
await database.dropDatabase('testing-database')
@@ -533,7 +613,7 @@ database.buildTable('products')
533613

534614
// Clone the database query chain, this will create a new instance of the Database class
535615
// but with the exactly same query chain.
536-
const clonedDatabase = await database.clone()
616+
const clonedDatabase = database.clone()
537617

538618
console.log(database === clonedDatabase) // false
539619

@@ -554,7 +634,7 @@ const arrayOfIds = await client.insert({ name: 'AirPods 2' }, 'id')
554634

555635
{
556636
// For mongoose you can set the Schema as type
557-
await database.connection('mongo').connect()
637+
database.connection('mongo')
558638

559639
const { client, session } = await database.cloneQuery<UserSchema>()
560640

@@ -563,23 +643,6 @@ const arrayOfIds = await client.insert({ name: 'AirPods 2' }, 'id')
563643
}
564644
```
565645

566-
### Subscribing configs of connections in runtime
567-
568-
```ts
569-
// Using connection method approach
570-
await database
571-
.connection('postgres', { database: 'test-db' })
572-
.connect()
573-
574-
// Using constructor method approach
575-
const newDatabase = new Database({ database: 'test-db' })
576-
577-
// You can reset configs using an empty object in the connection method
578-
await database
579-
.connection('postgres', {}) // Clear the runtime configuration
580-
.connect()
581-
```
582-
583646
### Extending connections and drivers
584647

585648
> Nowadays, @secjs/database has only MongoDriver, MySqlDriver, PostgresDriver, SqliteDriver and SqlServerDriver support, but you can extend the drivers for Database class if you implement DriverContract interface
@@ -634,7 +697,8 @@ console.log(Database.drivers) // ['mysql', 'mongo', 'sqlite', 'mssql', 'postgres
634697
> Now, if you have implemented your connection in config/database, you can use him inside Database
635698
636699
```ts
637-
// Will use CustomDriver to handle the database operations
700+
// Will use CustomDriver to handle the database operations and
701+
// save the shared connection in DriverFactory
638702
await database.connection('myconnection').connect()
639703
```
640704

index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export * from './src/Builders/ColumnBuilder'
1717
export * from './src/Builders/ReferenceColumnBuilder'
1818

1919
export * from './src/Utils/Transaction'
20-
export * from './src/Utils/ConnectionResolver'
20+
export * from './src/Utils/DriverFactory'
21+
export * from './src/Utils/ConnectionFactory'
2122

2223
export * from './src/Database'

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@secjs/database",
3-
"version": "1.0.1",
3+
"version": "1.0.2",
44
"description": "Handle your application database with factories, seeders and query builder in Node.js",
55
"license": "MIT",
66
"author": "João Lenon <lenon@secjs.com.br>",

src/Contracts/DatabaseContract.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export interface DatabaseContract {
3232
* The most important method from drivers. Creates the connection with database
3333
*
3434
*/
35-
connect(): Promise<DatabaseContract>
35+
connect(force?: boolean, saveOnDriver?: boolean): Promise<DatabaseContract>
3636

3737
/**
3838
* On method
@@ -51,7 +51,7 @@ export interface DatabaseContract {
5151
* @return Return the actual database chain
5252
*
5353
*/
54-
clone(): Promise<DatabaseContract>
54+
clone(): DatabaseContract
5555

5656
/**
5757
* CloneQuery method

src/Contracts/DriverContract.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ export interface DriverContract {
2020
* The most important method from drivers. Creates the connection with database
2121
*
2222
*/
23-
connect(): Promise<void>
23+
connect(force?: boolean, saveOnDriver?: boolean): Promise<void>
2424

2525
/**
2626
* On method

src/Database.ts

Lines changed: 39 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,10 @@
77
* file that was distributed with this source code.
88
*/
99

10-
import {
11-
InternalServerException,
12-
NotImplementedException,
13-
} from '@secjs/exceptions'
14-
15-
import { Drivers } from './Drivers/Drivers'
1610
import { JoinType } from './Contracts/JoinType'
17-
import { Config, PaginatedResponse, Path } from '@secjs/utils'
11+
import { DriverFactory } from './Utils/DriverFactory'
1812
import { DriverContract } from './Contracts/DriverContract'
13+
import { Config, PaginatedResponse, Path } from '@secjs/utils'
1914
import { DatabaseContract } from './Contracts/DatabaseContract'
2015
import { TransactionContract } from './Contracts/TransactionContract'
2116

@@ -24,71 +19,65 @@ export class Database implements DatabaseContract {
2419
private connectionName: string
2520
private driver: DriverContract
2621

27-
static build(
28-
name: string,
29-
driver: new (connection: string, configs?: any) => DriverContract,
30-
) {
31-
if (Drivers[name])
32-
throw new InternalServerException(`Driver ${name} already exists`)
22+
constructor(runtimeConfig: any = {}) {
23+
new Config().safeLoad(Path.config('database'))
3324

34-
Drivers[name] = driver
25+
this.runtimeConfig = runtimeConfig
26+
this.connectionName = 'default'
27+
this.driver = DriverFactory.fabricate('default', runtimeConfig)
3528
}
3629

3730
static get drivers(): string[] {
38-
return Object.keys(Drivers)
31+
return DriverFactory.availableDrivers()
3932
}
4033

41-
private createDriverInstance(connectionName?: string) {
42-
connectionName = connectionName || Config.get('database.default')
34+
static build(
35+
name: string,
36+
driver: new (connection: string, configs?: any) => DriverContract,
37+
) {
38+
DriverFactory.createDriver(name, driver)
39+
}
4340

44-
const connectionConfig = Config.get(
45-
`database.connections.${connectionName}`,
41+
static async openConnections(...connections: string[]): Promise<void> {
42+
const promises = connections.map(connection =>
43+
DriverFactory.generateConnectionClient(connection, {}, true),
4644
)
4745

48-
if (!connectionConfig) {
49-
throw new NotImplementedException(
50-
`Connection ${connectionName} is not configured inside database.connections object from config/database file`,
51-
)
52-
}
53-
54-
if (!Drivers[connectionConfig.driver]) {
55-
throw new NotImplementedException(
56-
`Driver ${connectionConfig.driver} does not exist, use Database.build method to create a new driver`,
57-
)
58-
}
59-
60-
this.connectionName = connectionName
46+
await Promise.all(promises)
47+
}
6148

62-
return new Drivers[connectionConfig.driver](
63-
connectionName,
64-
this.runtimeConfig,
49+
static async closeConnections(...connections: string[]): Promise<void> {
50+
const promises = connections.map(connection =>
51+
DriverFactory.closeConnection(connection),
6552
)
66-
}
6753

68-
constructor(runtimeConfig: any = {}) {
69-
new Config().safeLoad(Path.config('database'))
54+
await Promise.all(promises)
55+
}
7056

71-
this.runtimeConfig = runtimeConfig
72-
this.driver = this.createDriverInstance()
57+
static async closeAllDrivers(): Promise<void> {
58+
return DriverFactory.closeAllDriversConnection()
7359
}
7460

61+
// DriverContract Methods
62+
7563
connection(connection: string, runtimeConfig: any = {}): DatabaseContract {
7664
this.runtimeConfig = runtimeConfig
7765

78-
this.driver.close()
79-
this.driver = this.createDriverInstance(connection)
66+
this.connectionName = connection
67+
this.driver = DriverFactory.fabricate(connection, runtimeConfig)
8068

8169
return this
8270
}
8371

84-
// DriverContract Methods
85-
8672
setQueryBuilder(query: any): void {
8773
this.driver.setQueryBuilder(query)
8874
}
8975

90-
async connect(): Promise<DatabaseContract> {
91-
await this.driver.connect()
76+
async connect(
77+
force?: boolean,
78+
saveOnDriver?: boolean,
79+
): Promise<DatabaseContract> {
80+
await this.driver.connect(force, saveOnDriver)
9281

9382
return this
9483
}
@@ -101,10 +90,10 @@ export class Database implements DatabaseContract {
10190
return this.driver.cloneQuery()
10291
}
10392

104-
async clone(): Promise<DatabaseContract> {
105-
const database: any = await new Database()
106-
.connection(this.connectionName)
107-
.connect()
93+
clone(connection?: string): DatabaseContract {
94+
const database: any = new Database().connection(
95+
connection || this.connectionName,
96+
)
10897

10998
database.setQueryBuilder(this.cloneQuery())
11099

src/Drivers/Drivers.ts

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)