Skip to content

Commit

Permalink
Make connect/disconnect private
Browse files Browse the repository at this point in the history
  • Loading branch information
cressie176 committed Sep 25, 2023
1 parent c9d36fe commit 0b84ffb
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 105 deletions.
76 changes: 32 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,44 +1,46 @@
# PG-Scanner

PG-Scanner is a library to connect to a PostgreSQL database and perform scanning operations on tables to return statistics.
PG-Scanner is a library which reports statistics about PostgreSQL databasesstatistics.

## TL;DR

```js
const { Scanner } = require('pg-scanner');

const config = {
host: 'localhost',
host: "localhost",
port: 5432,
user: 'postgres',
password: 'password',
database: 'mydb'
user: "postgres",
password: "password",
database: "mydb",
};

const { Scanner } = new Scanner(config);

scanner.connect()
.then(() => scanner.init())
.then(() => scanner.scan())
.then((stats) => {
console.log(stats);
scanner.disconnect();
})
.catch((error) => {
console.error(error);
scanner.disconnect();
});
```
const scanner = new Scanner(config);

In this example, we create a new instance of the Scanner class with the database configuration. We then connect to the database, initialise the scanner, and perform a scan on the tables. Finally, we log the table statistics and disconnect from the database. If any errors occur during the process, we log the error and disconnect from the database.
async(() => {
await scanner.init();
scheduleScan(60 * 60 * 1000);
})();

function scheduleScan(delay) {
setTimeout(async () => {
const stats = await scanner.scan()
console.log({ stats });
scheduleScan(delay);
}).unref();
}
```

In this example, we create a new instance of the Scanner class with the database configuration. We intialise the scanner to establish a baseline, then re-scan once per hour, logging the statistics each time.

## Index

<!-- no toc -->
- [PG-Scanner API](#pg-scanner-api)

- [Installiation](#installation)
- [API](#pg-scanner-api)
- [init](#init)
- [scan](#scan)
- [connect](#connect)
- [disconnect](#disconnect)

### Installation

Expand All @@ -60,42 +62,28 @@ const { Scanner } = require('pg-scanner');
import { Scanner } from 'pg-scanner';
```
## PG-Scanner API
## API
### init()
```js
const scanner = await scanner.init();
```
The init method is responsible for initializing the scanner. It checks if the scanner has already been initialized, then calls the scan method to retrieve database table statistics. After that, it sets the initialised flag to true and returns the scanner instance.
### connect()
```js
const scanner = new Scanner(config);
await scanner.connect();
await scanner.init();
```
The connect method is responsible for establishing a connection to a PostgreSQL database using the provided configuration. It creates a new instance of the Client class with the given configuration and attempts to connect to the database. If an error occurs during the connection process, a ConnectionError is thrown with a detailed error message. Finally, the method returns the current instance of the Scanner class.
The init method is responsible for initialising the scanner wise baseline statistics. It will error if called repeatedly.
### scan()
```js
await scanner.scan();
```
The scan method is responsible for retrieving database table statistics, augmenting the statistics with additional information, and updating the previous statistics. It returns the augmented statistics.
### disconnect()
```js
await scanner.disconnect();
await scanner.scan();
```
The disconnect method is responsible for disconnecting the client from the database.
The scan method is responsible for retrieving and augmenting database statistics.
### Contributing
Contributions to the Scanner module are welcome. If you find a bug, have a feature request, or want to improve the code, please open an issue or submit a pull request on GitHub.
### License
This project is licensed under the MIT License. Feel free to use and modify the code as needed.
42 changes: 23 additions & 19 deletions lib/Scanner.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,10 @@ module.exports = class Scanner {
this.#filter = filter;
}

async connect() {
this.#client = new Client(this.#config);
try {
await this.#client.connect();
} catch (cause) {
throw new ConnectionError(`Error connecting to ${this.#config.host}:${this.#config.port} as ${this.#config.user}: ${cause.message}`, { cause });
}
return this;
}

async disconnect() {
return this.#client.end();
}

async init() {
this.#checkNotInitialised();
await this.#scan();
this.#initialised = true;
return this;
}

async scan() {
Expand All @@ -48,10 +33,29 @@ module.exports = class Scanner {
}

async #scan() {
const rawStats = await this.#readDatabaseTableStats();
const augmentedStats = this.#augmentStats(rawStats);
this.#previousStats = augmentedStats;
return augmentedStats;
try {
await this.#connect();
const rawStats = await this.#readDatabaseTableStats();
const augmentedStats = this.#augmentStats(rawStats);
this.#previousStats = augmentedStats;
return augmentedStats;
} finally {
this.#disconnect();
}
}

async #connect() {
this.#client = new Client(this.#config);
try {
await this.#client.connect();
} catch (cause) {
throw new ConnectionError(`Error connecting to ${this.#config.host}:${this.#config.port} as ${this.#config.user}: ${cause.message}`, { cause });
}
return this;
}

async #disconnect() {
return this.#client.end();
}

async #readDatabaseTableStats() {
Expand Down
57 changes: 20 additions & 37 deletions test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ const { ok, strictEqual: eq, rejects } = require('node:assert');
const { before, afterEach, describe, it } = require('zunit');
const Scanner = require('../lib/Scanner');
const Database = require('./utils/Database');
const NullScanner = require('./utils/NullScanner');

describe('PG Scanner', () => {
const config = {
Expand All @@ -14,29 +13,30 @@ describe('PG Scanner', () => {
};

const database = new Database(config);
let scanner = new NullScanner();
let scanner;

before(async () => {
await database.nuke();
});

afterEach(async () => {
await scanner.disconnect();
});

afterEach(async () => {
await database.nuke();
});

describe('connect', () => {
it('should connect successfully', async () => {
connect();
describe('init', () => {
it('should reject repeated initialisation attempts', async () => {
await initialiseScanner();
await rejects(() => scanner.init(), (err) => {
eq(err.message, 'The scanner is already initialised');
eq(err.code, 'ERR_PG_SCANNER_INITIALISATION_ERROR');
return true;
});
});

it('should report connection errors', async () => {
scanner = new Scanner({ host: 'doesnotexist-wibble-panda-totem.com', port: 1111, user: 'bob' });

await rejects(() => scanner.connect(), (err) => {
await rejects(() => scanner.init(), (err) => {
eq(err.message, 'Error connecting to doesnotexist-wibble-panda-totem.com:1111 as bob: getaddrinfo ENOTFOUND doesnotexist-wibble-panda-totem.com');
eq(err.code, 'ERR_PG_SCANNER_CONNECTION_ERROR');
eq(err.cause.code, 'ENOTFOUND');
Expand All @@ -45,20 +45,9 @@ describe('PG Scanner', () => {
});
});

describe('init', () => {
it('should reject repeated initialisation attempts', async () => {
scanner = await connectAndInitialise();
await rejects(() => scanner.init(), (err) => {
eq(err.message, 'The scanner is already initialised');
eq(err.code, 'ERR_PG_SCANNER_INITIALISATION_ERROR');
return true;
});
});
});

describe('scan', () => {
it('should reject when not initiliased', async () => {
scanner = await connect();
scanner = new Scanner(config);
await rejects(() => scanner.scan(), (err) => {
eq(err.message, 'Please initialise the scanner');
eq(err.code, 'ERR_PG_SCANNER_INITIALISATION_ERROR');
Expand All @@ -67,7 +56,7 @@ describe('PG Scanner', () => {
});

it('should ignore standard tables', async () => {
scanner = await connectAndInitialise();
await initialiseScanner();
const stats = await scanner.scan();
eq(stats.length, 0);
});
Expand All @@ -82,7 +71,6 @@ describe('PG Scanner', () => {
};
scanner = new Scanner(config, filter);

await scanner.connect();
await scanner.init();
const stats = await scanner.scan();

Expand All @@ -91,7 +79,7 @@ describe('PG Scanner', () => {

it('should return stats for custom tables', async () => {
await database.createTable('test_table');
scanner = await connectAndInitialise();
await initialiseScanner();

const [stats] = await scanner.scan();
ok(stats, 'No custom tables');
Expand All @@ -103,7 +91,7 @@ describe('PG Scanner', () => {

it('should return the total number of sequential table scans after reading the table', async () => {
await database.createTable('test_table');
scanner = await connectAndInitialise();
await initialiseScanner();

const [stats1] = await scanner.scan();
eq(stats1.sequentialScans, BigInt(1));
Expand All @@ -120,7 +108,7 @@ describe('PG Scanner', () => {
const numberOfReads = 3;
await setupTable(tableName, numberOfRows, numberOfReads);

scanner = await connectAndInitialise();
await initialiseScanner();
const [stats] = await scanner.scan();

const numberOfRowsScanned = numberOfRows * numberOfReads;
Expand All @@ -133,7 +121,7 @@ describe('PG Scanner', () => {
const startingNumberOfReads = 3;
await setupTable(tableName, startingNumberOfRows, startingNumberOfReads);

scanner = await connectAndInitialise();
await initialiseScanner();
await scanner.scan();

const additionalNumberOfRows = 3;
Expand All @@ -153,7 +141,7 @@ describe('PG Scanner', () => {
const startingNumberOfReads = 3;
await setupTable(tableName, startingNumberOfRows, startingNumberOfReads);

scanner = await connectAndInitialise();
await initialiseScanner();
await scanner.scan();

const additionalNumberOfRows = 3;
Expand Down Expand Up @@ -181,7 +169,7 @@ describe('PG Scanner', () => {
const tableTwoStartingNumberOfReads = 7;
await setupTable(tableTwo, tableTwoStartingNumberOfRows, tableTwoStartingNumberOfReads);

scanner = await connectAndInitialise();
await initialiseScanner();

await scanner.scan();
await database.readTable(tableOne);
Expand All @@ -191,14 +179,9 @@ describe('PG Scanner', () => {
});
});

async function connect() {
async function initialiseScanner() {
scanner = new Scanner(config);
return scanner.connect();
}

async function connectAndInitialise() {
scanner = await connect();
return scanner.init();
await scanner.init();
}

async function setupTable(tableName, numberOfRows, numberOfReads) {
Expand Down
5 changes: 0 additions & 5 deletions test/utils/NullScanner.js

This file was deleted.

0 comments on commit 0b84ffb

Please sign in to comment.