From 3f02549bcedddc8897d4c88d64776c1e8ca4587d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 13:04:08 +0000 Subject: [PATCH 1/7] Initial plan From 9b838c5579a571a6b350e55c5c21f08ca7153cd9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 15 Dec 2025 13:23:26 +0000 Subject: [PATCH 2/7] Enable test269.js output format modifiers and fix column ordering Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/40select.js | 70 +++++++++++++++++++++++++++++++++++------------- src/424select.js | 23 ++++++++-------- test/test269.js | 22 +++++++-------- 3 files changed, 74 insertions(+), 41 deletions(-) diff --git a/src/40select.js b/src/40select.js index 53a1b98335..3f95d8c27d 100755 --- a/src/40select.js +++ b/src/40select.js @@ -530,16 +530,37 @@ function modify(query, res) { // 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--) { + var maxKeys = []; + var maxKeyCount = 0; + + // Scan the data to find all column names and track the row with most keys + // This helps handle sparse data from OUTER JOINs where some rows may be missing columns + for (var i = 0; i < Math.min(res.length, alasql.options.columnlookup || 10); i++) { + var rowKeys = Object.keys(res[i]); + if (rowKeys.length > maxKeyCount) { + maxKeyCount = rowKeys.length; + maxKeys = rowKeys; + } for (var key in res[i]) { allcol[key] = true; } } - - // Create columns from data - var dataColumns = Object.keys(allcol).map(function (columnid) { - return {columnid: columnid}; + + // Use the order from the row with most keys, then add any missing keys + var dataColumns = []; + var addedKeys = {}; + + // First, add keys from the row with most keys (in their natural order) + maxKeys.forEach(function(key) { + dataColumns.push({columnid: key}); + addedKeys[key] = true; + }); + + // Then add any remaining keys that weren't in that row + Object.keys(allcol).forEach(function(key) { + if (!addedKeys[key]) { + dataColumns.push({columnid: key}); + } }); // If we don't have any columns yet, just use the data columns @@ -589,7 +610,8 @@ function modify(query, res) { switch (modifier) { case 'VALUE': if (res.length === 0) return undefined; - const keyValue = columns && columns.length > 0 ? columns[0].columnid : Object.keys(res[0])[0]; + // Use the first key from the actual data object to ensure correct order + const keyValue = Object.keys(res[0])[0]; return res[0][keyValue]; case 'ROW': @@ -599,12 +621,8 @@ function modify(query, res) { case 'COLUMN': if (res.length === 0) return []; - let key; - if (columns && columns.length > 0) { - key = columns[0].columnid; - } else { - key = Object.keys(res[0])[0]; - } + // Use the first key from the actual data object to ensure correct order + const key = Object.keys(res[0])[0]; let ar = []; for (var i = 0, ilen = res.length; i < ilen; i++) { @@ -620,12 +638,28 @@ function modify(query, res) { case 'MATRIX': if (res.length === 0) return undefined; - return res.map(row => columns.map(col => row[col.columnid])); + // Use columns array if available and non-empty, otherwise collect from data + let matrixKeys; + if (columns && columns.length > 0) { + matrixKeys = columns.map(col => col.columnid); + } else { + // Collect all unique keys from all rows to handle sparse data + const allKeys = {}; + res.forEach(row => { + Object.keys(row).forEach(k => { + allKeys[k] = true; + }); + }); + matrixKeys = Object.keys(allKeys); + } + return res.map(row => matrixKeys.map(k => row[k])); case 'INDEX': if (res.length === 0) return undefined; - const keyIndex = columns && columns.length > 0 ? columns[0].columnid : Object.keys(res[0])[0]; - const valIndex = columns && columns.length > 1 ? columns[1].columnid : Object.keys(res[0])[1]; + // Use the keys from the actual data object to ensure correct order + const dataKeys = Object.keys(res[0]); + const keyIndex = dataKeys[0]; + const valIndex = dataKeys[1]; return res.reduce((acc, row) => ({...acc, [row[keyIndex]]: row[valIndex]}), {}); case 'RECORDSET': @@ -634,8 +668,8 @@ function modify(query, res) { case 'TEXTSTRING': if (res.length === 0) return undefined; - const keyTextString = - columns && columns.length > 0 ? columns[0].columnid : Object.keys(res[0])[0]; + // Use the first key from the actual data object to ensure correct order + const keyTextString = Object.keys(res[0])[0]; return res.map(row => row[keyTextString]).join('\n'); case 'ALASQL_DETAILS': diff --git a/src/424select.js b/src/424select.js index c6bb630a6e..6ec5811c12 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(); From 4ac50ecc62ddf5d8d0cf43ac697bc9d3af2e599a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 12:45:42 +0000 Subject: [PATCH 3/7] Enable test270.js RECORDSET tests (25/27 passing, 2 skipped due to duplicate column issue) Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- test/test270.js | 56 ++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) 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'); From 9f57ed3eb0bfe057b84ade60aaab2b582793eb4a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Dec 2025 13:56:29 +0000 Subject: [PATCH 4/7] Simplify column ordering fix - use first complete row's key order Instead of complex logic with multiple cases, simply: 1. Find the row with the most keys (handles sparse OUTER JOIN data) 2. Use that row's Object.keys() order (preserves natural column order) 3. Add any additional keys from other rows This is much simpler than the previous approach and achieves the same result. Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/40select.js | 63 ++++++++++++++++++------------------------------- 1 file changed, 23 insertions(+), 40 deletions(-) diff --git a/src/40select.js b/src/40select.js index 3f95d8c27d..de569bcb0c 100755 --- a/src/40select.js +++ b/src/40select.js @@ -529,12 +529,12 @@ 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) { + // 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 allcol = {}; - var maxKeys = []; - var maxKeyCount = 0; - // Scan the data to find all column names and track the row with most keys - // This helps handle sparse data from OUTER JOINs where some rows may be missing columns for (var i = 0; i < Math.min(res.length, alasql.options.columnlookup || 10); i++) { var rowKeys = Object.keys(res[i]); if (rowKeys.length > maxKeyCount) { @@ -545,18 +545,14 @@ function modify(query, res) { allcol[key] = true; } } - - // Use the order from the row with most keys, then add any missing keys - var dataColumns = []; - var addedKeys = {}; - - // First, add keys from the row with most keys (in their natural order) - maxKeys.forEach(function(key) { - dataColumns.push({columnid: key}); - addedKeys[key] = true; + + // Start with keys from the row with most columns (preserves natural order) + // Then add any additional keys that might be in other rows + var dataColumns = maxKeys.map(function(columnid) { + return {columnid: columnid}; }); - - // Then add any remaining keys that weren't in that row + var addedKeys = {}; + maxKeys.forEach(function(k) { addedKeys[k] = true; }); Object.keys(allcol).forEach(function(key) { if (!addedKeys[key]) { dataColumns.push({columnid: key}); @@ -610,8 +606,7 @@ function modify(query, res) { switch (modifier) { case 'VALUE': if (res.length === 0) return undefined; - // Use the first key from the actual data object to ensure correct order - const keyValue = Object.keys(res[0])[0]; + const keyValue = columns && columns.length > 0 ? columns[0].columnid : Object.keys(res[0])[0]; return res[0][keyValue]; case 'ROW': @@ -621,8 +616,12 @@ function modify(query, res) { case 'COLUMN': if (res.length === 0) return []; - // Use the first key from the actual data object to ensure correct order - const key = Object.keys(res[0])[0]; + let key; + if (columns && columns.length > 0) { + key = columns[0].columnid; + } else { + key = Object.keys(res[0])[0]; + } let ar = []; for (var i = 0, ilen = res.length; i < ilen; i++) { @@ -638,28 +637,12 @@ function modify(query, res) { case 'MATRIX': if (res.length === 0) return undefined; - // Use columns array if available and non-empty, otherwise collect from data - let matrixKeys; - if (columns && columns.length > 0) { - matrixKeys = columns.map(col => col.columnid); - } else { - // Collect all unique keys from all rows to handle sparse data - const allKeys = {}; - res.forEach(row => { - Object.keys(row).forEach(k => { - allKeys[k] = true; - }); - }); - matrixKeys = Object.keys(allKeys); - } - return res.map(row => matrixKeys.map(k => row[k])); + return res.map(row => columns.map(col => row[col.columnid])); case 'INDEX': if (res.length === 0) return undefined; - // Use the keys from the actual data object to ensure correct order - const dataKeys = Object.keys(res[0]); - const keyIndex = dataKeys[0]; - const valIndex = dataKeys[1]; + const keyIndex = columns && columns.length > 0 ? columns[0].columnid : Object.keys(res[0])[0]; + const valIndex = columns && columns.length > 1 ? columns[1].columnid : Object.keys(res[0])[1]; return res.reduce((acc, row) => ({...acc, [row[keyIndex]]: row[valIndex]}), {}); case 'RECORDSET': @@ -668,8 +651,8 @@ function modify(query, res) { case 'TEXTSTRING': if (res.length === 0) return undefined; - // Use the first key from the actual data object to ensure correct order - const keyTextString = Object.keys(res[0])[0]; + const keyTextString = + columns && columns.length > 0 ? columns[0].columnid : Object.keys(res[0])[0]; return res.map(row => row[keyTextString]).join('\n'); case 'ALASQL_DETAILS': From 9c6008987cb47eea13980e2fc0ad626ddff04692 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 21 Dec 2025 05:12:57 +0000 Subject: [PATCH 5/7] Fix code formatting with prettier Ran `yarn format-all` to fix formatting issues in: - src/40select.js - src/424select.js All tests still passing (2114 passing, 338 pending) Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/40select.js | 10 ++++++---- src/424select.js | 2 +- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/40select.js b/src/40select.js index de569bcb0c..689a5cd745 100755 --- a/src/40select.js +++ b/src/40select.js @@ -534,7 +534,7 @@ function modify(query, res) { var maxKeys = Object.keys(res[0]); var maxKeyCount = maxKeys.length; var allcol = {}; - + for (var i = 0; i < Math.min(res.length, alasql.options.columnlookup || 10); i++) { var rowKeys = Object.keys(res[i]); if (rowKeys.length > maxKeyCount) { @@ -548,12 +548,14 @@ function modify(query, res) { // Start with keys from the row with most columns (preserves natural order) // Then add any additional keys that might be in other rows - var dataColumns = maxKeys.map(function(columnid) { + var dataColumns = maxKeys.map(function (columnid) { return {columnid: columnid}; }); var addedKeys = {}; - maxKeys.forEach(function(k) { addedKeys[k] = true; }); - Object.keys(allcol).forEach(function(key) { + maxKeys.forEach(function (k) { + addedKeys[k] = true; + }); + Object.keys(allcol).forEach(function (key) { if (!addedKeys[key]) { dataColumns.push({columnid: key}); } diff --git a/src/424select.js b/src/424select.js index 6ec5811c12..768a8e96be 100755 --- a/src/424select.js +++ b/src/424select.js @@ -75,7 +75,7 @@ function compileSelectStar(query, aliases, joinstar) { value: value, key: key, }; - + // Only add to query.columns for new columns (not duplicates) var coldef = { columnid: tcol.columnid, From 5d15d4167cc1da178fe4e205ebd74571418122e9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Dec 2025 02:13:28 +0000 Subject: [PATCH 6/7] Simplify column ordering logic per code review - Pre-calculate loop limit to avoid recalculating on each iteration - Replace map/forEach chains with simple for loops for better readability - Keep the same functionality with clearer, more efficient code Addresses review comments: - Line 538: Avoid recalculating Math.min in loop condition - Lines 549-562: Simplify convoluted logic with straightforward loops Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/40select.js | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/40select.js b/src/40select.js index 689a5cd745..3c7ddaaafe 100755 --- a/src/40select.js +++ b/src/40select.js @@ -534,8 +534,9 @@ function modify(query, res) { var maxKeys = Object.keys(res[0]); var maxKeyCount = maxKeys.length; var allcol = {}; + var maxRows = Math.min(res.length, alasql.options.columnlookup || 10); - for (var i = 0; i < Math.min(res.length, alasql.options.columnlookup || 10); i++) { + for (var i = 0; i < maxRows; i++) { var rowKeys = Object.keys(res[i]); if (rowKeys.length > maxKeyCount) { maxKeyCount = rowKeys.length; @@ -546,20 +547,22 @@ function modify(query, res) { } } - // Start with keys from the row with most columns (preserves natural order) - // Then add any additional keys that might be in other rows - var dataColumns = maxKeys.map(function (columnid) { - return {columnid: columnid}; - }); + // Build columns array: start with maxKeys, then add any missing keys from allcol + var dataColumns = []; var addedKeys = {}; - maxKeys.forEach(function (k) { - addedKeys[k] = true; - }); - Object.keys(allcol).forEach(function (key) { + + // Add keys from the row with most columns first (preserves natural order) + for (var j = 0; j < maxKeys.length; j++) { + dataColumns.push({columnid: maxKeys[j]}); + addedKeys[maxKeys[j]] = true; + } + + // Add any remaining keys not in maxKeys + for (var key in allcol) { 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) { From 36a3769bd5e27d0ebbfcf1e7bb7b44987c584776 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 22 Dec 2025 05:26:57 +0000 Subject: [PATCH 7/7] Optimize column collection loop to avoid redundant iterations - Reuse rowKeys array instead of iterating through res[i] again with for...in - This eliminates duplicate iteration over the same object properties - Changed variable name from 'allcol' to 'allcolSet' for clarity - Renamed loop variable from 'j' to 'k' in second loop to avoid confusion Performance improvement: Reduces from 2 iterations per row to 1 iteration. Addresses review comments: - Line 545-547: Why loop through res[i] again? Now reusing rowKeys - Line 556-563: Reduced redundant key iterations Co-authored-by: mathiasrw <1063454+mathiasrw@users.noreply.github.com> --- src/40select.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/40select.js b/src/40select.js index 3c7ddaaafe..45734f8d37 100755 --- a/src/40select.js +++ b/src/40select.js @@ -533,7 +533,7 @@ function modify(query, res) { // For sparse data (OUTER JOINs), find the row with the most keys var maxKeys = Object.keys(res[0]); var maxKeyCount = maxKeys.length; - var allcol = {}; + var allcolSet = {}; var maxRows = Math.min(res.length, alasql.options.columnlookup || 10); for (var i = 0; i < maxRows; i++) { @@ -542,23 +542,24 @@ function modify(query, res) { maxKeyCount = rowKeys.length; maxKeys = rowKeys; } - for (var key in res[i]) { - allcol[key] = true; + // Collect all keys from this row (reuse rowKeys we already have) + for (var j = 0; j < rowKeys.length; j++) { + allcolSet[rowKeys[j]] = true; } } - // Build columns array: start with maxKeys, then add any missing keys from allcol + // 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 j = 0; j < maxKeys.length; j++) { - dataColumns.push({columnid: maxKeys[j]}); - addedKeys[maxKeys[j]] = true; + 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 allcol) { + for (var key in allcolSet) { if (!addedKeys[key]) { dataColumns.push({columnid: key}); }