1 | import Promise from 'bluebird';
|
2 | import pgDriver from 'pg';
|
3 | import debug from './debug';
|
4 | import makeAsyncApi from './makeAsyncApi';
|
5 |
|
6 | function checkAsyncFunction(asyncFunc) {
|
7 | if (typeof asyncFunc !== 'function')
|
8 | throw new TypeError('async function expected');
|
9 | }
|
10 |
|
11 | export default class PgAsync {
|
12 | constructor(connectionOptions, driver) {
|
13 | this.setConnectionOptions(connectionOptions);
|
14 | this.setDriver(driver);
|
15 |
|
16 | const wrap = name => {
|
17 | this[name] = (sql, ...values) =>
|
18 | this.connect(client => client[`${name}Args`](sql, values));
|
19 | };
|
20 | const wrapArgs = name => {
|
21 | this[name] = (sql, values) =>
|
22 | this.connect(client => client[name](sql, values));
|
23 | };
|
24 |
|
25 | wrap('query');
|
26 | wrapArgs('queryArgs');
|
27 |
|
28 | wrap('rows');
|
29 | wrapArgs('rowsArgs');
|
30 |
|
31 | wrap('row');
|
32 | wrapArgs('rowArgs');
|
33 |
|
34 | wrap('value');
|
35 | wrapArgs('valueArgs');
|
36 | }
|
37 |
|
38 | setConnectionOptions(options) {
|
39 | this._connectionOptions = options;
|
40 | return this;
|
41 | }
|
42 |
|
43 | getConnectionOptions() {
|
44 | return this._connectionOptions || this.getDriver().defaults;
|
45 | }
|
46 |
|
47 | getDriver() {
|
48 | return this._driver;
|
49 | }
|
50 |
|
51 | setDriver(driver) {
|
52 | if (typeof driver === 'string')
|
53 | switch (driver) {
|
54 | case '': case 'pg':
|
55 | driver = pgDriver;
|
56 | break;
|
57 | case 'native': case 'pg.native':
|
58 | driver = pgDriver.native;
|
59 | break;
|
60 | default:
|
61 | throw new Error(`Unrecognized driver name: ${driver}`);
|
62 | }
|
63 | this._driver = driver || pgDriver;
|
64 | return this;
|
65 | }
|
66 |
|
67 | async getClient() {
|
68 | return new Promise((resolve, reject) => {
|
69 | this.getDriver().connect(this.getConnectionOptions(), (err, client, done) => {
|
70 | if (err) {
|
71 | debug('%s getClient(%j)', err, this.getConnectionOptions());
|
72 | if (done) done(err);
|
73 | return reject(err);
|
74 | }
|
75 | return resolve({client, done});
|
76 | });
|
77 | });
|
78 | }
|
79 |
|
80 | async connect(asyncFunc) {
|
81 | checkAsyncFunction(asyncFunc);
|
82 |
|
83 | const {client, done} = await this.getClient();
|
84 | try {
|
85 | const api = makeAsyncApi(client);
|
86 | const result = await asyncFunc(api);
|
87 | await api.end();
|
88 | done();
|
89 | return result;
|
90 | } catch (err) {
|
91 | done(err);
|
92 | throw err;
|
93 | }
|
94 | }
|
95 |
|
96 | async transaction(asyncFunc) {
|
97 | checkAsyncFunction(asyncFunc);
|
98 |
|
99 | return await this.connect(async (client) => {
|
100 | await client.startTransaction();
|
101 | try {
|
102 | const result = await asyncFunc(client);
|
103 | await client.commit();
|
104 | return result;
|
105 | } catch (err) {
|
106 | try {
|
107 | await client.rollback();
|
108 | } catch (_) {
|
109 |
|
110 | }
|
111 | throw err;
|
112 | }
|
113 | });
|
114 | }
|
115 |
|
116 | closeConnections = () => this.getDriver().end();
|
117 |
|
118 | }
|