|
| 1 | +if (typeof exports === 'object') { |
| 2 | + var assert = require('assert'); |
| 3 | + var alasql = require('..'); |
| 4 | +} |
| 5 | + |
| 6 | +describe('Test - Scalar Subquery Support', function () { |
| 7 | + const test = 'scalarsubquery'; |
| 8 | + |
| 9 | + before(function () { |
| 10 | + alasql('create database test' + test); |
| 11 | + alasql('use test' + test); |
| 12 | + }); |
| 13 | + |
| 14 | + after(function () { |
| 15 | + alasql('drop database test' + test); |
| 16 | + }); |
| 17 | + |
| 18 | + it('A) Scalar subquery in SELECT clause - basic', function () { |
| 19 | + alasql('CREATE TABLE products (id INT, name STRING, price INT)'); |
| 20 | + alasql( |
| 21 | + 'INSERT INTO products VALUES (1, "Widget", 10), (2, "Gadget", 20), (3, "Doohickey", 30)' |
| 22 | + ); |
| 23 | + |
| 24 | + var res = alasql( |
| 25 | + 'SELECT id, name, price, (SELECT MAX(price) FROM products) as max_price FROM products' |
| 26 | + ); |
| 27 | + |
| 28 | + assert.deepEqual(res, [ |
| 29 | + {id: 1, name: 'Widget', price: 10, max_price: 30}, |
| 30 | + {id: 2, name: 'Gadget', price: 20, max_price: 30}, |
| 31 | + {id: 3, name: 'Doohickey', price: 30, max_price: 30}, |
| 32 | + ]); |
| 33 | + }); |
| 34 | + |
| 35 | + it('B) Scalar subquery in SELECT clause - with aggregate functions', function () { |
| 36 | + var res = alasql( |
| 37 | + 'SELECT id, name, price, (SELECT AVG(price) FROM products) as avg_price, (SELECT MIN(price) FROM products) as min_price FROM products' |
| 38 | + ); |
| 39 | + |
| 40 | + assert.deepEqual(res, [ |
| 41 | + {id: 1, name: 'Widget', price: 10, avg_price: 20, min_price: 10}, |
| 42 | + {id: 2, name: 'Gadget', price: 20, avg_price: 20, min_price: 10}, |
| 43 | + {id: 3, name: 'Doohickey', price: 30, avg_price: 20, min_price: 10}, |
| 44 | + ]); |
| 45 | + }); |
| 46 | + |
| 47 | + it('C) Scalar subquery in WHERE clause', function () { |
| 48 | + var res = alasql('SELECT * FROM products WHERE price > (SELECT AVG(price) FROM products)'); |
| 49 | + |
| 50 | + assert.deepEqual(res, [{id: 3, name: 'Doohickey', price: 30}]); |
| 51 | + }); |
| 52 | + |
| 53 | + it('D) Scalar subquery in WHERE clause - with comparison operators', function () { |
| 54 | + var res = alasql('SELECT * FROM products WHERE price = (SELECT MAX(price) FROM products)'); |
| 55 | + |
| 56 | + assert.deepEqual(res, [{id: 3, name: 'Doohickey', price: 30}]); |
| 57 | + }); |
| 58 | + |
| 59 | + it('E) Correlated scalar subquery - SUM aggregate', function () { |
| 60 | + alasql('CREATE TABLE customers (id INT, name STRING, income INT)'); |
| 61 | + alasql( |
| 62 | + 'INSERT INTO customers VALUES (1, "Alice", 50000), (2, "Bob", 60000), (3, "Charlie", 70000)' |
| 63 | + ); |
| 64 | + alasql('CREATE TABLE orders (customer_id INT, amount INT)'); |
| 65 | + alasql('INSERT INTO orders VALUES (1, 100), (1, 200), (2, 150), (2, 250), (3, 300), (3, 400)'); |
| 66 | + |
| 67 | + var res = alasql( |
| 68 | + 'SELECT c.id, c.name, (SELECT SUM(amount) FROM orders o WHERE o.customer_id = c.id) as total_orders FROM customers c' |
| 69 | + ); |
| 70 | + |
| 71 | + assert.deepEqual(res, [ |
| 72 | + {id: 1, name: 'Alice', total_orders: 300}, |
| 73 | + {id: 2, name: 'Bob', total_orders: 400}, |
| 74 | + {id: 3, name: 'Charlie', total_orders: 700}, |
| 75 | + ]); |
| 76 | + }); |
| 77 | + |
| 78 | + it('F) Correlated scalar subquery - COUNT aggregate', function () { |
| 79 | + var res = alasql( |
| 80 | + 'SELECT c.id, c.name, (SELECT COUNT(*) FROM orders o WHERE o.customer_id = c.id) as order_count FROM customers c' |
| 81 | + ); |
| 82 | + |
| 83 | + assert.deepEqual(res, [ |
| 84 | + {id: 1, name: 'Alice', order_count: 2}, |
| 85 | + {id: 2, name: 'Bob', order_count: 2}, |
| 86 | + {id: 3, name: 'Charlie', order_count: 2}, |
| 87 | + ]); |
| 88 | + }); |
| 89 | + |
| 90 | + it('G) Correlated scalar subquery - AVG aggregate', function () { |
| 91 | + var res = alasql( |
| 92 | + 'SELECT c.id, c.name, (SELECT AVG(amount) FROM orders o WHERE o.customer_id = c.id) as avg_order FROM customers c' |
| 93 | + ); |
| 94 | + |
| 95 | + assert.deepEqual(res, [ |
| 96 | + {id: 1, name: 'Alice', avg_order: 150}, |
| 97 | + {id: 2, name: 'Bob', avg_order: 200}, |
| 98 | + {id: 3, name: 'Charlie', avg_order: 350}, |
| 99 | + ]); |
| 100 | + }); |
| 101 | + |
| 102 | + it('H) Multiple scalar subqueries in SELECT clause', function () { |
| 103 | + var res = alasql(` |
| 104 | + SELECT c.id, c.name, |
| 105 | + (SELECT SUM(amount) FROM orders o WHERE o.customer_id = c.id) as sum_amt, |
| 106 | + (SELECT AVG(amount) FROM orders o WHERE o.customer_id = c.id) as avg_amt, |
| 107 | + (SELECT COUNT(*) FROM orders o WHERE o.customer_id = c.id) as cnt |
| 108 | + FROM customers c |
| 109 | + WHERE c.id = 1 |
| 110 | + `); |
| 111 | + |
| 112 | + assert.deepEqual(res, [{id: 1, name: 'Alice', sum_amt: 300, avg_amt: 150, cnt: 2}]); |
| 113 | + }); |
| 114 | + |
| 115 | + it('I) Scalar subquery with WHERE condition in subquery', function () { |
| 116 | + var res = alasql( |
| 117 | + 'SELECT * FROM customers WHERE income > (SELECT AVG(income) FROM customers WHERE id > 1)' |
| 118 | + ); |
| 119 | + |
| 120 | + assert.deepEqual(res, [{id: 3, name: 'Charlie', income: 70000}]); |
| 121 | + }); |
| 122 | + |
| 123 | + it('J) Scalar subquery in complex WHERE condition', function () { |
| 124 | + alasql('CREATE TABLE stats (category STRING, avg_val INT)'); |
| 125 | + alasql('INSERT INTO stats VALUES ("high", 65000), ("low", 55000)'); |
| 126 | + |
| 127 | + var res = alasql( |
| 128 | + 'SELECT * FROM customers WHERE income > (SELECT avg_val FROM stats WHERE category = "high")' |
| 129 | + ); |
| 130 | + |
| 131 | + assert.deepEqual(res, [{id: 3, name: 'Charlie', income: 70000}]); |
| 132 | + }); |
| 133 | + |
| 134 | + it('K) Scalar subquery returns 0 for SUM when no rows match', function () { |
| 135 | + var res = alasql( |
| 136 | + 'SELECT c.id, c.name, (SELECT SUM(amount) FROM orders o WHERE o.customer_id = 999) as no_orders FROM customers c WHERE c.id = 1' |
| 137 | + ); |
| 138 | + |
| 139 | + // Note: In AlaSQL, SUM returns 0 when no rows match. |
| 140 | + // This differs from standard SQL where SUM typically returns NULL for empty result sets. |
| 141 | + assert.deepEqual(res, [{id: 1, name: 'Alice', no_orders: 0}]); |
| 142 | + }); |
| 143 | + |
| 144 | + it('L) Scalar subquery in arithmetic expression', function () { |
| 145 | + var res = alasql( |
| 146 | + 'SELECT id, name, price, price - (SELECT AVG(price) FROM products) as price_diff FROM products WHERE id = 1' |
| 147 | + ); |
| 148 | + |
| 149 | + assert.deepEqual(res, [{id: 1, name: 'Widget', price: 10, price_diff: -10}]); |
| 150 | + }); |
| 151 | +}); |
0 commit comments