Skip to content
This repository was archived by the owner on Sep 9, 2024. It is now read-only.

Commit 7026444

Browse files
authored
Merge pull request #20 from 2Toad/1.4.0
1.4.0
2 parents d1311df + 46717b7 commit 7026444

File tree

8 files changed

+413
-277
lines changed

8 files changed

+413
-277
lines changed

docs/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
## Documentation
2+
3+
### General
4+
5+
- [Config](./config.md)
6+
7+
### Questions
8+
- [How should I cleanup?](./cleanup.md)

docs/cleanup.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# Cleanup
2+
3+
node-teradata exposes the `closeAll` function to facilitate cleanup. How you implement cleanup in your app is entirely up to you, but here's one example:
4+
5+
## Example
6+
7+
In this example we use [node-cleanup](https://www.npmjs.com/package/node-cleanup), to cleanup node-teradata connections when:
8+
9+
* The process exits normally (exit code 0).
10+
* The process exits due to an error, such as an uncaught exception (exit code 1).
11+
* The process receives one of the following POSIX signals: SIGINT (e.g. Ctrl-C), SIGHUP, SIGQUIT, or SIGTERM.
12+
13+
```js
14+
var teradata = new Teradata(config);
15+
```
16+
17+
...
18+
19+
```js
20+
var cleanup = require('node-cleanup');
21+
22+
cleanup(function(exitCode, signal) {
23+
if (!signal || !teradata.initialized) return;
24+
25+
teradata.closeAll()
26+
.then(function() {
27+
process.kill(process.pid, signal);
28+
});
29+
30+
cleanup.uninstall();
31+
return false;
32+
});
33+
```

docs/config.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Config
2+
3+
The node-teradata constructor requires a config object:
4+
5+
## Properties
6+
| Property | Type | Details | Default |
7+
|-------------|--------|--------------------------------------------------------------------------------------------------------------------------------|-----------|
8+
| url | string | Teradata server URL | undefined |
9+
| username | string | Teradata username | undefined |
10+
| password | string | Teradata password | undefined |
11+
| driver | string | Location of the Teradata JDBC Driver | ./jars/ |
12+
| minPoolSize | number | The number of connections to fill the pool with when the lib is initialized | 1 |
13+
| maxPoolSize | number | When a connection is requested, and the pool is empty, a new connection will be added to the pool until this number is reached | 100 |
14+
| keepalive | object | (see [keepAlive Properties](#keepalive-properties)) | --- |
15+
| logger | object | (see [logger Properties](#logger-properties)) | --- |
16+
17+
### keepalive Properties
18+
| Property | Type | Details | Default |
19+
|----------|---------|-----------------------------------------------------|---------------|
20+
| interval | number | The number of milliseconds between query executions | 60000 |
21+
| query | string | The query to execute on the connetion | SELECT 1 |
22+
| enabled | boolean | When `false` the query is not executed | false |
23+
24+
### logger Properties
25+
| Property | Type | Details | Default |
26+
|----------|--------|-----------------------------------------------------|---------|
27+
| level | string | The maximum level of messages that should be logged | `error` |
28+
29+
> node-teradata uses [winston](https://github.com/winstonjs/winston) for logging. Please see winston's documentation for supported `level` values
30+
31+
## Example
32+
```js
33+
var config = {
34+
url: 'jdbc:teradata://myserver',
35+
username: 'MyUsername',
36+
password: 'MyPassword',
37+
driver: './jars/',
38+
minPoolSize: 1,
39+
maxPoolSize: 100,
40+
keepalive: {
41+
interval: 60000,
42+
query: 'SELECT 1',
43+
enabled: true
44+
},
45+
logger: {
46+
level: 'debug'
47+
}
48+
};
49+
```

index.js

100755100644
Lines changed: 2 additions & 274 deletions
Original file line numberDiff line numberDiff line change
@@ -3,280 +3,8 @@
33
* Copyright (c) 2017 2Toad, LLC
44
* https://github.com/2Toad/node-teradata
55
*
6-
* Version: 1.3.1
6+
* Version: 1.4.0
77
* License: MIT
88
*/
99

10-
var jinst = require('jdbc/lib/jinst');
11-
var Pool = require('jdbc/lib/pool');
12-
var Promise = require('bluebird');
13-
var _ = require('lodash');
14-
15-
var log = getLogger();
16-
17-
function Teradata(config) {
18-
if (!config) throw new Error('Configuration required');
19-
20-
this.connections = [];
21-
this.config = _.defaultsDeep(config, {
22-
driver: './jars/',
23-
minPoolSize: 1,
24-
maxPoolSize: 100,
25-
keepalive: {
26-
interval: 60000,
27-
query: 'SELECT 1',
28-
enabled: false
29-
}
30-
});
31-
}
32-
33-
Teradata.prototype.read = function(sql, connection) {
34-
var statement,
35-
resultSet;
36-
37-
return createStatement.call(this, connection)
38-
.then(function(s) {
39-
statement = s;
40-
return statement.executeQueryAsync(sql);
41-
})
42-
.then(function(rs) {
43-
resultSet = Promise.promisifyAll(rs);
44-
return resultSet.toObjArrayAsync();
45-
})
46-
.then(function(objectArray) {
47-
return objectArray;
48-
})
49-
.catch(function(error) {
50-
log.error('Unable to execute query: ' + sql);
51-
throw error;
52-
})
53-
.finally(function() {
54-
return Promise.resolve(statement && statement.closeAsync())
55-
.finally(function() {
56-
return Promise.resolve(resultSet && resultSet.closeAsync());
57-
});
58-
});
59-
};
60-
61-
Teradata.prototype.write = function(sql) {
62-
var statement;
63-
64-
return createStatement.call(this)
65-
.then(function(s) {
66-
statement = s;
67-
return statement.executeUpdateAsync(sql);
68-
})
69-
.then(function(count) {
70-
return count;
71-
})
72-
.finally(function() {
73-
return Promise.resolve(statement && statement.closeAsync());
74-
});
75-
};
76-
77-
Teradata.prototype.readPreparedStatement = function(sql, params) {
78-
var preparedStatement,
79-
resultSet;
80-
81-
return createPreparedStatement.call(this, sql, params)
82-
.then(function(ps) {
83-
preparedStatement = ps;
84-
return preparedStatement.executeQueryAsync();
85-
})
86-
.then(function(rs) {
87-
resultSet = Promise.promisifyAll(rs);
88-
return resultSet.toObjArrayAsync();
89-
})
90-
.then(function(objectArray) {
91-
return objectArray;
92-
})
93-
.catch(function(error) {
94-
log.error('Unable to execute query: ' + sql);
95-
throw error;
96-
})
97-
.finally(function() {
98-
return Promise.resolve(preparedStatement && preparedStatement.closeAsync())
99-
.finally(function() {
100-
return Promise.resolve(resultSet && resultSet.closeAsync());
101-
});
102-
});
103-
};
104-
105-
Teradata.prototype.writePreparedStatement = function(sql, params) {
106-
var preparedStatement;
107-
108-
return createPreparedStatement.call(this, sql, params)
109-
.then(function(ps) {
110-
preparedStatement = ps;
111-
return preparedStatement.executeUpdateAsync();
112-
})
113-
.then(function(count) {
114-
return count;
115-
})
116-
.catch(function(error) {
117-
log.error('Unable to execute query: ' + sql);
118-
throw error;
119-
})
120-
.finally(function() {
121-
return Promise.resolve(preparedStatement && preparedStatement.closeAsync());
122-
});
123-
};
124-
125-
Teradata.prototype.createPreparedStatementParam = function(index, type, value) {
126-
return {
127-
index: index,
128-
type: type,
129-
value: value
130-
};
131-
};
132-
133-
Teradata.prototype.closeAll = function() {
134-
_.each(this.connections, function(connection) {
135-
clearInterval(connection.keepAliveIntervalId);
136-
delete connection.keepAliveIntervalId;
137-
});
138-
139-
return this.pool.purgeAsync()
140-
.catch(function(error) {
141-
log.error('Unable to close all connections');
142-
throw error;
143-
});
144-
};
145-
146-
function createStatement(connection) {
147-
var promise = connection && Promise.resolve(connection) || open.call(this);
148-
149-
return promise
150-
.then(function(connection) {
151-
return connection.createStatementAsync()
152-
.then(function(statement) {
153-
return Promise.promisifyAll(statement);
154-
});
155-
})
156-
.catch(function(error){
157-
log.error('Unable to create statement');
158-
throw error;
159-
});
160-
}
161-
162-
function createPreparedStatement(sql, params) {
163-
return open.call(this)
164-
.then(function(connection) {
165-
return connection.prepareStatementAsync(sql)
166-
.then(function(preparedStatement) {
167-
Promise.promisifyAll(preparedStatement);
168-
169-
return Promise.all(params.map(function(param) {
170-
var setTypeAsync = 'set' + param.type + 'Async';
171-
if (!preparedStatement[setTypeAsync]) throw new Error('Invalid parameter type: ' + param.type);
172-
173-
return preparedStatement[setTypeAsync](param.index, param.value);
174-
}))
175-
.then(function() {
176-
return preparedStatement;
177-
});
178-
});
179-
})
180-
.catch(function(error){
181-
log.error('Unable to create prepared statement');
182-
throw error;
183-
});
184-
}
185-
186-
function open() {
187-
var connection;
188-
189-
return getConnection.call(this)
190-
.then(function(c) {
191-
connection = c;
192-
this.connections.push(connection);
193-
194-
return Promise.promisifyAll(connection.conn);
195-
}.bind(this))
196-
.tap(function() {
197-
if (connection.keepAliveIntervalId || !this.config.keepalive.enabled) return;
198-
199-
connection.keepAliveIntervalId = setInterval(function() {
200-
keepAlive.call(this, connection.conn);
201-
}.bind(this), this.config.keepalive.interval);
202-
}.bind(this))
203-
.catch(function(error) {
204-
log.error('Unable to open connection');
205-
throw error;
206-
})
207-
.finally(function() {
208-
return close.call(this, connection);
209-
}.bind(this));
210-
}
211-
212-
function getConnection() {
213-
if (this.pool) return this.pool.reserveAsync();
214-
215-
return initialize.call(this)
216-
.then(function(pool) {
217-
return pool.reserveAsync();
218-
});
219-
}
220-
221-
function initialize() {
222-
if (this.pool) return Promise.resolve(this.pool);
223-
224-
if (!jinst.isJvmCreated()) {
225-
jinst.addOption('-Xrs');
226-
jinst.setupClasspath([
227-
this.config.driver + 'terajdbc4.jar',
228-
this.config.driver + 'tdgssconfig.jar'
229-
]);
230-
}
231-
232-
var jdbcConfig = {
233-
url: this.config.url,
234-
properties: {
235-
user: this.config.username,
236-
password: this.config.password
237-
},
238-
minpoolsize: this.config.minPoolSize,
239-
maxpoolsize: this.config.maxPoolSize
240-
};
241-
242-
var pool = Promise.promisifyAll(new Pool(jdbcConfig));
243-
244-
return pool.initializeAsync()
245-
.then(function() {
246-
this.pool = pool;
247-
return pool;
248-
}.bind(this))
249-
.catch(function(error) {
250-
log.error('Unable to connect to database: ' + jdbcConfig.url);
251-
throw error;
252-
});
253-
}
254-
255-
function keepAlive(connection) {
256-
return this.read(this.config.keepalive.query, connection)
257-
.catch(function() {
258-
log.error('Keep Alive failed');
259-
});
260-
}
261-
262-
function close(connection) {
263-
if (!connection) return Promise.resolve();
264-
265-
return this.pool.releaseAsync(connection)
266-
.catch(function(error) {
267-
log.error('Unable to close connection: ' + connection.uuid);
268-
throw error;
269-
});
270-
}
271-
272-
// Make use of global logger if available (e.g., Winston),
273-
// otherwise fallback to console
274-
function getLogger() {
275-
return global.logger && typeof global.logger.error === 'function'
276-
? global.logger
277-
: global.log && typeof global.log.error === 'function'
278-
? global.log
279-
: global.winston || console;
280-
}
281-
282-
module.exports = Teradata;
10+
module.exports = require('./lib/teradata');

0 commit comments

Comments
 (0)