Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ dirsql = { path = "packages/rust" }
serde = { version = "1", features = ["derive"] }
# `preserve_order`: a serialized row must keep the projection order the SELECT
# list asked for, which the default BTreeMap-backed object discards.
serde_json = { version = "1", features = ["preserve_order"] }
serde_json = { version = "1", features = ["preserve_order", "float_roundtrip"] }
regex = "1"
thiserror = "2"
tokio = { version = "1", features = ["rt", "sync"] }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**Fixed** JSON numbers from `on-file` hooks and worker functions now parse to the exact double: `123456789.12345679` was stored one ULP off as `123456789.1234568`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"command": "uv run python -m pytest tests/e2e/on_file_query_test.py tests/e2e/jsonl_parse_speed_test.py tests/e2e/use_case_transcripts_test.py tests/e2e/query_contract_test.py -x -q",
"ran_at": 1793814794,
"exit_code": 0,
"commit": "4696a76d81c3080df86c416ef418d3d9b2dc0062",
"branch": "bot/1586-float-roundtrip-1104"
}
21 changes: 21 additions & 0 deletions packages/python/migrations.d/2026-11-04-exact-json-floats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
### Exact JSON float parsing

#### Summary

A JSON float an `on-file` hook or worker function prints is stored as the correctly rounded REAL, where some were one ULP off before. No API or configuration changes are required.

#### Required changes

_None._

#### Deprecations removed

_None._

#### Behavior changes without code changes

A REAL column fed from JSON can hold a value one ULP different from before the upgrade: the correct one.

#### Verification

In an empty directory, write `{"v":123456789.12345679}` to `a.ndjson` and run `dirsql query "SELECT v = 123456789.12345679 AS eq FROM './a.ndjson'" --on-file cat --format json`; the output is `[{"eq":1}]`.
1 change: 1 addition & 0 deletions packages/rust/changelog.d/2026-11-04-exact-json-floats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**Fixed** JSON numbers from `on-file` hooks and worker functions now parse to the exact double: `123456789.12345679` was stored one ULP off as `123456789.1234568`.
21 changes: 21 additions & 0 deletions packages/rust/migrations.d/2026-11-04-exact-json-floats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
### Exact JSON float parsing

#### Summary

A JSON float an `on-file` hook or worker function prints is stored as the correctly rounded REAL, where some were one ULP off before. No API or configuration changes are required.

#### Required changes

_None._

#### Deprecations removed

_None._

#### Behavior changes without code changes

A REAL column fed from JSON can hold a value one ULP different from before the upgrade: the correct one.

#### Verification

In an empty directory, write `{"v":123456789.12345679}` to `a.ndjson` and run `dirsql query "SELECT v = 123456789.12345679 AS eq FROM './a.ndjson'" --on-file cat --format json`; the output is `[{"eq":1}]`.
40 changes: 40 additions & 0 deletions packages/rust/tests/on_file_float.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//! A float an `on-file` hook prints is stored as the REAL a correctly
//! rounded JSON parser reads.

use std::fs;

use dirsql::{DirSQL, Value};
use tempfile::TempDir;

#[test]
fn a_real_column_keeps_the_exact_double() {
let doubles = [
"123456789.12345679",
"0.30000000000000004",
"1.7976931348623157e308",
];
let root = TempDir::new().unwrap();
fs::write(
root.path().join(".dirsql.toml"),
"[[table]]\nname = \"t\"\nddl = \"CREATE TABLE t (v REAL)\"\nglob = \"*.ndjson\"\non-file = \"cat\"\n",
)
.unwrap();
let lines: String = doubles.iter().map(|d| format!("{{\"v\":{d}}}\n")).collect();
fs::write(root.path().join("a.ndjson"), lines).unwrap();
let db = DirSQL::builder()
.root(root.path())
.config(root.path().join(".dirsql.toml"))
.build()
.unwrap();
let stored: Vec<Value> = db
.query("SELECT v FROM t ORDER BY rowid")
.unwrap()
.into_iter()
.map(|row| row["v"].clone())
.collect();
let expected: Vec<Value> = doubles
.iter()
.map(|d| Value::Real(d.parse().unwrap()))
.collect();
assert_eq!(stored, expected);
}
37 changes: 37 additions & 0 deletions packages/rust/tests/on_file_float_e2e.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! End-to-end: a float an `on-file` hook prints reaches SQLite as the same
//! REAL a correctly rounded JSON parser reads, through the real `dirsql`
//! binary. Nothing is mocked.

#![cfg(feature = "cli")]

use assert_cmd::prelude::*;
use tempfile::TempDir;

#[test]
fn an_on_file_float_round_trips_exactly() {
let root = TempDir::new().unwrap();
std::fs::write(root.path().join("a.ndjson"), "{\"v\":123456789.12345679}\n").unwrap();
let out = std::process::Command::cargo_bin("dirsql")
.expect("binary must exist")
.args([
"query",
"SELECT v, v = 123456789.12345679 AS eq FROM './a.ndjson'",
"--on-file",
"cat",
"--format",
"json",
])
.env("DIRSQL_PROGRESS", "never")
.current_dir(root.path())
.output()
.expect("spawning `dirsql` failed");
assert!(
out.status.success(),
"expected success, stderr: {}",
String::from_utf8_lossy(&out.stderr)
);
assert_eq!(
String::from_utf8(out.stdout).unwrap(),
"[{\"v\":123456789.12345679,\"eq\":1}]\n"
);
}
1 change: 1 addition & 0 deletions packages/ts/changelog.d/2026-11-04-exact-json-floats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**Fixed** JSON numbers from `on-file` hooks and worker functions now parse to the exact double: `123456789.12345679` was stored one ULP off as `123456789.1234568`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"command": "pnpm exec vitest run --dir tests/e2e query-contract query-params",
"ran_at": 1793814888,
"exit_code": 0,
"commit": "0340207c463df4173a0e59f0993bde832ee2c50e",
"branch": "bot/1586-float-roundtrip-1104"
}
21 changes: 21 additions & 0 deletions packages/ts/migrations.d/2026-11-04-exact-json-floats.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
### Exact JSON float parsing

#### Summary

A JSON float an `on-file` hook or worker function prints is stored as the correctly rounded REAL, where some were one ULP off before. No API or configuration changes are required.

#### Required changes

_None._

#### Deprecations removed

_None._

#### Behavior changes without code changes

A REAL column fed from JSON can hold a value one ULP different from before the upgrade: the correct one.

#### Verification

In an empty directory, write `{"v":123456789.12345679}` to `a.ndjson` and run `dirsql query "SELECT v = 123456789.12345679 AS eq FROM './a.ndjson'" --on-file cat --format json`; the output is `[{"eq":1}]`.
Loading