-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ExasolPool (allow more than 1 connection) (#37)
* add package 'generic pool' and run 'npm audit fix' to fix reported vulnerabilities * add signature to call query method from pool (ts specific) * add ExasolPool class * add exasolpool class to exports in index.ts * sql-client: use this.acquire method instead of this.pool.acquire (like in all other query methods) * add pool integration test classes * version bump + ran project-keeper * Add documentation on using ExasolPool * Add release notes on ExasolPool
- Loading branch information
1 parent
500cb55
commit d1aa19e
Showing
14 changed files
with
527 additions
and
18 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Exasol Driver ts 0.2.0, released 2024-??-?? | ||
|
||
Code name: TBD | ||
|
||
## Summary | ||
|
||
Adds `ExasolPool`, which is a connection pool using `ExasolDriver` underneath. See the user guide for a new section on how to configure and use the `ExasolPool` class. | ||
|
||
## Features | ||
|
||
- #28: Add a connection pool. | ||
|
||
## Dependency Updates | ||
|
||
### Compile Dependency Updates | ||
|
||
* Added `generic-pool:^3.9.0` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { ExaWebsocket } from '../../src'; | ||
import { basicPoolTests } from '../testcases/pool.basic.spec'; | ||
basicPoolTests('Browser', (url) => { | ||
return new WebSocket(url) as ExaWebsocket; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { WebSocket } from 'ws'; | ||
import { ExaWebsocket } from '../../src/lib/connection'; | ||
import { basicPoolTests } from '../testcases/pool.basic.spec'; | ||
basicPoolTests('Node', (url) => { | ||
return new WebSocket(url) as ExaWebsocket; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export const DOCKER_CONTAINER_VERSION: string = 'exasol/docker-db:7.1.22'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
import { GenericContainer, StartedTestContainer, Wait } from 'testcontainers'; | ||
import { ExasolDriver, websocketFactory } from '../../src/lib/sql-client'; | ||
import { ExasolPool } from '../../src/lib/sql-pool'; | ||
import { RandomUuid } from 'testcontainers/dist/uuid'; | ||
import { QueryResult } from '../../src/lib/query-result'; | ||
import { DOCKER_CONTAINER_VERSION } from '../runner.config'; | ||
|
||
export const basicPoolTests = (name: string, factory: websocketFactory) => | ||
describe(name, () => { | ||
const randomId = new RandomUuid(); | ||
let container: StartedTestContainer; | ||
jest.setTimeout(7000000); | ||
let schemaName = ''; | ||
|
||
beforeAll(async () => { | ||
container = await new GenericContainer(DOCKER_CONTAINER_VERSION) | ||
.withExposedPorts(8563, 2580) | ||
.withPrivilegedMode() | ||
.withDefaultLogDriver() | ||
.withReuse() | ||
.withWaitStrategy(Wait.forLogMessage('All stages finished')) | ||
.start(); | ||
}); | ||
|
||
beforeEach(() => { | ||
schemaName = 'TEST_SCHEMA' + randomId.nextUuid(); | ||
}); | ||
|
||
it('Connect to DB', async () => { | ||
const poolToQuery = createPool(factory, container, 1, 10); | ||
await poolToQuery.drain(); | ||
await poolToQuery.clear(); | ||
}); | ||
|
||
it('Exec and fetch (default min / max connection settings)', async () => { | ||
const setupClient = createSetupClient(factory, container); | ||
|
||
const poolToQuery = createPoolWithDefaultSize(factory, container); | ||
|
||
await setupClient.connect(); | ||
|
||
await createSimpleTestTable(setupClient, schemaName); | ||
|
||
const data = await poolToQuery.query('SELECT x FROM ' + schemaName + '.TEST_TABLE'); | ||
|
||
expect(data.getColumns()[0].name).toBe('X'); | ||
expect(data.getRows()[0]['X']).toBe(15); | ||
|
||
await poolToQuery.drain(); | ||
await poolToQuery.clear(); | ||
|
||
await setupClient.close(); | ||
}); | ||
|
||
it('Exec and fetch', async () => { | ||
const setupClient = createSetupClient(factory, container); | ||
|
||
const poolToQuery = createPool(factory, container, 1, 10); | ||
|
||
await setupClient.connect(); | ||
|
||
await createSimpleTestTable(setupClient, schemaName); | ||
|
||
const data = await poolToQuery.query('SELECT x FROM ' + schemaName + '.TEST_TABLE'); | ||
|
||
expect(data.getColumns()[0].name).toBe('X'); | ||
expect(data.getRows()[0]['X']).toBe(15); | ||
|
||
await poolToQuery.drain(); | ||
await poolToQuery.clear(); | ||
|
||
await setupClient.close(); | ||
}); | ||
|
||
it('Fetch multiple queries simultaneously/asynchronously', async () => { | ||
const setupClient = createSetupClient(factory, container); | ||
|
||
const poolToQuery = createPool(factory, container, 1, 10); | ||
|
||
await setupClient.connect(); | ||
|
||
await createSimpleTestTable(setupClient, schemaName); | ||
|
||
const dataPromise1 = poolToQuery.query('SELECT x FROM ' + schemaName + '.TEST_TABLE'); | ||
const dataPromise2 = poolToQuery.query('SELECT x FROM ' + schemaName + '.TEST_TABLE'); | ||
const dataPromise3 = poolToQuery.query('SELECT x FROM ' + schemaName + '.TEST_TABLE'); | ||
const dataPromise4 = poolToQuery.query('SELECT x FROM ' + schemaName + '.TEST_TABLE'); | ||
|
||
const data1 = await dataPromise1; | ||
expect(data1.getColumns()[0].name).toBe('X'); | ||
expect(data1.getRows()[0]['X']).toBe(15); | ||
|
||
const data2 = await dataPromise2; | ||
expect(data2.getColumns()[0].name).toBe('X'); | ||
expect(data2.getRows()[0]['X']).toBe(15); | ||
|
||
const data3 = await dataPromise3; | ||
expect(data3.getColumns()[0].name).toBe('X'); | ||
expect(data3.getRows()[0]['X']).toBe(15); | ||
|
||
const data4 = await dataPromise4; | ||
expect(data4.getColumns()[0].name).toBe('X'); | ||
expect(data4.getRows()[0]['X']).toBe(15); | ||
|
||
await poolToQuery.drain(); | ||
await poolToQuery.clear(); | ||
|
||
await setupClient.close(); | ||
}); | ||
|
||
it('Fetch multiple queries asynchronously (20)', async () => { | ||
const setupClient = createSetupClient(factory, container); | ||
|
||
const poolToQuery = createPool(factory, container, 1, 10); | ||
|
||
await setupClient.connect(); | ||
|
||
await createSimpleTestTable(setupClient, schemaName); | ||
|
||
const amountOfRequests = 20; | ||
|
||
await runQueryXNumberOfTimesAndCheckResult(amountOfRequests, poolToQuery, schemaName); | ||
|
||
await poolToQuery.drain(); | ||
await poolToQuery.clear(); | ||
|
||
await setupClient.close(); | ||
}); | ||
it('Fetch multiple queries asynchronously (100)', async () => { | ||
const setupClient = createSetupClient(factory, container); | ||
|
||
const poolToQuery = createPool(factory, container, 1, 10); | ||
|
||
await setupClient.connect(); | ||
|
||
await createSimpleTestTable(setupClient, schemaName); | ||
|
||
const amountOfRequests = 100; | ||
|
||
await runQueryXNumberOfTimesAndCheckResult(amountOfRequests, poolToQuery, schemaName); | ||
|
||
await poolToQuery.drain(); | ||
await poolToQuery.clear(); | ||
|
||
await setupClient.close(); | ||
}); | ||
|
||
afterAll(async () => {}); | ||
}); | ||
|
||
async function createSimpleTestTable(setupClient: ExasolDriver, schemaName: string) { | ||
await setupClient.execute('CREATE SCHEMA ' + schemaName); | ||
await setupClient.execute('CREATE TABLE ' + schemaName + '.TEST_TABLE(x INT)'); | ||
await setupClient.execute('INSERT INTO ' + schemaName + '.TEST_TABLE VALUES (15)'); | ||
} | ||
|
||
function createSetupClient(factory: websocketFactory, container: StartedTestContainer) { | ||
return new ExasolDriver(factory, { | ||
host: container.getHost(), | ||
port: container.getMappedPort(8563), | ||
user: 'sys', | ||
password: 'exasol', | ||
encryption: false, | ||
}); | ||
} | ||
|
||
function createPoolWithDefaultSize(factory: websocketFactory, container: StartedTestContainer) { | ||
return new ExasolPool(factory, { | ||
host: container.getHost(), | ||
port: container.getMappedPort(8563), | ||
user: 'sys', | ||
password: 'exasol', | ||
encryption: false, | ||
}); | ||
} | ||
|
||
function createPool(factory: websocketFactory, container: StartedTestContainer, minimumPoolSize: number, maximumPoolSize: number) { | ||
return new ExasolPool(factory, { | ||
host: container.getHost(), | ||
port: container.getMappedPort(8563), | ||
user: 'sys', | ||
password: 'exasol', | ||
encryption: false, | ||
minimumPoolSize: minimumPoolSize, | ||
maximumPoolSize: maximumPoolSize, | ||
}); | ||
} | ||
|
||
async function runQueryXNumberOfTimesAndCheckResult(amountOfRequests: number, poolToQuery: ExasolPool, schemaName: string) { | ||
const promiseArr: Promise<QueryResult>[] = []; | ||
|
||
for (let i = 0; i < amountOfRequests; i++) { | ||
const dataPromise = poolToQuery.query('SELECT x FROM ' + schemaName + '.TEST_TABLE'); | ||
promiseArr.push(dataPromise); | ||
} | ||
|
||
await Promise.all(promiseArr); | ||
|
||
for (let i = 0; i < amountOfRequests; i++) { | ||
const data = await promiseArr[i]; | ||
expect(data.getColumns()[0].name).toBe('X'); | ||
expect(data.getRows()[0]['X']).toBe(15); | ||
} | ||
} |
Oops, something went wrong.