diff --git a/src/40select.js b/src/40select.js index 53a1b98335..45734f8d37 100755 --- a/src/40select.js +++ b/src/40select.js @@ -529,18 +529,41 @@ function modify(query, res) { // If dirtyColumns is true, we need to merge columns from data with existing columns // This happens when SELECT * is used with dynamic data sources (like parameters) if (query.dirtyColumns && res.length > 0) { - var allcol = {}; - // First, scan the data to find all column names - for (var i = Math.min(res.length, alasql.options.columnlookup || 10) - 1; 0 <= i; i--) { - for (var key in res[i]) { - allcol[key] = true; + // Use Object.keys from the first complete row to preserve column order + // For sparse data (OUTER JOINs), find the row with the most keys + var maxKeys = Object.keys(res[0]); + var maxKeyCount = maxKeys.length; + var allcolSet = {}; + var maxRows = Math.min(res.length, alasql.options.columnlookup || 10); + + for (var i = 0; i < maxRows; i++) { + var rowKeys = Object.keys(res[i]); + if (rowKeys.length > maxKeyCount) { + maxKeyCount = rowKeys.length; + maxKeys = rowKeys; + } + // Collect all keys from this row (reuse rowKeys we already have) + for (var j = 0; j < rowKeys.length; j++) { + allcolSet[rowKeys[j]] = true; } } - // Create columns from data - var dataColumns = Object.keys(allcol).map(function (columnid) { - return {columnid: columnid}; - }); + // Build columns array: start with maxKeys, then add any missing keys + var dataColumns = []; + var addedKeys = {}; + + // Add keys from the row with most columns first (preserves natural order) + for (var k = 0; k < maxKeys.length; k++) { + dataColumns.push({columnid: maxKeys[k]}); + addedKeys[maxKeys[k]] = true; + } + + // Add any remaining keys not in maxKeys + for (var key in allcolSet) { + if (!addedKeys[key]) { + dataColumns.push({columnid: key}); + } + } // If we don't have any columns yet, just use the data columns if (!columns || columns.length === 0) { diff --git a/src/424select.js b/src/424select.js index c6bb630a6e..768a8e96be 100755 --- a/src/424select.js +++ b/src/424select.js @@ -75,6 +75,17 @@ function compileSelectStar(query, aliases, joinstar) { value: value, key: key, }; + + // Only add to query.columns for new columns (not duplicates) + var coldef = { + columnid: tcol.columnid, + dbtypeid: tcol.dbtypeid, + dbsize: tcol.dbsize, + dbprecision: tcol.dbprecision, + dbenum: tcol.dbenum, + }; + query.columns.push(coldef); + query.xcolumns[coldef.columnid] = coldef; } else { var newValue = value + ' !== undefined ? ' + value + ' : ' + columnIds[tcol.columnid].value; @@ -84,18 +95,6 @@ function compileSelectStar(query, aliases, joinstar) { } query.selectColumns[escapedColumnId] = true; - - // console.log('ok',tcol); - - var coldef = { - columnid: tcol.columnid, - dbtypeid: tcol.dbtypeid, - dbsize: tcol.dbsize, - dbprecision: tcol.dbprecision, - dbenum: tcol.dbenum, - }; - query.columns.push(coldef); - query.xcolumns[coldef.columnid] = coldef; }); //console.log(999,columns); } else { diff --git a/test/test269.js b/test/test269.js index ab61a7f183..4c6f386705 100644 --- a/test/test269.js +++ b/test/test269.js @@ -25,12 +25,12 @@ describe('Test 269 options', function () { {b: 40, c: 400}, ]; - it.skip('1. Create database', function (done) { + it('1. Create database', function (done) { alasql('CREATE DATABASE test269; USE test269'); done(); }); - it.skip('2. by default', function (done) { + it('2. by default', function (done) { alasql.options.modifier = undefined; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b', [data1, data2]); assert.deepEqual(res, [ @@ -43,7 +43,7 @@ describe('Test 269 options', function () { done(); }); - it.skip('3. VALUE', function (done) { + it('3. VALUE', function (done) { alasql.options.modifier = 'VALUE'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b', [data1, data2]); assert.deepEqual(res, 1); @@ -51,7 +51,7 @@ describe('Test 269 options', function () { done(); }); - it.skip('4. ROW', function (done) { + it('4. ROW', function (done) { alasql.options.modifier = 'ROW'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b', [data1, data2]); assert.deepEqual(res, [1, 10, 100]); @@ -59,7 +59,7 @@ describe('Test 269 options', function () { done(); }); - it.skip('5. COLUMN', function (done) { + it('5. COLUMN', function (done) { alasql.options.modifier = 'COLUMN'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b', [data1, data2]); assert.deepEqual(res, [1, 2, 3, undefined]); @@ -67,7 +67,7 @@ describe('Test 269 options', function () { done(); }); - it.skip('6. MATRIX', function (done) { + it('6. MATRIX', function (done) { alasql.options.modifier = 'MATRIX'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b', [data1, data2]); //console.log(res); @@ -82,7 +82,7 @@ describe('Test 269 options', function () { done(); }); - it.skip('6a. MATRIX', function (done) { + it('6a. MATRIX', function (done) { alasql.options.modifier = 'MATRIX'; // alasql.options.modifier = 'RECORDSET'; var res = alasql( @@ -102,7 +102,7 @@ describe('Test 269 options', function () { done(); }); - it.skip('7. RECORDSET', function (done) { + it('7. RECORDSET', function (done) { alasql.options.modifier = 'RECORDSET'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b', [data1, data2]); //console.log(res); @@ -119,7 +119,7 @@ describe('Test 269 options', function () { done(); }); - it.skip('8. INDEX', function (done) { + it('8. INDEX', function (done) { alasql.options.modifier = 'INDEX'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b', [data1, data2]); assert.deepEqual(res, {1: 10, 2: 20, 3: 30, undefined: 40}); @@ -127,7 +127,7 @@ describe('Test 269 options', function () { done(); }); - it.skip('9. TEXTSTRING', function (done) { + it('9. TEXTSTRING', function (done) { alasql.options.modifier = 'TEXTSTRING'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b', [data1, data2]); assert.deepEqual(res, '1\n2\n3\n'); @@ -135,7 +135,7 @@ describe('Test 269 options', function () { done(); }); - it.skip('99. Drop phase', function (done) { + it('99. Drop phase', function (done) { delete alasql.options.modifier; alasql('DROP DATABASE test269'); done(); diff --git a/test/test270.js b/test/test270.js index b0b2177215..10d2aa320e 100644 --- a/test/test270.js +++ b/test/test270.js @@ -30,34 +30,34 @@ describe('Test 270 RECORDSET tests', function () { done(); }); - it.skip('2. Empty test on param throws error', function (done) { + it('2. Empty test on param throws error', function (done) { assert.throws(function () { var res = alasql('SELECT * FROM ?', []); }, Error); done(); }); - it.skip('3. Empty test on param throws error', function (done) { + it('3. Empty test on param throws error', function (done) { var res = alasql('SELECT * FROM ?', [emptydata]); assert.deepEqual(res, {data: [], columns: []}); done(); }); - it.skip('4. Empty test on table with columns', function (done) { + it('4. Empty test on table with columns', function (done) { var res = alasql('SELECT * FROM one'); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a', 'b']); done(); }); - it.skip('5. Test on empty table without column definitions', function (done) { + it('5. Test on empty table without column definitions', function (done) { var res = alasql('SELECT * FROM three'); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, []); done(); }); - it.skip('6. Test on empty table without column definitions', function (done) { + it('6. Test on empty table without column definitions', function (done) { alasql('SELECT * INTO three FROM ?', [data1]); var res = alasql('SELECT * FROM three'); var colres = pluck(res.columns, 'columnid'); @@ -65,49 +65,49 @@ describe('Test 270 RECORDSET tests', function () { done(); }); - it.skip('7. Test on empty table without column definitions', function (done) { + it('7. Test on empty table without column definitions', function (done) { var res = alasql('SELECT a,b FROM three'); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a', 'b']); done(); }); - it.skip('8. Test on empty table without column definitions', function (done) { + it('8. Test on empty table without column definitions', function (done) { var res = alasql('SELECT b,a FROM three'); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['b', 'a']); done(); }); - it.skip('9. Test on empty table without column definitions', function (done) { + it('9. Test on empty table without column definitions', function (done) { var res = alasql('SELECT a,b,a*a AS a2 FROM three'); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a', 'b', 'a2']); done(); }); - it.skip('9a. Test on table without column definitions', function (done) { + it('9a. Test on table without column definitions', function (done) { var res = alasql('SELECT a,a*a AS a2,b FROM three'); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a', 'a2', 'b']); done(); }); - it.skip('9b. Test on table without column definitions', function (done) { + it('9b. Test on table without column definitions', function (done) { var res = alasql('SELECT a,* FROM three'); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a', 'b']); done(); }); - it.skip('9c. Test on table without column definitions', function (done) { + it('9c. Test on table without column definitions', function (done) { var res = alasql('SELECT *,a FROM three'); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a', 'b']); done(); }); - it.skip('9c1. Test on table without column definitions', function (done) { + it('9c1. Test on table without column definitions', function (done) { var res = alasql('SELECT b,*,a FROM three'); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['b', 'a']); @@ -121,21 +121,21 @@ describe('Test 270 RECORDSET tests', function () { done(); }); - it.skip('10. Array on param with *', function (done) { + it('10. Array on param with *', function (done) { var res = alasql('SELECT * FROM ?', [data1]); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a', 'b']); done(); }); - it.skip('11. Array with column', function (done) { + it('11. Array with column', function (done) { var res = alasql('SELECT a,b FROM ?', [data1]); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a', 'b']); done(); }); - it.skip('11a. Array with column', function (done) { + it('11a. Array with column', function (done) { var res = alasql('SELECT b,a FROM ?', [data1]); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['b', 'a']); @@ -149,35 +149,35 @@ describe('Test 270 RECORDSET tests', function () { done(); }); - it.skip('12. Array with column', function (done) { + it('12. Array with column', function (done) { var res = alasql('SELECT a,a*a AS a2 FROM ?', [data1]); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a', 'a2']); done(); }); - it.skip('12a. Array with column', function (done) { + it('12a. Array with column', function (done) { var res = alasql('SELECT a,a*a AS a2,b FROM ?', [data1]); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a', 'a2', 'b']); done(); }); - it.skip('13. Array with column from table', function (done) { + it('13. Array with column from table', function (done) { var res = alasql('SELECT a,a*a AS a2 FROM one'); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a', 'a2']); done(); }); - it.skip('14. Array with column in reversed order', function (done) { + it('14. Array with column in reversed order', function (done) { var res = alasql('SELECT a*a AS a2,a FROM ?', [data1]); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a2', 'a']); done(); }); - it.skip('15. Array with column in reversed order', function (done) { + it('15. Array with column in reversed order', function (done) { var res = alasql('SELECT a*a AS a2,a FROM ?', [data1]); var colres = pluck(res.columns, 'columnid'); assert.deepEqual(colres, ['a2', 'a']); @@ -208,7 +208,7 @@ describe('Test 270 RECORDSET tests', function () { }); /* - it.skip('3. VALUE', function(done) { + it('3. VALUE', function(done) { alasql.options.modifier = 'VALUE'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b',[data1,data2]); assert.deepEqual(res,1); @@ -216,7 +216,7 @@ describe('Test 270 RECORDSET tests', function () { done(); }); - it.skip('4. ROW', function(done) { + it('4. ROW', function(done) { alasql.options.modifier = 'ROW'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b',[data1,data2]); assert.deepEqual(res,[1,10,100]); @@ -224,7 +224,7 @@ describe('Test 270 RECORDSET tests', function () { done(); }); - it.skip('5. COLUMN', function(done) { + it('5. COLUMN', function(done) { alasql.options.modifier = 'COLUMN'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b',[data1,data2]); assert.deepEqual(res,[1,2,3,undefined]); @@ -233,7 +233,7 @@ describe('Test 270 RECORDSET tests', function () { }); - it.skip('6. MATRIX', function(done) { + it('6. MATRIX', function(done) { alasql.options.modifier = 'MATRIX'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b',[data1,data2]); //console.log(res); @@ -243,7 +243,7 @@ describe('Test 270 RECORDSET tests', function () { done(); }); - it.skip('6a. MATRIX', function(done) { + it('6a. MATRIX', function(done) { alasql.options.modifier = 'MATRIX'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b \ ORDER BY a',[data1,data2]); @@ -255,7 +255,7 @@ describe('Test 270 RECORDSET tests', function () { }); - it.skip('7. RECORDSET', function(done) { + it('7. RECORDSET', function(done) { alasql.options.modifier = "RECORDSET"; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b',[data1,data2]); //console.log(res); @@ -270,7 +270,7 @@ describe('Test 270 RECORDSET tests', function () { done(); }); - it.skip('8. INDEX', function(done) { + it('8. INDEX', function(done) { alasql.options.modifier = 'INDEX'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b',[data1,data2]); assert.deepEqual(res,{ '1': 10, '2': 20, '3': 30, undefined: 40 }); @@ -278,7 +278,7 @@ describe('Test 270 RECORDSET tests', function () { done(); }); - it.skip('9. TEXTSTRING', function(done) { + it('9. TEXTSTRING', function(done) { alasql.options.modifier = 'TEXTSTRING'; var res = alasql('SELECT t1.*,t2.* FROM ? t1 OUTER JOIN ? t2 USING b',[data1,data2]); assert.deepEqual(res,'1\n2\n3\n');