squirreling 0.15.0 → 0.15.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squirreling",
3
- "version": "0.15.0",
3
+ "version": "0.15.1",
4
4
  "description": "Squirreling Async SQL Engine",
5
5
  "author": "Hyperparam",
6
6
  "homepage": "https://hyperparam.app",
@@ -39,10 +39,10 @@
39
39
  "test": "vitest run"
40
40
  },
41
41
  "devDependencies": {
42
- "@types/node": "26.1.1",
42
+ "@types/node": "26.2.0",
43
43
  "@vitest/coverage-v8": "4.1.10",
44
44
  "eslint": "9.39.4",
45
- "eslint-plugin-jsdoc": "63.0.13",
45
+ "eslint-plugin-jsdoc": "64.1.0",
46
46
  "typescript": "7.0.2",
47
47
  "vitest": "4.1.10"
48
48
  }
@@ -166,6 +166,9 @@ export function planStreamingAggregates({ columns, having, orderBy, groupBy }, c
166
166
  case 'function': {
167
167
  const funcName = node.funcName.toUpperCase()
168
168
  if (!isAggregateFunc(funcName)) {
169
+ if (funcName === 'COALESCE') {
170
+ return node.args.every((arg, i) => walk(arg, lazy || i > 0))
171
+ }
169
172
  return node.args.every(arg => walk(arg, lazy))
170
173
  }
171
174
  if (!STREAMABLE_FUNCS.has(funcName)) return false
@@ -394,6 +394,18 @@ export async function evaluateExpr({ node, row, rowIndex, rows, context }) {
394
394
  }
395
395
  }
396
396
 
397
+ // COALESCE must be handled before the eager arg evaluation below, or it
398
+ // evaluates every argument once eagerly and the arguments up to the first
399
+ // non-null value a second time. Nested calls compound that duplication.
400
+ if (funcName === 'COALESCE') {
401
+ // Short-circuit: evaluate args one at a time, return first non-null
402
+ for (const arg of node.args) {
403
+ const val = await evaluateExpr({ node: arg, row, rowIndex, rows, context })
404
+ if (val != null) return val
405
+ }
406
+ return null
407
+ }
408
+
397
409
  /** @type {SqlPrimitive[]} */
398
410
  const args = node.args.length === 1
399
411
  ? [await evaluateExpr({ node: node.args[0], row, rowIndex, rows, context })]
@@ -415,20 +427,9 @@ export async function evaluateExpr({ node, row, rowIndex, rows, context }) {
415
427
  return evaluateSpatialFunc({ funcName, args })
416
428
  }
417
429
 
418
- if (funcName === 'COALESCE') {
419
- // Short-circuit: evaluate args one at a time, return first non-null
420
- for (const arg of node.args) {
421
- const val = await evaluateExpr({ node: arg, row, rowIndex, rows, context })
422
- if (val != null) return val
423
- }
424
- return null
425
- }
426
-
427
430
  if (funcName === 'NULLIF') {
428
431
  // NULLIF(a, b) returns null if a = b, otherwise returns a
429
- const val2 = evaluateExpr({ node: node.args[1], row, rowIndex, rows, context })
430
- const val1 = await evaluateExpr({ node: node.args[0], row, rowIndex, rows, context })
431
- return val1 == await val2 ? null : val1
432
+ return args[0] == args[1] ? null : args[0]
432
433
  }
433
434
 
434
435
  if (funcName === 'GREATEST' || funcName === 'LEAST') {