spice-couchbase 2.0.14 → 2.0.17

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.
Files changed (3) hide show
  1. package/build/index.js +332 -230
  2. package/package.json +5 -3
  3. package/src/index.js +348 -198
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spice-couchbase",
3
- "version": "2.0.14",
3
+ "version": "2.0.17",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "scripts": {
@@ -9,8 +9,10 @@
9
9
  "author": "Chad Fraser <chad@sonover.com> (http://sonover.com)",
10
10
  "license": "ISC",
11
11
  "dependencies": {
12
- "couchbase": "^3.0.6",
13
- "lodash": "^4.17.15"
12
+ "axios": "^0.26.1",
13
+ "couchbase": "^4.0.0",
14
+ "lodash": "^4.17.15",
15
+ "qs": "^6.10.3"
14
16
  },
15
17
  "devDependencies": {
16
18
  "@babel/cli": "^7.7.7",
package/src/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
 
3
- let _ = require('lodash');
4
- let couchbase = require('couchbase');
3
+ let _ = require("lodash");
4
+ let couchbase = require("couchbase");
5
+ const { default: axios } = require("axios");
6
+ var qs = require("qs");
5
7
 
6
8
  if (!Promise.allSettled) {
7
9
  Promise.allSettled = (promises) =>
@@ -20,134 +22,264 @@ if (!Promise.allSettled) {
20
22
  );
21
23
  }
22
24
  module.exports = class Database {
23
- constructor(connection, full_text_index) {
25
+ constructor(
26
+ connection,
27
+ {
28
+ full_text_index,
29
+ collection,
30
+ scope,
31
+ query_scope = "cluster",
32
+ auto_create_collection,
33
+ } = {}
34
+ ) {
24
35
  if (connection) {
25
36
  this.connection_name = connection;
26
37
  this.connection = spice.database.connections[connection];
27
- this.cluster = spice.database.clusters[connection]
38
+ this.query_scope = query_scope;
39
+ this.cluster = spice.database.clusters[connection];
28
40
  this.bucket = this.connection._scope._bucket._name;
29
- this.full_text_index = spice.config.database.connections[connection].full_text_index || full_text_index;
30
- this.N1qlQuery = couchbase.N1qlQuery
41
+ this.db_config = spice.config.database.connections[connection];
42
+ this.collection_manager =
43
+ spice.database.buckets[connection].collections();
44
+ this.auto_create_collection =
45
+ auto_create_collection ||
46
+ ((collection ||
47
+ spice.config.database.connections[connection].collection) !=
48
+ undefined &&
49
+ (collection ||
50
+ spice.config.database.connections[connection].collection) !=
51
+ "default" &&
52
+ (scope || spice.config.database.connections[connection].scope) !=
53
+ "_default");
54
+ this.collection_name =
55
+ collection ||
56
+ spice.config.database.connections[connection].collection ||
57
+ "_default";
58
+ this.scope_name =
59
+ scope ||
60
+ spice.config.database.connections[connection].scope ||
61
+ "_default";
62
+ this.scope = spice.database.scopes[connection];
63
+ this.full_text_index =
64
+ spice.config.database.connections[connection].full_text_index ||
65
+ full_text_index;
66
+ this.N1qlQuery = couchbase.N1qlQuery;
31
67
  this.SearchQuery = couchbase.SearchQuery;
32
- }
33
- }
34
- connect(key, value) {
35
- return new Promise((resolve, reject) => {
36
- try {
37
- let cluster = new couchbase.Cluster(value.nodes, {
38
- username: value.username,
39
- password: value.password,
40
- });
41
- let bucket = cluster.bucket(value.bucket);
42
- let collection = bucket.defaultCollection();
43
- resolve({
44
- connection: key,
45
- bucket,
46
- cluster,
47
- collection,
48
- });
49
- } catch (e) {
50
- spice.logger.debug(e, e.stack);
51
- reject(e);
68
+ this.connection = this.scope.collection(this.collection_name);
69
+ this.userManager = this.getUserManager(connection);
70
+ if (this.auto_create_collection) {
71
+ this.upsertCollection();
52
72
  }
53
- })
73
+
74
+ this.use_bucket_name = !(
75
+ spice.config.database.connections[this.connection_name].scope &&
76
+ spice.config.database.connections[this.connection_name].collection
77
+ );
78
+ }
54
79
  }
55
80
 
56
- get(doc_id) {
57
- let that = this;
58
- return new Promise(async function (resolve, reject) {
59
- that.connection.get(doc_id, function (err, res) {
60
- var return_value = {};
61
- if (err) {
62
- reject(err);
63
- } else {
64
- _.defaults(return_value, res.value);
65
- return_value.id = doc_id;
66
- resolve(return_value);
67
- }
68
- });
81
+ async connect(connection_name, config) {
82
+ let cluster = await couchbase.connect(config.nodes, {
83
+ username: config.username,
84
+ password: config.password,
69
85
  });
86
+ let bucket = cluster.bucket(config.bucket);
87
+ let collection;
88
+ let scope_name = this.scope_name || config.scope || "_default";
89
+ let collection_name =
90
+ this.collection_name || config.collection || "_default";
91
+ let scope = bucket.scope(scope_name);
92
+
93
+ collection = bucket
94
+ .scope(scope_name)
95
+ .collection(collection_name || "_default");
96
+
97
+ return {
98
+ connection: connection_name,
99
+ bucket,
100
+ cluster,
101
+ scope,
102
+ collection,
103
+ };
70
104
  }
71
105
 
72
- insert(doc_id, document, expiry) {
73
- var that = this;
74
- return new Promise(async function (resolve, reject) {
75
- that.connection.insert(doc_id, document, {
76
- expiry: expiry,
77
- }, async function (err, res) {
78
- if (err) {
79
- reject(err);
80
- } else {
81
- try {
82
- let created = await that.get(doc_id)
83
- resolve(created)
84
- } catch (e) {
85
- reject(e)
86
- }
87
- }
88
- });
89
- });
106
+ getUserManager(connection) {
107
+ return spice.database.clusters[connection].users();
90
108
  }
91
109
 
92
- touch(doc_id, expiry = 0) {
93
- var that = this;
94
- return new Promise(async function (resolve, reject) {
95
- that.connection.touch(doc_id, expiry, async function (err, res) {
96
- if (err) {
97
- reject(err);
98
- } else {
99
- try {
100
- let created = await that.get(doc_id)
101
- resolve(created)
102
- } catch (e) {
103
- reject(e)
104
- }
110
+ async assignUserPermission() {
111
+ try {
112
+ let allUsers = await this.userManager.getAllUsers({ timeout: 6000 });
113
+ let update_user_response = await this.userManager.upsertUser(
114
+ this.db_config.username,
115
+ {
116
+ roles: [
117
+ { name: "scope_admin", bucket: this.db_config.bucket },
118
+ { name: "data_reader", bucket: this.db_config.bucket },
119
+ ],
105
120
  }
106
- });
107
- });
121
+ );
122
+ } catch (e) {
123
+ console.log(e);
124
+ }
108
125
  }
109
126
 
127
+ getCouchbaseHost(default_port = 8091) {
128
+ return (
129
+ (this.db_config.api_base ||
130
+ `http://${_.last(
131
+ _.first(this.db_config.nodes.split(",")).split("://")
132
+ )}`) +
133
+ ":" +
134
+ default_port
135
+ );
136
+ }
110
137
 
111
- count(doc_id, adjustment, initial_value) {
112
- var that = this;
113
- return new Promise(async function (resolve, reject) {
114
- that.connection.counter(doc_id, adjustment, {
115
- initial: initial_value,
116
- }, function (err, res) {
117
- if (err) {
118
- reject(err);
119
- } else {
120
- resolve(res.value)
121
- }
122
- });
123
- });
138
+ //create wait function
139
+ async wait(ms) {
140
+ return new Promise((resolve) => setTimeout(resolve, ms));
124
141
  }
125
142
 
143
+ async upsertCollection() {
144
+ try {
145
+ let collection_exists = await this.collectionExists(
146
+ this.collection_name,
147
+ this.scope_name
148
+ );
149
+ if (!collection_exists) {
150
+ await this.createCollection(this.collection_name, this.scope_name);
151
+ await this.wait(2000);
152
+ await this.createPrimaryIndex(this.scope_name, this.collection_name);
153
+ }
154
+ } catch (e) {
155
+ console.log(e);
156
+ }
157
+ }
126
158
 
127
- update(doc_id, document) {
128
- var that = this;
129
- return new Promise(async function (resolve, reject) {
130
- that.connection.replace(doc_id, document, function (err, res) {
131
- if (err) {
132
- reject(err);
133
- } else {
134
- resolve(res.value)
159
+ async collectionExists(collection_name, scope_name) {
160
+ try {
161
+ let all_scopes = await axios.get(
162
+ `${this.getCouchbaseHost()}/pools/default/buckets/${
163
+ this.db_config.bucket
164
+ }/scopes`,
165
+ {
166
+ auth: {
167
+ username: this.db_config.username,
168
+ password: this.db_config.password,
169
+ },
135
170
  }
136
- });
137
- });
171
+ );
172
+ let collection_e =
173
+ _.find(
174
+ _.find(all_scopes.data.scopes, { name: scope_name })?.collections ||
175
+ [],
176
+ { name: collection_name }
177
+ ) != undefined;
178
+ return collection_e;
179
+ } catch (e) {
180
+ console.log("Exists error happened", e);
181
+ }
138
182
  }
139
183
 
140
- delete(doc_id) {
141
- var that = this;
142
- return new Promise(async function (resolve, reject) {
143
- that.connection.remove(doc_id, function (err, res) {
144
- if (err) {
145
- reject(err);
146
- } else {
147
- resolve(res.value)
148
- }
149
- });
184
+ async createCollection(connection_name, scope_name) {
185
+ try {
186
+ const token = `${this.db_config.username}:${this.db_config.password}`;
187
+ const encodedToken = Buffer.from(token).toString("base64");
188
+ const headers = {
189
+ Authorization: "Basic " + encodedToken,
190
+ "Content-Type": "application/x-www-form-urlencoded",
191
+ };
192
+ let response = await axios({
193
+ method: "post",
194
+ url: `${this.getCouchbaseHost()}/pools/default/buckets/${
195
+ this.db_config.bucket
196
+ }/scopes/${scope_name}/collections`,
197
+ headers,
198
+ data: qs.stringify({ name: connection_name }),
199
+ }).data;
200
+ return response;
201
+ } catch (e) {}
202
+ }
203
+
204
+ async createPrimaryIndex(scope_name, col_name) {
205
+ try {
206
+ let response = await this.query(
207
+ `CREATE PRIMARY INDEX ON default:\`${this.db_config.bucket}\`.\`${scope_name}\`.\`${col_name}\``
208
+ );
209
+ return response;
210
+ } catch (e) {
211
+ console.log("CREATE Index :::", e);
212
+ }
213
+ }
214
+
215
+ async createScope(scope_name) {
216
+ try {
217
+ await this.collection_manager.createScope(scope_name);
218
+ } catch (e) {
219
+ if (e instanceof couchbase.ScopeExistsError) {
220
+ console.log("The scope already exists");
221
+ } else {
222
+ throw e;
223
+ }
224
+ }
225
+ }
226
+
227
+ async get(doc_id) {
228
+ try {
229
+ let response = await (this.use_bucket_name
230
+ ? this.connection
231
+ : this.collection
232
+ ).get(doc_id);
233
+
234
+ return { id: doc_id, ...response.content };
235
+ } catch (e) {
236
+ console.error(e);
237
+ }
238
+ }
239
+
240
+ async insert(doc_id, document, expiry) {
241
+ await (this.use_bucket_name ? this.connection : this.collection).insert(
242
+ doc_id,
243
+ document,
244
+ {
245
+ expiry: expiry,
246
+ }
247
+ );
248
+ return await this.get(doc_id);
249
+ }
250
+
251
+ async touch(doc_id, expiry = 0) {
252
+ await (this.use_bucket_name ? this.connection : this.collection).touch(
253
+ doc_id,
254
+ expiry
255
+ );
256
+ return await this.get(doc_id);
257
+ }
258
+
259
+ async count(doc_id, adjustment, initial_value) {
260
+ let res = await (this.use_bucket_name
261
+ ? this.connection
262
+ : this.collection
263
+ ).counter(doc_id, adjustment, {
264
+ initial: initial_value,
150
265
  });
266
+ return res.value;
267
+ }
268
+
269
+ async update(doc_id, document) {
270
+ let res = await (this.use_bucket_name
271
+ ? this.connection
272
+ : this.collection
273
+ ).replace(doc_id, document);
274
+ return res.value;
275
+ }
276
+
277
+ async delete(doc_id) {
278
+ let res = await (this.use_bucket_name
279
+ ? this.connection
280
+ : this.collection
281
+ ).remove(doc_id);
282
+ return res.value;
151
283
  }
152
284
 
153
285
  async multi_get(keys, keep_type) {
@@ -158,7 +290,9 @@ module.exports = class Database {
158
290
  }
159
291
  // console.log("on Multiget", keys);
160
292
  if (_.isArray(keys) && keys.length > 0) {
161
- let functions = _.map(keys, key => this.connection.get(key))
293
+ let functions = _.map(keys, (key) =>
294
+ (this.use_bucket_name ? this.connection : this.collection).get(key)
295
+ );
162
296
  let returned_all = await Promise.allSettled(functions);
163
297
 
164
298
  let responses = _.flatten(
@@ -176,24 +310,6 @@ module.exports = class Database {
176
310
  res.value.id = keys[index];
177
311
  return res.value;
178
312
  });
179
-
180
- /* that.connection.getMulti(keys, function (err, res) {
181
- if (res) {
182
- let return_value = [];
183
- for (var i in res) {
184
- if (res[i].value) {
185
- if (!keep_type) {
186
- delete res[i].value['type']
187
- }
188
- res[i].value.id = i;
189
- return_value.push(res[i].value);
190
- }
191
- }
192
- resolve(return_value);
193
- } else if (err) {
194
- reject(err);
195
- }
196
- }); */
197
313
  } else {
198
314
  return [];
199
315
  }
@@ -228,7 +344,7 @@ module.exports = class Database {
228
344
  that.connection.query(query, async function (err, results, matrix) {
229
345
  var return_value = [];
230
346
  if (err) {
231
- reject(err)
347
+ reject(err);
232
348
  } else {
233
349
  for (var i = 0; i < results.length; i++) {
234
350
  if (results[i].value) {
@@ -239,88 +355,114 @@ module.exports = class Database {
239
355
  }
240
356
 
241
357
  try {
242
- let created = await that.multi_get(return_value)
243
- resolve(created)
358
+ let created = await that.multi_get(return_value);
359
+ resolve(created);
244
360
  } catch (e) {
245
- reject(e)
361
+ reject(e);
246
362
  }
247
363
  }
248
364
  });
249
365
  });
250
366
  }
251
367
 
368
+ async search(
369
+ type,
370
+ columns,
371
+ query,
372
+ limit,
373
+ offset,
374
+ order_by,
375
+ do_count,
376
+ query_scope
377
+ ) {
378
+ let is_legacy =
379
+ this.scope_name !== "_default" && this.collection_name !== "_default";
380
+ let alias = "_reference";
381
+ let bucket = `\`${
382
+ this.use_bucket_name ? this.bucket : this.collection_name
383
+ }\``;
384
+
385
+ try {
386
+ //let uses_scopes = this.scope this.scope_name !== "_default";
387
+
388
+ if (do_count == undefined) {
389
+ do_count = "false";
390
+ }
391
+ var fix = "";
392
+ var count_query = "";
393
+ if (!limit) {
394
+ limit = 0;
395
+ }
252
396
 
253
- search(type, columns, query, limit, offset, order_by, do_count, statement_consistent) {
254
- let that = this;
255
- return new Promise(async (resolve, reject) => {
256
- try {
257
- if (do_count == undefined) {
258
- do_count = "false";
259
- }
260
- var fix = "";
261
- var count_query = "";
262
- if (!limit) {
263
- limit = 0;
264
- }
397
+ if (!offset) {
398
+ offset = 0;
399
+ }
265
400
 
266
- if (!offset) {
267
- offset = 0;
268
- }
401
+ if (columns == "*") {
402
+ columns = "(" + bucket + ").*";
403
+ fix = ", META(" + bucket + ").id AS id";
404
+ }
269
405
 
270
- if (columns == "*") {
271
- columns = "(" + that.bucket + ").*";
272
- fix = ", META(" + that.bucket + ").id AS id";
273
- }
406
+ if (!columns) {
407
+ columns = "(" + bucket + ").*";
408
+ fix = ", META(" + bucket + ").id AS id";
409
+ }
274
410
 
275
- if (!columns) {
276
- columns = "(" + that.bucket + ").*";
277
- fix = ", META(" + that.bucket + ").id AS id";
278
- }
411
+ if (columns == "id") {
412
+ fix = ", META(" + bucket + ").id AS id";
413
+ columns = "";
414
+ }
279
415
 
280
- if (columns == "id") {
281
- fix = ", META(" + that.bucket + ").id AS id";
282
- columns = "";
283
- }
416
+ var front_query = `SELECT ${columns} ${fix} FROM ${bucket}`;
284
417
 
285
- var front_query = "SELECT " + columns + fix + " FROM " + that.bucket + " WHERE type='" + type + "'";
286
- count_query = "SELECT count(meta().id) as count FROM " + that.bucket + " WHERE type='" + type + "'";
287
- if (query) {
288
- count_query = count_query + " AND " + query;
289
- query = front_query + " AND " + query;
290
- } else {
291
- query = front_query;
292
- }
418
+ if (is_legacy || query) {
419
+ front_query += " WHERE ";
420
+ }
293
421
 
294
- if (order_by) {
295
- query = `${query} ORDER BY ${order_by}`;
296
- }
422
+ let conditions = [];
423
+ if (this.use_bucket_name) {
424
+ conditions.push(`type = '${type}'`);
425
+ }
426
+ if (query) {
427
+ conditions.push(query);
428
+ }
297
429
 
298
- if (limit > 0) {
299
- query = query + " LIMIT " + limit;
300
- }
430
+ query = front_query + conditions.join(" AND ");
301
431
 
302
- if (offset > 0) {
303
- query = query + " OFFSET " + offset;
304
- }
432
+ count_query = `SELECT count(meta().id) as count FROM ${bucket}`;
433
+ if (this.use_bucket_name || query) {
434
+ count_query += " WHERE ";
435
+ }
436
+ query = front_query + conditions.join(" AND ");
305
437
 
306
- var query_element = query;
307
- var count_query_element = count_query;
438
+ if (order_by) {
439
+ query = `${query} ORDER BY ${order_by}`;
440
+ }
308
441
 
309
- let queries = [that.getData(query_element)]
310
- if (do_count === "true") {
311
- queries.push(that.getCount(count_query_element));
312
- }
313
- let responses = await Promise.all(queries);
442
+ if (limit > 0) {
443
+ query = query + " LIMIT " + limit;
444
+ }
314
445
 
315
- resolve({
316
- data: responses[0],
317
- total: responses.length > 1 ? responses[1] : null,
318
- });
319
- } catch (error) {
320
- console.log(error.stack);
321
- reject(error);
446
+ if (offset > 0) {
447
+ query = query + " OFFSET " + offset;
322
448
  }
323
- });
449
+
450
+ let active_query_space =
451
+ query_scope || !this.use_bucket_name ? "scope" : "cluster";
452
+
453
+ let queries = [this.getData(query, active_query_space)];
454
+ if (do_count === "true") {
455
+ queries.push(this.getCount(count_query, active_query_space));
456
+ }
457
+ let responses = await Promise.all(queries);
458
+
459
+ return {
460
+ data: responses[0],
461
+ total: responses.length > 1 ? responses[1] : null,
462
+ };
463
+ } catch (error) {
464
+ throw error;
465
+ }
324
466
  }
325
467
 
326
468
  full_text_search(type, search_query, limit, offset = 0, full_text_index) {
@@ -328,7 +470,10 @@ module.exports = class Database {
328
470
  return new Promise(async function (resolve, reject) {
329
471
  try {
330
472
  let full_query = search_query + " AND type:" + type;
331
- var query = that.SearchQuery.new(that.full_text_index || full_text_index, that.SearchQuery.queryString(full_query));
473
+ var query = that.SearchQuery.new(
474
+ that.full_text_index || full_text_index,
475
+ that.SearchQuery.queryString(full_query)
476
+ );
332
477
 
333
478
  if (!limit) {
334
479
  limit = 0;
@@ -347,7 +492,7 @@ module.exports = class Database {
347
492
  that.cluster.query(query, async function (err, results, matrix) {
348
493
  var return_value = [];
349
494
  if (err) {
350
- reject(err)
495
+ reject(err);
351
496
  } else {
352
497
  for (var i = 0; i < results.length; i++) {
353
498
  if (results[i].value) {
@@ -358,7 +503,7 @@ module.exports = class Database {
358
503
  }
359
504
 
360
505
  try {
361
- let getted = await that.multi_get(return_value)
506
+ let getted = await that.multi_get(return_value);
362
507
  resolve({
363
508
  data: getted,
364
509
  total: null,
@@ -374,16 +519,21 @@ module.exports = class Database {
374
519
  });
375
520
  }
376
521
 
377
- async getCount(count_query_element) {
378
- let response = await this.cluster.query(count_query_element);
522
+ async getCount(count_query_element, query_scope = "cluster") {
523
+ let response = await this.query(count_query_element, query_scope);
379
524
  return response.rows[0].count;
380
525
  }
381
- async getData(query_element) {
382
- let response = await this.cluster.query(query_element)
526
+ async getData(query_element, query_scope = "cluster") {
527
+ let response = await this.query(query_element, query_scope);
383
528
  return response.rows;
384
529
  }
385
530
 
386
- async query(query) {
387
- return this.cluster.query(query)
531
+ async query(query, query_scope = "cluster") {
532
+ let scope = query_scope || this.query_scope;
533
+ if (scope == "cluster") {
534
+ return await this.cluster.query(query);
535
+ } else {
536
+ return await this.scope.query(query);
537
+ }
388
538
  }
389
- }
539
+ };