sqlmath 2026.8.31 → 2026.10.30

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/test.mjs CHANGED
@@ -135,9 +135,9 @@ jstestDescribe((
135
135
  moduleChildProcess.execFile
136
136
  )(
137
137
  (
138
- process.cwd()
139
- + modulePath.sep
140
- + SQLMATH_EXE
138
+ process.cwd() +
139
+ modulePath.sep +
140
+ SQLMATH_EXE
141
141
  ),
142
142
  [
143
143
  ":memory:",
@@ -203,10 +203,10 @@ jstestDescribe((
203
203
  valExpect, valExpect, 0
204
204
  ],
205
205
  (
206
- "SELECT 0;"
207
- + " SELECT ? AS c1, ? AS c2, ? AS c3, ? AS c4"
208
- + " UNION ALL SELECT ?1, ?2, ?3, ?4"
209
- + " UNION ALL SELECT ?1, ?2, ?3, ?4"
206
+ "SELECT 0;" +
207
+ " SELECT ? AS c1, ? AS c2, ? AS c3, ? AS c4" +
208
+ " UNION ALL SELECT ?1, ?2, ?3, ?4" +
209
+ " UNION ALL SELECT ?1, ?2, ?3, ?4"
210
210
  )
211
211
  ],
212
212
  [
@@ -216,10 +216,10 @@ jstestDescribe((
216
216
  k3: 0
217
217
  },
218
218
  (
219
- "SELECT 0;"
220
- + " SELECT $k1 AS c1, $k2 AS c2, $k3 AS c3, $k4 AS c4"
221
- + " UNION ALL SELECT :k1, :k2, :k3, :k4"
222
- + " UNION ALL SELECT @k1, @k2, @k3, @k4"
219
+ "SELECT 0;" +
220
+ " SELECT $k1 AS c1, $k2 AS c2, $k3 AS c3, $k4 AS c4" +
221
+ " UNION ALL SELECT :k1, :k2, :k3, :k4" +
222
+ " UNION ALL SELECT @k1, @k2, @k3, @k4"
223
223
  )
224
224
  ]
225
225
  ].map(async function ([
@@ -309,8 +309,8 @@ jstestDescribe((
309
309
  break;
310
310
  }
311
311
  if (
312
- valIn?.constructor === ArrayBuffer
313
- || ArrayBuffer.isView(valIn)
312
+ valIn?.constructor === ArrayBuffer ||
313
+ ArrayBuffer.isView(valIn)
314
314
  ) {
315
315
  bufExpect = new TextDecoder().decode(valIn);
316
316
  break;
@@ -698,7 +698,7 @@ SELECT 401 AS c401, 402 AS c402, 403 AS c403
698
698
  UNION ALL
699
699
  VALUES
700
700
  (501, 502.0123, 5030123456789),
701
- (601, '602', '603_\"\x01\x08\x09\x0a\x0b\x0c\x0d\x0e'),
701
+ (601, '602', '603_"\u0001\u0008\u0009\u000a\u000b\u000c\u000d\u000e'),
702
702
  (?1, ?2, ?3),
703
703
  (CAST(?1 AS TEXT), CAST(?2 AS TEXT), CAST(?3 AS TEXT)),
704
704
  (
@@ -1394,7 +1394,7 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1394
1394
  }));
1395
1395
  });
1396
1396
  jstestIt((
1397
- "test_sqlite_extension_idate_xxx handling-behavior"
1397
+ "test sqlite-extension-idate_xxx handling-behavior"
1398
1398
  ), async function test_sqlite_extension_idate_xxx() {
1399
1399
  let db = await dbOpenAsync({});
1400
1400
  let promiseList = [];
@@ -1429,8 +1429,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1429
1429
  return arg - (arg % 1_00);
1430
1430
  }
1431
1431
  if (
1432
- (/^IDATEYMDFROM|'ITEXTYMD'/).test(sqlFunc)
1433
- || ((/_YMD$/).test(sqlFunc) && !(/IDATEFROM/).test(sqlFunc))
1432
+ (/^IDATEYMDFROM|'ITEXTYMD'/).test(sqlFunc) ||
1433
+ ((/_YMD$/).test(sqlFunc) && !(/IDATEFROM/).test(sqlFunc))
1434
1434
  ) {
1435
1435
  return idateArgYmdTruncate(arg);
1436
1436
  }
@@ -1840,8 +1840,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1840
1840
  "CASTTEXTOREMPTY": "",
1841
1841
  "COPYBLOB": "",
1842
1842
  "SHA256": (
1843
- "E3B0C44298FC1C149AFBF4C8996FB924"
1844
- + "27AE41E4649B934CA495991B7852B855"
1843
+ "E3B0C44298FC1C149AFBF4C8996FB924" +
1844
+ "27AE41E4649B934CA495991B7852B855"
1845
1845
  )
1846
1846
  },
1847
1847
  "'-0.5'": {
@@ -1850,8 +1850,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1850
1850
  "CASTTEXTOREMPTY": "-0.5",
1851
1851
  "COPYBLOB": "-0.5",
1852
1852
  "SHA256": (
1853
- "1B07B0CFFA0B3F596B5E048B01151688"
1854
- + "86CC5183DD518655B5515EE5DDDAC6D1"
1853
+ "1B07B0CFFA0B3F596B5E048B01151688" +
1854
+ "86CC5183DD518655B5515EE5DDDAC6D1"
1855
1855
  )
1856
1856
  },
1857
1857
  "'-1'": {
@@ -1862,8 +1862,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1862
1862
  "COT": -0.642092615934331,
1863
1863
  "COTH": -1.31303528549933,
1864
1864
  "SHA256": (
1865
- "1BAD6B8CF97131FCEAB8543E81F77571"
1866
- + "95FBB1D36B376EE994AD1CF17699C464"
1865
+ "1BAD6B8CF97131FCEAB8543E81F77571" +
1866
+ "95FBB1D36B376EE994AD1CF17699C464"
1867
1867
  ),
1868
1868
  "SIGN": -1,
1869
1869
  "SQRTWITHSIGN": -1
@@ -1876,8 +1876,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1876
1876
  "COT": null,
1877
1877
  "COTH": null,
1878
1878
  "SHA256": (
1879
- "5FECEB66FFC86F38D952786C6D696C79"
1880
- + "C2DBC239DD4E91B46729D73A27FB57E9"
1879
+ "5FECEB66FFC86F38D952786C6D696C79" +
1880
+ "C2DBC239DD4E91B46729D73A27FB57E9"
1881
1881
  ),
1882
1882
  "SIGN": 0,
1883
1883
  "SQRTWITHSIGN": 0
@@ -1888,8 +1888,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1888
1888
  "CASTTEXTOREMPTY": "0.5",
1889
1889
  "COPYBLOB": "0.5",
1890
1890
  "SHA256": (
1891
- "D2CBAD71FF333DE67D07EC676E352AB7"
1892
- + "F38248EB69C942950157220607C55E84"
1891
+ "D2CBAD71FF333DE67D07EC676E352AB7" +
1892
+ "F38248EB69C942950157220607C55E84"
1893
1893
  )
1894
1894
  },
1895
1895
  "'1'": {
@@ -1900,8 +1900,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1900
1900
  "COT": 0.642092615934331,
1901
1901
  "COTH": 1.31303528549933,
1902
1902
  "SHA256": (
1903
- "6B86B273FF34FCE19D6B804EFF5A3F57"
1904
- + "47ADA4EAA22F1D49C01E52DDB7875B4B"
1903
+ "6B86B273FF34FCE19D6B804EFF5A3F57" +
1904
+ "47ADA4EAA22F1D49C01E52DDB7875B4B"
1905
1905
  ),
1906
1906
  "SIGN": 1,
1907
1907
  "SQRTWITHSIGN": 1
@@ -1912,20 +1912,20 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1912
1912
  "CASTTEXTOREMPTY": "aa",
1913
1913
  "COPYBLOB": "aa",
1914
1914
  "SHA256": (
1915
- "961B6DD3EDE3CB8ECBAACBD68DE040CD"
1916
- + "78EB2ED5889130CCEB4C49268EA4D506"
1915
+ "961B6DD3EDE3CB8ECBAACBD68DE040CD" +
1916
+ "78EB2ED5889130CCEB4C49268EA4D506"
1917
1917
  )
1918
1918
  },
1919
1919
  "'abc'": {
1920
1920
  "SHA256": (
1921
- "BA7816BF8F01CFEA414140DE5DAE2223"
1922
- + "B00361A396177A9CB410FF61F20015AD"
1921
+ "BA7816BF8F01CFEA414140DE5DAE2223" +
1922
+ "B00361A396177A9CB410FF61F20015AD"
1923
1923
  )
1924
1924
  },
1925
1925
  "'abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq'": {
1926
1926
  "SHA256": (
1927
- "248D6A61D20638B8E5C026930C3E6039"
1928
- + "A33CE45964FF2167F6ECEDD419DB06C1"
1927
+ "248D6A61D20638B8E5C026930C3E6039" +
1928
+ "A33CE45964FF2167F6ECEDD419DB06C1"
1929
1929
  )
1930
1930
  },
1931
1931
  "'hello'": {
@@ -1934,8 +1934,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1934
1934
  "CASTTEXTOREMPTY": "hello",
1935
1935
  "COPYBLOB": "hello",
1936
1936
  "SHA256": (
1937
- "2CF24DBA5FB0A30E26E83B2AC5B9E29E"
1938
- + "1B161E5C1FA7425E73043362938B9824"
1937
+ "2CF24DBA5FB0A30E26E83B2AC5B9E29E" +
1938
+ "1B161E5C1FA7425E73043362938B9824"
1939
1939
  )
1940
1940
  },
1941
1941
  "-0.5": {
@@ -1944,16 +1944,16 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1944
1944
  "CASTTEXTOREMPTY": "-0.5",
1945
1945
  "COPYBLOB": -0.5,
1946
1946
  "SHA256": (
1947
- "1B07B0CFFA0B3F596B5E048B01151688"
1948
- + "86CC5183DD518655B5515EE5DDDAC6D1"
1947
+ "1B07B0CFFA0B3F596B5E048B01151688" +
1948
+ "86CC5183DD518655B5515EE5DDDAC6D1"
1949
1949
  )
1950
1950
  },
1951
1951
  "-0x7fffffffffffffff": {
1952
1952
  "COT": -0.0118008981305845,
1953
1953
  "COTH": -1,
1954
1954
  "SHA256": ( // '-9223372036854775807'
1955
- "B7AE81320053F61245ED2D36E72E1D05"
1956
- + "AD4235D8C784E60285F1EB1F06DA7845"
1955
+ "B7AE81320053F61245ED2D36E72E1D05" +
1956
+ "AD4235D8C784E60285F1EB1F06DA7845"
1957
1957
  ),
1958
1958
  "SIGN": -1,
1959
1959
  "SQRTWITHSIGN": -3037000499.97605
@@ -1966,8 +1966,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1966
1966
  "COT": -0.642092615934331,
1967
1967
  "COTH": -1.31303528549933,
1968
1968
  "SHA256": (
1969
- "1BAD6B8CF97131FCEAB8543E81F77571"
1970
- + "95FBB1D36B376EE994AD1CF17699C464"
1969
+ "1BAD6B8CF97131FCEAB8543E81F77571" +
1970
+ "95FBB1D36B376EE994AD1CF17699C464"
1971
1971
  ),
1972
1972
  "SIGN": -1,
1973
1973
  "SQRTWITHSIGN": -1
@@ -1976,8 +1976,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1976
1976
  "COT": null,
1977
1977
  "COTH": -1,
1978
1978
  "SHA256": ( // '-Inf'
1979
- "8C1FB05600CEB1FF74474E66DDD603F5"
1980
- + "FE8C839B03598A124E2AACB6A08C8837"
1979
+ "8C1FB05600CEB1FF74474E66DDD603F5" +
1980
+ "FE8C839B03598A124E2AACB6A08C8837"
1981
1981
  ),
1982
1982
  "SIGN": -1,
1983
1983
  "SQRTWITHSIGN": null
@@ -1990,8 +1990,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
1990
1990
  "COT": null,
1991
1991
  "COTH": null,
1992
1992
  "SHA256": (
1993
- "5FECEB66FFC86F38D952786C6D696C79"
1994
- + "C2DBC239DD4E91B46729D73A27FB57E9"
1993
+ "5FECEB66FFC86F38D952786C6D696C79" +
1994
+ "C2DBC239DD4E91B46729D73A27FB57E9"
1995
1995
  ),
1996
1996
  "SIGN": 0,
1997
1997
  "SQRTWITHSIGN": 0
@@ -2002,8 +2002,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2002
2002
  "CASTTEXTOREMPTY": "0.5",
2003
2003
  "COPYBLOB": 0.5,
2004
2004
  "SHA256": (
2005
- "D2CBAD71FF333DE67D07EC676E352AB7"
2006
- + "F38248EB69C942950157220607C55E84"
2005
+ "D2CBAD71FF333DE67D07EC676E352AB7" +
2006
+ "F38248EB69C942950157220607C55E84"
2007
2007
  )
2008
2008
  },
2009
2009
  "0.5, 0.5": {
@@ -2019,8 +2019,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2019
2019
  "COT": 0.0118008981305845,
2020
2020
  "COTH": 1,
2021
2021
  "SHA256": ( // '9223372036854775807'
2022
- "B34A1C30A715F6BF8B7243AFA7FAB883"
2023
- + "CE3612B7231716BDCBBDC1982E1AED29"
2022
+ "B34A1C30A715F6BF8B7243AFA7FAB883" +
2023
+ "CE3612B7231716BDCBBDC1982E1AED29"
2024
2024
  ),
2025
2025
  "SIGN": 1,
2026
2026
  "SQRTWITHSIGN": 3037000499.97605
@@ -2029,8 +2029,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2029
2029
  "COT": -0.0118008981305845,
2030
2030
  "COTH": -1,
2031
2031
  "SHA256": ( // '-9223372036854775808'
2032
- "85386477F3AF47E4A0B308EE3B3A688D"
2033
- + "F16E8B2228105DD7D4DCD42A9807CB78"
2032
+ "85386477F3AF47E4A0B308EE3B3A688D" +
2033
+ "F16E8B2228105DD7D4DCD42A9807CB78"
2034
2034
  ),
2035
2035
  "SIGN": -1,
2036
2036
  "SQRTWITHSIGN": -3037000499.97605
@@ -2039,8 +2039,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2039
2039
  "COT": -0.642092615934331,
2040
2040
  "COTH": -1.31303528549933,
2041
2041
  "SHA256": ( // '-1'
2042
- "1BAD6B8CF97131FCEAB8543E81F77571"
2043
- + "95FBB1D36B376EE994AD1CF17699C464"
2042
+ "1BAD6B8CF97131FCEAB8543E81F77571" +
2043
+ "95FBB1D36B376EE994AD1CF17699C464"
2044
2044
  ),
2045
2045
  "SIGN": -1,
2046
2046
  "SQRTWITHSIGN": -1
@@ -2053,8 +2053,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2053
2053
  "COT": 0.642092615934331,
2054
2054
  "COTH": 1.31303528549933,
2055
2055
  "SHA256": (
2056
- "6B86B273FF34FCE19D6B804EFF5A3F57"
2057
- + "47ADA4EAA22F1D49C01E52DDB7875B4B"
2056
+ "6B86B273FF34FCE19D6B804EFF5A3F57" +
2057
+ "47ADA4EAA22F1D49C01E52DDB7875B4B"
2058
2058
  ),
2059
2059
  "SIGN": 1,
2060
2060
  "SQRTWITHSIGN": 1
@@ -2065,8 +2065,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2065
2065
  "COT": null,
2066
2066
  "COTH": 1,
2067
2067
  "SHA256": ( // 'Inf'
2068
- "1DAEC9C71EE2A842CDEE6977AD8C562E"
2069
- + "D4AA4FB1338BECD25D79A104B473D9D8"
2068
+ "1DAEC9C71EE2A842CDEE6977AD8C562E" +
2069
+ "D4AA4FB1338BECD25D79A104B473D9D8"
2070
2070
  ),
2071
2071
  "SIGN": 1,
2072
2072
  "SQRTWITHSIGN": null
@@ -2097,8 +2097,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2097
2097
  "CASTTEXTOREMPTY": "",
2098
2098
  "COPYBLOB": null,
2099
2099
  "SHA256": (
2100
- "E3B0C44298FC1C149AFBF4C8996FB924"
2101
- + "27AE41E4649B934CA495991B7852B855"
2100
+ "E3B0C44298FC1C149AFBF4C8996FB924" +
2101
+ "27AE41E4649B934CA495991B7852B855"
2102
2102
  )
2103
2103
  },
2104
2104
  "ZEROBLOB(1)": {
@@ -2107,8 +2107,8 @@ SELECT DOUBLEARRAY_JSONTO(DOUBLEARRAY_JSONFROM($valIn)) AS result;
2107
2107
  "CASTTEXTOREMPTY": "",
2108
2108
  "COPYBLOB": null,
2109
2109
  "SHA256": (
2110
- "6E340B9CFFB37A989CA544E6BB780A2C"
2111
- + "78901D3FB33738768511A30617AFA01D"
2110
+ "6E340B9CFFB37A989CA544E6BB780A2C" +
2111
+ "78901D3FB33738768511A30617AFA01D"
2112
2112
  )
2113
2113
  }
2114
2114
  }).forEach(function ([
@@ -2452,6 +2452,201 @@ SELECT DOUBLEARRAY_JSONTO(WIN_AVG2(1, 2, 3)) FROM __tmp1;
2452
2452
  })
2453
2453
  ]);
2454
2454
  });
2455
+ jstestIt((
2456
+ "test sqlite-extension-win_coinflip2 handling-behavior"
2457
+ ), async function test_sqlite_extension_win_coinflip2() {
2458
+ // win_coinflip2 reads ONE value per column, and key biasba50 needs a
2459
+ // second bit per row - was the flip called correctly - so it reads the
2460
+ // 4-state code SIGN(outcome) * (1 + hit) documented at struct
2461
+ // WinCoinflip, sqlmath_base.c:
2462
+ // +2 head-hit +1 head-miss 0 excluded -1 tail-miss -2 tail-hit
2463
+ // Sign is the OUTCOME class, so nhead and ntail are the two denominators
2464
+ // balanced-accuracy divides by, and biashead reads the CLASS BALANCE
2465
+ // under this code, not the hit-rate.
2466
+ let db = await dbOpenAsync({});
2467
+ async function test_coinflip_extract({
2468
+ sqlBetween,
2469
+ valExpect,
2470
+ valIn
2471
+ }) {
2472
+ let valActual = await dbExecAndReturnLastRow({
2473
+ bindList: {
2474
+ valIn: JSON.stringify(valIn)
2475
+ },
2476
+ db,
2477
+ sql: (`
2478
+ SELECT
2479
+ COINFLIP_EXTRACT(__wcf, 0, 'nflip') AS nflip,
2480
+ COINFLIP_EXTRACT(__wcf, 0, 'nhead') AS nhead,
2481
+ COINFLIP_EXTRACT(__wcf, 0, 'nhithead') AS nhithead,
2482
+ COINFLIP_EXTRACT(__wcf, 0, 'nhittail') AS nhittail,
2483
+ COINFLIP_EXTRACT(__wcf, 0, 'ntail') AS ntail,
2484
+ ROUND(COINFLIP_EXTRACT(__wcf, 0, 'biasba50'), 6) AS biasba50,
2485
+ ROUND(COINFLIP_EXTRACT(__wcf, 0, 'biashead'), 6) AS biashead
2486
+ FROM (
2487
+ SELECT
2488
+ WIN_COINFLIP2(value) OVER (
2489
+ ORDER BY key ASC
2490
+ ${sqlBetween}
2491
+ ) AS __wcf
2492
+ FROM JSON_EACH($valIn)
2493
+ );
2494
+ `)
2495
+ });
2496
+ assertJsonEqual(valActual, valExpect);
2497
+ }
2498
+ await Promise.all([
2499
+ // test biasba50-unbalanced-panel handling-behavior
2500
+ // 8 up-days with 7 called right, 2 down-days with 0 called
2501
+ // right - a 70% RAW hit-rate that balanced-accuracy scores
2502
+ // BELOW chance, which is the whole reason for the key.
2503
+ test_coinflip_extract({
2504
+ sqlBetween: "",
2505
+ valExpect: {
2506
+ biasba50: -0.0625,
2507
+ biashead: 0.3,
2508
+ nflip: 10,
2509
+ nhead: 8,
2510
+ nhithead: 7,
2511
+ nhittail: 0,
2512
+ ntail: 2
2513
+ },
2514
+ valIn: [2, 2, 2, 2, 2, 2, 2, 1, -1, -1]
2515
+ }),
2516
+ // test biasba50-parrot-null handling-behavior
2517
+ // an always-up caller hits every up-day and misses every
2518
+ // down-day, and MUST score exactly 0.
2519
+ test_coinflip_extract({
2520
+ sqlBetween: "",
2521
+ valExpect: {
2522
+ biasba50: 0,
2523
+ biashead: 0.2,
2524
+ nflip: 10,
2525
+ nhead: 7,
2526
+ nhithead: 7,
2527
+ nhittail: 0,
2528
+ ntail: 3
2529
+ },
2530
+ valIn: [2, 2, 2, 2, 2, 2, 2, -1, -1, -1]
2531
+ }),
2532
+ // test biasba50-range handling-behavior
2533
+ test_coinflip_extract({
2534
+ sqlBetween: "",
2535
+ valExpect: {
2536
+ biasba50: 0.5,
2537
+ biashead: 0.1,
2538
+ nflip: 5,
2539
+ nhead: 3,
2540
+ nhithead: 3,
2541
+ nhittail: 2,
2542
+ ntail: 2
2543
+ },
2544
+ valIn: [2, 2, 2, -2, -2]
2545
+ }),
2546
+ test_coinflip_extract({
2547
+ sqlBetween: "",
2548
+ valExpect: {
2549
+ biasba50: -0.5,
2550
+ biashead: 0.1,
2551
+ nflip: 5,
2552
+ nhead: 3,
2553
+ nhithead: 0,
2554
+ nhittail: 0,
2555
+ ntail: 2
2556
+ },
2557
+ valIn: [1, 1, 1, -1, -1]
2558
+ }),
2559
+ // test biasba50-one-sided-panel handling-behavior
2560
+ // no down-days means no balanced-accuracy - 0.0/0.0 is NaN,
2561
+ // which sqlite3_result_double_or_null maps to NULL.
2562
+ test_coinflip_extract({
2563
+ sqlBetween: "",
2564
+ valExpect: {
2565
+ biasba50: null,
2566
+ biashead: 0.5,
2567
+ nflip: 3,
2568
+ nhead: 3,
2569
+ nhithead: 2,
2570
+ nhittail: 0,
2571
+ ntail: 0
2572
+ },
2573
+ valIn: [2, 2, 1]
2574
+ }),
2575
+ // test biasba50-legacy-column handling-behavior
2576
+ // a plain 0/1 column carries no hit-bit, so the pre-existing
2577
+ // keys are unchanged and the two hit-counters stay 0.
2578
+ test_coinflip_extract({
2579
+ sqlBetween: "",
2580
+ valExpect: {
2581
+ biasba50: null,
2582
+ biashead: 0.166667,
2583
+ nflip: 6,
2584
+ nhead: 4,
2585
+ nhithead: 0,
2586
+ nhittail: 0,
2587
+ ntail: 0
2588
+ },
2589
+ valIn: [1, 1, 0, 1, 0, 1]
2590
+ }),
2591
+ // test biasba50-sliding-window handling-behavior
2592
+ // a bounded frame forces xInverse - the 6 leading rows are
2593
+ // all HITS, so an inverse that failed to decrement the two
2594
+ // hit-counters would inflate biasba50 here.
2595
+ test_coinflip_extract({
2596
+ sqlBetween: "ROWS BETWEEN 3 PRECEDING AND CURRENT ROW",
2597
+ valExpect: {
2598
+ biasba50: 0.25,
2599
+ biashead: 0,
2600
+ nflip: 4,
2601
+ nhead: 2,
2602
+ nhithead: 2,
2603
+ nhittail: 1,
2604
+ ntail: 2
2605
+ },
2606
+ valIn: [2, 2, 2, -2, -2, -2, 2, -1, -2, 2]
2607
+ })
2608
+ ]);
2609
+ // test win_coinflip2-multi-column handling-behavior
2610
+ assertJsonEqual(await dbExecAndReturnLastRow({
2611
+ db,
2612
+ sql: (`
2613
+ SELECT
2614
+ COINFLIP_EXTRACT(__wcf, 0, 'biasba50') AS aa,
2615
+ COINFLIP_EXTRACT(__wcf, 1, 'biasba50') AS bb,
2616
+ COINFLIP_EXTRACT(__wcf, 1, 'nstreak') AS cc
2617
+ FROM (
2618
+ SELECT
2619
+ WIN_COINFLIP2(aa, bb) OVER (ORDER BY id ASC) AS __wcf
2620
+ FROM (
2621
+ SELECT 1 AS id, 2 AS aa, 1 AS bb
2622
+ UNION ALL SELECT 2, 2, -1
2623
+ UNION ALL SELECT 3, -2, -1
2624
+ UNION ALL SELECT 4, -1, -1
2625
+ )
2626
+ );
2627
+ `)
2628
+ }), {
2629
+ aa: 0.25,
2630
+ bb: -0.5,
2631
+ cc: -3
2632
+ });
2633
+ // test coinflip_extract-error handling-behavior
2634
+ await assertErrorThrownAsync(
2635
+ dbExecAsync.bind(undefined, {
2636
+ db,
2637
+ sql: (`
2638
+ SELECT
2639
+ COINFLIP_EXTRACT(__wcf, 0, 'biasba49')
2640
+ FROM (
2641
+ SELECT
2642
+ WIN_COINFLIP2(value) OVER (ORDER BY key ASC) AS __wcf
2643
+ FROM JSON_EACH('[2,-2]')
2644
+ );
2645
+ `)
2646
+ }),
2647
+ "invalid key"
2648
+ );
2649
+ });
2455
2650
  jstestIt((
2456
2651
  "test sqlite-extension-win_emax handling-behavior"
2457
2652
  ), async function test_sqlite_extension_win_emax() {