alasql 4.1.10 → 4.2.0

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,7 +1,7 @@
1
- //! AlaSQL v4.1.9 build: develop-a3395d54 | © 2014-2023 Andrey Gershun & Mathias Wulff | License: MIT
1
+ //! AlaSQL v4.1.11 build: develop-6870c00d | © 2014-2023 Andrey Gershun & Mathias Wulff | License: MIT
2
2
  /*
3
3
  @module alasql
4
- @version 4.1.9
4
+ @version 4.1.11
5
5
 
6
6
  AlaSQL - JavaScript SQL database
7
7
  © 2014-2023 Andrey Gershun & Mathias Wulff
@@ -141,8 +141,8 @@ var alasql = function(sql, params, cb, scope) {
141
141
  Current version of alasql
142
142
  @constant {string}
143
143
  */
144
- alasql.version = '4.1.9';
145
- alasql.build = 'develop-a3395d54';
144
+ alasql.version = '4.1.11';
145
+ alasql.build = 'develop-6870c00d';
146
146
 
147
147
  /**
148
148
  Debug flag
@@ -3168,10 +3168,10 @@ alasql.pretty = function (sql, flag) {
3168
3168
 
3169
3169
  /*jshint unused:false*/
3170
3170
  /*
3171
- Utilities for Alasql.js
3171
+ Utilities for Alasql.js
3172
3172
 
3173
- @todo Review the list of utilities
3174
- @todo Find more effective utilities
3173
+ @todo Review the list of utilities
3174
+ @todo Find more effective utilities
3175
3175
  */
3176
3176
 
3177
3177
  /**
@@ -3227,7 +3227,7 @@ function returnTrue() {
3227
3227
  @function
3228
3228
  @return {undefined} Always undefined
3229
3229
  */
3230
- function returnUndefined() {}
3230
+ function returnUndefined() { }
3231
3231
 
3232
3232
  /**
3233
3233
  Escape string
@@ -3522,7 +3522,7 @@ var loadFile = (utils.loadFile = function (path, asy, success, error) {
3522
3522
  } else if (utils.isCordova) {
3523
3523
  /* If Cordova */
3524
3524
  utils.global.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
3525
- fileSystem.root.getFile(path, {create: false}, function (fileEntry) {
3525
+ fileSystem.root.getFile(path, { create: false }, function (fileEntry) {
3526
3526
  fileEntry.file(function (file) {
3527
3527
  var fileReader = new FileReader();
3528
3528
  fileReader.onloadend = function (e) {
@@ -3711,7 +3711,7 @@ var removeFile = (utils.removeFile = function (path, cb) {
3711
3711
  utils.global.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
3712
3712
  fileSystem.root.getFile(
3713
3713
  path,
3714
- {create: false},
3714
+ { create: false },
3715
3715
  function (fileEntry) {
3716
3716
  fileEntry.remove(cb);
3717
3717
  cb && cb(); // jshint ignore:line
@@ -3779,7 +3779,7 @@ var fileExists = (utils.fileExists = function (path, cb) {
3779
3779
  utils.global.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
3780
3780
  fileSystem.root.getFile(
3781
3781
  path,
3782
- {create: false},
3782
+ { create: false },
3783
3783
  function (fileEntry) {
3784
3784
  cb(true);
3785
3785
  },
@@ -3845,7 +3845,7 @@ var saveFile = (utils.saveFile = function (path, data, cb, opts) {
3845
3845
  } else if (utils.isCordova) {
3846
3846
  utils.global.requestFileSystem(LocalFileSystem.PERSISTENT, 0, function (fileSystem) {
3847
3847
  // alasql.utils.removeFile(path,function(){
3848
- fileSystem.root.getFile(path, {create: true}, function (fileEntry) {
3848
+ fileSystem.root.getFile(path, { create: true }, function (fileEntry) {
3849
3849
  fileEntry.createWriter(function (fileWriter) {
3850
3850
  fileWriter.onwriteend = function () {
3851
3851
  if (cb) {
@@ -3866,7 +3866,7 @@ var saveFile = (utils.saveFile = function (path, data, cb, opts) {
3866
3866
  disableAutoBom: false,
3867
3867
  };
3868
3868
  alasql.utils.extend(opt, opts);
3869
- var blob = new Blob([data], {type: 'text/plain;charset=utf-8'});
3869
+ var blob = new Blob([data], { type: 'text/plain;charset=utf-8' });
3870
3870
  saveAs(blob, path, opt.disableAutoBom);
3871
3871
  if (cb) {
3872
3872
  res = cb(res);
@@ -4210,43 +4210,46 @@ var domEmptyChildren = (utils.domEmptyChildren = function (container) {
4210
4210
  @parameter {string} escape Escape character (optional)
4211
4211
  @return {boolean} If value LIKE pattern ESCAPE escape
4212
4212
  */
4213
-
4213
+ var patternCache = {};
4214
4214
  var like = (utils.like = function (pattern, value, escape) {
4215
- // Verify escape character
4216
- if (!escape) escape = '';
4215
+ if (!patternCache[pattern]) {
4216
+ // Verify escape character
4217
+ if (!escape) escape = '';
4217
4218
 
4218
- var i = 0;
4219
- var s = '^';
4219
+ var i = 0;
4220
+ var s = '^';
4220
4221
 
4221
- while (i < pattern.length) {
4222
- var c = pattern[i],
4223
- c1 = '';
4224
- if (i < pattern.length - 1) c1 = pattern[i + 1];
4222
+ while (i < pattern.length) {
4223
+ var c = pattern[i],
4224
+ c1 = '';
4225
+ if (i < pattern.length - 1) c1 = pattern[i + 1];
4225
4226
 
4226
- if (c === escape) {
4227
- s += '\\' + c1;
4228
- i++;
4229
- } else if (c === '[' && c1 === '^') {
4230
- s += '[^';
4227
+ if (c === escape) {
4228
+ s += '\\' + c1;
4229
+ i++;
4230
+ } else if (c === '[' && c1 === '^') {
4231
+ s += '[^';
4232
+ i++;
4233
+ } else if (c === '[' || c === ']') {
4234
+ s += c;
4235
+ } else if (c === '%') {
4236
+ s += '[\\s\\S]*';
4237
+ } else if (c === '_') {
4238
+ s += '.';
4239
+ } else if ('/.*+?|(){}'.indexOf(c) > -1) {
4240
+ s += '\\' + c;
4241
+ } else {
4242
+ s += c;
4243
+ }
4231
4244
  i++;
4232
- } else if (c === '[' || c === ']') {
4233
- s += c;
4234
- } else if (c === '%') {
4235
- s += '[\\s\\S]*';
4236
- } else if (c === '_') {
4237
- s += '.';
4238
- } else if ('/.*+?|(){}'.indexOf(c) > -1) {
4239
- s += '\\' + c;
4240
- } else {
4241
- s += c;
4242
4245
  }
4243
- i++;
4244
- }
4245
4246
 
4246
- s += '$';
4247
- // if(value == undefined) return false;
4247
+ s += '$';
4248
+ // if(value == undefined) return false;
4248
4249
 
4249
- return ('' + (value ?? '')).search(RegExp(s, 'i')) > -1;
4250
+ patternCache[pattern] = RegExp(s, 'i');
4251
+ }
4252
+ return ('' + (value ?? '')).search(patternCache[pattern]) > -1;
4250
4253
  });
4251
4254
 
4252
4255
  utils.glob = function (value, pattern) {
@@ -4436,32 +4439,32 @@ alasql.parser.parseError = function (str, hash) {
4436
4439
  };
4437
4440
 
4438
4441
  /**
4439
- Jison parser
4440
- @param {string} sql SQL statement
4441
- @return {object} AST (Abstract Syntax Tree)
4442
+ Jison parser
4443
+ @param {string} sql SQL statement
4444
+ @return {object} AST (Abstract Syntax Tree)
4442
4445
 
4443
- @todo Create class AST
4444
- @todo Add other parsers
4446
+ @todo Create class AST
4447
+ @todo Add other parsers
4445
4448
 
4446
- @example
4447
- alasql.parse = function(sql) {
4449
+ @example
4450
+ alasql.parse = function(sql) {
4448
4451
  // My own parser here
4449
- }
4452
+ }
4450
4453
  */
4451
4454
  alasql.parse = function (sql) {
4452
4455
  return alasqlparser.parse(alasql.utils.uncomment(sql));
4453
4456
  };
4454
4457
 
4455
4458
  /**
4456
- List of engines of external databases
4457
- @type {object}
4458
- @todo Create collection type
4459
+ List of engines of external databases
4460
+ @type {object}
4461
+ @todo Create collection type
4459
4462
  */
4460
4463
  alasql.engines = {};
4461
4464
 
4462
4465
  /**
4463
- List of databases
4464
- @type {object}
4466
+ List of databases
4467
+ @type {object}
4465
4468
  */
4466
4469
  alasql.databases = {};
4467
4470
 
@@ -4472,7 +4475,7 @@ alasql.databases = {};
4472
4475
  alasql.databasenum = 0;
4473
4476
 
4474
4477
  /**
4475
- Alasql options object
4478
+ Alasql options object
4476
4479
  */
4477
4480
  alasql.options = {
4478
4481
  /** Log or throw error */
@@ -4540,12 +4543,15 @@ alasql.options = {
4540
4543
  /** Check for NaN and convert it to undefined */
4541
4544
  nan: false,
4542
4545
 
4543
- excel: {cellDates: true},
4546
+ excel: { cellDates: true },
4544
4547
 
4545
4548
  /** Option for SELECT * FROM a,b */
4546
4549
  joinstar: 'overwrite',
4547
4550
 
4548
4551
  loopbreak: 100000,
4552
+
4553
+ /** Whether GETDATE() and NOW() return dates as string. If false, then a Date object is returned */
4554
+ dateAsString: true,
4549
4555
  };
4550
4556
 
4551
4557
  //alasql.options.worker = false;
@@ -4628,7 +4634,7 @@ alasql.autoval = function (tablename, colname, getNext, databaseid) {
4628
4634
 
4629
4635
  return (
4630
4636
  db.tables[tablename].identities[colname].value -
4631
- db.tables[tablename].identities[colname].step || null
4637
+ db.tables[tablename].identities[colname].step || null
4632
4638
  );
4633
4639
  };
4634
4640
 
@@ -4666,10 +4672,10 @@ alasql.dexec = function (databaseid, sql, params, cb, scope) {
4666
4672
  var db = alasql.databases[databaseid];
4667
4673
  // if(db.databaseid != databaseid) console.trace('got!');
4668
4674
 
4669
- var hh;
4675
+ var hh = hash(sql);
4676
+
4670
4677
  // Create hash
4671
4678
  if (alasql.options.cache) {
4672
- hh = hash(sql);
4673
4679
  var statement = db.sqlCache[hh];
4674
4680
  // If database structure was not changed since last time return cache
4675
4681
  if (statement && db.dbversion === statement.dbversion) {
@@ -4677,8 +4683,17 @@ alasql.dexec = function (databaseid, sql, params, cb, scope) {
4677
4683
  }
4678
4684
  }
4679
4685
 
4680
- // Create AST
4681
- var ast = alasql.parse(sql);
4686
+ var ast = db.astCache[hh];
4687
+ if (alasql.options.cache && !ast) {
4688
+ // Create AST cache
4689
+ ast = alasql.parse(sql);
4690
+ if (ast) {
4691
+ // add to AST cache
4692
+ db.astCache[hh] = ast;
4693
+ }
4694
+ } else {
4695
+ ast = alasql.parse(sql);
4696
+ }
4682
4697
  if (!ast.statements) {
4683
4698
  return;
4684
4699
  }
@@ -4991,6 +5006,7 @@ var Database = (alasql.Database = function (databaseid) {
4991
5006
  Database.prototype.resetSqlCache = function () {
4992
5007
  this.sqlCache = {}; // Cache for compiled SQL statements
4993
5008
  this.sqlCacheSize = 0;
5009
+ this.astCache = {}; // Cache for AST objects
4994
5010
  };
4995
5011
 
4996
5012
  // Main SQL function
@@ -6613,9 +6629,8 @@ function queryfn3(query) {
6613
6629
  var d = query.selectgfn(g, query.params, alasql);
6614
6630
 
6615
6631
  for (const key in query.groupColumns) {
6616
- if (query.groupColumns[key] !== key
6617
- && d[query.groupColumns[key]])
6618
- delete d[query.groupColumns[key]]
6632
+ if (query.groupColumns[key] !== key && d[query.groupColumns[key]])
6633
+ delete d[query.groupColumns[key]];
6619
6634
  }
6620
6635
  query.data.push(d);
6621
6636
  }
@@ -6883,7 +6898,7 @@ var preIndex = function (query) {
6883
6898
  // Check if index already exists
6884
6899
  var ixx =
6885
6900
  alasql.databases[source.databaseid].tables[source.tableid].indices[
6886
- hash(source.onrightfns + '`' + source.srcwherefns)
6901
+ hash(source.onrightfns + '`' + source.srcwherefns)
6887
6902
  ];
6888
6903
  if (!alasql.databases[source.databaseid].tables[source.tableid].dirty && ixx) {
6889
6904
  source.ix = ixx;
@@ -6938,7 +6953,7 @@ var preIndex = function (query) {
6938
6953
  // Check if index exists
6939
6954
  ixx =
6940
6955
  alasql.databases[source.databaseid].tables[source.tableid].indices[
6941
- hash(source.wxleftfns + '`')
6956
+ hash(source.wxleftfns + '`')
6942
6957
  ];
6943
6958
  }
6944
6959
  if (!alasql.databases[source.databaseid].tables[source.tableid].dirty && ixx) {
@@ -9073,9 +9088,10 @@ function compileSelectStar(query, aliases, joinstar) {
9073
9088
 
9074
9089
  if (columns && columns.length > 0) {
9075
9090
  columns.forEach(function (tcol) {
9091
+ const escapedColumnId = escapeq(tcol.columnid);
9076
9092
  if (joinstar && alasql.options.joinstar == 'underscore') {
9077
9093
  ss.push(
9078
- "'" + alias + '_' + tcol.columnid + "':p['" + alias + "']['" + tcol.columnid + "']"
9094
+ "'" + alias + '_' + escapedColumnId + "':p['" + alias + "']['" + escapedColumnId + "']"
9079
9095
  );
9080
9096
  } else if (joinstar && alasql.options.joinstar == 'json') {
9081
9097
  // ss.push('\''+alias+'_'+tcol.columnid+'\':p[\''+alias+'\'][\''+tcol.columnid+'\']');
@@ -9083,16 +9099,16 @@ function compileSelectStar(query, aliases, joinstar) {
9083
9099
  "r['" +
9084
9100
  alias +
9085
9101
  "']['" +
9086
- tcol.columnid +
9102
+ escapedColumnId +
9087
9103
  "']=p['" +
9088
9104
  alias +
9089
9105
  "']['" +
9090
- tcol.columnid +
9106
+ escapedColumnId +
9091
9107
  "'];";
9092
9108
  } else {
9093
- var value = "p['" + alias + "']['" + tcol.columnid + "']";
9109
+ var value = "p['" + alias + "']['" + escapedColumnId + "']";
9094
9110
  if (!columnIds[tcol.columnid]) {
9095
- var key = "'" + tcol.columnid + "':";
9111
+ var key = "'" + escapedColumnId + "':";
9096
9112
  ss.push(key + value);
9097
9113
  columnIds[tcol.columnid] = {
9098
9114
  id: ss.length - 1,
@@ -9107,7 +9123,7 @@ function compileSelectStar(query, aliases, joinstar) {
9107
9123
  }
9108
9124
  }
9109
9125
 
9110
- query.selectColumns[escapeq(tcol.columnid)] = true;
9126
+ query.selectColumns[escapedColumnId] = true;
9111
9127
 
9112
9128
  var coldef = {
9113
9129
  columnid: tcol.columnid,
@@ -10574,7 +10590,7 @@ yy.Over = class Over {
10574
10590
  var ljs = '(' + leftJS() + '||{})';
10575
10591
 
10576
10592
  if (typeof this.right === 'string') {
10577
- s = ljs + '["' + this.right + '"]';
10593
+ s = ljs + '["' + escapeq(this.right) + '"]';
10578
10594
  } else if (typeof this.right === 'number') {
10579
10595
  s = ljs + '[' + this.right + ']';
10580
10596
  } else if (this.right instanceof yy.FuncValue) {
@@ -10689,14 +10705,17 @@ yy.Over = class Over {
10689
10705
  s += '.indexOf(';
10690
10706
  s += 'alasql.utils.getValueOf(' + leftJS() + '))>-1)';
10691
10707
  } else if (Array.isArray(this.right)) {
10692
- // if(this.right.length == 0) return 'false';
10693
- s =
10694
- '([' +
10695
- this.right.map(ref).join(',') +
10696
- '].indexOf(alasql.utils.getValueOf(' +
10697
- leftJS() +
10698
- '))>-1)';
10699
-
10708
+ // Added patch to have a better performance for when you have a lot of entries in an IN statement
10709
+ if (!alasql.sets) {
10710
+ alasql.sets = {};
10711
+ }
10712
+ const allValues = this.right.map((value) => value.value);
10713
+ const allValuesStr = allValues.join(",");
10714
+ if (!alasql.sets[allValuesStr]) {
10715
+ // leverage JS Set, which is faster for lookups than arrays
10716
+ alasql.sets[allValuesStr] = new Set(allValues);
10717
+ }
10718
+ s = 'alasql.sets["' + allValuesStr + '"].has(alasql.utils.getValueOf(' + leftJS() + '))';
10700
10719
  } else {
10701
10720
  s = '(' + rightJS() + '.indexOf(' + leftJS() + ')>-1)';
10702
10721
 
@@ -10712,8 +10731,17 @@ yy.Over = class Over {
10712
10731
  s += '.indexOf(';
10713
10732
  s += 'alasql.utils.getValueOf(' + leftJS() + '))<0)';
10714
10733
  } else if (Array.isArray(this.right)) {
10715
- s = '([' + this.right.map(ref).join(',') + '].indexOf(';
10716
- s += 'alasql.utils.getValueOf(' + leftJS() + '))<0)';
10734
+ // Added patch to have a better performance for when you have a lot of entries in a NOT IN statement
10735
+ if (!alasql.sets) {
10736
+ alasql.sets = {};
10737
+ }
10738
+ const allValues = this.right.map((value) => value.value);
10739
+ const allValuesStr = allValues.join(",");
10740
+ if (!alasql.sets[allValuesStr]) {
10741
+ // leverage JS Set, which is faster for lookups than arrays
10742
+ alasql.sets[allValuesStr] = new Set(allValues);
10743
+ }
10744
+ s = '!alasql.sets["' + allValuesStr + '"].has(alasql.utils.getValueOf(' + leftJS() + '))';
10717
10745
  } else {
10718
10746
  s = '(' + rightJS() + '.indexOf(';
10719
10747
  s += leftJS() + ')==-1)';
@@ -10813,7 +10841,7 @@ yy.Over = class Over {
10813
10841
  }
10814
10842
 
10815
10843
  toJS() {
10816
- return "alasql.vars['" + this.variable + "']";
10844
+ return "alasql.vars['" + escapeq(this.variable) + "']";
10817
10845
  }
10818
10846
  }
10819
10847
 
@@ -10956,7 +10984,7 @@ yy.Over = class Over {
10956
10984
 
10957
10985
  toString() {
10958
10986
  var s;
10959
- const {op, right} = this;
10987
+ const { op, right } = this;
10960
10988
  const res = right.toString();
10961
10989
 
10962
10990
  if (op === '~') {
@@ -11202,7 +11230,7 @@ yy.Over = class Over {
11202
11230
  toJS() {
11203
11231
  var colas = this.nick;
11204
11232
  if (colas === undefined) {
11205
- colas = this.toString();
11233
+ colas = escapeq(this.toString());
11206
11234
  }
11207
11235
  return "g['" + colas + "']";
11208
11236
  }
@@ -12991,27 +13019,30 @@ stdfn.OBJECT_ID = function (objid) {
12991
13019
  };
12992
13020
 
12993
13021
  stdfn.DATE = function (d) {
12994
- if (/\d{8}/.test(d)) return new Date(+d.substr(0, 4), +d.substr(4, 2) - 1, +d.substr(6, 2));
13022
+ if (!isNaN(d) && d.length === 8) return new Date(+d.substr(0, 4), +d.substr(4, 2) - 1, +d.substr(6, 2));
12995
13023
  return newDate(d);
12996
13024
  };
12997
13025
 
12998
13026
  stdfn.NOW = function () {
12999
- var d = new Date();
13000
- var s =
13001
- d.getFullYear() +
13002
- '-' +
13003
- ('0' + (d.getMonth() + 1)).substr(-2) +
13004
- '-' +
13005
- ('0' + d.getDate()).substr(-2);
13006
- s +=
13007
- ' ' +
13008
- ('0' + d.getHours()).substr(-2) +
13009
- ':' +
13010
- ('0' + d.getMinutes()).substr(-2) +
13011
- ':' +
13012
- ('0' + d.getSeconds()).substr(-2);
13013
- s += '.' + ('00' + d.getMilliseconds()).substr(-3);
13014
- return s;
13027
+ if (alasql.options.dateAsString) {
13028
+ var d = new Date();
13029
+ var s =
13030
+ d.getFullYear() +
13031
+ '-' +
13032
+ ('0' + (d.getMonth() + 1)).substr(-2) +
13033
+ '-' +
13034
+ ('0' + d.getDate()).substr(-2);
13035
+ s +=
13036
+ ' ' +
13037
+ ('0' + d.getHours()).substr(-2) +
13038
+ ':' +
13039
+ ('0' + d.getMinutes()).substr(-2) +
13040
+ ':' +
13041
+ ('0' + d.getSeconds()).substr(-2);
13042
+ s += '.' + ('00' + d.getMilliseconds()).substr(-3);
13043
+ return s;
13044
+ }
13045
+ return new Date();
13015
13046
  };
13016
13047
 
13017
13048
  stdfn.GETDATE = stdfn.NOW;