dirsql 0.3.35__tar.gz → 0.3.37__tar.gz
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.
- {dirsql-0.3.35 → dirsql-0.3.37}/Cargo.lock +1 -1
- {dirsql-0.3.35 → dirsql-0.3.37}/PKG-INFO +1 -1
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/Cargo.toml +1 -1
- dirsql-0.3.37/packages/python/e2e-attestation.json +6 -0
- {dirsql-0.3.35/packages/python/tests/integration → dirsql-0.3.37/packages/python/tests/e2e}/interpret_subprocess.py +1 -1
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/cli/mod.rs +9 -32
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/cli/native_config.rs +14 -215
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/cli/router.rs +9 -8
- {dirsql-0.3.35 → dirsql-0.3.37}/Cargo.toml +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/README.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/__init__.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/_async.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/_dirsql.pyi +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/cli/__init__.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/cli/binary_path.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/cli/interpret/__init__.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/cli/interpret/dispatch_extract.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/cli/interpret/load_app.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/cli/interpret/run.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/cli/interpret/write_message.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/cli/is_windows.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/cli/main.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/py.typed +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/dirsql/resolve_config.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/AGENTS.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/api/index.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/cli/config.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/cli/http-api.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/cli/index.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/cli/init.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/cli/server.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/getting-started.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/guide/async.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/guide/crdt.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/guide/persistence.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/guide/querying.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/guide/tables.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/guide/watching.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/index.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/migrations.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/package.json +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/playwright.config.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/docs/vitest.config.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/README.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/conftest.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/api/index.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/cli/config.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/cli/http-api.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/cli/index.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/cli/init.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/cli/server.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/getting-started.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/guide/async.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/guide/crdt.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/guide/persistence.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/guide/querying.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/guide/tables.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/guide/watching.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/index.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/migrations.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/package.json +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/playwright.config.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/vitest.config.ts +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/src/lib.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.3.35/packages/python/tests/integration → dirsql-0.3.37/packages/python/tests/e2e}/__fixtures__/data/a/meta.json +0 -0
- {dirsql-0.3.35/packages/python/tests/integration → dirsql-0.3.37/packages/python/tests/e2e}/__fixtures__/data/b/meta.json +0 -0
- {dirsql-0.3.35/packages/python/tests/integration → dirsql-0.3.37/packages/python/tests/e2e}/__fixtures__/dirsql.config.py +0 -0
- {dirsql-0.3.35/packages/python/tests/integration → dirsql-0.3.37/packages/python/tests/e2e}/__fixtures__/interpret/data/a/meta.json +0 -0
- {dirsql-0.3.35/packages/python/tests/integration → dirsql-0.3.37/packages/python/tests/e2e}/__fixtures__/interpret/data/b/meta.json +0 -0
- {dirsql-0.3.35/packages/python/tests/integration → dirsql-0.3.37/packages/python/tests/e2e}/__fixtures__/interpret/dirsql.config.py +0 -0
- {dirsql-0.3.35/packages/python/tests/integration → dirsql-0.3.37/packages/python/tests/e2e}/__fixtures__/interpret/dirsql.config_no_app.py +0 -0
- {dirsql-0.3.35/packages/python/tests/integration → dirsql-0.3.37/packages/python/tests/e2e}/__fixtures__/interpret/dirsql.config_raises.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/Cargo.toml +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/README.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/api/index.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/cli/config.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/cli/http-api.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/cli/index.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/cli/init.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/cli/server.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/getting-started.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/guide/async.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/guide/crdt.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/guide/persistence.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/guide/querying.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/guide/tables.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/guide/watching.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/index.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/docs/migrations.md +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/bin/dirsql.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/config.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/db.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/lib.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/persist.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.3.35 → dirsql-0.3.37}/pyproject.toml +0 -0
|
@@ -4,7 +4,7 @@ name = "dirsql-py-ext"
|
|
|
4
4
|
# pypi/maturin handler can rewrite it via `write-version` before
|
|
5
5
|
# `maturin build`. `pyproject.toml` declares `dynamic = ["version"]`
|
|
6
6
|
# and maturin reads this field. Mirrors `packages/rust/Cargo.toml`.
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.37"
|
|
8
8
|
edition.workspace = true
|
|
9
9
|
publish = false
|
|
10
10
|
readme = "README.md"
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Subprocess plumbing for the `dirsql interpret`
|
|
1
|
+
"""Subprocess plumbing for the `dirsql interpret` e2e tests.
|
|
2
2
|
|
|
3
3
|
Kept in its own module (rather than `conftest.py` or inline in the
|
|
4
4
|
test file) because these helpers are not pytest fixtures -- they are
|
|
@@ -160,7 +160,15 @@ pub enum ServerError {
|
|
|
160
160
|
#[cfg(test)]
|
|
161
161
|
mod tests {
|
|
162
162
|
use super::*;
|
|
163
|
-
|
|
163
|
+
|
|
164
|
+
// `From<DirSQL> for AppState` produces the `Ready` arm -- this is
|
|
165
|
+
// verified at the integration tier by `from_dirsql_yields_ready_state`
|
|
166
|
+
// in `tests/cli_integration.rs`, which builds a real `DirSQL` over a
|
|
167
|
+
// temp directory (so the initial scan runs) and asserts the public
|
|
168
|
+
// `AppState::Ready` variant. It lived here once but needed
|
|
169
|
+
// `std::fs::write` to populate the scanned directory, which the
|
|
170
|
+
// `testing-conventions` `unit lint` isolation rule forbids in a unit
|
|
171
|
+
// test (effectful std). The pure config-default test below stays inline.
|
|
164
172
|
|
|
165
173
|
#[test]
|
|
166
174
|
fn default_config_binds_localhost_7117_with_30s_timeout() {
|
|
@@ -169,35 +177,4 @@ mod tests {
|
|
|
169
177
|
assert_eq!(cfg.port, 7117);
|
|
170
178
|
assert_eq!(cfg.query_timeout, Duration::from_secs(30));
|
|
171
179
|
}
|
|
172
|
-
|
|
173
|
-
#[test]
|
|
174
|
-
fn app_state_from_dirsql_is_ready() {
|
|
175
|
-
// `AppState: !Debug` (it wraps a `DirSQL`). Assert the `Ready` variant
|
|
176
|
-
// without a dead match arm by routing through `require_ready`, which
|
|
177
|
-
// returns `Ok` only for `Ready` -- a branch-free `.is_ok()` check.
|
|
178
|
-
let dir = TempDir::new().unwrap();
|
|
179
|
-
// Write a matching file so the extract closure runs during the initial
|
|
180
|
-
// scan (otherwise the closure body would be a dead coverage region).
|
|
181
|
-
std::fs::write(dir.path().join("a.txt"), b"").unwrap();
|
|
182
|
-
let db = DirSQL::with_ignore(
|
|
183
|
-
dir.path(),
|
|
184
|
-
vec![crate::Table::new(
|
|
185
|
-
"CREATE TABLE t (name TEXT)",
|
|
186
|
-
"*.txt",
|
|
187
|
-
|_| {
|
|
188
|
-
vec![crate::Row::from_iter([(
|
|
189
|
-
"name".to_string(),
|
|
190
|
-
crate::Value::Text("x".into()),
|
|
191
|
-
)])]
|
|
192
|
-
},
|
|
193
|
-
)],
|
|
194
|
-
Vec::<String>::new(),
|
|
195
|
-
)
|
|
196
|
-
.unwrap();
|
|
197
|
-
let state: AppState = db.into();
|
|
198
|
-
assert!(
|
|
199
|
-
router::require_ready(&state).is_ok(),
|
|
200
|
-
"From<DirSQL> must produce AppState::Ready",
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
180
|
}
|
|
@@ -296,7 +296,16 @@ fn json_to_value(v: serde_json::Value) -> Value {
|
|
|
296
296
|
mod tests {
|
|
297
297
|
use super::*;
|
|
298
298
|
use std::io::Cursor;
|
|
299
|
-
|
|
299
|
+
|
|
300
|
+
// The subprocess-driven tests (`InterpretHelper::from_child` against a
|
|
301
|
+
// real `bash`/`true` child, and the `build_dirsql` round-trips that
|
|
302
|
+
// spawn a fake helper and write real fixture files) live in
|
|
303
|
+
// `tests/native_config.rs`. They exercise effectful std
|
|
304
|
+
// (`std::process::Command`, `std::fs::write`) and so belong at the
|
|
305
|
+
// integration tier per the `testing-conventions` `unit lint` isolation
|
|
306
|
+
// rule. The pure wire-format tests below operate on in-memory
|
|
307
|
+
// `Cursor`/`Vec` streams and stay inline next to the private functions
|
|
308
|
+
// they cover.
|
|
300
309
|
|
|
301
310
|
// -- parse_handshake -----------------------------------------------
|
|
302
311
|
|
|
@@ -511,160 +520,10 @@ mod tests {
|
|
|
511
520
|
}
|
|
512
521
|
|
|
513
522
|
// -- build_dirsql --------------------------------------------------
|
|
514
|
-
|
|
515
|
-
//
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
/// emits one canned response per line received on stdin (an infinite
|
|
519
|
-
/// loop until stdin closes). Returns the helper paired with the
|
|
520
|
-
/// parsed [`NativeConfig`]. Drives the production
|
|
521
|
-
/// `InterpretHelper::from_child` constructor so the post-spawn
|
|
522
|
-
/// plumbing is exercised by these tests.
|
|
523
|
-
fn spawn_fake_helper(
|
|
524
|
-
handshake: &str,
|
|
525
|
-
response_per_request: &str,
|
|
526
|
-
) -> (Arc<InterpretHelper>, NativeConfig) {
|
|
527
|
-
let child = Command::new("bash")
|
|
528
|
-
.arg("-c")
|
|
529
|
-
.arg(format!(
|
|
530
|
-
"printf '%s\\n' '{handshake}'; while IFS= read -r line; do printf '%s\\n' '{response_per_request}'; done",
|
|
531
|
-
))
|
|
532
|
-
.stdin(Stdio::piped())
|
|
533
|
-
.stdout(Stdio::piped())
|
|
534
|
-
.spawn()
|
|
535
|
-
.unwrap();
|
|
536
|
-
InterpretHelper::from_child(child).unwrap()
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
#[test]
|
|
540
|
-
fn build_dirsql_threads_persist_and_persist_path_into_the_builder() {
|
|
541
|
-
// Cover the `if config.persist` and `if let Some(p) = config.persist_path`
|
|
542
|
-
// branches in `build_dirsql`. A real persist build needs the cache file
|
|
543
|
-
// to live under root, so point persist_path at a path inside the
|
|
544
|
-
// tempdir and pass persist=true.
|
|
545
|
-
let tmp = tempfile::TempDir::new().unwrap();
|
|
546
|
-
std::fs::write(tmp.path().join("a.json"), b"{}").unwrap();
|
|
547
|
-
let cache_path = tmp.path().join(".dirsql/cache.db");
|
|
548
|
-
|
|
549
|
-
let handshake = format!(
|
|
550
|
-
r#"{{"type":"config","state":{{"root":"{}","tables":[{{"ddl":"CREATE TABLE papers (title TEXT)","glob":"*.json"}}],"persist":true,"persist_path":"{}"}}}}"#,
|
|
551
|
-
tmp.path().display(),
|
|
552
|
-
cache_path.display(),
|
|
553
|
-
);
|
|
554
|
-
let (helper, config) = spawn_fake_helper(
|
|
555
|
-
&handshake,
|
|
556
|
-
r#"{"type":"result","id":1,"ok":true,"rows":[{"title":"y"}]}"#,
|
|
557
|
-
);
|
|
558
|
-
assert!(config.persist);
|
|
559
|
-
assert_eq!(config.persist_path.as_ref().unwrap(), &cache_path);
|
|
560
|
-
|
|
561
|
-
let db = build_dirsql(helper, config).unwrap();
|
|
562
|
-
let rows = db.query("SELECT COUNT(*) AS n FROM papers").unwrap();
|
|
563
|
-
assert_eq!(rows[0].get("n"), Some(&Value::Integer(1)));
|
|
564
|
-
assert!(cache_path.exists(), "persist build should create the cache");
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
#[test]
|
|
568
|
-
fn build_dirsql_threads_extensions_into_the_builder() {
|
|
569
|
-
// A handshake whose `extensions` names a missing shared library must
|
|
570
|
-
// fail the build, proving the parsed extensions reach the core's
|
|
571
|
-
// load-at-startup path (enable -> load -> disable). (#229)
|
|
572
|
-
let tmp = tempfile::TempDir::new().unwrap();
|
|
573
|
-
std::fs::write(tmp.path().join("a.json"), b"{}").unwrap();
|
|
574
|
-
|
|
575
|
-
let handshake = format!(
|
|
576
|
-
r#"{{"type":"config","state":{{"root":"{}","tables":[{{"ddl":"CREATE TABLE papers (title TEXT)","glob":"*.json"}}],"extensions":[{{"path":"/nonexistent/dirsql-no-such-ext.so"}}]}}}}"#,
|
|
577
|
-
tmp.path().display(),
|
|
578
|
-
);
|
|
579
|
-
let (helper, config) = spawn_fake_helper(
|
|
580
|
-
&handshake,
|
|
581
|
-
r#"{"type":"result","id":1,"ok":true,"rows":[{"title":"y"}]}"#,
|
|
582
|
-
);
|
|
583
|
-
assert_eq!(config.extensions.len(), 1);
|
|
584
|
-
assert_eq!(
|
|
585
|
-
config.extensions[0].path,
|
|
586
|
-
PathBuf::from("/nonexistent/dirsql-no-such-ext.so"),
|
|
587
|
-
);
|
|
588
|
-
|
|
589
|
-
let err = match build_dirsql(helper, config) {
|
|
590
|
-
Ok(_) => panic!("expected build to fail on a missing extension"),
|
|
591
|
-
Err(e) => e,
|
|
592
|
-
};
|
|
593
|
-
assert!(err.contains("failed to load extension"), "got: {err}");
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
#[test]
|
|
597
|
-
fn build_dirsql_round_trip_with_fake_helper_invokes_extract_per_matched_file() {
|
|
598
|
-
// Create a tempdir with two matching files so the scan invokes
|
|
599
|
-
// `extract` twice — exercising the closure created inside
|
|
600
|
-
// `build_dirsql`, the `dispatch_extract` path through the
|
|
601
|
-
// helper's IO mutex, and end-to-end DDL/glob wiring.
|
|
602
|
-
let tmp = tempfile::TempDir::new().unwrap();
|
|
603
|
-
std::fs::write(tmp.path().join("a.json"), b"{}").unwrap();
|
|
604
|
-
std::fs::write(tmp.path().join("b.json"), b"{}").unwrap();
|
|
605
|
-
|
|
606
|
-
let handshake = format!(
|
|
607
|
-
r#"{{"type":"config","state":{{"root":"{}","tables":[{{"ddl":"CREATE TABLE papers (title TEXT)","glob":"*.json"}}]}}}}"#,
|
|
608
|
-
tmp.path().display(),
|
|
609
|
-
);
|
|
610
|
-
let (helper, config) = spawn_fake_helper(
|
|
611
|
-
&handshake,
|
|
612
|
-
r#"{"type":"result","id":1,"ok":true,"rows":[{"title":"x"}]}"#,
|
|
613
|
-
);
|
|
614
|
-
|
|
615
|
-
let db = build_dirsql(helper, config).unwrap();
|
|
616
|
-
let rows = db.query("SELECT COUNT(*) AS n FROM papers").unwrap();
|
|
617
|
-
assert_eq!(rows.len(), 1);
|
|
618
|
-
assert_eq!(rows[0].get("n"), Some(&Value::Integer(2)));
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
#[test]
|
|
622
|
-
fn helper_extract_round_trip_succeeds_against_a_fake_subprocess() {
|
|
623
|
-
let (helper, _config) = spawn_fake_helper(
|
|
624
|
-
r#"{"type":"config","state":{"root":"/tmp","tables":[{"ddl":"CREATE TABLE papers (title TEXT)","glob":"*"}]}}"#,
|
|
625
|
-
r#"{"type":"result","id":1,"ok":true,"rows":[{"title":"Alpha"}]}"#,
|
|
626
|
-
);
|
|
627
|
-
|
|
628
|
-
let rows = helper.extract("papers", "/x/a.json").unwrap();
|
|
629
|
-
assert_eq!(rows.len(), 1);
|
|
630
|
-
assert_eq!(rows[0].get("title"), Some(&Value::Text("Alpha".into())));
|
|
631
|
-
|
|
632
|
-
// Second request increments the id counter and still works against
|
|
633
|
-
// the canned response (the fake echoes the same line per request).
|
|
634
|
-
let rows2 = helper.extract("papers", "/x/b.json").unwrap();
|
|
635
|
-
assert_eq!(rows2.len(), 1);
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
#[test]
|
|
639
|
-
fn helper_from_child_errors_when_stdin_was_not_piped() {
|
|
640
|
-
// `Command::spawn` without `.stdin(Stdio::piped())` inherits the
|
|
641
|
-
// parent's stdin — `child.stdin.take()` returns `None`, driving
|
|
642
|
-
// the first `.ok_or_else` arm in `from_child`.
|
|
643
|
-
let child = Command::new("true").spawn().unwrap();
|
|
644
|
-
let err = match InterpretHelper::from_child(child) {
|
|
645
|
-
Ok(_) => panic!("expected error when stdin is not piped"),
|
|
646
|
-
Err(e) => e,
|
|
647
|
-
};
|
|
648
|
-
assert!(
|
|
649
|
-
err.contains("failed to capture interpret stdin"),
|
|
650
|
-
"got: {err}",
|
|
651
|
-
);
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
#[test]
|
|
655
|
-
fn helper_from_child_errors_when_stdout_was_not_piped() {
|
|
656
|
-
// Pipe stdin but leave stdout inherited — `child.stdout.take()`
|
|
657
|
-
// returns `None`, driving the second `.ok_or_else` arm.
|
|
658
|
-
let child = Command::new("true").stdin(Stdio::piped()).spawn().unwrap();
|
|
659
|
-
let err = match InterpretHelper::from_child(child) {
|
|
660
|
-
Ok(_) => panic!("expected error when stdout is not piped"),
|
|
661
|
-
Err(e) => e,
|
|
662
|
-
};
|
|
663
|
-
assert!(
|
|
664
|
-
err.contains("failed to capture interpret stdout"),
|
|
665
|
-
"got: {err}",
|
|
666
|
-
);
|
|
667
|
-
}
|
|
523
|
+
//
|
|
524
|
+
// The `build_dirsql` round-trips and the `InterpretHelper::from_child`
|
|
525
|
+
// success/error paths spawn a real subprocess (`bash`/`true`) and write
|
|
526
|
+
// real fixture files, so they live in `tests/native_config.rs`.
|
|
668
527
|
|
|
669
528
|
/// A writer that fails every write with the given `io::ErrorKind`,
|
|
670
529
|
/// used to exercise `dispatch_extract`'s IO-error arms.
|
|
@@ -720,64 +579,4 @@ mod tests {
|
|
|
720
579
|
let err = dispatch_extract(&mut stdout, &mut stdin, 1, "t", "p").unwrap_err();
|
|
721
580
|
assert!(err.contains("read from interpret"), "got: {err}");
|
|
722
581
|
}
|
|
723
|
-
|
|
724
|
-
#[test]
|
|
725
|
-
fn helper_from_child_errors_when_subprocess_emits_no_handshake() {
|
|
726
|
-
// A subprocess that exits without writing anything drives
|
|
727
|
-
// `from_child` through to `parse_handshake`'s empty-line arm.
|
|
728
|
-
let child = Command::new("true")
|
|
729
|
-
.stdin(Stdio::piped())
|
|
730
|
-
.stdout(Stdio::piped())
|
|
731
|
-
.spawn()
|
|
732
|
-
.unwrap();
|
|
733
|
-
let err = match InterpretHelper::from_child(child) {
|
|
734
|
-
Ok(_) => panic!("expected error from empty-stdout subprocess"),
|
|
735
|
-
Err(e) => e,
|
|
736
|
-
};
|
|
737
|
-
assert!(
|
|
738
|
-
err.contains("exited before sending handshake"),
|
|
739
|
-
"got: {err}"
|
|
740
|
-
);
|
|
741
|
-
}
|
|
742
|
-
|
|
743
|
-
#[test]
|
|
744
|
-
fn build_dirsql_errors_when_ddl_has_no_table_name() {
|
|
745
|
-
// The DDL is rejected by `parse_table_name` before any extract
|
|
746
|
-
// closure is created, so the helper's IO is never touched. Use a
|
|
747
|
-
// real child (`true` exits cleanly) just to satisfy the
|
|
748
|
-
// `InterpretHelper` shape.
|
|
749
|
-
let mut child = Command::new("true")
|
|
750
|
-
.stdin(Stdio::piped())
|
|
751
|
-
.stdout(Stdio::piped())
|
|
752
|
-
.spawn()
|
|
753
|
-
.unwrap();
|
|
754
|
-
let stdin = child.stdin.take().unwrap();
|
|
755
|
-
let stdout = child.stdout.take().unwrap();
|
|
756
|
-
let helper = Arc::new(InterpretHelper {
|
|
757
|
-
_child: child,
|
|
758
|
-
io: Arc::new(Mutex::new(HelperIo {
|
|
759
|
-
stdin: BufWriter::new(stdin),
|
|
760
|
-
stdout: BufReader::new(stdout),
|
|
761
|
-
})),
|
|
762
|
-
next_id: AtomicU64::new(1),
|
|
763
|
-
});
|
|
764
|
-
let config = NativeConfig {
|
|
765
|
-
root: PathBuf::from("/tmp"),
|
|
766
|
-
tables: vec![HandshakeTable {
|
|
767
|
-
ddl: "NOT VALID DDL".into(),
|
|
768
|
-
glob: "*.json".into(),
|
|
769
|
-
strict: false,
|
|
770
|
-
}],
|
|
771
|
-
ignore: Vec::new(),
|
|
772
|
-
persist: false,
|
|
773
|
-
persist_path: None,
|
|
774
|
-
extensions: Vec::new(),
|
|
775
|
-
};
|
|
776
|
-
// `DirSQL` doesn't impl Debug, so we can't use `unwrap_err` directly.
|
|
777
|
-
let err = match build_dirsql(helper, config) {
|
|
778
|
-
Ok(_) => panic!("expected build_dirsql to fail on invalid DDL"),
|
|
779
|
-
Err(e) => e,
|
|
780
|
-
};
|
|
781
|
-
assert!(err.contains("could not parse table name"), "got: {err}");
|
|
782
|
-
}
|
|
783
582
|
}
|
|
@@ -167,15 +167,16 @@ pub(super) fn error_response(status: StatusCode, message: impl Into<String>) ->
|
|
|
167
167
|
#[cfg(test)]
|
|
168
168
|
mod tests {
|
|
169
169
|
use super::*;
|
|
170
|
-
use crate::db::DbError;
|
|
171
170
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
171
|
+
// The `DirSqlError::Core => 400` arm of `classify_query_error` is
|
|
172
|
+
// exercised end-to-end at the integration tier by
|
|
173
|
+
// `post_query_malformed_sql_returns_400_not_500` in
|
|
174
|
+
// `tests/cli_integration.rs`, which posts malformed SQL to `/query` and
|
|
175
|
+
// asserts the 400. Constructing a `Core` value inline would require
|
|
176
|
+
// importing the first-party `crate::db::DbError`, which the
|
|
177
|
+
// `testing-conventions` `unit lint` isolation rule forbids (a unit test
|
|
178
|
+
// may reach only `super::` and pure `std`). The non-Core arm below is
|
|
179
|
+
// pure -- it builds a `super::DirSqlError::Lock` -- so it stays inline.
|
|
179
180
|
|
|
180
181
|
#[test]
|
|
181
182
|
fn classify_non_core_error_is_internal_server_error() {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{dirsql-0.3.35 → dirsql-0.3.37}/packages/python/docs/tests/integration/language-flag.spec.ts
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|