squirreling 0.7.9 → 0.7.10

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/README.md CHANGED
@@ -104,4 +104,5 @@ Squirreling mostly follows the SQL standard. The following features are supporte
104
104
  - Date: `CURRENT_DATE`, `CURRENT_TIME`, `CURRENT_TIMESTAMP`, `INTERVAL`
105
105
  - Json: `JSON_VALUE`, `JSON_QUERY`, `JSON_OBJECT`
106
106
  - Regex: `REGEXP_SUBSTR`, `REGEXP_REPLACE`
107
+ - Conditional: `COALESCE`, `NULLIF`
107
108
  - User-defined functions (UDFs)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "squirreling",
3
- "version": "0.7.9",
3
+ "version": "0.7.10",
4
4
  "description": "Squirreling SQL Engine",
5
5
  "author": "Hyperparam",
6
6
  "homepage": "https://hyperparam.app",
@@ -37,11 +37,11 @@
37
37
  "test": "vitest run"
38
38
  },
39
39
  "devDependencies": {
40
- "@types/node": "25.0.9",
41
- "@vitest/coverage-v8": "4.0.17",
40
+ "@types/node": "25.2.0",
41
+ "@vitest/coverage-v8": "4.0.18",
42
42
  "eslint": "9.39.2",
43
- "eslint-plugin-jsdoc": "62.0.0",
43
+ "eslint-plugin-jsdoc": "62.5.0",
44
44
  "typescript": "5.9.3",
45
- "vitest": "4.0.17"
45
+ "vitest": "4.0.18"
46
46
  }
47
47
  }
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @import { AsyncCell, AsyncCells, AsyncDataSource, AsyncRow, ScanOptions, SqlPrimitive } from '../types.js'
2
+ * @import { AsyncCells, AsyncDataSource, AsyncRow, ScanOptions, SqlPrimitive } from '../types.js'
3
3
  */
4
4
 
5
5
  /**
@@ -268,6 +268,13 @@ export async function evaluateExpr({ node, row, tables, functions, rowIndex, row
268
268
  return null
269
269
  }
270
270
 
271
+ if (funcName === 'NULLIF') {
272
+ // NULLIF(a, b) returns null if a = b, otherwise returns a
273
+ const val1 = await evaluateExpr({ node: node.args[0], row, tables, functions, rowIndex, rows })
274
+ const val2 = await evaluateExpr({ node: node.args[1], row, tables, functions, rowIndex, rows })
275
+ return val1 == val2 ? null : val1
276
+ }
277
+
271
278
  if (funcName === 'CURRENT_DATE') {
272
279
  return new Date().toISOString().split('T')[0]
273
280
  }
package/src/index.d.ts CHANGED
@@ -1,5 +1,18 @@
1
1
  import type { AsyncDataSource, AsyncRow, ExecuteSqlOptions, ParseSqlOptions, SelectStatement, SqlPrimitive, Token } from './types.js'
2
- export type { AsyncCells, AsyncDataSource, AsyncRow, ExprNode, ParseSqlOptions, SelectStatement, SqlPrimitive, Token, UserDefinedFunction } from './types.js'
2
+ export type {
3
+ AsyncCells,
4
+ AsyncDataSource,
5
+ AsyncRow,
6
+ ExecuteSqlOptions,
7
+ ExprNode,
8
+ ParseSqlOptions,
9
+ QueryHints,
10
+ ScanOptions,
11
+ SelectStatement,
12
+ SqlPrimitive,
13
+ Token,
14
+ UserDefinedFunction,
15
+ } from './types.js'
3
16
 
4
17
  /**
5
18
  * Executes a SQL SELECT query against an array of data rows
@@ -24,21 +24,15 @@ export function parseJoins(state) {
24
24
  joinType = 'INNER'
25
25
  } else if (tok.value === 'LEFT') {
26
26
  consume(state)
27
- if (match(state, 'keyword', 'OUTER')) {
28
- // LEFT OUTER JOIN
29
- }
27
+ match(state, 'keyword', 'OUTER') // LEFT OUTER JOIN
30
28
  joinType = 'LEFT'
31
29
  } else if (tok.value === 'RIGHT') {
32
30
  consume(state)
33
- if (match(state, 'keyword', 'OUTER')) {
34
- // RIGHT OUTER JOIN
35
- }
31
+ match(state, 'keyword', 'OUTER') // RIGHT OUTER JOIN
36
32
  joinType = 'RIGHT'
37
33
  } else if (tok.value === 'FULL') {
38
34
  consume(state)
39
- if (match(state, 'keyword', 'OUTER')) {
40
- // FULL OUTER JOIN
41
- }
35
+ match(state, 'keyword', 'OUTER') // FULL OUTER JOIN
42
36
  joinType = 'FULL'
43
37
  } else if (tok.value === 'POSITIONAL') {
44
38
  consume(state)
package/src/validation.js CHANGED
@@ -117,6 +117,7 @@ export const FUNCTION_ARG_COUNTS = {
117
117
 
118
118
  // Conditional functions
119
119
  COALESCE: { min: 1 },
120
+ NULLIF: { min: 2, max: 2 },
120
121
 
121
122
  // Aggregate functions
122
123
  COUNT: { min: 1, max: 1 },
@@ -194,7 +195,7 @@ export function isKnownFunction(funcName, functions) {
194
195
  if ([
195
196
  'CURRENT_DATE', 'CURRENT_TIME', 'CURRENT_TIMESTAMP',
196
197
  'JSON_VALUE', 'JSON_QUERY', 'JSON_OBJECT',
197
- 'COALESCE', 'CAST',
198
+ 'COALESCE', 'NULLIF', 'CAST',
198
199
  ].includes(funcName)) {
199
200
  return true
200
201
  }
@@ -66,6 +66,8 @@ export const FUNCTION_SIGNATURES = {
66
66
  AVG: 'expression',
67
67
  MIN: 'expression',
68
68
  MAX: 'expression',
69
+ STDDEV_SAMP: 'expression',
70
+ STDDEV_POP: 'expression',
69
71
  }
70
72
 
71
73
  /**