dirsql 0.3.27__tar.gz → 0.3.29__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 (171) hide show
  1. {dirsql-0.3.27 → dirsql-0.3.29}/Cargo.lock +1 -1
  2. dirsql-0.3.29/PKG-INFO +121 -0
  3. dirsql-0.3.29/README.md +102 -0
  4. {dirsql-0.3.27 → dirsql-0.3.29}/docs/cli/index.md +6 -4
  5. {dirsql-0.3.27/packages/rust → dirsql-0.3.29}/docs/getting-started.md +4 -1
  6. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/Cargo.toml +1 -1
  7. dirsql-0.3.29/packages/python/README.md +102 -0
  8. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/cli/index.md +6 -4
  9. {dirsql-0.3.27 → dirsql-0.3.29/packages/python}/docs/getting-started.md +4 -1
  10. dirsql-0.3.29/packages/rust/README.md +139 -0
  11. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/cli/index.md +6 -4
  12. {dirsql-0.3.27/packages/python → dirsql-0.3.29/packages/rust}/docs/getting-started.md +4 -1
  13. dirsql-0.3.27/PKG-INFO +0 -217
  14. dirsql-0.3.27/README.md +0 -198
  15. dirsql-0.3.27/packages/python/README.md +0 -198
  16. dirsql-0.3.27/packages/rust/README.md +0 -56
  17. {dirsql-0.3.27 → dirsql-0.3.29}/Cargo.toml +0 -0
  18. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/__init__.py +0 -0
  19. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/_async.py +0 -0
  20. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/_async_test.py +0 -0
  21. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/_dirsql.pyi +0 -0
  22. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/__init__.py +0 -0
  23. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/binary_path.py +0 -0
  24. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/binary_path_test.py +0 -0
  25. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/interpret/__init__.py +0 -0
  26. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/interpret/dispatch_extract.py +0 -0
  27. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/interpret/dispatch_extract_test.py +0 -0
  28. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/interpret/load_app.py +0 -0
  29. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/interpret/load_app_test.py +0 -0
  30. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/interpret/run.py +0 -0
  31. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/interpret/run_test.py +0 -0
  32. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/interpret/write_message.py +0 -0
  33. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/interpret/write_message_test.py +0 -0
  34. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/is_windows.py +0 -0
  35. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/is_windows_test.py +0 -0
  36. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/main.py +0 -0
  37. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/cli/main_test.py +0 -0
  38. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/py.typed +0 -0
  39. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/resolve_config.py +0 -0
  40. {dirsql-0.3.27 → dirsql-0.3.29}/dirsql/resolve_config_test.py +0 -0
  41. {dirsql-0.3.27 → dirsql-0.3.29}/docs/.claude/CLAUDE.md +0 -0
  42. {dirsql-0.3.27 → dirsql-0.3.29}/docs/.vitepress/config.ts +0 -0
  43. {dirsql-0.3.27 → dirsql-0.3.29}/docs/.vitepress/theme/index.ts +0 -0
  44. {dirsql-0.3.27 → dirsql-0.3.29}/docs/.vitepress/theme/lang.ts +0 -0
  45. {dirsql-0.3.27 → dirsql-0.3.29}/docs/AGENTS.md +0 -0
  46. {dirsql-0.3.27 → dirsql-0.3.29}/docs/api/index.md +0 -0
  47. {dirsql-0.3.27 → dirsql-0.3.29}/docs/cli/config.md +0 -0
  48. {dirsql-0.3.27 → dirsql-0.3.29}/docs/cli/http-api.md +0 -0
  49. {dirsql-0.3.27 → dirsql-0.3.29}/docs/cli/init.md +0 -0
  50. {dirsql-0.3.27 → dirsql-0.3.29}/docs/cli/server.md +0 -0
  51. {dirsql-0.3.27 → dirsql-0.3.29}/docs/guide/async.md +0 -0
  52. {dirsql-0.3.27 → dirsql-0.3.29}/docs/guide/crdt.md +0 -0
  53. {dirsql-0.3.27 → dirsql-0.3.29}/docs/guide/persistence.md +0 -0
  54. {dirsql-0.3.27 → dirsql-0.3.29}/docs/guide/querying.md +0 -0
  55. {dirsql-0.3.27 → dirsql-0.3.29}/docs/guide/tables.md +0 -0
  56. {dirsql-0.3.27 → dirsql-0.3.29}/docs/guide/watching.md +0 -0
  57. {dirsql-0.3.27 → dirsql-0.3.29}/docs/index.md +0 -0
  58. {dirsql-0.3.27 → dirsql-0.3.29}/docs/migrations.md +0 -0
  59. {dirsql-0.3.27 → dirsql-0.3.29}/docs/package.json +0 -0
  60. {dirsql-0.3.27 → dirsql-0.3.29}/docs/playwright.config.ts +0 -0
  61. {dirsql-0.3.27 → dirsql-0.3.29}/docs/pnpm-lock.yaml +0 -0
  62. {dirsql-0.3.27 → dirsql-0.3.29}/docs/pnpm-workspace.yaml +0 -0
  63. {dirsql-0.3.27 → dirsql-0.3.29}/docs/tests/integration/home.spec.ts +0 -0
  64. {dirsql-0.3.27 → dirsql-0.3.29}/docs/tests/integration/language-flag.spec.ts +0 -0
  65. {dirsql-0.3.27 → dirsql-0.3.29}/docs/tests/unit/config.test.ts +0 -0
  66. {dirsql-0.3.27 → dirsql-0.3.29}/docs/tests/unit/lang.test.ts +0 -0
  67. {dirsql-0.3.27 → dirsql-0.3.29}/docs/vitest.config.ts +0 -0
  68. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/conftest.py +0 -0
  69. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/.claude/CLAUDE.md +0 -0
  70. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/.vitepress/config.ts +0 -0
  71. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/.vitepress/theme/index.ts +0 -0
  72. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
  73. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/AGENTS.md +0 -0
  74. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/api/index.md +0 -0
  75. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/cli/config.md +0 -0
  76. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/cli/http-api.md +0 -0
  77. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/cli/init.md +0 -0
  78. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/cli/server.md +0 -0
  79. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/guide/async.md +0 -0
  80. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/guide/crdt.md +0 -0
  81. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/guide/persistence.md +0 -0
  82. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/guide/querying.md +0 -0
  83. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/guide/tables.md +0 -0
  84. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/guide/watching.md +0 -0
  85. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/index.md +0 -0
  86. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/migrations.md +0 -0
  87. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/package.json +0 -0
  88. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/playwright.config.ts +0 -0
  89. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/pnpm-lock.yaml +0 -0
  90. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/pnpm-workspace.yaml +0 -0
  91. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/tests/integration/home.spec.ts +0 -0
  92. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
  93. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/tests/unit/config.test.ts +0 -0
  94. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/tests/unit/lang.test.ts +0 -0
  95. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/docs/vitest.config.ts +0 -0
  96. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/src/lib.rs +0 -0
  97. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/__init__.py +0 -0
  98. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/conftest.py +0 -0
  99. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/e2e/__init__.py +0 -0
  100. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/__fixtures__/data/a/meta.json +0 -0
  101. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/__fixtures__/data/b/meta.json +0 -0
  102. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/__fixtures__/dirsql.config.py +0 -0
  103. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/__fixtures__/interpret/data/a/meta.json +0 -0
  104. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/__fixtures__/interpret/data/b/meta.json +0 -0
  105. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/__fixtures__/interpret/dirsql.config.py +0 -0
  106. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/__fixtures__/interpret/dirsql.config_no_app.py +0 -0
  107. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/__fixtures__/interpret/dirsql.config_raises.py +0 -0
  108. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/__init__.py +0 -0
  109. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/interpret_subprocess.py +0 -0
  110. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/test_async_dirsql.py +0 -0
  111. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/test_binding.py +0 -0
  112. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/test_dirsql.py +0 -0
  113. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/test_docs_examples.py +0 -0
  114. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/test_docs_gaps.py +0 -0
  115. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/test_from_config.py +0 -0
  116. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/test_interpret.py +0 -0
  117. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/test_native_config.py +0 -0
  118. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/test_persist.py +0 -0
  119. {dirsql-0.3.27 → dirsql-0.3.29}/packages/python/tests/integration/test_serialization.py +0 -0
  120. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/Cargo.toml +0 -0
  121. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/benches/db_bench.rs +0 -0
  122. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/benches/differ_bench.rs +0 -0
  123. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/benches/matcher_bench.rs +0 -0
  124. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/benches/scanner_bench.rs +0 -0
  125. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/api/index.md +0 -0
  126. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/cli/config.md +0 -0
  127. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/cli/http-api.md +0 -0
  128. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/cli/init.md +0 -0
  129. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/cli/server.md +0 -0
  130. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/guide/async.md +0 -0
  131. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/guide/crdt.md +0 -0
  132. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/guide/persistence.md +0 -0
  133. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/guide/querying.md +0 -0
  134. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/guide/tables.md +0 -0
  135. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/guide/watching.md +0 -0
  136. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/index.md +0 -0
  137. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/docs/migrations.md +0 -0
  138. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/bin/dirsql.rs +0 -0
  139. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/cli/init.rs +0 -0
  140. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/cli/mod.rs +0 -0
  141. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/cli/native_config.rs +0 -0
  142. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/cli/router.rs +0 -0
  143. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/cli/serialize.rs +0 -0
  144. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/cli/server.rs +0 -0
  145. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/config.rs +0 -0
  146. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/db.rs +0 -0
  147. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/differ.rs +0 -0
  148. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/lib.rs +0 -0
  149. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/matcher.rs +0 -0
  150. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/persist.rs +0 -0
  151. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/scanner.rs +0 -0
  152. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/src/watcher.rs +0 -0
  153. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/async_sdk.rs +0 -0
  154. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/cli_e2e.rs +0 -0
  155. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/cli_integration.rs +0 -0
  156. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/code_review_findings.rs +0 -0
  157. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/config.rs +0 -0
  158. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/docs_examples.rs +0 -0
  159. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/docs_gaps.rs +0 -0
  160. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/extensions.rs +0 -0
  161. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/from_config.rs +0 -0
  162. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/init_e2e.rs +0 -0
  163. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/init_integration.rs +0 -0
  164. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/persist.rs +0 -0
  165. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/readonly_query.rs +0 -0
  166. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/scanner.rs +0 -0
  167. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/sdk.rs +0 -0
  168. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/serialization.rs +0 -0
  169. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/watch_relative_root.rs +0 -0
  170. {dirsql-0.3.27 → dirsql-0.3.29}/packages/rust/tests/watcher.rs +0 -0
  171. {dirsql-0.3.27 → dirsql-0.3.29}/pyproject.toml +0 -0
@@ -499,7 +499,7 @@ dependencies = [
499
499
 
500
500
  [[package]]
501
501
  name = "dirsql-py-ext"
502
- version = "0.3.27"
502
+ version = "0.3.29"
503
503
  dependencies = [
504
504
  "dirsql",
505
505
  "pyo3",
dirsql-0.3.29/PKG-INFO ADDED
@@ -0,0 +1,121 @@
1
+ Metadata-Version: 2.4
2
+ Name: dirsql
3
+ Version: 0.3.29
4
+ Requires-Dist: pytest>=8 ; extra == 'dev'
5
+ Requires-Dist: pytest-describe>=2 ; extra == 'dev'
6
+ Requires-Dist: pytest-asyncio>=0.23 ; extra == 'dev'
7
+ Requires-Dist: pytest-cov>=5 ; extra == 'dev'
8
+ Requires-Dist: ruff>=0.4 ; extra == 'dev'
9
+ Requires-Dist: maturin>=1.0 ; extra == 'dev'
10
+ Requires-Dist: ty==0.0.42 ; extra == 'dev'
11
+ Provides-Extra: dev
12
+ Summary: Ephemeral SQL index over a local directory
13
+ Keywords: sql,filesystem,directory,sqlite,index
14
+ Author: Kevin Scott
15
+ License-Expression: MIT
16
+ Requires-Python: >=3.11
17
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
18
+
19
+ # `dirsql` (Python SDK)
20
+
21
+ Ephemeral SQL index over a local directory. `dirsql` watches a filesystem, ingests structured files into an in-memory SQLite database, and exposes a SQL query interface -- the filesystem is always the source of truth.
22
+
23
+ [Documentation](https://thekevinscott.github.io/dirsql/?lang=python)
24
+
25
+ Also available as [`dirsql` on crates.io](https://crates.io/crates/dirsql) and [`dirsql` on npm](https://www.npmjs.com/package/dirsql).
26
+
27
+ ## Installation
28
+
29
+ ```bash
30
+ pip install dirsql
31
+ ```
32
+
33
+ Requires Python >= 3.12. Ships as a native extension (Rust via PyO3); prebuilt binary wheels are provided for common platforms.
34
+
35
+ ## Quick start
36
+
37
+ `DirSQL` is async by default: the constructor returns immediately, scanning runs in a background thread, and you `await db.ready()` before querying. Each table is a `(ddl, glob, extract)` triple: the DDL defines the SQLite schema, the glob selects files (relative to the root), and `extract` turns a matched file into a list of row dicts. `dirsql` does not read file contents -- if `extract` needs the file body it reads `path` itself; return an empty list to skip a file.
38
+
39
+ ```python
40
+ import asyncio
41
+ import json
42
+ from dirsql import DirSQL, Table
43
+
44
+ async def main():
45
+ db = DirSQL(
46
+ "./my-blog",
47
+ tables=[
48
+ Table(
49
+ ddl="CREATE TABLE posts (title TEXT, author TEXT)",
50
+ glob="posts/*.json",
51
+ extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
52
+ ),
53
+ ],
54
+ )
55
+ await db.ready()
56
+
57
+ posts = await db.query("SELECT * FROM posts WHERE author = 'alice'")
58
+ print(posts)
59
+
60
+ asyncio.run(main())
61
+ ```
62
+
63
+ ## Multiple tables and joins
64
+
65
+ ```python
66
+ db = DirSQL(
67
+ "./my-blog",
68
+ tables=[
69
+ Table(
70
+ ddl="CREATE TABLE posts (title TEXT, author_id TEXT)",
71
+ glob="posts/*.json",
72
+ extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
73
+ ),
74
+ Table(
75
+ ddl="CREATE TABLE authors (id TEXT, name TEXT)",
76
+ glob="authors/*.json",
77
+ extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
78
+ ),
79
+ ],
80
+ )
81
+ await db.ready()
82
+
83
+ results = await db.query("""
84
+ SELECT posts.title, authors.name
85
+ FROM posts JOIN authors ON posts.author_id = authors.id
86
+ """)
87
+ ```
88
+
89
+ ## Ignoring files
90
+
91
+ Pass `ignore` patterns to skip files during scanning and watching:
92
+
93
+ ```python
94
+ db = DirSQL(
95
+ "./my-blog",
96
+ ignore=["**/drafts/**", "**/.git/**"],
97
+ tables=[...],
98
+ )
99
+ ```
100
+
101
+ ## Watching for changes
102
+
103
+ `db.watch()` returns an async iterator of row-level change events as files change on disk:
104
+
105
+ ```python
106
+ async for event in db.watch():
107
+ print(f"{event.action} on {event.table}: {event.row}")
108
+ if event.action == "error":
109
+ print(f" error: {event.error}")
110
+ ```
111
+
112
+ Each event has `.action` (`"insert"`, `"update"`, `"delete"`, or `"error"`), `.table`, `.row` (the new row, or the deleted row on `delete`), `.old_row` (the previous row, on `update`), `.file_path`, and `.error` (on `error`).
113
+
114
+ ## CLI
115
+
116
+ `pip install dirsql` also installs a `dirsql` console script that runs an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Run `dirsql` (or `uvx dirsql`) to start it. See the [CLI guide](https://thekevinscott.github.io/dirsql/cli/).
117
+
118
+ ## License
119
+
120
+ MIT
121
+
@@ -0,0 +1,102 @@
1
+ # `dirsql` (Python SDK)
2
+
3
+ Ephemeral SQL index over a local directory. `dirsql` watches a filesystem, ingests structured files into an in-memory SQLite database, and exposes a SQL query interface -- the filesystem is always the source of truth.
4
+
5
+ [Documentation](https://thekevinscott.github.io/dirsql/?lang=python)
6
+
7
+ Also available as [`dirsql` on crates.io](https://crates.io/crates/dirsql) and [`dirsql` on npm](https://www.npmjs.com/package/dirsql).
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install dirsql
13
+ ```
14
+
15
+ Requires Python >= 3.12. Ships as a native extension (Rust via PyO3); prebuilt binary wheels are provided for common platforms.
16
+
17
+ ## Quick start
18
+
19
+ `DirSQL` is async by default: the constructor returns immediately, scanning runs in a background thread, and you `await db.ready()` before querying. Each table is a `(ddl, glob, extract)` triple: the DDL defines the SQLite schema, the glob selects files (relative to the root), and `extract` turns a matched file into a list of row dicts. `dirsql` does not read file contents -- if `extract` needs the file body it reads `path` itself; return an empty list to skip a file.
20
+
21
+ ```python
22
+ import asyncio
23
+ import json
24
+ from dirsql import DirSQL, Table
25
+
26
+ async def main():
27
+ db = DirSQL(
28
+ "./my-blog",
29
+ tables=[
30
+ Table(
31
+ ddl="CREATE TABLE posts (title TEXT, author TEXT)",
32
+ glob="posts/*.json",
33
+ extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
34
+ ),
35
+ ],
36
+ )
37
+ await db.ready()
38
+
39
+ posts = await db.query("SELECT * FROM posts WHERE author = 'alice'")
40
+ print(posts)
41
+
42
+ asyncio.run(main())
43
+ ```
44
+
45
+ ## Multiple tables and joins
46
+
47
+ ```python
48
+ db = DirSQL(
49
+ "./my-blog",
50
+ tables=[
51
+ Table(
52
+ ddl="CREATE TABLE posts (title TEXT, author_id TEXT)",
53
+ glob="posts/*.json",
54
+ extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
55
+ ),
56
+ Table(
57
+ ddl="CREATE TABLE authors (id TEXT, name TEXT)",
58
+ glob="authors/*.json",
59
+ extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
60
+ ),
61
+ ],
62
+ )
63
+ await db.ready()
64
+
65
+ results = await db.query("""
66
+ SELECT posts.title, authors.name
67
+ FROM posts JOIN authors ON posts.author_id = authors.id
68
+ """)
69
+ ```
70
+
71
+ ## Ignoring files
72
+
73
+ Pass `ignore` patterns to skip files during scanning and watching:
74
+
75
+ ```python
76
+ db = DirSQL(
77
+ "./my-blog",
78
+ ignore=["**/drafts/**", "**/.git/**"],
79
+ tables=[...],
80
+ )
81
+ ```
82
+
83
+ ## Watching for changes
84
+
85
+ `db.watch()` returns an async iterator of row-level change events as files change on disk:
86
+
87
+ ```python
88
+ async for event in db.watch():
89
+ print(f"{event.action} on {event.table}: {event.row}")
90
+ if event.action == "error":
91
+ print(f" error: {event.error}")
92
+ ```
93
+
94
+ Each event has `.action` (`"insert"`, `"update"`, `"delete"`, or `"error"`), `.table`, `.row` (the new row, or the deleted row on `delete`), `.old_row` (the previous row, on `update`), `.file_path`, and `.error` (on `error`).
95
+
96
+ ## CLI
97
+
98
+ `pip install dirsql` also installs a `dirsql` console script that runs an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Run `dirsql` (or `uvx dirsql`) to start it. See the [CLI guide](https://thekevinscott.github.io/dirsql/cli/).
99
+
100
+ ## License
101
+
102
+ MIT
@@ -44,11 +44,13 @@ dirsql
44
44
 
45
45
  :::
46
46
 
47
+ ::: warning Node version
48
+ Requires **Node ≥ 20.11**.
49
+ :::
50
+
47
51
  ::: tip For Rust library consumers
48
- The `cli` feature is **opt-in**. Adding `dirsql` as a library dependency
49
- (`cargo add dirsql`) pulls no CLI dependencies only the core library. See the
50
- [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust)
51
- for the library-vs-CLI feature split.
52
+ The `cli` feature is **opt-in**. See the
53
+ [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust) for instructions on how to include.
52
54
  :::
53
55
 
54
56
  ## Quick start
@@ -19,7 +19,8 @@ cargo add dirsql
19
19
  ```
20
20
 
21
21
  ```bash [TypeScript]
22
- pnpm add dirsql
22
+ # The npm CLI requires **Node ≥ 20.11**.
23
+ npm add dirsql
23
24
  ```
24
25
 
25
26
  ```bash [CLI]
@@ -31,6 +32,8 @@ cargo install dirsql --features cli
31
32
 
32
33
  :::
33
34
 
35
+
36
+
34
37
  See the [CLI section](./cli/) for details on the command-line interface, and the [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust) for the library-vs-CLI feature split.
35
38
 
36
39
  ## Quick start
@@ -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.27"
7
+ version = "0.3.29"
8
8
  edition.workspace = true
9
9
  publish = false
10
10
  readme = "README.md"
@@ -0,0 +1,102 @@
1
+ # `dirsql` (Python SDK)
2
+
3
+ Ephemeral SQL index over a local directory. `dirsql` watches a filesystem, ingests structured files into an in-memory SQLite database, and exposes a SQL query interface -- the filesystem is always the source of truth.
4
+
5
+ [Documentation](https://thekevinscott.github.io/dirsql/?lang=python)
6
+
7
+ Also available as [`dirsql` on crates.io](https://crates.io/crates/dirsql) and [`dirsql` on npm](https://www.npmjs.com/package/dirsql).
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ pip install dirsql
13
+ ```
14
+
15
+ Requires Python >= 3.12. Ships as a native extension (Rust via PyO3); prebuilt binary wheels are provided for common platforms.
16
+
17
+ ## Quick start
18
+
19
+ `DirSQL` is async by default: the constructor returns immediately, scanning runs in a background thread, and you `await db.ready()` before querying. Each table is a `(ddl, glob, extract)` triple: the DDL defines the SQLite schema, the glob selects files (relative to the root), and `extract` turns a matched file into a list of row dicts. `dirsql` does not read file contents -- if `extract` needs the file body it reads `path` itself; return an empty list to skip a file.
20
+
21
+ ```python
22
+ import asyncio
23
+ import json
24
+ from dirsql import DirSQL, Table
25
+
26
+ async def main():
27
+ db = DirSQL(
28
+ "./my-blog",
29
+ tables=[
30
+ Table(
31
+ ddl="CREATE TABLE posts (title TEXT, author TEXT)",
32
+ glob="posts/*.json",
33
+ extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
34
+ ),
35
+ ],
36
+ )
37
+ await db.ready()
38
+
39
+ posts = await db.query("SELECT * FROM posts WHERE author = 'alice'")
40
+ print(posts)
41
+
42
+ asyncio.run(main())
43
+ ```
44
+
45
+ ## Multiple tables and joins
46
+
47
+ ```python
48
+ db = DirSQL(
49
+ "./my-blog",
50
+ tables=[
51
+ Table(
52
+ ddl="CREATE TABLE posts (title TEXT, author_id TEXT)",
53
+ glob="posts/*.json",
54
+ extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
55
+ ),
56
+ Table(
57
+ ddl="CREATE TABLE authors (id TEXT, name TEXT)",
58
+ glob="authors/*.json",
59
+ extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
60
+ ),
61
+ ],
62
+ )
63
+ await db.ready()
64
+
65
+ results = await db.query("""
66
+ SELECT posts.title, authors.name
67
+ FROM posts JOIN authors ON posts.author_id = authors.id
68
+ """)
69
+ ```
70
+
71
+ ## Ignoring files
72
+
73
+ Pass `ignore` patterns to skip files during scanning and watching:
74
+
75
+ ```python
76
+ db = DirSQL(
77
+ "./my-blog",
78
+ ignore=["**/drafts/**", "**/.git/**"],
79
+ tables=[...],
80
+ )
81
+ ```
82
+
83
+ ## Watching for changes
84
+
85
+ `db.watch()` returns an async iterator of row-level change events as files change on disk:
86
+
87
+ ```python
88
+ async for event in db.watch():
89
+ print(f"{event.action} on {event.table}: {event.row}")
90
+ if event.action == "error":
91
+ print(f" error: {event.error}")
92
+ ```
93
+
94
+ Each event has `.action` (`"insert"`, `"update"`, `"delete"`, or `"error"`), `.table`, `.row` (the new row, or the deleted row on `delete`), `.old_row` (the previous row, on `update`), `.file_path`, and `.error` (on `error`).
95
+
96
+ ## CLI
97
+
98
+ `pip install dirsql` also installs a `dirsql` console script that runs an HTTP server exposing the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Run `dirsql` (or `uvx dirsql`) to start it. See the [CLI guide](https://thekevinscott.github.io/dirsql/cli/).
99
+
100
+ ## License
101
+
102
+ MIT
@@ -44,11 +44,13 @@ dirsql
44
44
 
45
45
  :::
46
46
 
47
+ ::: warning Node version
48
+ Requires **Node ≥ 20.11**.
49
+ :::
50
+
47
51
  ::: tip For Rust library consumers
48
- The `cli` feature is **opt-in**. Adding `dirsql` as a library dependency
49
- (`cargo add dirsql`) pulls no CLI dependencies only the core library. See the
50
- [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust)
51
- for the library-vs-CLI feature split.
52
+ The `cli` feature is **opt-in**. See the
53
+ [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust) for instructions on how to include.
52
54
  :::
53
55
 
54
56
  ## Quick start
@@ -19,7 +19,8 @@ cargo add dirsql
19
19
  ```
20
20
 
21
21
  ```bash [TypeScript]
22
- pnpm add dirsql
22
+ # The npm CLI requires **Node ≥ 20.11**.
23
+ npm add dirsql
23
24
  ```
24
25
 
25
26
  ```bash [CLI]
@@ -31,6 +32,8 @@ cargo install dirsql --features cli
31
32
 
32
33
  :::
33
34
 
35
+
36
+
34
37
  See the [CLI section](./cli/) for details on the command-line interface, and the [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust) for the library-vs-CLI feature split.
35
38
 
36
39
  ## Quick start
@@ -0,0 +1,139 @@
1
+ # `dirsql` (Rust SDK)
2
+
3
+ Ephemeral SQL index over a local directory. `dirsql` watches a filesystem, ingests structured files into an in-memory SQLite database, and exposes a SQL query interface -- the filesystem is always the source of truth.
4
+
5
+ [Documentation](https://thekevinscott.github.io/dirsql/?lang=rust)
6
+
7
+ Also available as [`dirsql` on PyPI](https://pypi.org/project/dirsql/) and [`dirsql` on npm](https://www.npmjs.com/package/dirsql).
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ cargo add dirsql
13
+ ```
14
+
15
+ ## Quick start
16
+
17
+ `DirSQL::new` scans the directory synchronously and returns a ready instance. Each table is a `(ddl, glob, extract)` triple: the DDL defines the SQLite schema, the glob selects files (relative to the root), and `extract` turns a matched file into rows (`Vec<HashMap<String, Value>>`). `dirsql` does not read file contents -- the callback reads `path` itself; return an empty `Vec` to skip a file.
18
+
19
+ ```rust
20
+ use dirsql::{DirSQL, Table, Value};
21
+ use std::collections::HashMap;
22
+
23
+ // Convert a JSON object string into a dirsql row. Reused by the examples below.
24
+ fn row_from_json(raw: &str) -> HashMap<String, Value> {
25
+ let v: serde_json::Value = serde_json::from_str(raw).unwrap();
26
+ let serde_json::Value::Object(obj) = v else { return HashMap::new() };
27
+ obj.into_iter()
28
+ .map(|(k, val)| {
29
+ let v = match val {
30
+ serde_json::Value::String(s) => Value::Text(s),
31
+ serde_json::Value::Number(n) => n
32
+ .as_i64()
33
+ .map(Value::Integer)
34
+ .unwrap_or_else(|| Value::Real(n.as_f64().unwrap_or(0.0))),
35
+ serde_json::Value::Bool(b) => Value::Integer(b as i64),
36
+ serde_json::Value::Null => Value::Null,
37
+ other => Value::Text(other.to_string()),
38
+ };
39
+ (k, v)
40
+ })
41
+ .collect()
42
+ }
43
+
44
+ let db = DirSQL::new(
45
+ "./my-blog",
46
+ vec![Table::new(
47
+ "CREATE TABLE posts (title TEXT, author TEXT)",
48
+ "posts/*.json",
49
+ |path| vec![row_from_json(&std::fs::read_to_string(path).unwrap())],
50
+ )],
51
+ )?;
52
+
53
+ let posts = db.query("SELECT * FROM posts WHERE author = 'alice'")?;
54
+ ```
55
+
56
+ ## Multiple tables and joins
57
+
58
+ ```rust
59
+ let db = DirSQL::new(
60
+ "./my-blog",
61
+ vec![
62
+ Table::new(
63
+ "CREATE TABLE posts (title TEXT, author_id TEXT)",
64
+ "posts/*.json",
65
+ |path| vec![row_from_json(&std::fs::read_to_string(path).unwrap())],
66
+ ),
67
+ Table::new(
68
+ "CREATE TABLE authors (id TEXT, name TEXT)",
69
+ "authors/*.json",
70
+ |path| vec![row_from_json(&std::fs::read_to_string(path).unwrap())],
71
+ ),
72
+ ],
73
+ )?;
74
+
75
+ let results = db.query(
76
+ "SELECT posts.title, authors.name \
77
+ FROM posts JOIN authors ON posts.author_id = authors.id",
78
+ )?;
79
+ ```
80
+
81
+ ## Ignoring files
82
+
83
+ Use `DirSQL::with_ignore` to skip files during scanning and watching:
84
+
85
+ ```rust
86
+ let db = DirSQL::with_ignore(
87
+ "./my-blog",
88
+ vec![/* tables */],
89
+ vec!["**/drafts/**", "**/.git/**"],
90
+ )?;
91
+ ```
92
+
93
+ ## Watching for changes
94
+
95
+ `db.watch()` returns a stream of row-level change events as files change on disk. `.next()` comes from `StreamExt` in the `futures` crate (`cargo add futures`), driven inside an async runtime such as tokio:
96
+
97
+ ```rust
98
+ use dirsql::RowEvent;
99
+ use futures::StreamExt;
100
+
101
+ let mut stream = db.watch()?;
102
+ while let Some(event) = stream.next().await {
103
+ match event {
104
+ RowEvent::Insert { table, row, file_path } => {
105
+ println!("insert on {table} ({file_path}): {row:?}")
106
+ }
107
+ RowEvent::Update { table, old_row, new_row, file_path } => {
108
+ println!("update on {table} ({file_path}): {old_row:?} -> {new_row:?}")
109
+ }
110
+ RowEvent::Delete { table, row, file_path } => {
111
+ println!("delete on {table} ({file_path}): {row:?}")
112
+ }
113
+ RowEvent::Error { table, file_path, error } => {
114
+ println!("error on {table:?} {file_path:?}: {error}")
115
+ }
116
+ }
117
+ }
118
+ ```
119
+
120
+ ## CLI
121
+
122
+ ```bash
123
+ cargo install dirsql --features cli
124
+ dirsql
125
+ ```
126
+
127
+ Running `dirsql` starts an HTTP server bound to `localhost:7117` that exposes the SDK over HTTP: `POST /query` for SQL and `GET /events` for a Server-Sent Events change stream. Override with `--host`, `--port`, `--config`. See the [CLI guide](https://thekevinscott.github.io/dirsql/cli/).
128
+
129
+ The `cli` feature is **opt-in** -- `cargo add dirsql` pulls no CLI dependencies. `cargo install dirsql` without `--features cli` silently installs nothing (`required-features` skips the bin target with no warning); always include the flag, or use `npx dirsql` / `uvx dirsql` for prebuilt binaries.
130
+
131
+ ### Feature flags
132
+
133
+ | Feature | Default | Description |
134
+ |---|---|---|
135
+ | `cli` | no | Enables the `dirsql` binary and its dependencies. |
136
+
137
+ ## License
138
+
139
+ MIT
@@ -44,11 +44,13 @@ dirsql
44
44
 
45
45
  :::
46
46
 
47
+ ::: warning Node version
48
+ Requires **Node ≥ 20.11**.
49
+ :::
50
+
47
51
  ::: tip For Rust library consumers
48
- The `cli` feature is **opt-in**. Adding `dirsql` as a library dependency
49
- (`cargo add dirsql`) pulls no CLI dependencies only the core library. See the
50
- [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust)
51
- for the library-vs-CLI feature split.
52
+ The `cli` feature is **opt-in**. See the
53
+ [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust) for instructions on how to include.
52
54
  :::
53
55
 
54
56
  ## Quick start
@@ -19,7 +19,8 @@ cargo add dirsql
19
19
  ```
20
20
 
21
21
  ```bash [TypeScript]
22
- pnpm add dirsql
22
+ # The npm CLI requires **Node ≥ 20.11**.
23
+ npm add dirsql
23
24
  ```
24
25
 
25
26
  ```bash [CLI]
@@ -31,6 +32,8 @@ cargo install dirsql --features cli
31
32
 
32
33
  :::
33
34
 
35
+
36
+
34
37
  See the [CLI section](./cli/) for details on the command-line interface, and the [Rust library README](https://github.com/thekevinscott/dirsql/tree/main/packages/rust) for the library-vs-CLI feature split.
35
38
 
36
39
  ## Quick start