alasql 4.2.6 → 4.2.7

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/dist/alasql.js CHANGED
@@ -1,15 +1,15 @@
1
- //! AlaSQL v4.2.5 build: develop-40f8e9c3 | © 2014-2023 Andrey Gershun & Mathias Wulff | License: MIT
1
+ //! AlaSQL v4.2.6 build: develop-6db74fcc | © 2014-2024 Andrey Gershun & Mathias Wulff | License: MIT
2
2
  /*
3
3
  @module alasql
4
- @version 4.2.5
4
+ @version 4.2.6
5
5
 
6
6
  AlaSQL - JavaScript SQL database
7
- © 2014-2023 Andrey Gershun & Mathias Wulff
7
+ © 2014-2024 Andrey Gershun & Mathias Wulff
8
8
 
9
9
  @license
10
10
  The MIT License (MIT)
11
11
 
12
- Copyright 2014-2023 Andrey Gershun (agershun@gmail.com) & Mathias Wulff (m@rawu.dk)
12
+ Copyright 2014-2024 Andrey Gershun (agershun@gmail.com) & Mathias Wulff (m@rawu.dk)
13
13
 
14
14
  Permission is hereby granted, free of charge, to any person obtaining a copy
15
15
  of this software and associated documentation files (the "Software"), to deal
@@ -49,109 +49,109 @@ SOFTWARE.
49
49
  */
50
50
 
51
51
  (function (root, factory) {
52
- if (typeof define === 'function' && define.amd) {
53
- define([], factory);
54
- } else if (typeof exports === 'object') {
55
- /** alasql main function */
56
- module.exports = factory();
57
- } else {
58
- root.alasql = factory();
59
- }
52
+ if (typeof define === 'function' && define.amd) {
53
+ define([], factory);
54
+ } else if (typeof exports === 'object') {
55
+ /** alasql main function */
56
+ module.exports = factory();
57
+ } else {
58
+ root.alasql = factory();
59
+ }
60
60
  }(this, function () {
61
61
 
62
- /**
63
- AlaSQL - Main Alasql class
64
- @function
65
- @param {string|function|object} sql - SQL-statement or data object for fluent interface
66
- @param {object} params - SQL parameters
67
- @param {function} cb - callback function
68
- @param {object} scope - Scope for nested queries
69
- @return {any} - Result data object
70
-
71
- @example
72
- Standard sync call:
73
- alasql('CREATE TABLE one');
74
- Query:
75
- var res = alasql('SELECT * FROM one');
76
- Call with parameters:
77
- var res = alasql('SELECT * FROM ?',[data]);
78
- Standard async call with callback function:
79
- alasql('SELECT * FROM ?',[data],function(res){
80
- console.log(data);
81
- });
82
- Call with scope for subquery (to pass common values):
83
- var scope = {one:{a:2,b;20}}
84
- alasql('SELECT * FROM ? two WHERE two.a = one.a',[data],null,scope);
85
- Call for fluent interface with data object:
86
- alasql(data).Where(function(x){return x.a == 10}).exec();
87
- Call for fluent interface without data object:
88
- alasql().From(data).Where(function(x){return x.a == 10}).exec();
89
- */
62
+ /**
63
+ AlaSQL - Main Alasql class
64
+ @function
65
+ @param {string|function|object} sql - SQL-statement or data object for fluent interface
66
+ @param {object} params - SQL parameters
67
+ @param {function} cb - callback function
68
+ @param {object} scope - Scope for nested queries
69
+ @return {any} - Result data object
70
+
71
+ @example
72
+ Standard sync call:
73
+ alasql('CREATE TABLE one');
74
+ Query:
75
+ var res = alasql('SELECT * FROM one');
76
+ Call with parameters:
77
+ var res = alasql('SELECT * FROM ?',[data]);
78
+ Standard async call with callback function:
79
+ alasql('SELECT * FROM ?',[data],function(res){
80
+ console.log(data);
81
+ });
82
+ Call with scope for subquery (to pass common values):
83
+ var scope = {one:{a:2,b;20}}
84
+ alasql('SELECT * FROM ? two WHERE two.a = one.a',[data],null,scope);
85
+ Call for fluent interface with data object:
86
+ alasql(data).Where(function(x){return x.a == 10}).exec();
87
+ Call for fluent interface without data object:
88
+ alasql().From(data).Where(function(x){return x.a == 10}).exec();
89
+ */
90
90
 
91
- var alasql = function(sql, params, cb, scope) {
91
+ let alasql = function (sql, params, cb, scope) {
92
92
 
93
- params = params||[];
93
+ params = params || [];
94
94
 
95
- if(typeof importScripts !== 'function' && alasql.webworker) {
96
- var id = alasql.lastid++;
97
- alasql.buffer[id] = cb;
98
- alasql.webworker.postMessage({id:id,sql:sql,params:params});
99
- return;
100
- }
95
+ if (typeof importScripts !== 'function' && alasql.webworker) {
96
+ var id = alasql.lastid++;
97
+ alasql.buffer[id] = cb;
98
+ alasql.webworker.postMessage({ id: id, sql: sql, params: params });
99
+ return;
100
+ }
101
101
 
102
- if(arguments.length === 0) {
103
- // Without arguments - Fluent interface
104
- return new yy.Select({
105
- columns:[new yy.Column({columnid:'*'})],
106
- from: [new yy.ParamValue({param:0})]
107
- });
108
- } else if(arguments.length === 1){
109
- // Access promise notation without using `.promise(...)`
110
- if(sql.constructor === Array){
111
- return alasql.promise(sql);
102
+ if (arguments.length === 0) {
103
+ // Without arguments - Fluent interface
104
+ return new yy.Select({
105
+ columns: [new yy.Column({ columnid: '*' })],
106
+ from: [new yy.ParamValue({ param: 0 })]
107
+ });
108
+ } else if (arguments.length === 1) {
109
+ // Access promise notation without using `.promise(...)`
110
+ if (sql.constructor === Array) {
111
+ return alasql.promise(sql);
112
+ }
113
+ }
114
+ // Avoid setting params if not needed even with callback
115
+ if (typeof params === 'function') {
116
+ scope = cb;
117
+ cb = params;
118
+ params = [];
112
119
  }
113
- }
114
- // Avoid setting params if not needed even with callback
115
- if(typeof params === 'function'){
116
- scope = cb;
117
- cb = params;
118
- params = [];
119
- }
120
120
 
121
- if(typeof params !== 'object'){
121
+ if (typeof params !== 'object') {
122
122
  params = [params];
123
- }
123
+ }
124
124
 
125
- // Standard interface
126
- // alasql('#sql');
127
- if(typeof sql === 'string' && sql[0]==='#' && typeof document === "object") {
128
- sql = document.querySelector(sql).textContent;
129
- } else if(typeof sql === 'object' && sql instanceof HTMLElement) {
130
- sql = sql.textContent;
131
- } else if(typeof sql === 'function') {
132
- // to run multiline functions
133
- sql = sql.toString();
134
- sql = (/\/\*([\S\s]+)\*\//m.exec(sql) || ['','Function given as SQL. Plese Provide SQL string or have a /* ... */ syle comment with SQL in the function.'])[1];
135
- }
136
- // Run SQL
137
- return alasql.exec(sql, params, cb, scope);
138
- };
125
+ // Standard interface
126
+ // alasql('#sql');
127
+ if (typeof sql === 'string' && sql[0] === '#' && typeof document === "object") {
128
+ sql = document.querySelector(sql).textContent;
129
+ } else if (typeof sql === 'object' && sql instanceof HTMLElement) {
130
+ sql = sql.textContent;
131
+ } else if (typeof sql === 'function') {
132
+ // to run multiline functions
133
+ sql = sql.toString();
134
+ sql = (/\/\*([\S\s]+)\*\//m.exec(sql) || ['', 'Function given as SQL. Plese Provide SQL string or have a /* ... */ syle comment with SQL in the function.'])[1];
135
+ }
136
+ // Run SQL
137
+ return alasql.exec(sql, params, cb, scope);
138
+ };
139
139
 
140
- /**
141
- Current version of alasql
142
- @constant {string}
143
- */
144
- alasql.version = '4.2.5';
145
- alasql.build = 'develop-40f8e9c3';
140
+ /**
141
+ Current version of alasql
142
+ @constant {string}
143
+ */
144
+ alasql.version = '4.2.6';
145
+ alasql.build = 'develop-6db74fcc';
146
146
 
147
- /**
148
- Debug flag
149
- @type {boolean}
150
- */
151
- alasql.debug = undefined; // Initial debug variable
147
+ /**
148
+ Debug flag
149
+ @type {boolean}
150
+ */
151
+ alasql.debug = undefined; // Initial debug variable
152
152
 
153
153
  //*only-for-browser/*
154
- var require = function(){return null}; // as alasqlparser.js is generated, we can not "remove" references to
154
+ var require = function(){return null}; // as alasqlparser.js is generated, we can not "remove" references to
155
155
  var __dirname = '';
156
156
  //*/
157
157
  /* parser generated by jison 0.4.18 */
@@ -3144,7 +3144,7 @@ if (typeof module !== 'undefined' && require.main === module) {
3144
3144
  */
3145
3145
 
3146
3146
  /**
3147
- Pretty flag - nice HTML output or standard text without any tags
3147
+ Pretty flag - nice HTML output or standard text without any tags
3148
3148
  @type {boolean}
3149
3149
  */
3150
3150
 
@@ -3155,7 +3155,7 @@ alasql.prettyflag = false;
3155
3155
  @function
3156
3156
  @param {string} sql SQL statement
3157
3157
  @param {boolean} flag value
3158
- @return {string} HTML or text string with pretty output
3158
+ @return {string} HTML or text string with pretty output
3159
3159
  */
3160
3160
 
3161
3161
  alasql.pretty = function (sql, flag) {
@@ -3165,7 +3165,6 @@ alasql.pretty = function (sql, flag) {
3165
3165
  alasql.prettyflag = pf;
3166
3166
  return s;
3167
3167
  };
3168
-
3169
3168
  /*jshint unused:false*/
3170
3169
  /*
3171
3170
  Utilities for Alasql.js
@@ -3455,6 +3454,7 @@ utils.hasIndexedDB = (function () {
3455
3454
  utils.isArray = function (obj) {
3456
3455
  return '[object Array]' === Object.prototype.toString.call(obj);
3457
3456
  };
3457
+
3458
3458
  /**
3459
3459
  Load text file from anywhere
3460
3460
  @param {string|object} path File path or HTML event
@@ -3466,7 +3466,9 @@ utils.isArray = function (obj) {
3466
3466
  @todo Define Event type
3467
3467
  @todo Smaller if-else structures.
3468
3468
  */
3469
- var loadFile = (utils.loadFile = function (path, asy, success, error) {
3469
+
3470
+ const protocolRegex = /^[a-z]+:\/\//i;
3471
+ let loadFile = (utils.loadFile = function (path, asy, success, error) {
3470
3472
  var data, fs;
3471
3473
  if (utils.isNode || utils.isMeteorServer) {
3472
3474
  /*not-for-browser/*
@@ -3485,30 +3487,38 @@ var loadFile = (utils.loadFile = function (path, asy, success, error) {
3485
3487
  process.stdin.on('end', function () {
3486
3488
  success(cutbom(buff));
3487
3489
  });
3488
- } else {
3489
- if (/^[a-z]+:\/\//i.test(path)) {
3490
- fetchData(path, x => success(cutbom(x)), error, asy);
3491
- } else {
3492
- //If async callthen call async
3493
- if (asy) {
3494
- fs.readFile(path, function (err, data) {
3495
- if (err) {
3496
- return error(err, null);
3497
- }
3498
- success(cutbom(data.toString()));
3499
- });
3500
- } else {
3501
- // Call sync version
3502
- try {
3503
- data = fs.readFileSync(path);
3504
- } catch (e) {
3505
- return error(err, null);
3506
- }
3507
- success(cutbom(data.toString()));
3490
+ return;
3491
+ }
3492
+
3493
+ if (protocolRegex.test(path)) {
3494
+ fetchData(path, x => success(cutbom(x)), error, asy);
3495
+ return;
3496
+ }
3497
+
3498
+ //If async callthen call async
3499
+ if (asy) {
3500
+ fs.readFile(path, function (err, data) {
3501
+ if (err) {
3502
+ return error(err, null);
3508
3503
  }
3509
- }
3504
+ success(cutbom(data.toString()));
3505
+ });
3506
+ return;
3510
3507
  }
3511
- } else if (utils.isReactNative) {
3508
+
3509
+ // Call sync version
3510
+ try {
3511
+ data = fs.readFileSync(path);
3512
+ } catch (e) {
3513
+ error(err, null);
3514
+ return;
3515
+ }
3516
+
3517
+ success(cutbom(data.toString()));
3518
+ return;
3519
+ }
3520
+
3521
+ if (utils.isReactNative) {
3512
3522
  // If ReactNative
3513
3523
  var RNFS = require('react-native-fs');
3514
3524
  RNFS.readFile(path, 'utf8')
@@ -3519,7 +3529,10 @@ var loadFile = (utils.loadFile = function (path, asy, success, error) {
3519
3529
  return error(err, null);
3520
3530
  });
3521
3531
  //*/
3522
- } else if (utils.isCordova) {
3532
+ return;
3533
+ }
3534
+
3535
+ if (utils.isCordova) {
3523
3536
  /* If Cordova */
3524
3537
  utils.global.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
3525
3538
  fileSystem.root.getFile(path, {create: false}, function (fileEntry) {
@@ -3533,48 +3546,52 @@ var loadFile = (utils.loadFile = function (path, asy, success, error) {
3533
3546
  });
3534
3547
  });
3535
3548
 
3536
- /** @todo Check eliminated code below */
3549
+ return;
3550
+ }
3537
3551
 
3538
- } else {
3539
- /* For string */
3540
- if (typeof path === 'string') {
3541
- // For browser read from tag
3542
- /*
3543
- SELECT * FROM TXT('#one') -- read data from HTML element with id="one"
3544
- */
3545
- if (path.substr(0, 1) === '#' && typeof document !== 'undefined') {
3546
- data = document.querySelector(path).textContent;
3547
- success(data);
3548
- } else {
3549
- /*
3550
- Simply read file from HTTP request, like:
3551
- SELECT * FROM TXT('http://alasql.org/README.md');
3552
- */
3553
- fetchData(path, x => success(cutbom(x)), error, asy);
3554
- }
3555
- } else if (path instanceof Event) {
3556
- /*
3557
- For browser read from files input element
3558
- <input type="files" onchange="readFile(event)">
3559
- <script>
3560
- function readFile(event) {
3561
- alasql('SELECT * FROM TXT(?)',[event])
3562
- }
3563
- </script>
3564
- */
3565
- /** @type {array} List of files from <input> element */
3566
- var files = path.target.files;
3567
- /** type {object} */
3568
- var reader = new FileReader();
3569
- /** type {string} */
3570
- var name = files[0].name;
3571
- reader.onload = function (e) {
3572
- var data = e.target.result;
3573
- success(cutbom(data));
3574
- };
3575
- reader.readAsText(files[0]);
3552
+ /* For string */
3553
+ if (typeof path === 'string') {
3554
+ // For browser read from tag
3555
+ /*
3556
+ SELECT * FROM TXT('#one') -- read data from HTML element with id="one"
3557
+ */
3558
+ if (path.substr(0, 1) === '#' && typeof document !== 'undefined') {
3559
+ data = document.querySelector(path).textContent;
3560
+ success(data);
3561
+ return;
3576
3562
  }
3563
+
3564
+ /*
3565
+ Simply read file from HTTP request, like:
3566
+ SELECT * FROM TXT('http://alasql.org/README.md');
3567
+ */
3568
+ fetchData(path, x => success(cutbom(x)), error, asy);
3569
+ return;
3570
+ }
3571
+
3572
+ if (path instanceof Event) {
3573
+ /*
3574
+ For browser read from files input element
3575
+ <input type="files" onchange="readFile(event)">
3576
+ <script>
3577
+ function readFile(event) {
3578
+ alasql('SELECT * FROM TXT(?)',[event])
3579
+ }
3580
+ </script>
3581
+ */
3582
+ /** @type {array} List of files from <input> element */
3583
+ var files = path.target.files;
3584
+ /** type {object} */
3585
+ var reader = new FileReader();
3586
+ /** type {string} */
3587
+ var name = files[0].name;
3588
+ reader.onload = function (e) {
3589
+ var data = e.target.result;
3590
+ success(cutbom(data));
3591
+ };
3592
+ reader.readAsText(files[0]);
3577
3593
  }
3594
+ fetchData(path, x => success(cutbom(x)), error, asy);
3578
3595
  });
3579
3596
 
3580
3597
  let _fetch = typeof fetch !== 'undefined' ? fetch : null;
@@ -4340,15 +4357,15 @@ var getXLSX = function () {
4340
4357
  // set AlaSQl path
4341
4358
  alasql.path = alasql.utils.findAlaSQLPath();
4342
4359
  /**
4343
- Strip all comments.
4344
- @function
4345
- @param {string} str
4346
- @return {string}
4347
- Based om the https://github.com/lehni/uncomment.js/blob/master/uncomment.js
4348
- I just replaced JavaScript's '//' to SQL's '--' and remove other stuff
4349
-
4350
- @todo Fixed [aaa/*bbb] for column names
4351
- @todo Bug if -- comments in the last line
4360
+ Strip all comments.
4361
+ @function
4362
+ @param {string} str
4363
+ @return {string}
4364
+ Based om the https://github.com/lehni/uncomment.js/blob/master/uncomment.js
4365
+ I just replaced JavaScript's '//' to SQL's '--' and remove other stuff
4366
+
4367
+ @todo Fixed [aaa/*bbb] for column names
4368
+ @todo Bug if -- comments in the last line
4352
4369
  @todo Check if it possible to model it with Jison parser
4353
4370
  @todo Remove unused code
4354
4371
  */
@@ -4367,7 +4384,6 @@ alasql.utils.uncomment = function (str) {
4367
4384
  // preserveComment = false;
4368
4385
 
4369
4386
  for (var i = 0, l = str.length; i < l; i++) {
4370
-
4371
4387
  // When checking for quote escaping, we also need to check that the
4372
4388
  // escape sign itself is not escaped, as otherwise '\\' would cause
4373
4389
  // the wrong impression of an unclosed string:
@@ -4377,7 +4393,6 @@ alasql.utils.uncomment = function (str) {
4377
4393
  if (str[i] === quoteSign && unescaped) {
4378
4394
  quote = false;
4379
4395
  }
4380
-
4381
4396
  } else if (blockComment) {
4382
4397
  // Is the block comment closing?
4383
4398
  if (str[i] === '*' && str[i + 1] === '/') {
@@ -4414,7 +4429,6 @@ alasql.utils.uncomment = function (str) {
4414
4429
  // if (!preserveComment)
4415
4430
  str[i] = '';
4416
4431
  blockComment = true;
4417
-
4418
4432
  }
4419
4433
  }
4420
4434
  }
@@ -4600,17 +4614,18 @@ alasql.use = function (databaseid) {
4600
4614
  if (!databaseid) {
4601
4615
  databaseid = alasql.DEFAULTDATABASEID;
4602
4616
  }
4617
+
4603
4618
  if (alasql.useid === databaseid) {
4604
4619
  return;
4605
4620
  }
4621
+
4606
4622
  if (alasql.databases[databaseid] !== undefined) {
4607
4623
  alasql.useid = databaseid;
4608
- var db = alasql.databases[alasql.useid];
4624
+ let db = alasql.databases[alasql.useid];
4609
4625
  alasql.tables = db.tables;
4610
- // alasql.fn = db.fn;
4611
4626
  db.resetSqlCache();
4612
4627
  if (alasql.options.usedbo) {
4613
- alasql.databases.dbo = db; // Operator???
4628
+ alasql.databases.dbo = db;
4614
4629
  }
4615
4630
  } else {
4616
4631
  throw Error('Database does not exist: ' + databaseid);
@@ -4650,7 +4665,9 @@ alasql.exec = function (sql, params, cb, scope) {
4650
4665
  }
4651
4666
 
4652
4667
  delete alasql.error;
4668
+
4653
4669
  params = params || {};
4670
+
4654
4671
  if (alasql.options.errorlog) {
4655
4672
  try {
4656
4673
  return alasql.dexec(alasql.useid, sql, params, cb, scope);
@@ -4676,14 +4693,14 @@ alasql.dexec = function (databaseid, sql, params, cb, scope) {
4676
4693
 
4677
4694
  // Create hash
4678
4695
  if (alasql.options.cache) {
4679
- var statement = db.sqlCache[hh];
4696
+ let statement = db.sqlCache[hh];
4680
4697
  // If database structure was not changed since last time return cache
4681
4698
  if (statement && db.dbversion === statement.dbversion) {
4682
4699
  return statement(params, cb);
4683
4700
  }
4684
4701
  }
4685
4702
 
4686
- var ast = db.astCache[hh];
4703
+ let ast = db.astCache[hh];
4687
4704
  if (alasql.options.cache && !ast) {
4688
4705
  // Create AST cache
4689
4706
  ast = alasql.parse(sql);
@@ -4694,12 +4711,16 @@ alasql.dexec = function (databaseid, sql, params, cb, scope) {
4694
4711
  } else {
4695
4712
  ast = alasql.parse(sql);
4696
4713
  }
4714
+
4697
4715
  if (!ast.statements) {
4698
4716
  return;
4699
4717
  }
4718
+
4700
4719
  if (0 === ast.statements.length) {
4701
4720
  return 0;
4702
- } else if (1 === ast.statements.length) {
4721
+ }
4722
+
4723
+ if (1 === ast.statements.length) {
4703
4724
  if (ast.statements[0].compile) {
4704
4725
  // Compile and Execute
4705
4726
  var statement = ast.statements[0].compile(databaseid, params);
@@ -4719,20 +4740,18 @@ alasql.dexec = function (databaseid, sql, params, cb, scope) {
4719
4740
  }
4720
4741
  var res = (alasql.res = statement(params, cb, scope));
4721
4742
  return res;
4722
- } else {
4723
-
4724
- alasql.precompile(ast.statements[0], alasql.useid, params);
4725
- var res = (alasql.res = ast.statements[0].execute(databaseid, params, cb, scope));
4726
- return res;
4727
- }
4728
- } else {
4729
- // Multiple statements
4730
- if (cb) {
4731
- alasql.adrun(databaseid, ast, params, cb, scope);
4732
- } else {
4733
- return alasql.drun(databaseid, ast, params, cb, scope);
4734
4743
  }
4744
+ alasql.precompile(ast.statements[0], alasql.useid, params);
4745
+ var res = (alasql.res = ast.statements[0].execute(databaseid, params, cb, scope));
4746
+ return res;
4735
4747
  }
4748
+
4749
+ if (cb) {
4750
+ alasql.adrun(databaseid, ast, params, cb, scope);
4751
+ return;
4752
+ }
4753
+
4754
+ return alasql.drun(databaseid, ast, params, cb, scope);
4736
4755
  };
4737
4756
 
4738
4757
  /**
@@ -4791,28 +4810,30 @@ alasql.adrun = function (databaseid, ast, params, cb, scope) {
4791
4810
  if (data !== undefined) {
4792
4811
  res.push(data);
4793
4812
  }
4813
+
4794
4814
  var astatement = ast.statements.shift();
4795
4815
  if (!astatement) {
4796
4816
  if (useid !== databaseid) {
4797
4817
  alasql.use(useid);
4798
4818
  }
4799
4819
  cb(res);
4800
- // alasql.busy--;
4801
- // if(alasql.busy<0) alasql.busy = 0;
4802
- } else {
4803
- if (astatement.compile) {
4804
- var statement = astatement.compile(alasql.useid);
4805
- statement(params, adrunone, scope);
4806
- if (alasql.options.progress !== false) {
4807
- alasql.options.progress(noqueries, idx++);
4808
- }
4809
- } else {
4810
- alasql.precompile(ast.statements[0], alasql.useid, params);
4811
- astatement.execute(alasql.useid, params, adrunone);
4812
- if (alasql.options.progress !== false) {
4813
- alasql.options.progress(noqueries, idx++);
4814
- }
4820
+ return;
4821
+ }
4822
+
4823
+ if (astatement.compile) {
4824
+ var statement = astatement.compile(alasql.useid);
4825
+ statement(params, adrunone, scope);
4826
+ if (alasql.options.progress !== false) {
4827
+ alasql.options.progress(noqueries, idx++);
4815
4828
  }
4829
+ return;
4830
+ }
4831
+
4832
+ alasql.precompile(ast.statements[0], alasql.useid, params);
4833
+ astatement.execute(alasql.useid, params, adrunone);
4834
+
4835
+ if (alasql.options.progress !== false) {
4836
+ alasql.options.progress(noqueries, idx++);
4816
4837
  }
4817
4838
  }
4818
4839
 
@@ -4828,29 +4849,27 @@ alasql.adrun = function (databaseid, ast, params, cb, scope) {
4828
4849
  alasql.compile = function (sql, databaseid) {
4829
4850
  databaseid = databaseid || alasql.useid;
4830
4851
 
4831
- var ast = alasql.parse(sql); // Create AST
4852
+ let ast = alasql.parse(sql); // Create AST
4832
4853
 
4833
- if (1 === ast.statements.length) {
4834
- var statement = ast.statements[0].compile(databaseid);
4835
- statement.promise = function (params) {
4836
- return new Promise(function (resolve, reject) {
4837
- statement(params, function (data, err) {
4838
- if (err) {
4839
- reject(err);
4840
- } else {
4841
- resolve(data);
4842
- }
4843
- });
4844
- });
4845
- };
4854
+ if (1 !== ast.statements.length)
4855
+ throw new Error('Cannot compile, because number of statements in SQL is not equal to 1');
4846
4856
 
4847
- return statement;
4857
+ var statement = ast.statements[0].compile(databaseid);
4848
4858
 
4849
- } else {
4850
- throw new Error('Cannot compile, because number of statements in SQL is not equal to 1');
4851
- }
4852
- };
4859
+ statement.promise = function (params) {
4860
+ return new Promise(function (resolve, reject) {
4861
+ statement(params, function (data, err) {
4862
+ if (err) {
4863
+ reject(err);
4864
+ } else {
4865
+ resolve(data);
4866
+ }
4867
+ });
4868
+ });
4869
+ };
4853
4870
 
4871
+ return statement;
4872
+ };
4854
4873
  //
4855
4874
  // Promises for AlaSQL
4856
4875
  //
@@ -4876,6 +4895,7 @@ var promiseExec = function (sql, params, counterStep, counterTotal) {
4876
4895
 
4877
4896
  const sequentialPromiseResolver = (promiseData, Promise) => {
4878
4897
  var startingPoint = Promise.resolve([]);
4898
+
4879
4899
  promiseData.forEach(p => {
4880
4900
  startingPoint = startingPoint.then(previousResult =>
4881
4901
  promiseExec(p.sql, p.params, p.i, p.length).then(result => [...previousResult, result])
@@ -5233,7 +5253,6 @@ class Recordset {
5233
5253
 
5234
5254
  alasql.Recordset = Recordset;
5235
5255
  alasql.Query = Query;
5236
-
5237
5256
  /*
5238
5257
  //
5239
5258
  // Parser helper for Alasql.js
@@ -5626,7 +5645,6 @@ yy.Search = class Search {
5626
5645
  alasql.vars[sel.args[0]] = oldv;
5627
5646
  return r1;
5628
5647
  }
5629
-
5630
5648
  } else if (sel.selid === 'ARRAY') {
5631
5649
  var nest = processSelector(sel.args, 0, value);
5632
5650
  if (nest.length > 0) {
@@ -5919,10 +5937,6 @@ yy.Search = class Search {
5919
5937
  ) {
5920
5938
  fromdata = fromdata.find().fetch();
5921
5939
  }
5922
-
5923
- // if(typeof fromdata == 'object' && Array.isArray(fromdata)) {
5924
- // selectors.unshift({srchid:'CHILD'});
5925
- // }
5926
5940
  }
5927
5941
 
5928
5942
  // If source data is array than first step is to run over array
@@ -6386,7 +6400,7 @@ var compileSearchOrder = function (order) {
6386
6400
  s += `if (
6387
6401
  (a[${JSON.stringify(columnid)}]||'')${dg}
6388
6402
  ${ord.direction === 'ASC' ? '>' : '<'}
6389
- (b[${JSON.stringify(columnid)}]||'')${dg}
6403
+ (b[${JSON.stringify(columnid)}]||'')${dg}
6390
6404
  ) return 1;
6391
6405
 
6392
6406
  if(
@@ -6402,26 +6416,17 @@ var compileSearchOrder = function (order) {
6402
6416
  if (ord.nocase) {
6403
6417
  dg += '.toUpperCase()';
6404
6418
  }
6405
- s +=
6406
- 'if((' +
6407
- ord.toJS('a', '') +
6408
- "||'')" +
6409
- dg +
6410
- (ord.direction === 'ASC' ? '>(' : '<(') +
6411
- ord.toJS('b', '') +
6412
- "||'')" +
6413
- dg +
6414
- ')return 1;';
6415
- s +=
6416
- 'if((' +
6417
- ord.toJS('a', '') +
6418
- "||'')" +
6419
- dg +
6420
- '==(' +
6421
- ord.toJS('b', '') +
6422
- "||'')" +
6423
- dg +
6424
- '){';
6419
+ s += `
6420
+ if (
6421
+ (${ord.toJS('a', '')} || '')${dg}
6422
+ ${ord.direction === 'ASC' ? '>' : '<'}
6423
+ (${ord.toJS('b', '')} || '')${dg}
6424
+ ) return 1;
6425
+
6426
+ if (
6427
+ (${ord.toJS('a', '')} || '')${dg} ==
6428
+ (${ord.toJS('b', '')} || '')${dg}
6429
+ ) {`;
6425
6430
  }
6426
6431
 
6427
6432
  // TODO Add date comparision
@@ -6438,11 +6443,8 @@ var compileSearchOrder = function (order) {
6438
6443
  };
6439
6444
  // Main query procedure
6440
6445
  function queryfn(query, oldscope, cb, A, B) {
6441
- var aaa = query.sources.length;
6442
-
6443
- var ms;
6444
6446
  query.sourceslen = query.sources.length;
6445
- var slen = query.sourceslen;
6447
+ let slen = query.sourceslen;
6446
6448
  query.query = query; // TODO Remove to prevent memory leaks
6447
6449
  query.A = A;
6448
6450
  query.B = B;
@@ -6479,10 +6481,7 @@ function queryfn(query, oldscope, cb, A, B) {
6479
6481
 
6480
6482
  }
6481
6483
 
6482
- var scope;
6483
- if (!oldscope) scope = {};
6484
- else scope = cloneDeep(oldscope);
6485
- query.scope = scope;
6484
+ query.scope = oldscope ? cloneDeep(oldscope) : {};
6486
6485
 
6487
6486
  // First - refresh data sources
6488
6487
 
@@ -6494,19 +6493,21 @@ function queryfn(query, oldscope, cb, A, B) {
6494
6493
  var rs = source.datafn(query, query.params, queryfn2, idx, alasql);
6495
6494
 
6496
6495
  if (typeof rs !== 'undefined') {
6497
- // TODO - this is a hack: check if result is array - check all cases and
6498
- // make it more logical
6499
- if ((query.intofn || query.intoallfn) && Array.isArray(rs)) rs = rs.length;
6496
+ // TODO - this is a hack: check if result is array - check all cases and make it more logical
6497
+ if ((query.intofn || query.intoallfn) && Array.isArray(rs)) {
6498
+ rs = rs.length;
6499
+ }
6500
6500
  result = rs;
6501
6501
  }
6502
6502
  //
6503
6503
  // Ugly hack to use in query.wherefn and source.srcwherefns functions
6504
6504
  // constructions like this.queriesdata['test'].
6505
- // I can elimite it with source.srcwherefn.bind(this)()
6505
+ // We can elimite it with source.srcwherefn.bind(this)()
6506
6506
  // but it may be slow.
6507
6507
  //
6508
6508
  source.queriesdata = query.queriesdata;
6509
6509
  });
6510
+
6510
6511
  if (query.sources.length == 0 || 0 === slen) {
6511
6512
  try {
6512
6513
  result = queryfn3(query);
@@ -6554,13 +6555,7 @@ function queryfn3(query) {
6554
6555
  jlen;
6555
6556
 
6556
6557
  // Preindexation of data sources
6557
- // if(!oldscope) {
6558
6558
  preIndex(query);
6559
- // }
6560
-
6561
- // query.sources.forEach(function(source) {
6562
-
6563
- // });
6564
6559
 
6565
6560
  // Prepare variables
6566
6561
  query.data = [];
@@ -6571,17 +6566,14 @@ function queryfn3(query) {
6571
6566
  var h = 0;
6572
6567
 
6573
6568
  // Start walking over data
6574
-
6575
6569
  doJoin(query, scope, h);
6576
6570
 
6577
6571
  // If grouping, then filter groups with HAVING function
6578
-
6579
6572
  if (query.groupfn) {
6580
6573
  query.data = [];
6581
6574
  if (query.groups.length === 0 && query.allgroups.length === 0) {
6582
6575
  var g = {};
6583
6576
  if (query.selectGroup.length > 0) {
6584
-
6585
6577
  query.selectGroup.forEach(function (sg) {
6586
6578
  if (
6587
6579
  sg.aggregatorid == 'COUNT' ||
@@ -6595,37 +6587,25 @@ function queryfn3(query) {
6595
6587
  });
6596
6588
  }
6597
6589
  query.groups = [g];
6598
-
6599
6590
  }
6600
6591
 
6601
- // ******
6602
-
6603
6592
  if (query.aggrKeys.length > 0) {
6604
6593
  var gfns = '';
6605
6594
  query.aggrKeys.forEach(function (col) {
6606
- gfns += `g[${JSON.stringify(col.nick)}] = alasql.aggr[${JSON.stringify(
6595
+ gfns += `
6596
+ g[${JSON.stringify(col.nick)}] = alasql.aggr[${JSON.stringify(
6607
6597
  col.funcid
6608
- )}](undefined,g[${JSON.stringify(col.nick)}],3);`;
6609
-
6610
- // gfns += 'return g[\''+col.nick+'\];';
6598
+ )}](undefined,g[${JSON.stringify(col.nick)}],3); `;
6611
6599
  });
6612
-
6613
6600
  var gfn = new Function('g,params,alasql', 'var y;' + gfns);
6614
6601
  }
6615
6602
 
6616
- // *******
6617
-
6618
- // debugger;
6619
- // if(false && (query.groups.length == 1) && (Object.keys(query.groups[0]).length == 0)) {
6620
-
6621
- // } else {
6622
6603
  for (var i = 0, ilen = query.groups.length; i < ilen; i++) {
6623
6604
  var g = query.groups[i];
6624
6605
 
6625
6606
  if (gfn) gfn(g, query.params, alasql);
6626
6607
 
6627
6608
  if (!query.havingfn || query.havingfn(g, query.params, alasql)) {
6628
-
6629
6609
  var d = query.selectgfn(g, query.params, alasql);
6630
6610
 
6631
6611
  for (const key in query.groupColumns) {
@@ -6641,9 +6621,6 @@ function queryfn3(query) {
6641
6621
  query.data.push(d);
6642
6622
  }
6643
6623
  }
6644
- // }
6645
-
6646
- // query.groups = query.groups.filter();
6647
6624
  }
6648
6625
  // Remove distinct values
6649
6626
  doDistinct(query);
@@ -6752,9 +6729,6 @@ function queryfn3(query) {
6752
6729
  // Reduce to limit and offset
6753
6730
  doLimit(query);
6754
6731
 
6755
- // Remove Angular.js artifacts and other unnecessary columns
6756
- // Issue #25
6757
-
6758
6732
  // TODO: Check what artefacts rest from Angular.js
6759
6733
  if (typeof angular != 'undefined') {
6760
6734
  query.removeKeys.push('$$hashKey');
@@ -6796,7 +6770,6 @@ function queryfn3(query) {
6796
6770
  for (var k in r) {
6797
6771
  for (j = 0; j < query.removeLikeKeys.length; j++) {
6798
6772
  if (alasql.utils.like(query.removeLikeKeys[j], k)) {
6799
- // if(k.match(query.removeLikeKeys[j])) {
6800
6773
  delete r[k];
6801
6774
  }
6802
6775
  }
@@ -6807,7 +6780,6 @@ function queryfn3(query) {
6807
6780
  query.columns = query.columns.filter(function (column) {
6808
6781
  var found = false;
6809
6782
  removeLikeKeys.forEach(function (key) {
6810
- // if(column.columnid.match(key)) found = true;
6811
6783
  if (alasql.utils.like(key, column.columnid)) {
6812
6784
  found = true;
6813
6785
  }
@@ -6818,31 +6790,25 @@ function queryfn3(query) {
6818
6790
  }
6819
6791
 
6820
6792
  if (query.pivotfn) query.pivotfn();
6793
+
6821
6794
  if (query.unpivotfn) query.unpivotfn();
6822
6795
 
6823
6796
  if (query.intoallfn) {
6824
-
6825
- // var res = query.intoallfn(query.columns,query.cb,query.A, query.B, alasql);
6826
6797
  var res = query.intoallfn(query.columns, query.cb, query.params, query.alasql);
6827
-
6828
- // if(query.cb) res = query.cb(res,query.A, query.B);
6829
-
6830
- // debugger;
6831
6798
  return res;
6832
- } else if (query.intofn) {
6799
+ }
6800
+
6801
+ if (query.intofn) {
6833
6802
  ilen = query.data.length;
6834
6803
  for (i = 0; i < ilen; i++) {
6835
6804
  query.intofn(query.data[i], i, query.params, query.alasql);
6836
6805
  }
6837
-
6838
6806
  if (query.cb) query.cb(query.data.length, query.A, query.B);
6839
6807
  return query.data.length;
6840
- } else {
6841
-
6842
- res = query.data;
6843
- if (query.cb) res = query.cb(query.data, query.A, query.B);
6844
- return res;
6845
6808
  }
6809
+ res = query.data;
6810
+ if (query.cb) res = query.cb(query.data, query.A, query.B);
6811
+ return res;
6846
6812
  }
6847
6813
 
6848
6814
  // Limiting
@@ -6895,14 +6861,13 @@ var preIndex = function (query) {
6895
6861
  var source = query.sources[k];
6896
6862
  delete source.ix;
6897
6863
  // If there is indexation rule
6898
-
6899
6864
  if (k > 0 && source.optimization == 'ix' && source.onleftfn && source.onrightfn) {
6900
6865
  // If there is no table.indices - create it
6901
6866
  if (source.databaseid && alasql.databases[source.databaseid].tables[source.tableid]) {
6902
6867
  if (!alasql.databases[source.databaseid].tables[source.tableid].indices)
6903
6868
  query.database.tables[source.tableid].indices = {};
6904
6869
  // Check if index already exists
6905
- var ixx =
6870
+ let ixx =
6906
6871
  alasql.databases[source.databaseid].tables[source.tableid].indices[
6907
6872
  hash(source.onrightfns + '`' + source.srcwherefns)
6908
6873
  ];
@@ -6914,10 +6879,10 @@ var preIndex = function (query) {
6914
6879
  if (!source.ix) {
6915
6880
  source.ix = {};
6916
6881
  // Walking over source data
6917
- var scope = {};
6918
- var i = 0;
6919
- var ilen = source.data.length;
6920
- var dataw;
6882
+ let scope = {};
6883
+ let i = 0;
6884
+ let ilen = source.data.length;
6885
+ let dataw;
6921
6886
  // while(source.getfn i<ilen) {
6922
6887
 
6923
6888
  while (
@@ -6926,9 +6891,7 @@ var preIndex = function (query) {
6926
6891
  i < ilen
6927
6892
  ) {
6928
6893
  if (source.getfn && !source.dontcache) source.data[i] = dataw;
6929
- // scope[tableid] = dataw;
6930
6894
 
6931
- // for(var i=0, ilen=source.data.length; i<ilen; i++) {
6932
6895
  // Prepare scope for indexation
6933
6896
  scope[source.alias || source.tableid] = dataw;
6934
6897
 
@@ -6995,7 +6958,6 @@ var preIndex = function (query) {
6995
6958
  group.push(source.data[i]);
6996
6959
  i++;
6997
6960
  }
6998
- // query.database.tables[source.tableid].indices[hash(source.wxleftfns+'`'+source.onwherefns)] = source.ix;
6999
6961
  if (!alasql.databases[source.databaseid].engineid) {
7000
6962
  alasql.databases[source.databaseid].tables[source.tableid].indices[
7001
6963
  hash(source.wxleftfns + '`')
@@ -7014,7 +6976,6 @@ var preIndex = function (query) {
7014
6976
  source.data = [];
7015
6977
  }
7016
6978
  }
7017
- // }
7018
6979
  // If there is no any optimization than apply srcwhere filter
7019
6980
  } else if (source.srcwherefns && !source.dontcache) {
7020
6981
  if (source.data) {
@@ -7023,16 +6984,13 @@ var preIndex = function (query) {
7023
6984
 
7024
6985
  source.data = source.data.filter(function (r) {
7025
6986
  scope[source.alias] = r;
7026
-
7027
6987
  return source.srcwherefn(scope, query.params, alasql);
7028
6988
  });
7029
6989
 
7030
6990
  scope = {};
7031
6991
  i = 0;
7032
6992
  ilen = source.data.length;
7033
- //var dataw;
7034
- var res = [];
7035
- // while(source.getfn i<ilen) {
6993
+ let res = [];
7036
6994
 
7037
6995
  while (
7038
6996
  (dataw = source.data[i]) ||
@@ -7051,7 +7009,6 @@ var preIndex = function (query) {
7051
7009
  }
7052
7010
  // Change this to another place (this is a wrong)
7053
7011
  if (source.databaseid && alasql.databases[source.databaseid].tables[source.tableid]) {
7054
- //query.database.tables[source.tableid].dirty = false;
7055
7012
  } else {
7056
7013
  // this is a subquery?
7057
7014
  }
@@ -7062,34 +7019,24 @@ var preIndex = function (query) {
7062
7019
  //
7063
7020
 
7064
7021
  function doJoin(query, scope, h) {
7065
-
7066
7022
  // Check, if this is a last join?
7067
7023
  if (h >= query.sources.length) {
7068
7024
  // Todo: check if this runs once too many
7069
-
7070
7025
  // Then apply where and select
7071
-
7072
7026
  if (query.wherefn(scope, query.params, alasql)) {
7073
-
7074
- // var res = query.selectfn(scope, query.params, alasql);
7075
-
7076
7027
  // If there is a GROUP BY then pipe to grouping function
7077
7028
  if (query.groupfn) {
7078
7029
  query.groupfn(scope, query.params, alasql);
7079
7030
  } else {
7080
- // query.qwerty = 999;
7081
-
7082
7031
  query.data.push(query.selectfn(scope, query.params, alasql));
7083
7032
  }
7084
7033
  }
7085
7034
  } else if (query.sources[h].applyselect) {
7086
-
7087
7035
  var source = query.sources[h];
7088
7036
  source.applyselect(
7089
7037
  query.params,
7090
7038
  function (data) {
7091
7039
  if (data.length > 0) {
7092
-
7093
7040
  for (var i = 0; i < data.length; i++) {
7094
7041
  scope[source.alias] = data[i];
7095
7042
  doJoin(query, scope, h + 1);
@@ -7103,101 +7050,79 @@ function doJoin(query, scope, h) {
7103
7050
  },
7104
7051
  scope
7105
7052
  );
7106
-
7107
7053
  } else {
7108
7054
  // STEP 1
7109
7055
 
7110
- var source = query.sources[h];
7111
- var nextsource = query.sources[h + 1];
7112
-
7113
- // if(source.joinmode == "LEFT" || source.joinmode == "INNER" || source.joinmode == "RIGHT"
7114
- // || source.joinmode == "OUTER" || source.joinmode == "SEMI") {
7115
- // Todo: check if this is smart
7116
- if (true) {
7117
- //source.joinmode != "ANTI") {
7118
-
7119
- var tableid = source.alias || source.tableid;
7120
- var pass = false; // For LEFT JOIN
7121
- var data = source.data;
7122
- var opt = false;
7056
+ let source = query.sources[h];
7057
+ let nextsource = query.sources[h + 1];
7123
7058
 
7124
- // Reduce data for looping if there is optimization hint
7125
- if (!source.getfn || (source.getfn && !source.dontcache)) {
7126
- if (
7127
- source.joinmode != 'RIGHT' &&
7128
- source.joinmode != 'OUTER' &&
7129
- source.joinmode != 'ANTI' &&
7130
- source.optimization == 'ix'
7131
- ) {
7132
- data = source.ix[source.onleftfn(scope, query.params, alasql)] || [];
7133
- opt = true;
7059
+ let tableid = source.alias || source.tableid;
7060
+ let pass = false; // For LEFT JOIN
7061
+ let data = source.data;
7062
+ let opt = false;
7134
7063
 
7135
- }
7136
- }
7137
-
7138
- // Main cycle
7139
- var i = 0;
7140
- if (typeof data == 'undefined') {
7141
- throw new Error('Data source number ' + h + ' in undefined');
7064
+ // Reduce data for looping if there is optimization hint
7065
+ if (!source.getfn || (source.getfn && !source.dontcache)) {
7066
+ if (
7067
+ source.joinmode != 'RIGHT' &&
7068
+ source.joinmode != 'OUTER' &&
7069
+ source.joinmode != 'ANTI' &&
7070
+ source.optimization == 'ix'
7071
+ ) {
7072
+ data = source.ix[source.onleftfn(scope, query.params, alasql)] || [];
7073
+ opt = true;
7142
7074
  }
7143
- var ilen = data.length;
7144
- var dataw;
7145
-
7146
- while ((dataw = data[i]) || (!opt && source.getfn && (dataw = source.getfn(i))) || i < ilen) {
7147
- if (!opt && source.getfn && !source.dontcache) data[i] = dataw;
7148
-
7149
- scope[tableid] = dataw;
7150
-
7151
- // Reduce with ON and USING clause
7152
- var usingPassed = !source.onleftfn;
7153
- if (!usingPassed) {
7154
- var left = source.onleftfn(scope, query.params, alasql);
7155
- var right = source.onrightfn(scope, query.params, alasql);
7156
- if (left instanceof String || left instanceof Number) left = left.valueOf();
7157
- if (right instanceof String || right instanceof Number) right = left.valueOf();
7158
- usingPassed = left == right;
7159
- }
7160
-
7161
- if (usingPassed) {
7162
- // For all non-standard JOINs like a-b=0
7163
- if (source.onmiddlefn(scope, query.params, alasql)) {
7164
- // Recursively call new join
7165
- // if(source.joinmode == "LEFT" || source.joinmode == "INNER" || source.joinmode == "OUTER" || source.joinmode == "RIGHT" ) {
7166
- if (source.joinmode != 'SEMI' && source.joinmode != 'ANTI') {
7075
+ }
7167
7076
 
7168
- doJoin(query, scope, h + 1);
7169
- }
7077
+ // Main cycle
7078
+ let i = 0;
7079
+ if (typeof data == 'undefined') {
7080
+ throw new Error('Data source number ' + h + ' in undefined');
7081
+ }
7082
+ let ilen = data.length;
7083
+ let dataw;
7170
7084
 
7171
- // if(source.data[i].f = 200) debugger;
7085
+ while ((dataw = data[i]) || (!opt && source.getfn && (dataw = source.getfn(i))) || i < ilen) {
7086
+ if (!opt && source.getfn && !source.dontcache) data[i] = dataw;
7087
+ scope[tableid] = dataw;
7172
7088
 
7173
- // if(source.joinmode == "RIGHT" || source.joinmode == "ANTI" || source.joinmode == "OUTER") {
7174
- if (source.joinmode != 'LEFT' && source.joinmode != 'INNER') {
7175
- dataw._rightjoin = true;
7176
- }
7089
+ // Reduce with ON and USING clause
7090
+ var usingPassed = !source.onleftfn;
7091
+ if (!usingPassed) {
7092
+ var left = source.onleftfn(scope, query.params, alasql);
7093
+ var right = source.onrightfn(scope, query.params, alasql);
7094
+ if (left instanceof String || left instanceof Number) left = left.valueOf();
7095
+ if (right instanceof String || right instanceof Number) right = left.valueOf();
7096
+ usingPassed = left == right;
7097
+ }
7177
7098
 
7178
- // for LEFT JOIN
7179
- pass = true;
7099
+ if (usingPassed) {
7100
+ // For all non-standard JOINs like a-b=0
7101
+ if (source.onmiddlefn(scope, query.params, alasql)) {
7102
+ // Recursively call new join
7103
+ if (source.joinmode != 'SEMI' && source.joinmode != 'ANTI') {
7104
+ doJoin(query, scope, h + 1);
7105
+ }
7106
+ if (source.joinmode != 'LEFT' && source.joinmode != 'INNER') {
7107
+ dataw._rightjoin = true;
7180
7108
  }
7181
- }
7182
- i++;
7183
- }
7184
7109
 
7185
- // Additional join for LEFT JOINS
7186
- if (
7187
- (source.joinmode == 'LEFT' || source.joinmode == 'OUTER' || source.joinmode == 'SEMI') &&
7188
- !pass
7189
- ) {
7190
- // Clear the scope after the loop
7191
- scope[tableid] = {};
7192
- doJoin(query, scope, h + 1);
7110
+ // for LEFT JOIN
7111
+ pass = true;
7112
+ }
7193
7113
  }
7114
+ i++;
7194
7115
  }
7195
7116
 
7196
- // When there is no records
7197
- // if(data.length == 0 && query.groupfn) {
7198
- // scope[tableid] = undefined;
7199
- // doJoin(query,scope,h+1);
7200
- // }
7117
+ // Additional join for LEFT JOINS
7118
+ if (
7119
+ (source.joinmode == 'LEFT' || source.joinmode == 'OUTER' || source.joinmode == 'SEMI') &&
7120
+ !pass
7121
+ ) {
7122
+ // Clear the scope after the loop
7123
+ scope[tableid] = {};
7124
+ doJoin(query, scope, h + 1);
7125
+ }
7201
7126
 
7202
7127
  // STEP 2
7203
7128
 
@@ -7210,9 +7135,9 @@ function doJoin(query, scope, h) {
7210
7135
  ) {
7211
7136
  scope[source.alias] = {};
7212
7137
 
7213
- var j = 0;
7214
- var jlen = nextsource.data.length;
7215
- var dataw;
7138
+ let j = 0;
7139
+ let jlen = nextsource.data.length;
7140
+ let dataw;
7216
7141
 
7217
7142
  while (
7218
7143
  (dataw = nextsource.data[j]) ||
@@ -7243,7 +7168,6 @@ function doJoin(query, scope, h) {
7243
7168
  }
7244
7169
 
7245
7170
  scope[tableid] = undefined;
7246
-
7247
7171
  }
7248
7172
  }
7249
7173
 
@@ -7631,7 +7555,6 @@ yy.Select = class Select {
7631
7555
  query.intoallfn = new Function('columns,cb,params,alasql', 'var y;' + query.intoallfns);
7632
7556
  }
7633
7557
  }
7634
-
7635
7558
  // Now, compile all togeather into one function with query object in scope
7636
7559
  var statement = function (params, cb, oldscope) {
7637
7560
  query.params = params;
@@ -16776,10 +16699,14 @@ alasql.into.XLSX = function (filename, opts, data, columns, cb) {
16776
16699
  var dataLength = Object.keys(data).length;
16777
16700
 
16778
16701
  // Generate columns if they are not defined
16779
- if ((!columns || columns.length == 0) && dataLength > 0) {
16780
- columns = Object.keys(data[0]).map(function (columnid) {
16781
- return {columnid: columnid};
16782
- });
16702
+ if (!columns || columns.length == 0) {
16703
+ if (dataLength > 0) {
16704
+ columns = Object.keys(data[0]).map(function (columnid) {
16705
+ return {columnid: columnid};
16706
+ });
16707
+ } else {
16708
+ columns = [];
16709
+ }
16783
16710
  }
16784
16711
 
16785
16712
  var cells = {};