dirsql 0.3.1__tar.gz → 0.3.3__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.
Files changed (121) hide show
  1. {dirsql-0.3.1 → dirsql-0.3.3}/Cargo.lock +1 -1
  2. {dirsql-0.3.1 → dirsql-0.3.3}/PKG-INFO +1 -1
  3. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/Cargo.toml +1 -1
  4. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/tests/cli_e2e.rs +17 -20
  5. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/tests/cli_integration.rs +31 -23
  6. {dirsql-0.3.1 → dirsql-0.3.3}/Cargo.toml +0 -0
  7. {dirsql-0.3.1 → dirsql-0.3.3}/README.md +0 -0
  8. {dirsql-0.3.1 → dirsql-0.3.3}/docs/.claude/CLAUDE.md +0 -0
  9. {dirsql-0.3.1 → dirsql-0.3.3}/docs/.vitepress/config.ts +0 -0
  10. {dirsql-0.3.1 → dirsql-0.3.3}/docs/.vitepress/theme/index.ts +0 -0
  11. {dirsql-0.3.1 → dirsql-0.3.3}/docs/.vitepress/theme/lang.ts +0 -0
  12. {dirsql-0.3.1 → dirsql-0.3.3}/docs/AGENTS.md +0 -0
  13. {dirsql-0.3.1 → dirsql-0.3.3}/docs/api/index.md +0 -0
  14. {dirsql-0.3.1 → dirsql-0.3.3}/docs/getting-started.md +0 -0
  15. {dirsql-0.3.1 → dirsql-0.3.3}/docs/guide/async.md +0 -0
  16. {dirsql-0.3.1 → dirsql-0.3.3}/docs/guide/cli.md +0 -0
  17. {dirsql-0.3.1 → dirsql-0.3.3}/docs/guide/config.md +0 -0
  18. {dirsql-0.3.1 → dirsql-0.3.3}/docs/guide/crdt.md +0 -0
  19. {dirsql-0.3.1 → dirsql-0.3.3}/docs/guide/persistence.md +0 -0
  20. {dirsql-0.3.1 → dirsql-0.3.3}/docs/guide/querying.md +0 -0
  21. {dirsql-0.3.1 → dirsql-0.3.3}/docs/guide/tables.md +0 -0
  22. {dirsql-0.3.1 → dirsql-0.3.3}/docs/guide/watching.md +0 -0
  23. {dirsql-0.3.1 → dirsql-0.3.3}/docs/index.md +0 -0
  24. {dirsql-0.3.1 → dirsql-0.3.3}/docs/migrations.md +0 -0
  25. {dirsql-0.3.1 → dirsql-0.3.3}/docs/package.json +0 -0
  26. {dirsql-0.3.1 → dirsql-0.3.3}/docs/playwright.config.ts +0 -0
  27. {dirsql-0.3.1 → dirsql-0.3.3}/docs/pnpm-lock.yaml +0 -0
  28. {dirsql-0.3.1 → dirsql-0.3.3}/docs/pnpm-workspace.yaml +0 -0
  29. {dirsql-0.3.1 → dirsql-0.3.3}/docs/tests/integration/home.spec.ts +0 -0
  30. {dirsql-0.3.1 → dirsql-0.3.3}/docs/tests/integration/language-flag.spec.ts +0 -0
  31. {dirsql-0.3.1 → dirsql-0.3.3}/docs/tests/unit/config.test.ts +0 -0
  32. {dirsql-0.3.1 → dirsql-0.3.3}/docs/tests/unit/lang.test.ts +0 -0
  33. {dirsql-0.3.1 → dirsql-0.3.3}/docs/vitest.config.ts +0 -0
  34. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/README.md +0 -0
  35. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/.claude/CLAUDE.md +0 -0
  36. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/.vitepress/config.ts +0 -0
  37. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  38. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  39. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/AGENTS.md +0 -0
  40. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/api/index.md +0 -0
  41. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/getting-started.md +0 -0
  42. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/guide/async.md +0 -0
  43. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/guide/cli.md +0 -0
  44. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/guide/config.md +0 -0
  45. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/guide/crdt.md +0 -0
  46. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/guide/persistence.md +0 -0
  47. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/guide/querying.md +0 -0
  48. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/guide/tables.md +0 -0
  49. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/guide/watching.md +0 -0
  50. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/index.md +0 -0
  51. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/migrations.md +0 -0
  52. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/package.json +0 -0
  53. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/playwright.config.ts +0 -0
  54. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/pnpm-lock.yaml +0 -0
  55. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/pnpm-workspace.yaml +0 -0
  56. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/tests/integration/home.spec.ts +0 -0
  57. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
  58. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/tests/unit/config.test.ts +0 -0
  59. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/tests/unit/lang.test.ts +0 -0
  60. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/docs/vitest.config.ts +0 -0
  61. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/python/conftest.py +0 -0
  62. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/src/lib.rs +0 -0
  63. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/tests/__init__.py +0 -0
  64. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/tests/conftest.py +0 -0
  65. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/tests/integration/__init__.py +0 -0
  66. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/tests/integration/test_async_dirsql.py +0 -0
  67. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/tests/integration/test_binding.py +0 -0
  68. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/tests/integration/test_dirsql.py +0 -0
  69. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/tests/integration/test_docs_examples.py +0 -0
  70. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/tests/integration/test_docs_gaps.py +0 -0
  71. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/tests/integration/test_from_config.py +0 -0
  72. {dirsql-0.3.1 → dirsql-0.3.3}/packages/python/tests/integration/test_persist.py +0 -0
  73. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/Cargo.toml +0 -0
  74. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/README.md +0 -0
  75. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/benches/db_bench.rs +0 -0
  76. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/benches/differ_bench.rs +0 -0
  77. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/benches/matcher_bench.rs +0 -0
  78. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/benches/scanner_bench.rs +0 -0
  79. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/api/index.md +0 -0
  80. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/getting-started.md +0 -0
  81. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/guide/async.md +0 -0
  82. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/guide/cli.md +0 -0
  83. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/guide/config.md +0 -0
  84. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/guide/crdt.md +0 -0
  85. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/guide/persistence.md +0 -0
  86. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/guide/querying.md +0 -0
  87. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/guide/tables.md +0 -0
  88. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/guide/watching.md +0 -0
  89. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/index.md +0 -0
  90. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/docs/migrations.md +0 -0
  91. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/bin/dirsql.rs +0 -0
  92. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/cli/mod.rs +0 -0
  93. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/cli/router.rs +0 -0
  94. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/cli/serialize.rs +0 -0
  95. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/cli/server.rs +0 -0
  96. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/config.rs +0 -0
  97. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/db.rs +0 -0
  98. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/differ.rs +0 -0
  99. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/lib.rs +0 -0
  100. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/matcher.rs +0 -0
  101. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/persist.rs +0 -0
  102. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/scanner.rs +0 -0
  103. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/src/watcher.rs +0 -0
  104. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/tests/async_sdk.rs +0 -0
  105. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/tests/docs_examples.rs +0 -0
  106. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/tests/docs_gaps.rs +0 -0
  107. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/tests/from_config.rs +0 -0
  108. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/tests/persist.rs +0 -0
  109. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/tests/readonly_query.rs +0 -0
  110. {dirsql-0.3.1 → dirsql-0.3.3}/packages/rust/tests/sdk.rs +0 -0
  111. {dirsql-0.3.1 → dirsql-0.3.3}/pyproject.toml +0 -0
  112. {dirsql-0.3.1 → dirsql-0.3.3}/python/dirsql/__init__.py +0 -0
  113. {dirsql-0.3.1 → dirsql-0.3.3}/python/dirsql/_async.py +0 -0
  114. {dirsql-0.3.1 → dirsql-0.3.3}/python/dirsql/_cli/__init__.py +0 -0
  115. {dirsql-0.3.1 → dirsql-0.3.3}/python/dirsql/_cli/binary_path.py +0 -0
  116. {dirsql-0.3.1 → dirsql-0.3.3}/python/dirsql/_cli/binary_path_test.py +0 -0
  117. {dirsql-0.3.1 → dirsql-0.3.3}/python/dirsql/_cli/is_windows.py +0 -0
  118. {dirsql-0.3.1 → dirsql-0.3.3}/python/dirsql/_cli/is_windows_test.py +0 -0
  119. {dirsql-0.3.1 → dirsql-0.3.3}/python/dirsql/_cli/main.py +0 -0
  120. {dirsql-0.3.1 → dirsql-0.3.3}/python/dirsql/_cli/main_test.py +0 -0
  121. {dirsql-0.3.1 → dirsql-0.3.3}/python/dirsql/test_async.py +0 -0
@@ -499,7 +499,7 @@ dependencies = [
499
499
 
500
500
  [[package]]
501
501
  name = "dirsql-py-ext"
502
- version = "0.3.1"
502
+ version = "0.3.3"
503
503
  dependencies = [
504
504
  "dirsql",
505
505
  "pyo3",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.3.1
3
+ Version: 0.3.3
4
4
  Requires-Dist: pytest>=8 ; extra == 'dev'
5
5
  Requires-Dist: pytest-describe>=2 ; extra == 'dev'
6
6
  Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
@@ -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.1"
7
+ version = "0.3.3"
8
8
  edition.workspace = true
9
9
  publish = false
10
10
  readme = "README.md"
@@ -30,25 +30,22 @@ use tempfile::TempDir;
30
30
 
31
31
  /// Write a two-post blog fixture into a fresh tempdir and return it.
32
32
  /// The `.dirsql.toml` lives at the root so `dirsql` can discover it.
33
+ ///
34
+ /// `title` and `author` are captured from the file path (`posts/{author}/
35
+ /// {title}.json`) rather than parsed from file content -- the new model
36
+ /// derives row columns from filesystem facts only.
33
37
  fn blog_fixture() -> TempDir {
34
38
  let root = TempDir::new().unwrap();
35
- fs::create_dir_all(root.path().join("posts")).unwrap();
36
- fs::write(
37
- root.path().join("posts/hello.json"),
38
- r#"{"title":"Hello World","author":"alice"}"#,
39
- )
40
- .unwrap();
41
- fs::write(
42
- root.path().join("posts/second.json"),
43
- r#"{"title":"Second Post","author":"bob"}"#,
44
- )
45
- .unwrap();
39
+ fs::create_dir_all(root.path().join("posts/alice")).unwrap();
40
+ fs::create_dir_all(root.path().join("posts/bob")).unwrap();
41
+ fs::write(root.path().join("posts/alice/Hello-World.json"), "{}").unwrap();
42
+ fs::write(root.path().join("posts/bob/Second-Post.json"), "{}").unwrap();
46
43
  fs::write(
47
44
  root.path().join(".dirsql.toml"),
48
45
  r#"
49
46
  [[table]]
50
- ddl = "CREATE TABLE posts (title TEXT, author TEXT)"
51
- glob = "posts/*.json"
47
+ ddl = "CREATE TABLE posts (title TEXT, author TEXT, _basename TEXT, _size INTEGER)"
48
+ glob = "posts/{author}/{title}.json"
52
49
  "#,
53
50
  )
54
51
  .unwrap();
@@ -194,8 +191,8 @@ fn post_query_returns_rows_over_http() {
194
191
  assert_eq!(
195
192
  body,
196
193
  vec![
197
- json!({"title": "Hello World"}),
198
- json!({"title": "Second Post"}),
194
+ json!({"title": "Hello-World"}),
195
+ json!({"title": "Second-Post"}),
199
196
  ]
200
197
  );
201
198
 
@@ -248,11 +245,11 @@ fn get_events_emits_insert_event_when_file_created() {
248
245
  .recv_timeout(Duration::from_secs(5))
249
246
  .expect("SSE stream never produced a ready sentinel");
250
247
  std::thread::sleep(Duration::from_millis(200));
251
- fs::write(
252
- root.path().join("posts/third.json"),
253
- r#"{"title":"Third Post","author":"carol"}"#,
254
- )
255
- .unwrap();
248
+ // Write into an author dir that already exists at startup so notify's
249
+ // watch is guaranteed to be installed. Creating a new dir + writing
250
+ // immediately races inotify's recursive-watch installation; that race
251
+ // is observable and flaky, not a feature under test here.
252
+ fs::write(root.path().join("posts/alice/Brand-New-Post.json"), "{}").unwrap();
256
253
 
257
254
  let data = rx
258
255
  .recv_timeout(Duration::from_secs(10))
@@ -31,25 +31,24 @@ use tempfile::TempDir;
31
31
  /// Build a `DirSQL` over a two-post blog fixture driven by `.dirsql.toml`,
32
32
  /// matching the e2e fixture shape. Returns the tempdir so the caller can
33
33
  /// mutate files while the server runs.
34
+ ///
35
+ /// `title` and `author` are captured from the file path (`posts/{author}/
36
+ /// {title}.json`) rather than parsed from file content -- the new model
37
+ /// derives row columns from filesystem facts only. `_size` is included so
38
+ /// that content-only edits still change a column value and surface as
39
+ /// `Update` events in the SSE stream.
34
40
  fn blog_fixture() -> (TempDir, DirSQL) {
35
41
  let root = TempDir::new().unwrap();
36
- fs::create_dir_all(root.path().join("posts")).unwrap();
37
- fs::write(
38
- root.path().join("posts/hello.json"),
39
- r#"{"title":"Hello World","author":"alice"}"#,
40
- )
41
- .unwrap();
42
- fs::write(
43
- root.path().join("posts/second.json"),
44
- r#"{"title":"Second Post","author":"bob"}"#,
45
- )
46
- .unwrap();
42
+ fs::create_dir_all(root.path().join("posts/alice")).unwrap();
43
+ fs::create_dir_all(root.path().join("posts/bob")).unwrap();
44
+ fs::write(root.path().join("posts/alice/Hello-World.json"), "{}").unwrap();
45
+ fs::write(root.path().join("posts/bob/Second-Post.json"), "{}").unwrap();
47
46
  fs::write(
48
47
  root.path().join(".dirsql.toml"),
49
48
  r#"
50
49
  [[table]]
51
- ddl = "CREATE TABLE posts (title TEXT, author TEXT)"
52
- glob = "posts/*.json"
50
+ ddl = "CREATE TABLE posts (title TEXT, author TEXT, _basename TEXT, _size INTEGER)"
51
+ glob = "posts/{author}/{title}.json"
53
52
  "#,
54
53
  )
55
54
  .unwrap();
@@ -129,8 +128,8 @@ async fn post_query_returns_json_rows_on_success() {
129
128
  assert_eq!(
130
129
  body,
131
130
  vec![
132
- json!({"title": "Hello World"}),
133
- json!({"title": "Second Post"}),
131
+ json!({"title": "Hello-World"}),
132
+ json!({"title": "Second-Post"}),
134
133
  ]
135
134
  );
136
135
  handle.shutdown().await.unwrap();
@@ -263,9 +262,11 @@ async fn get_events_streams_mutation_events() {
263
262
  // exists.
264
263
  await_ready(&mut stream).await;
265
264
 
265
+ // Modify the file's content; `_size` is part of the row, so the diff
266
+ // produces an Update event even though no captured path changed.
266
267
  fs::write(
267
- root.path().join("posts/hello.json"),
268
- r#"{"title":"Hello, world","author":"alice"}"#,
268
+ root.path().join("posts/alice/Hello-World.json"),
269
+ r#"{"some":"larger","payload":"to change _size"}"#,
269
270
  )
270
271
  .unwrap();
271
272
 
@@ -284,7 +285,7 @@ async fn get_events_streams_mutation_events() {
284
285
 
285
286
  #[tokio::test]
286
287
  async fn get_events_surfaces_parse_errors_as_error_events_not_fatal() {
287
- // Per docs/guide/cli.md: an error during extraction is a per-event problem,
288
+ // Per docs/guide/cli.md: an error during ingestion is a per-event problem,
288
289
  // not a server-wide one. The stream must keep delivering subsequent events.
289
290
  let (root, db) = blog_fixture();
290
291
  let handle = spawn_server(db).await;
@@ -297,13 +298,20 @@ async fn get_events_surfaces_parse_errors_as_error_events_not_fatal() {
297
298
 
298
299
  await_ready(&mut stream).await;
299
300
 
300
- // Break a file extract should fail on this one.
301
- fs::write(root.path().join("posts/hello.json"), "not valid json").unwrap();
302
- // Then fix another file to produce a valid event.
301
+ // Break a file with invalid UTF-8 -- the pipeline reads file bytes
302
+ // before invoking the synthesized extract, and `read_to_string` rejects
303
+ // non-UTF-8 bytes with InvalidData. That surfaces as a per-file error
304
+ // event without taking the stream down.
305
+ fs::write(
306
+ root.path().join("posts/alice/Hello-World.json"),
307
+ [0xff_u8, 0xfe, 0xfd, 0xfc],
308
+ )
309
+ .unwrap();
310
+ // Then mutate another file to produce a valid event after the error.
303
311
  tokio::time::sleep(Duration::from_millis(50)).await;
304
312
  fs::write(
305
- root.path().join("posts/second.json"),
306
- r#"{"title":"Second Post v2","author":"bob"}"#,
313
+ root.path().join("posts/bob/Second-Post.json"),
314
+ r#"{"some":"new content to change _size"}"#,
307
315
  )
308
316
  .unwrap();
309
317
 
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