@trenskow/pged 5.1.32 → 5.1.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.js CHANGED
@@ -1,252 +1,11 @@
1
- import Puqeue from 'puqeue';
2
- import caseit from '@trenskow/caseit';
3
- import pg from 'pg';
4
- import EventEmitter from '@trenskow/async-event-emitter';
1
+ //
2
+ // index.js
3
+ // @trenskow/pged
4
+ //
5
+ // Created by Kristian Trenskow on 2019/09/03
6
+ // See license in LICENSE.
7
+ //
5
8
 
6
- import QueryBuilder from './query-builder.js';
9
+ import PGed from './lib/index.js';
7
10
 
8
- const { Pool } = pg;
9
-
10
- let id = 0;
11
-
12
- let pgOptions;
13
- let pool;
14
-
15
- export default class PGed extends EventEmitter {
16
-
17
- static get pg() {
18
- return pgOptions;
19
- }
20
-
21
- static set pg(options) {
22
- pgOptions = options;
23
- }
24
-
25
- static async end() {
26
- if (pool) await pool.end();
27
- pool = undefined;
28
- }
29
-
30
- constructor(options = {}) {
31
-
32
- super();
33
-
34
- pool = pool || new Pool(pgOptions);
35
-
36
- options.casing = options.casing || {};
37
- options.casing.db = options.casing.db || 'snake';
38
- options.casing.js = options.casing.hs || 'camel';
39
-
40
- options.defaultPrimaryKey = options.defaultPrimaryKey || 'id';
41
-
42
- this._options = options;
43
-
44
- this._connectionCount = 0;
45
- this._connectionQueue = new Puqeue();
46
-
47
- this._transactions = options.transactions || {};
48
- this._transactions.mode = this._transactions.mode = options.transactions.mode || 'readCommitted';
49
- this._transactions.always = this._transactions.always || false;
50
- this._transactions.count = 0;
51
-
52
- this._id = id++;
53
-
54
- this._history = [];
55
-
56
- this._cache = {};
57
- this._cacheQueue = {};
58
- this._cacheHits = 0;
59
-
60
- this._nullIsUndefined = options.nullIsUndefined !== false;
61
-
62
- this._commit = options.commit !== false;
63
-
64
- this._cacheQueue = new Puqeue();
65
-
66
- }
67
-
68
- get id() {
69
- return this._id;
70
- }
71
-
72
- get history() {
73
- return this._history;
74
- }
75
-
76
- async _query(query, ...args) {
77
- let info = {
78
- query,
79
- parameters: args[0],
80
- timing: {
81
- start: new Date()
82
- }
83
- };
84
- this._history.push(info);
85
- if (!this._client) {
86
- console.warn(`We had a query without a client for query: ${query} (${JSON.stringify(...args)}).`);
87
- }
88
- const result = await this._client.query(query, ...args);
89
- info.timing.ms = (new Date()).getTime() - info.timing.start.getTime();
90
- return result;
91
- }
92
-
93
- _convertResult(result, options) {
94
- if ((options || {}).format === 'raw') return (result || {}).rows;
95
- return ((result || {}).rows || []).map((row) => {
96
- let newRow = {};
97
- Object.keys(row).forEach((key) => {
98
- if (this._nullIsUndefined && typeof row[key] === 'object' && !row[key]) return;
99
- newRow[caseit(key, this._options.casing.js)] = row[key];
100
- });
101
- return newRow;
102
- });
103
- }
104
-
105
- async _retain() {
106
- this._connectionCount++;
107
- if (this._connectionCount == 1) {
108
- this._client = await pool.connect();
109
- await this.emit('connected');
110
- }
111
- }
112
-
113
- async _release() {
114
- this._connectionCount--;
115
- if (this._connectionCount == 0) {
116
- await this._client.release();
117
- this._client = undefined;
118
- await this.emit('disconnected');
119
- }
120
- }
121
-
122
- async retain() {
123
- await this._connectionQueue.add(async () => {
124
- await this._retain();
125
- });
126
- }
127
-
128
- async release() {
129
- await this._connectionQueue.add(async () => {
130
- await this._release();
131
- });
132
- }
133
-
134
- async retained(todo) {
135
- await this.retain();
136
- let error;
137
- let result;
138
- try {
139
- result = await todo(this);
140
- } catch (err) {
141
- error = err;
142
- }
143
- await this.release();
144
- if (error) throw error;
145
- return result;
146
- }
147
-
148
- async beginTransaction() {
149
- await this._connectionQueue.add(async () => {
150
- this._transactions.count++;
151
- await this._retain();
152
- if (this._transactions.count == 1) {
153
- await this._query('begin;');
154
- if (this._transactions.mode !== 'readCommitted') {
155
- await this.set.transactionMode[this._transactions.mode]();
156
- }
157
- await this.emit('startedTransaction');
158
- }
159
- });
160
- }
161
-
162
- async endTransaction(err, opt = {}) {
163
- await this._connectionQueue.add(async () => {
164
- opt.rethrow = opt.rethrow !== false;
165
- this._transactions.count--;
166
- if (this._transactions.count == 0) {
167
- const shouldCommit = typeof err === 'undefined' && this._commit;
168
- await this._query(shouldCommit ? 'commit;' : 'rollback;');
169
- await this.emit('endedTransaction', err, shouldCommit);
170
- }
171
- await this._release();
172
- if (err && opt.rethrow) throw err;
173
- });
174
- }
175
-
176
- async transaction(todo) {
177
- await this.beginTransaction();
178
- let error;
179
- let result;
180
- try {
181
- result = await todo(this);
182
- } catch (err) {
183
- error = err;
184
- }
185
- await this.endTransaction(error);
186
- return result;
187
- }
188
-
189
- get set() {
190
- return {
191
- transactionMode: {
192
- readCommitted: async () => {
193
- await this._query('set transaction isolation level read committed;');
194
- },
195
- repeatableRead: async () => {
196
- await this._query('set transaction isolation level repeatable read;');
197
- },
198
- serializable: async () => {
199
- await this._query('set transaction isolation level serializable;');
200
- }
201
- }
202
- };
203
- }
204
-
205
- get connectionCount() {
206
- return {
207
- get: async () => {
208
- return await this._connectionQueue.add(async () => {
209
- return this._connectionCount;
210
- });
211
- }
212
- };
213
- }
214
-
215
- async exec(query, parameters, options = {}) {
216
-
217
- let result;
218
-
219
- const todo = async () => result = this._convertResult(await this._query(query, parameters), options);
220
-
221
- await this.emit('preQuery', query, parameters);
222
-
223
- try {
224
- if (this._transactions.always || options.transaction) await this.transaction(todo);
225
- else await this.retained(todo);
226
- } finally {
227
- await this.emit('query', query, parameters);
228
- }
229
-
230
- if (options.first === true) {
231
- return (result || [])[0];
232
- } else if (options.first) {
233
- return ((result || [])[0] || {})[options.first];
234
- }
235
-
236
- return result;
237
-
238
- }
239
-
240
- _queryBuild(table) {
241
- return new QueryBuilder(table, this._options, this);
242
- }
243
-
244
- from(table) {
245
- return this._queryBuild(table);
246
- }
247
-
248
- into(table) {
249
- return this._queryBuild(table);
250
- }
251
-
252
- };
11
+ export default PGed;
package/lib/index.js ADDED
@@ -0,0 +1,260 @@
1
+ //
2
+ // index.js
3
+ // @trenskow/pged
4
+ //
5
+ // Created by Kristian Trenskow on 2019/09/03
6
+ // See license in LICENSE.
7
+ //
8
+
9
+ import Puqeue from 'puqeue';
10
+ import caseit from '@trenskow/caseit';
11
+ import pg from 'pg';
12
+ import EventEmitter from '@trenskow/async-event-emitter';
13
+
14
+ import QueryBuilder from './query-builder.js';
15
+
16
+ const { Pool } = pg;
17
+
18
+ let id = 0;
19
+
20
+ let pgOptions;
21
+ let pool;
22
+
23
+ export default class PGed extends EventEmitter {
24
+
25
+ static get pg() {
26
+ return pgOptions;
27
+ }
28
+
29
+ static set pg(options) {
30
+ pgOptions = options;
31
+ }
32
+
33
+ static async end() {
34
+ if (pool) await pool.end();
35
+ pool = undefined;
36
+ }
37
+
38
+ constructor(options = {}) {
39
+
40
+ super();
41
+
42
+ pool = pool || new Pool(pgOptions);
43
+
44
+ options.casing = options.casing || {};
45
+ options.casing.db = options.casing.db || 'snake';
46
+ options.casing.js = options.casing.hs || 'camel';
47
+
48
+ options.defaultPrimaryKey = options.defaultPrimaryKey || 'id';
49
+
50
+ this._options = options;
51
+
52
+ this._connectionCount = 0;
53
+ this._connectionQueue = new Puqeue();
54
+
55
+ this._transactions = options.transactions || {};
56
+ this._transactions.mode = this._transactions.mode = options.transactions.mode || 'readCommitted';
57
+ this._transactions.always = this._transactions.always || false;
58
+ this._transactions.count = 0;
59
+
60
+ this._id = id++;
61
+
62
+ this._history = [];
63
+
64
+ this._cache = {};
65
+ this._cacheQueue = {};
66
+ this._cacheHits = 0;
67
+
68
+ this._nullIsUndefined = options.nullIsUndefined !== false;
69
+
70
+ this._commit = options.commit !== false;
71
+
72
+ this._cacheQueue = new Puqeue();
73
+
74
+ }
75
+
76
+ get id() {
77
+ return this._id;
78
+ }
79
+
80
+ get history() {
81
+ return this._history;
82
+ }
83
+
84
+ async _query(query, ...args) {
85
+ let info = {
86
+ query,
87
+ parameters: args[0],
88
+ timing: {
89
+ start: new Date()
90
+ }
91
+ };
92
+ this._history.push(info);
93
+ if (!this._client) {
94
+ console.warn(`We had a query without a client for query: ${query} (${JSON.stringify(...args)}).`);
95
+ }
96
+ const result = await this._client.query(query, ...args);
97
+ info.timing.ms = (new Date()).getTime() - info.timing.start.getTime();
98
+ return result;
99
+ }
100
+
101
+ _convertResult(result, options) {
102
+ if ((options || {}).format === 'raw') return (result || {}).rows;
103
+ return ((result || {}).rows || []).map((row) => {
104
+ let newRow = {};
105
+ Object.keys(row).forEach((key) => {
106
+ if (this._nullIsUndefined && typeof row[key] === 'object' && !row[key]) return;
107
+ newRow[caseit(key, this._options.casing.js)] = row[key];
108
+ });
109
+ return newRow;
110
+ });
111
+ }
112
+
113
+ async _retain() {
114
+ this._connectionCount++;
115
+ if (this._connectionCount == 1) {
116
+ this._client = await pool.connect();
117
+ await this.emit('connected');
118
+ }
119
+ }
120
+
121
+ async _release() {
122
+ this._connectionCount--;
123
+ if (this._connectionCount == 0) {
124
+ await this._client.release();
125
+ this._client = undefined;
126
+ await this.emit('disconnected');
127
+ }
128
+ }
129
+
130
+ async retain() {
131
+ await this._connectionQueue.add(async () => {
132
+ await this._retain();
133
+ });
134
+ }
135
+
136
+ async release() {
137
+ await this._connectionQueue.add(async () => {
138
+ await this._release();
139
+ });
140
+ }
141
+
142
+ async retained(todo) {
143
+ await this.retain();
144
+ let error;
145
+ let result;
146
+ try {
147
+ result = await todo(this);
148
+ } catch (err) {
149
+ error = err;
150
+ }
151
+ await this.release();
152
+ if (error) throw error;
153
+ return result;
154
+ }
155
+
156
+ async beginTransaction() {
157
+ await this._connectionQueue.add(async () => {
158
+ this._transactions.count++;
159
+ await this._retain();
160
+ if (this._transactions.count == 1) {
161
+ await this._query('begin;');
162
+ if (this._transactions.mode !== 'readCommitted') {
163
+ await this.set.transactionMode[this._transactions.mode]();
164
+ }
165
+ await this.emit('startedTransaction');
166
+ }
167
+ });
168
+ }
169
+
170
+ async endTransaction(err, opt = {}) {
171
+ await this._connectionQueue.add(async () => {
172
+ opt.rethrow = opt.rethrow !== false;
173
+ this._transactions.count--;
174
+ if (this._transactions.count == 0) {
175
+ const shouldCommit = typeof err === 'undefined' && this._commit;
176
+ await this._query(shouldCommit ? 'commit;' : 'rollback;');
177
+ await this.emit('endedTransaction', err, shouldCommit);
178
+ }
179
+ await this._release();
180
+ if (err && opt.rethrow) throw err;
181
+ });
182
+ }
183
+
184
+ async transaction(todo) {
185
+ await this.beginTransaction();
186
+ let error;
187
+ let result;
188
+ try {
189
+ result = await todo(this);
190
+ } catch (err) {
191
+ error = err;
192
+ }
193
+ await this.endTransaction(error);
194
+ return result;
195
+ }
196
+
197
+ get set() {
198
+ return {
199
+ transactionMode: {
200
+ readCommitted: async () => {
201
+ await this._query('set transaction isolation level read committed;');
202
+ },
203
+ repeatableRead: async () => {
204
+ await this._query('set transaction isolation level repeatable read;');
205
+ },
206
+ serializable: async () => {
207
+ await this._query('set transaction isolation level serializable;');
208
+ }
209
+ }
210
+ };
211
+ }
212
+
213
+ get connectionCount() {
214
+ return {
215
+ get: async () => {
216
+ return await this._connectionQueue.add(async () => {
217
+ return this._connectionCount;
218
+ });
219
+ }
220
+ };
221
+ }
222
+
223
+ async exec(query, parameters, options = {}) {
224
+
225
+ let result;
226
+
227
+ const todo = async () => result = this._convertResult(await this._query(query, parameters), options);
228
+
229
+ await this.emit('preQuery', query, parameters);
230
+
231
+ try {
232
+ if (this._transactions.always || options.transaction) await this.transaction(todo);
233
+ else await this.retained(todo);
234
+ } finally {
235
+ await this.emit('query', query, parameters);
236
+ }
237
+
238
+ if (options.first === true) {
239
+ return (result || [])[0];
240
+ } else if (options.first) {
241
+ return ((result || [])[0] || {})[options.first];
242
+ }
243
+
244
+ return result;
245
+
246
+ }
247
+
248
+ _queryBuild(table) {
249
+ return new QueryBuilder(table, this._options, this);
250
+ }
251
+
252
+ from(table) {
253
+ return this._queryBuild(table);
254
+ }
255
+
256
+ into(table) {
257
+ return this._queryBuild(table);
258
+ }
259
+
260
+ };
@@ -1,3 +1,11 @@
1
+ //
2
+ // index.js
3
+ // @trenskow/pged
4
+ //
5
+ // Created by Kristian Trenskow on 2019/09/03
6
+ // See license in LICENSE.
7
+ //
8
+
1
9
  import caseit from '@trenskow/caseit';
2
10
  import CustomPromise from '@trenskow/custom-promise';
3
11
  import Puqeue from 'puqeue';
@@ -299,6 +307,45 @@ export default class QueryBuilder extends CustomPromise {
299
307
  return this;
300
308
  }
301
309
 
310
+ search({ column, query, language, type = 'web' }) {
311
+
312
+ if (language?.[0] === ':') language = this._dbCase(language.substring(1));
313
+ else {
314
+ this._queryParameters = (this._queryParameters || []).concat([language]);
315
+ language = `$${this._queryParameters.length}`;
316
+ }
317
+
318
+ this._queryParameters = (this._queryParameters || []).concat([query]);
319
+ query = `$${this._queryParameters.length}`;
320
+
321
+ const vectorConverter = type === 'web' ? 'websearch_to_tsquery' : 'to_tsquery';
322
+
323
+ let vectorConverterArgs = [query];
324
+
325
+ if (language) {
326
+ vectorConverterArgs.unshift(language);
327
+ }
328
+
329
+ column = this._dbCase(column);
330
+
331
+ this._selectKeys = (this._selectKeys || []).concat([
332
+ `ts_rank(${column}, ${vectorConverter}(${vectorConverterArgs.join(', ')})) as rank`
333
+ ]);
334
+
335
+ this._sortingKeys = this._sortingKeys.concat([{
336
+ key: 'rank',
337
+ order: 'desc'
338
+ }]);
339
+
340
+ return this
341
+ .where({
342
+ $fullText: {
343
+ [`:${column}`]: `:${vectorConverter}(${vectorConverterArgs.join(', ')})`
344
+ }
345
+ });
346
+
347
+ }
348
+
302
349
  _canQuote(key) {
303
350
  if (key === '*') return false;
304
351
  if (key.toLowerCase().includes(' as ')) return false;
@@ -345,7 +392,8 @@ export default class QueryBuilder extends CustomPromise {
345
392
  $regexp: '~*',
346
393
  $jsonContains: '@>',
347
394
  $jsonNotContains: '@>',
348
- $jsonArrayContains: '?'
395
+ $jsonArrayContains: '?',
396
+ $fullText: '@@'
349
397
  };
350
398
  }
351
399
 
@@ -387,6 +435,7 @@ export default class QueryBuilder extends CustomPromise {
387
435
  case '$jsonContains':
388
436
  case '$jsonNotContains':
389
437
  case '$jsonArrayContains':
438
+ case '$fullText':
390
439
  return this._buildConditions(condition[key], operator, key, true);
391
440
  default:
392
441
  throw new TypeError(`Unknown modifier ${caseit(key)}.`);
@@ -570,7 +619,7 @@ export default class QueryBuilder extends CustomPromise {
570
619
 
571
620
  _build() {
572
621
 
573
- this._queryParameters = [];
622
+ this._queryParameters = (this._queryParameters || []);
574
623
 
575
624
  const command = this._command || 'select';
576
625
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trenskow/pged",
3
- "version": "5.1.32",
3
+ "version": "5.1.33",
4
4
  "description": "Just a silly little db management and query builder for PostgreSQL.",
5
5
  "main": "index.js",
6
6
  "type": "module",