Skip to content

Commit 03ca734

Browse files
Copilotmathiasrw
andauthored
Test coverage for JOIN with duplicate column names to close #547 (#2347)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: mathiasrw <[email protected]>
1 parent 5e75d54 commit 03ca734

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed

test/test547.js

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
if (typeof exports === 'object') {
2+
var assert = require('assert');
3+
var alasql = require('..');
4+
}
5+
6+
// Test for issue #547 - JOIN should return fields from both tables
7+
8+
describe('Test 547 - JOIN with duplicate column names', function () {
9+
after(function () {
10+
// Restore default joinstar option
11+
alasql.options.joinstar = 'overwrite';
12+
});
13+
14+
it('1. OVERWRITE mode (default) - later columns overwrite earlier ones', function () {
15+
alasql.options.joinstar = 'overwrite';
16+
17+
var data = [{dep: 'A', qt: 10, price: 5, extra: 1}];
18+
var data2 = [{dep: 'B', qt: 2, price: 5}];
19+
20+
// JOIN without ON clause produces cartesian product (1 row × 1 row = 1 row)
21+
var res = alasql('SELECT * FROM ? as a JOIN ? as b', [data, data2]);
22+
23+
// With overwrite mode, duplicate columns (dep, qt, price) should be overwritten by b's values
24+
// Non-duplicate column (extra) should be preserved from a
25+
assert.deepEqual(res, [{dep: 'B', qt: 2, price: 5, extra: 1}]);
26+
});
27+
28+
it('2. JSON mode - nested objects by table alias', function () {
29+
alasql.options.joinstar = 'json';
30+
31+
var data = [{dep: 'A', qt: 10, price: 5, extra: 1}];
32+
var data2 = [{dep: 'B', qt: 2, price: 5}];
33+
34+
// JOIN without ON clause produces cartesian product (1 row × 1 row = 1 row)
35+
var res = alasql('SELECT * FROM ? as a JOIN ? as b', [data, data2]);
36+
37+
// With json mode, each table's data should be nested under its alias
38+
assert.deepEqual(res, [
39+
{
40+
a: {dep: 'A', qt: 10, price: 5, extra: 1},
41+
b: {dep: 'B', qt: 2, price: 5},
42+
},
43+
]);
44+
});
45+
46+
it('3. UNDERSCORE mode - prefix columns with table alias', function () {
47+
alasql.options.joinstar = 'underscore';
48+
49+
var data = [{dep: 'A', qt: 10, price: 5, extra: 1}];
50+
var data2 = [{dep: 'B', qt: 2, price: 5}];
51+
52+
// JOIN without ON clause produces cartesian product (1 row × 1 row = 1 row)
53+
var res = alasql('SELECT * FROM ? as a JOIN ? as b', [data, data2]);
54+
55+
// With underscore mode, columns should be prefixed with their table alias
56+
assert.deepEqual(res, [
57+
{
58+
a_dep: 'A',
59+
a_qt: 10,
60+
a_price: 5,
61+
a_extra: 1,
62+
b_dep: 'B',
63+
b_qt: 2,
64+
b_price: 5,
65+
},
66+
]);
67+
});
68+
69+
it('4. OVERWRITE mode with CROSS JOIN', function () {
70+
alasql.options.joinstar = 'overwrite';
71+
72+
var data = [{a: 1}, {a: 2}];
73+
var data2 = [{a: 10}, {a: 20}];
74+
75+
var res = alasql('SELECT * FROM ? as one, ? as two', [data, data2]);
76+
77+
// Cartesian product with overwrite - column 'a' from 'two' overwrites 'a' from 'one'
78+
assert.deepEqual(res, [{a: 10}, {a: 20}, {a: 10}, {a: 20}]);
79+
});
80+
81+
it('5. JSON mode with CROSS JOIN', function () {
82+
alasql.options.joinstar = 'json';
83+
84+
var data = [{a: 1}, {a: 2}];
85+
var data2 = [{a: 10}, {a: 20}];
86+
87+
var res = alasql('SELECT * FROM ? as one, ? as two', [data, data2]);
88+
89+
// Cartesian product with nested objects
90+
assert.deepEqual(res, [
91+
{one: {a: 1}, two: {a: 10}},
92+
{one: {a: 1}, two: {a: 20}},
93+
{one: {a: 2}, two: {a: 10}},
94+
{one: {a: 2}, two: {a: 20}},
95+
]);
96+
});
97+
98+
it('6. UNDERSCORE mode with CROSS JOIN', function () {
99+
alasql.options.joinstar = 'underscore';
100+
101+
var data = [{a: 1}, {a: 2}];
102+
var data2 = [{a: 10}, {a: 20}];
103+
104+
var res = alasql('SELECT * FROM ? as one, ? as two', [data, data2]);
105+
106+
// Cartesian product with prefixed columns
107+
assert.deepEqual(res, [
108+
{one_a: 1, two_a: 10},
109+
{one_a: 1, two_a: 20},
110+
{one_a: 2, two_a: 10},
111+
{one_a: 2, two_a: 20},
112+
]);
113+
});
114+
115+
it('7. Mixed columns - some shared, some unique', function () {
116+
alasql.options.joinstar = 'json';
117+
118+
var data = [{id: 1, name: 'Alice', age: 30}];
119+
var data2 = [{id: 2, name: 'Bob', salary: 50000}];
120+
121+
// JOIN without ON clause produces cartesian product (1 row × 1 row = 1 row)
122+
var res = alasql('SELECT * FROM ? as employees JOIN ? as contractors', [data, data2]);
123+
124+
// Both tables have 'id' and 'name', but different other columns
125+
assert.deepEqual(res, [
126+
{
127+
employees: {id: 1, name: 'Alice', age: 30},
128+
contractors: {id: 2, name: 'Bob', salary: 50000},
129+
},
130+
]);
131+
});
132+
133+
it('8. UNDERSCORE mode with mixed columns', function () {
134+
alasql.options.joinstar = 'underscore';
135+
136+
var data = [{id: 1, name: 'Alice', age: 30}];
137+
var data2 = [{id: 2, name: 'Bob', salary: 50000}];
138+
139+
// JOIN without ON clause produces cartesian product (1 row × 1 row = 1 row)
140+
var res = alasql('SELECT * FROM ? as employees JOIN ? as contractors', [data, data2]);
141+
142+
// All columns prefixed with table alias
143+
assert.deepEqual(res, [
144+
{
145+
employees_id: 1,
146+
employees_name: 'Alice',
147+
employees_age: 30,
148+
contractors_id: 2,
149+
contractors_name: 'Bob',
150+
contractors_salary: 50000,
151+
},
152+
]);
153+
});
154+
});

0 commit comments

Comments
 (0)