alasql 4.6.4 → 4.6.6

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.
@@ -1,7 +1,7 @@
1
- //! AlaSQL v4.6.3 build: develop-3129f37a | © 2014-2024 Andrey Gershun & Mathias Wulff | License: MIT
1
+ //! AlaSQL v4.6.5 build: develop-f6e298b2 | © 2014-2024 Andrey Gershun & Mathias Wulff | License: MIT
2
2
  /*
3
3
  @module alasql
4
- @version 4.6.3
4
+ @version 4.6.5
5
5
 
6
6
  AlaSQL - JavaScript SQL database
7
7
  © 2014-2024 Andrey Gershun & Mathias Wulff
package/dist/alasql.fs.js CHANGED
@@ -1,7 +1,7 @@
1
- //! AlaSQL v4.6.3 build: develop-3129f37a | © 2014-2024 Andrey Gershun & Mathias Wulff | License: MIT
1
+ //! AlaSQL v4.6.5 build: develop-f6e298b2 | © 2014-2024 Andrey Gershun & Mathias Wulff | License: MIT
2
2
  /*
3
3
  @module alasql
4
- @version 4.6.3
4
+ @version 4.6.5
5
5
 
6
6
  AlaSQL - JavaScript SQL database
7
7
  © 2014-2024 Andrey Gershun & Mathias Wulff
@@ -141,8 +141,8 @@ SOFTWARE.
141
141
  Current version of alasql
142
142
  @constant {string}
143
143
  */
144
- alasql.version = '4.6.3';
145
- alasql.build = 'develop-3129f37a';
144
+ alasql.version = '4.6.5';
145
+ alasql.build = 'develop-f6e298b2';
146
146
 
147
147
  /**
148
148
  Debug flag
@@ -9473,104 +9473,220 @@ yy.Select.prototype.compilePivot = function (query) {
9473
9473
  });
9474
9474
  }
9475
9475
 
9476
- // Function for PIVOT post production
9476
+ // Function for PIVOT post production (returned by compilePivot)
9477
9477
  return function () {
9478
- var query = this;
9479
- var cols = query.columns
9480
- .filter(function (col) {
9481
- return col.columnid != columnid && col.columnid != exprcolid;
9482
- })
9483
- .map(function (col) {
9484
- return col.columnid;
9485
- });
9478
+ var query = this; // Keep reference to the query object
9479
+
9480
+ // Exit if no data to pivot
9481
+ if (!query.data || query.data.length === 0) {
9482
+ query.columns = []; // Reset columns if no data
9483
+ return;
9484
+ }
9485
+
9486
+ // --- Determine grouping columns robustly ---
9487
+ var firstRowKeys = Object.keys(query.data[0]);
9488
+ var cols = firstRowKeys.filter(function (key) {
9489
+ return key !== columnid && key !== exprcolid;
9490
+ });
9491
+ // -----------------------------------------
9492
+
9493
+ var newcols = []; // Stores the new column headers (e.g., 'MON', 'TUE')
9494
+ var gnewcols = {}; // Tracks unique new columns encountered
9495
+ var gr = {}; // Stores the grouped & pivoted results (key: gx, value: g)
9496
+ var ga = {}; // Stores counts for AVG calculation (key: gx, value: {day: count})
9497
+ var data = []; // The final pivoted data array
9486
9498
 
9487
- var newcols = [];
9488
- var gnewcols = {};
9489
- var gr = {};
9490
- var ga = {};
9491
- var data = [];
9492
9499
  query.data.forEach(function (d) {
9493
- if (!inlist || inlist.indexOf(d[columnid]) > -1) {
9494
- var gx = cols
9495
- .map(function (colid) {
9496
- return d[colid];
9497
- })
9498
- .join('`');
9499
- var g = gr[gx];
9500
- if (!g) {
9501
- g = {};
9502
- gr[gx] = g;
9503
- data.push(g);
9504
- cols.forEach(function (colid) {
9505
- g[colid] = d[colid];
9506
- });
9507
- }
9500
+ // Skip row if the pivot column value is not in the IN list (if provided)
9501
+ if (inlist && inlist.indexOf(d[columnid]) === -1) {
9502
+ return;
9503
+ }
9508
9504
 
9509
- if (!ga[gx]) {
9510
- ga[gx] = {};
9511
- }
9505
+ var gx = cols
9506
+ .map(function (colid) {
9507
+ return d[colid] === undefined || d[colid] === null ? '' : d[colid];
9508
+ })
9509
+ .join('`');
9512
9510
 
9513
- if (ga[gx][d[columnid]]) {
9514
- ga[gx][d[columnid]]++;
9515
- } else {
9516
- ga[gx][d[columnid]] = 1;
9517
- }
9511
+ var g = gr[gx];
9512
+ if (!g) {
9513
+ g = {};
9514
+ gr[gx] = g;
9515
+ data.push(g);
9516
+ cols.forEach(function (colid) {
9517
+ g[colid] = d[colid];
9518
+ });
9519
+ }
9520
+
9521
+ if (!ga[gx]) {
9522
+ ga[gx] = {};
9523
+ }
9518
9524
 
9519
- if (!gnewcols[d[columnid]]) {
9520
- gnewcols[d[columnid]] = true;
9521
- newcols.push(d[columnid]);
9525
+ var pivotColValue = d[columnid];
9526
+ var aggValue = d[exprcolid];
9527
+
9528
+ // Increment count only for non-null/undefined values when calculating AVG
9529
+ if (ga[gx][pivotColValue]) {
9530
+ if (aggValue !== null && typeof aggValue !== 'undefined') {
9531
+ ga[gx][pivotColValue]++;
9522
9532
  }
9533
+ } else {
9534
+ ga[gx][pivotColValue] = aggValue !== null && typeof aggValue !== 'undefined' ? 1 : 0;
9535
+ }
9536
+
9537
+ if (!gnewcols[pivotColValue]) {
9538
+ gnewcols[pivotColValue] = true;
9539
+ newcols.push(pivotColValue);
9540
+ }
9523
9541
 
9524
- if (aggr == 'SUM' || aggr == 'AVG' || aggr == 'TOTAL') {
9525
- if (typeof g[d[columnid]] == 'undefined') g[d[columnid]] = 0;
9526
- g[d[columnid]] += +d[exprcolid];
9527
- } else if (aggr == 'COUNT') {
9528
- if (typeof g[d[columnid]] == 'undefined') g[d[columnid]] = 0;
9529
- g[d[columnid]]++;
9530
- } else if (aggr == 'MIN') {
9531
- if (typeof g[d[columnid]] == 'undefined') g[d[columnid]] = d[exprcolid];
9532
- if (d[exprcolid] < g[d[columnid]]) g[d[columnid]] = d[exprcolid];
9533
- } else if (aggr == 'MAX') {
9534
- if (typeof g[d[columnid]] == 'undefined') g[d[columnid]] = d[exprcolid];
9535
- if (d[exprcolid] > g[d[columnid]]) g[d[columnid]] = d[exprcolid];
9536
- } else if (aggr == 'FIRST') {
9537
- if (typeof g[d[columnid]] == 'undefined') g[d[columnid]] = d[exprcolid];
9538
- } else if (aggr == 'LAST') {
9539
- g[d[columnid]] = d[exprcolid];
9540
- } else if (alasql.aggr[aggr]) {
9541
- // Custom aggregator
9542
- alasql.aggr[aggr](g[d[columnid]], d[exprcolid]);
9542
+ // Apply the specified aggregation
9543
+ if (aggr == 'SUM' || aggr == 'AVG' || aggr == 'TOTAL') {
9544
+ if (aggValue !== null && typeof aggValue !== 'undefined') {
9545
+ g[pivotColValue] =
9546
+ typeof g[pivotColValue] === 'undefined' || g[pivotColValue] === null
9547
+ ? Number(aggValue)
9548
+ : g[pivotColValue] + Number(aggValue);
9549
+ } else if (typeof g[pivotColValue] === 'undefined') {
9550
+ g[pivotColValue] = null;
9551
+ }
9552
+ } else if (aggr == 'COUNT') {
9553
+ if (exprcolid === '*' || (aggValue !== null && typeof aggValue !== 'undefined')) {
9554
+ g[pivotColValue] = (g[pivotColValue] || 0) + 1;
9555
+ } else if (typeof g[pivotColValue] === 'undefined') {
9556
+ g[pivotColValue] = 0;
9557
+ }
9558
+ } else if (aggr == 'MIN') {
9559
+ if (aggValue !== null && typeof aggValue !== 'undefined') {
9560
+ if (
9561
+ typeof g[pivotColValue] === 'undefined' ||
9562
+ g[pivotColValue] === null ||
9563
+ aggValue < g[pivotColValue]
9564
+ ) {
9565
+ g[pivotColValue] = aggValue;
9566
+ }
9567
+ } else if (typeof g[pivotColValue] === 'undefined') {
9568
+ g[pivotColValue] = null;
9569
+ }
9570
+ } else if (aggr == 'MAX') {
9571
+ if (aggValue !== null && typeof aggValue !== 'undefined') {
9572
+ if (
9573
+ typeof g[pivotColValue] === 'undefined' ||
9574
+ g[pivotColValue] === null ||
9575
+ aggValue > g[pivotColValue]
9576
+ ) {
9577
+ g[pivotColValue] = aggValue;
9578
+ }
9579
+ } else if (typeof g[pivotColValue] === 'undefined') {
9580
+ g[pivotColValue] = null;
9581
+ }
9582
+ } else if (aggr == 'FIRST') {
9583
+ if (typeof g[pivotColValue] === 'undefined') {
9584
+ g[pivotColValue] = aggValue;
9585
+ }
9586
+ } else if (aggr == 'LAST') {
9587
+ g[pivotColValue] = aggValue;
9588
+ } else if (alasql.aggr[aggr]) {
9589
+ if (typeof g[pivotColValue] === 'undefined') {
9590
+ g[pivotColValue] = alasql.aggr[aggr](aggValue, undefined, 1);
9543
9591
  } else {
9544
- throw new Error('Wrong aggregator in PIVOT clause');
9592
+ g[pivotColValue] = alasql.aggr[aggr](aggValue, g[pivotColValue], 2);
9545
9593
  }
9594
+ } else {
9595
+ throw new Error('Unknown aggregator in PIVOT clause: ' + aggr);
9546
9596
  }
9547
9597
  });
9548
9598
 
9599
+ // Finalize AVG calculation
9549
9600
  if (aggr == 'AVG') {
9550
9601
  for (var gx in gr) {
9551
9602
  var d = gr[gx];
9552
- for (var colid in d) {
9553
- if (cols.indexOf(colid) == -1 && colid != exprcolid) {
9554
- d[colid] = d[colid] / ga[gx][colid];
9603
+ for (var pivotColValue in ga[gx]) {
9604
+ if (d.hasOwnProperty(pivotColValue) && d[pivotColValue] !== null) {
9605
+ var count = ga[gx][pivotColValue];
9606
+ if (count > 0) {
9607
+ d[pivotColValue] = d[pivotColValue] / count;
9608
+ } else {
9609
+ d[pivotColValue] = null;
9610
+ }
9555
9611
  }
9556
9612
  }
9557
9613
  }
9558
9614
  }
9559
9615
 
9560
- // columns
9616
+ // --- Rebuild query.columns ---
9561
9617
  query.data = data;
9562
9618
 
9563
- if (inlist) newcols = inlist;
9619
+ if (inlist) {
9620
+ newcols = inlist;
9621
+ } else {
9622
+ newcols.sort();
9623
+ }
9624
+
9625
+ // Find original column definition - might be basic if SELECT * was used
9626
+ let aggColDef = query.columns.find(col => col.columnid === exprcolid);
9627
+ // If SELECT * was used, aggColDef might be missing, find it from the table definition if possible
9628
+ if (!aggColDef && query.sources && query.sources.length > 0) {
9629
+ let sourceTableId = query.sources[0].tableid;
9630
+ let sourceDbId = query.sources[0].databaseid;
9631
+ if (
9632
+ sourceTableId &&
9633
+ sourceDbId &&
9634
+ alasql.databases[sourceDbId]?.tables?.[sourceTableId]?.xcolumns
9635
+ ) {
9636
+ aggColDef = alasql.databases[sourceDbId].tables[sourceTableId].xcolumns[exprcolid];
9637
+ }
9638
+ }
9639
+ // Provide a fallback if still not found
9640
+ aggColDef = aggColDef || {columnid: exprcolid, dbtypeid: 'OBJECT'};
9564
9641
 
9565
- var ncol = query.columns.filter(function (col) {
9566
- return col.columnid == exprcolid;
9567
- })[0];
9642
+ // Keep only the grouping columns initially
9568
9643
  query.columns = query.columns.filter(function (col) {
9569
- return !(col.columnid == columnid || col.columnid == exprcolid);
9644
+ return cols.includes(col.columnid);
9570
9645
  });
9571
- newcols.forEach(function (colid) {
9572
- var nc = cloneDeep(ncol);
9573
- nc.columnid = colid;
9646
+
9647
+ // Add the new pivoted columns
9648
+ newcols.forEach(function (newColId) {
9649
+ var nc = cloneDeep(aggColDef);
9650
+ nc.columnid = newColId;
9651
+
9652
+ // ---- Final Refined Type Logic ----
9653
+ const originalType = (aggColDef.dbtypeid || 'OBJECT').toUpperCase();
9654
+ const integerTypes = [
9655
+ 'INT',
9656
+ 'INTEGER',
9657
+ 'SMALLINT',
9658
+ 'BIGINT',
9659
+ 'SERIAL',
9660
+ 'SMALLSERIAL',
9661
+ 'BIGSERIAL',
9662
+ ];
9663
+ const numericTypes = [...integerTypes, 'NUMBER', 'FLOAT', 'DECIMAL', 'NUMERIC', 'MONEY'];
9664
+
9665
+ if (aggr === 'COUNT') {
9666
+ nc.dbtypeid = 'INT';
9667
+ } else if (aggr === 'AVG') {
9668
+ // Keep INT type if original was INT-like, otherwise use FLOAT
9669
+ if (integerTypes.includes(originalType)) {
9670
+ nc.dbtypeid = aggColDef.dbtypeid; // Preserve original INT-like type
9671
+ } else {
9672
+ nc.dbtypeid = 'FLOAT';
9673
+ }
9674
+ } else if (aggr === 'SUM' || aggr === 'TOTAL') {
9675
+ // Preserve numeric types, default to FLOAT otherwise
9676
+ if (numericTypes.includes(originalType)) {
9677
+ nc.dbtypeid = aggColDef.dbtypeid;
9678
+ } else {
9679
+ nc.dbtypeid = 'FLOAT'; // Default for non-numeric or unknown sums
9680
+ }
9681
+ } else if (aggr === 'MIN' || aggr === 'MAX' || aggr === 'FIRST' || aggr === 'LAST') {
9682
+ // Preserve original type as comparisons work across types
9683
+ nc.dbtypeid = aggColDef.dbtypeid;
9684
+ }
9685
+ // For custom aggregators (AGGR, REDUCE), inherit type from clone, ensure fallback
9686
+ else if (!nc.dbtypeid) {
9687
+ nc.dbtypeid = 'OBJECT';
9688
+ }
9689
+
9574
9690
  query.columns.push(nc);
9575
9691
  });
9576
9692
  };
@@ -16429,7 +16545,12 @@ alasql.from.JSON = function (filename, opts, cb, idx, query) {
16429
16545
  }
16430
16546
  }),
16431
16547
  err => {
16432
- throw new Error(err);
16548
+ const error = err instanceof Error ? err : new Error(err);
16549
+ if(query && query.cb) {
16550
+ query.cb(null, error);
16551
+ return;
16552
+ }
16553
+ throw error;
16433
16554
  };
16434
16555
  return res;
16435
16556
  };
@@ -16454,11 +16575,16 @@ const jsonl = ext => {
16454
16575
  }
16455
16576
  });
16456
16577
  if (cb) {
16457
- res = cb(out, idx, query);
16578
+ out = cb(out, idx, query);
16458
16579
  }
16459
16580
  },
16460
16581
  err => {
16461
- throw new Error(err);
16582
+ const error = err instanceof Error ? err : new Error(err);
16583
+ if(query && query.cb) {
16584
+ query.cb(null, error);
16585
+ return;
16586
+ }
16587
+ throw error;
16462
16588
  }
16463
16589
  );
16464
16590
  return out;
@@ -16783,7 +16909,7 @@ function XLSXLSX(X, filename, opts, cb, idx, query) {
16783
16909
  }
16784
16910
  },
16785
16911
  function (err) {
16786
- if(query && query.cb) {
16912
+ if (query && query.cb) {
16787
16913
  query.cb(null, err);
16788
16914
  return;
16789
16915
  }