spice-couchbase 2.0.55 → 2.0.57

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/build/index.js CHANGED
@@ -704,10 +704,15 @@ module.exports = class Database {
704
704
 
705
705
  if (query) {
706
706
  conditions.push(query);
707
- }
707
+ } // The conditions are folded into `where_clause` itself so that both queries below are built
708
+ // from one string. Previously this held the bare literal " WHERE " and only the data query
709
+ // appended `conditions.join(" AND ")`, which left the count query emitting a dangling
710
+ // `WHERE` — Couchbase answered "syntax error - at end of input" and every `do_count=true`
711
+ // request failed with a 400, on every resource.
712
+
708
713
 
709
- var where_clause = conditions.length ? " WHERE " : "";
710
- query = front_query + where_clause + conditions.join(" AND ");
714
+ var where_clause = conditions.length ? " WHERE ".concat(conditions.join(" AND ")) : "";
715
+ query = front_query + where_clause;
711
716
  var count_query = "SELECT count(meta(".concat(bucket, ").id) as count FROM ").concat(bucket, " ").concat(join, " ").concat(where_clause); //console.log("Cound Query::", count_query);
712
717
 
713
718
  var order_by_clause = order_by ? " ORDER BY ".concat(order_by) : "";
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "spice-couchbase",
3
- "version": "2.0.55",
3
+ "version": "2.0.57",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "scripts": {
7
7
  "test": "node src/utility.test.js",
8
- "test:query-consistency": "node src/index.query-consistency.test.js"
8
+ "test:query-consistency": "node src/index.query-consistency.test.js",
9
+ "test:count-query": "node src/index.count-query.test.js"
9
10
  },
10
11
  "author": "Chad Fraser <chad@sonover.com> (http://sonover.com)",
11
12
  "license": "ISC",
@@ -0,0 +1,129 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Regression tests for the WHERE clause shared by the data and count queries in `search()`.
5
+ *
6
+ * The count query used to be built from a `where_clause` that held the bare literal `" WHERE "`,
7
+ * while the conditions were appended only to the data query. Every `do_count` request therefore
8
+ * emitted `... FROM \`bucket\` WHERE` and Couchbase answered
9
+ * "syntax error - at end of input" (code 3000) with a 400 — on every resource, for every caller.
10
+ *
11
+ * It survived the existing suite because nothing exercised the count statement.
12
+ */
13
+
14
+ const assert = require("assert");
15
+ const Database = require("./index");
16
+
17
+ let passed = 0;
18
+ let failed = 0;
19
+
20
+ /** Captures the two statements `search()` produces without touching a cluster. */
21
+ function createSearchDb() {
22
+ const statements = { data: null, count: null };
23
+ const db = Object.create(Database.prototype);
24
+
25
+ db.use_bucket_name = false;
26
+ db.bucket = "test";
27
+ db.scope_name = "scope";
28
+ db.collection_name = "platformtask";
29
+
30
+ db.getData = async (statement) => {
31
+ statements.data = statement;
32
+ return [];
33
+ };
34
+ db.getCount = async (statement) => {
35
+ statements.count = statement;
36
+ return 0;
37
+ };
38
+ db.optimize = () => {};
39
+
40
+ return { db, statements };
41
+ }
42
+
43
+ async function test(name, fn) {
44
+ try {
45
+ await fn();
46
+ console.log(`✓ ${name}`);
47
+ passed += 1;
48
+ } catch (error) {
49
+ console.log(`✗ ${name}`);
50
+ console.log(` Error: ${error.stack || error.message}`);
51
+ failed += 1;
52
+ }
53
+ }
54
+
55
+ async function run() {
56
+ console.log("\n--- count query tests ---");
57
+
58
+ await test("the count query carries the predicates, not a dangling WHERE", async () => {
59
+ const { db, statements } = createSearchDb();
60
+
61
+ await db.search("platformtask", "id", `status = "pending"`, 1, 0, null, "true");
62
+
63
+ assert.ok(
64
+ statements.count.includes(`status = "pending"`),
65
+ `count query lost its predicate: ${statements.count}`
66
+ );
67
+ assert.ok(
68
+ !/WHERE\s*$/.test(statements.count.trim()),
69
+ `count query ends in a dangling WHERE: ${statements.count}`
70
+ );
71
+ });
72
+
73
+ await test("multiple conditions are joined with AND in the count query", async () => {
74
+ const { db, statements } = createSearchDb();
75
+
76
+ await db.search(
77
+ "platformtask",
78
+ "id",
79
+ `status = "pending" AND assignee_type = "user"`,
80
+ 1,
81
+ 0,
82
+ null,
83
+ "true"
84
+ );
85
+
86
+ assert.ok(statements.count.includes(`status = "pending"`));
87
+ assert.ok(statements.count.includes(`assignee_type = "user"`));
88
+ });
89
+
90
+ await test("an unfiltered count emits no WHERE at all", async () => {
91
+ const { db, statements } = createSearchDb();
92
+
93
+ await db.search("platformtask", "id", "", 1, 0, null, "true");
94
+
95
+ assert.ok(
96
+ !/WHERE/i.test(statements.count),
97
+ `unfiltered count should have no WHERE: ${statements.count}`
98
+ );
99
+ });
100
+
101
+ await test("the data and count queries agree on the WHERE clause", async () => {
102
+ const { db, statements } = createSearchDb();
103
+
104
+ await db.search("platformtask", "id", `status = "blocked"`, 1, 0, null, "true");
105
+
106
+ const whereOf = (sql) => {
107
+ const m = sql.match(/WHERE\s+(.*?)(?:\s+ORDER BY|\s+LIMIT|\s+OFFSET|$)/is);
108
+ return m ? m[1].trim() : null;
109
+ };
110
+ assert.strictEqual(whereOf(statements.data), whereOf(statements.count));
111
+ });
112
+
113
+ await test("no count statement is produced when do_count is off", async () => {
114
+ const { db, statements } = createSearchDb();
115
+
116
+ await db.search("platformtask", "id", `status = "pending"`, 1, 0, null, "false");
117
+
118
+ assert.strictEqual(statements.count, null);
119
+ assert.ok(statements.data.includes(`status = "pending"`));
120
+ });
121
+
122
+ console.log("\n========================================");
123
+ console.log(`Tests: ${passed + failed} | Passed: ${passed} | Failed: ${failed}`);
124
+ console.log("========================================");
125
+
126
+ if (failed > 0) process.exit(1);
127
+ }
128
+
129
+ run();
package/src/index.js CHANGED
@@ -671,8 +671,15 @@ module.exports = class Database {
671
671
  conditions.push(query);
672
672
  }
673
673
 
674
- const where_clause = conditions.length ? " WHERE " : "";
675
- query = front_query + where_clause + conditions.join(" AND ");
674
+ // The conditions are folded into `where_clause` itself so that both queries below are built
675
+ // from one string. Previously this held the bare literal " WHERE " and only the data query
676
+ // appended `conditions.join(" AND ")`, which left the count query emitting a dangling
677
+ // `WHERE` — Couchbase answered "syntax error - at end of input" and every `do_count=true`
678
+ // request failed with a 400, on every resource.
679
+ const where_clause = conditions.length
680
+ ? ` WHERE ${conditions.join(" AND ")}`
681
+ : "";
682
+ query = front_query + where_clause;
676
683
 
677
684
  const count_query = `SELECT count(meta(${bucket}).id) as count FROM ${bucket} ${join} ${where_clause}`;
678
685
  //console.log("Cound Query::", count_query);