dirsql 0.2.5__tar.gz → 0.2.7__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 (116) hide show
  1. {dirsql-0.2.5 → dirsql-0.2.7}/PKG-INFO +1 -1
  2. dirsql-0.2.7/docs/.claude/CLAUDE.md +3 -0
  3. dirsql-0.2.7/docs/.vitepress/config.ts +63 -0
  4. dirsql-0.2.7/docs/.vitepress/theme/index.ts +154 -0
  5. dirsql-0.2.7/docs/.vitepress/theme/lang.ts +33 -0
  6. dirsql-0.2.7/docs/AGENTS.md +51 -0
  7. dirsql-0.2.7/docs/api/index.md +232 -0
  8. dirsql-0.2.7/docs/getting-started.md +186 -0
  9. dirsql-0.2.7/docs/guide/async.md +224 -0
  10. dirsql-0.2.7/docs/guide/cli.md +124 -0
  11. dirsql-0.2.7/docs/guide/config.md +205 -0
  12. dirsql-0.2.7/docs/guide/crdt.md +160 -0
  13. dirsql-0.2.7/docs/guide/querying.md +216 -0
  14. dirsql-0.2.7/docs/guide/tables.md +268 -0
  15. dirsql-0.2.7/docs/guide/watching.md +264 -0
  16. dirsql-0.2.7/docs/index.md +81 -0
  17. dirsql-0.2.7/docs/migrations.md +8 -0
  18. dirsql-0.2.7/docs/package.json +18 -0
  19. dirsql-0.2.7/docs/playwright.config.ts +40 -0
  20. dirsql-0.2.7/docs/pnpm-lock.yaml +1952 -0
  21. dirsql-0.2.7/docs/pnpm-workspace.yaml +2 -0
  22. dirsql-0.2.7/docs/tests/integration/home.spec.ts +6 -0
  23. dirsql-0.2.7/docs/tests/integration/language-flag.spec.ts +66 -0
  24. dirsql-0.2.7/docs/tests/unit/config.test.ts +9 -0
  25. dirsql-0.2.7/docs/tests/unit/lang.test.ts +35 -0
  26. dirsql-0.2.7/docs/vitest.config.ts +8 -0
  27. dirsql-0.2.7/packages/python/docs/.claude/CLAUDE.md +3 -0
  28. dirsql-0.2.7/packages/python/docs/.vitepress/config.ts +63 -0
  29. dirsql-0.2.7/packages/python/docs/.vitepress/theme/index.ts +154 -0
  30. dirsql-0.2.7/packages/python/docs/.vitepress/theme/lang.ts +33 -0
  31. dirsql-0.2.7/packages/python/docs/AGENTS.md +51 -0
  32. dirsql-0.2.7/packages/python/docs/api/index.md +232 -0
  33. dirsql-0.2.7/packages/python/docs/getting-started.md +186 -0
  34. dirsql-0.2.7/packages/python/docs/guide/async.md +224 -0
  35. dirsql-0.2.7/packages/python/docs/guide/cli.md +124 -0
  36. dirsql-0.2.7/packages/python/docs/guide/config.md +205 -0
  37. dirsql-0.2.7/packages/python/docs/guide/crdt.md +160 -0
  38. dirsql-0.2.7/packages/python/docs/guide/querying.md +216 -0
  39. dirsql-0.2.7/packages/python/docs/guide/tables.md +268 -0
  40. dirsql-0.2.7/packages/python/docs/guide/watching.md +264 -0
  41. dirsql-0.2.7/packages/python/docs/index.md +81 -0
  42. dirsql-0.2.7/packages/python/docs/migrations.md +8 -0
  43. dirsql-0.2.7/packages/python/docs/package.json +18 -0
  44. dirsql-0.2.7/packages/python/docs/playwright.config.ts +40 -0
  45. dirsql-0.2.7/packages/python/docs/pnpm-lock.yaml +1952 -0
  46. dirsql-0.2.7/packages/python/docs/pnpm-workspace.yaml +2 -0
  47. dirsql-0.2.7/packages/python/docs/tests/integration/home.spec.ts +6 -0
  48. dirsql-0.2.7/packages/python/docs/tests/integration/language-flag.spec.ts +66 -0
  49. dirsql-0.2.7/packages/python/docs/tests/unit/config.test.ts +9 -0
  50. dirsql-0.2.7/packages/python/docs/tests/unit/lang.test.ts +35 -0
  51. dirsql-0.2.7/packages/python/docs/vitest.config.ts +8 -0
  52. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/Cargo.toml +13 -0
  53. dirsql-0.2.7/packages/rust/docs/api/index.md +232 -0
  54. dirsql-0.2.7/packages/rust/docs/getting-started.md +186 -0
  55. dirsql-0.2.7/packages/rust/docs/guide/async.md +224 -0
  56. dirsql-0.2.7/packages/rust/docs/guide/cli.md +124 -0
  57. dirsql-0.2.7/packages/rust/docs/guide/config.md +205 -0
  58. dirsql-0.2.7/packages/rust/docs/guide/crdt.md +160 -0
  59. dirsql-0.2.7/packages/rust/docs/guide/querying.md +216 -0
  60. dirsql-0.2.7/packages/rust/docs/guide/tables.md +268 -0
  61. dirsql-0.2.7/packages/rust/docs/guide/watching.md +264 -0
  62. dirsql-0.2.7/packages/rust/docs/index.md +81 -0
  63. dirsql-0.2.7/packages/rust/docs/migrations.md +8 -0
  64. {dirsql-0.2.5 → dirsql-0.2.7}/pyproject.toml +2 -1
  65. {dirsql-0.2.5 → dirsql-0.2.7}/Cargo.lock +0 -0
  66. {dirsql-0.2.5 → dirsql-0.2.7}/Cargo.toml +0 -0
  67. {dirsql-0.2.5 → dirsql-0.2.7}/README.md +0 -0
  68. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/Cargo.toml +0 -0
  69. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/README.md +0 -0
  70. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/python/conftest.py +0 -0
  71. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/src/lib.rs +0 -0
  72. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/tests/__init__.py +0 -0
  73. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/tests/conftest.py +0 -0
  74. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/tests/integration/__init__.py +0 -0
  75. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/tests/integration/test_async_dirsql.py +0 -0
  76. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/tests/integration/test_binding.py +0 -0
  77. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/tests/integration/test_dirsql.py +0 -0
  78. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/tests/integration/test_docs_examples.py +0 -0
  79. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/tests/integration/test_docs_gaps.py +0 -0
  80. {dirsql-0.2.5 → dirsql-0.2.7}/packages/python/tests/integration/test_from_config.py +0 -0
  81. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/README.md +0 -0
  82. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/benches/db_bench.rs +0 -0
  83. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/benches/differ_bench.rs +0 -0
  84. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/benches/matcher_bench.rs +0 -0
  85. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/benches/scanner_bench.rs +0 -0
  86. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/bin/dirsql.rs +0 -0
  87. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/cli/mod.rs +0 -0
  88. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/cli/router.rs +0 -0
  89. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/cli/serialize.rs +0 -0
  90. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/cli/server.rs +0 -0
  91. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/config.rs +0 -0
  92. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/db.rs +0 -0
  93. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/differ.rs +0 -0
  94. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/lib.rs +0 -0
  95. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/matcher.rs +0 -0
  96. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/parser.rs +0 -0
  97. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/scanner.rs +0 -0
  98. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/src/watcher.rs +0 -0
  99. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/tests/async_sdk.rs +0 -0
  100. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/tests/cli_e2e.rs +0 -0
  101. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/tests/cli_integration.rs +0 -0
  102. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/tests/docs_examples.rs +0 -0
  103. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/tests/docs_gaps.rs +0 -0
  104. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/tests/from_config.rs +0 -0
  105. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/tests/readonly_query.rs +0 -0
  106. {dirsql-0.2.5 → dirsql-0.2.7}/packages/rust/tests/sdk.rs +0 -0
  107. {dirsql-0.2.5 → dirsql-0.2.7}/python/dirsql/__init__.py +0 -0
  108. {dirsql-0.2.5 → dirsql-0.2.7}/python/dirsql/_async.py +0 -0
  109. {dirsql-0.2.5 → dirsql-0.2.7}/python/dirsql/_cli/__init__.py +0 -0
  110. {dirsql-0.2.5 → dirsql-0.2.7}/python/dirsql/_cli/binary_path.py +0 -0
  111. {dirsql-0.2.5 → dirsql-0.2.7}/python/dirsql/_cli/binary_path_test.py +0 -0
  112. {dirsql-0.2.5 → dirsql-0.2.7}/python/dirsql/_cli/is_windows.py +0 -0
  113. {dirsql-0.2.5 → dirsql-0.2.7}/python/dirsql/_cli/is_windows_test.py +0 -0
  114. {dirsql-0.2.5 → dirsql-0.2.7}/python/dirsql/_cli/main.py +0 -0
  115. {dirsql-0.2.5 → dirsql-0.2.7}/python/dirsql/_cli/main_test.py +0 -0
  116. {dirsql-0.2.5 → dirsql-0.2.7}/python/dirsql/test_async.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.2.5
3
+ Version: 0.2.7
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'
@@ -0,0 +1,3 @@
1
+ # dirsql docs
2
+
3
+ @../AGENTS.md
@@ -0,0 +1,63 @@
1
+ import { defineConfig } from 'vitepress'
2
+
3
+ export default defineConfig({
4
+ title: 'dirsql',
5
+ description: 'Ephemeral SQL index over a local directory. Watches a filesystem, ingests structured files into an in-memory SQLite database, and exposes a SQL query interface.',
6
+ base: '/dirsql/',
7
+
8
+ themeConfig: {
9
+ search: {
10
+ provider: 'local'
11
+ },
12
+
13
+ nav: [
14
+ { text: 'Getting Started', link: '/getting-started' },
15
+ { text: 'Guide', link: '/guide/tables' },
16
+ { text: 'Reference', link: '/api/' },
17
+ { text: 'Migrations', link: '/migrations' },
18
+ { text: 'GitHub', link: 'https://github.com/thekevinscott/dirsql' }
19
+ ],
20
+
21
+ sidebar: [
22
+ {
23
+ text: 'Tutorials',
24
+ items: [
25
+ { text: 'Getting Started', link: '/getting-started' }
26
+ ]
27
+ },
28
+ {
29
+ text: 'How-to Guides',
30
+ items: [
31
+ { text: 'Configuration File', link: '/guide/config' },
32
+ { text: 'Defining Tables', link: '/guide/tables' },
33
+ { text: 'Querying', link: '/guide/querying' },
34
+ { text: 'File Watching', link: '/guide/watching' },
35
+ { text: 'Async API', link: '/guide/async' },
36
+ { text: 'Command-Line Interface', link: '/guide/cli' },
37
+ { text: 'Collaboration with CRDTs', link: '/guide/crdt' }
38
+ ]
39
+ },
40
+ {
41
+ text: 'Reference',
42
+ items: [
43
+ { text: 'API Reference', link: '/api/' },
44
+ { text: 'Migrations', link: '/migrations' }
45
+ ]
46
+ },
47
+ ],
48
+
49
+ outline: {
50
+ level: [2, 3],
51
+ label: 'On this page'
52
+ },
53
+
54
+ socialLinks: [
55
+ { icon: 'github', link: 'https://github.com/thekevinscott/dirsql' }
56
+ ],
57
+
58
+ footer: {
59
+ message: 'Released under the MIT License.',
60
+ copyright: 'Copyright 2024-present'
61
+ }
62
+ }
63
+ })
@@ -0,0 +1,154 @@
1
+ import DefaultTheme from 'vitepress/theme'
2
+ import type { Theme } from 'vitepress'
3
+
4
+ /**
5
+ * Language tab persistence for VitePress code groups.
6
+ *
7
+ * VitePress code groups render as:
8
+ * .vp-code-group
9
+ * .tabs
10
+ * input[type=radio] (hidden, controls checked state)
11
+ * label[for=...] (visible tab)
12
+ * input
13
+ * label
14
+ * ...
15
+ * .blocks
16
+ * div.language-python.active (visible block)
17
+ * div.language-typescript (hidden block)
18
+ * ...
19
+ *
20
+ * Tab switching is driven by click events on the hidden inputs.
21
+ * Active blocks are toggled via the .active CSS class.
22
+ */
23
+
24
+ import { STORAGE_KEY, parseLanguageFromUrl } from './lang'
25
+
26
+ const getLanguageFromUrl = (): string | null =>
27
+ parseLanguageFromUrl(window.location.search, window.location.hash)
28
+
29
+ /**
30
+ * Given a code group element, return parallel arrays of inputs, labels, and blocks.
31
+ */
32
+ function getGroupParts(group: Element) {
33
+ const inputs = Array.from(group.querySelectorAll<HTMLInputElement>('.tabs input'))
34
+ const labels = Array.from(group.querySelectorAll<HTMLLabelElement>('.tabs label'))
35
+ const blocks = group.querySelector('.blocks')
36
+ const blockChildren = blocks
37
+ ? Array.from(blocks.children) as HTMLElement[]
38
+ : []
39
+ return { inputs, labels, blocks: blockChildren }
40
+ }
41
+
42
+ function applyStoredLanguage() {
43
+ const lang = localStorage.getItem(STORAGE_KEY)
44
+ if (!lang) return
45
+
46
+ document.querySelectorAll('.vp-code-group').forEach((group) => {
47
+ const { inputs, labels, blocks } = getGroupParts(group)
48
+
49
+ const idx = labels.findIndex(
50
+ (label) => label.textContent?.trim().toLowerCase() === lang
51
+ )
52
+ if (idx < 0) return
53
+
54
+ const input = inputs[idx]
55
+ if (!input || input.checked) return
56
+
57
+ // Check the radio button (drives CSS styling via input:checked + label)
58
+ input.checked = true
59
+
60
+ // Toggle .active class on blocks (drives visibility)
61
+ blocks.forEach((block, j) => {
62
+ block.classList.toggle('active', j === idx)
63
+ })
64
+ })
65
+ }
66
+
67
+ function observeTabClicks() {
68
+ // VitePress code groups use click events on inputs, not change events.
69
+ window.addEventListener('click', (e) => {
70
+ const el = e.target as HTMLElement
71
+ if (!el.matches('.vp-code-group input')) return
72
+
73
+ // input -> .tabs -> .vp-code-group
74
+ const group = el.parentElement?.parentElement
75
+ if (!group) return
76
+
77
+ const { inputs, labels } = getGroupParts(group)
78
+ const idx = inputs.indexOf(el as HTMLInputElement)
79
+ if (idx < 0 || !labels[idx]) return
80
+
81
+ const lang = labels[idx].textContent?.trim().toLowerCase()
82
+ if (!lang) return
83
+
84
+ localStorage.setItem(STORAGE_KEY, lang)
85
+
86
+ // Sync all other code groups on the same page
87
+ document.querySelectorAll('.vp-code-group').forEach((otherGroup) => {
88
+ if (otherGroup === group) return
89
+ const other = getGroupParts(otherGroup)
90
+ const otherIdx = other.labels.findIndex(
91
+ (l) => l.textContent?.trim().toLowerCase() === lang
92
+ )
93
+ if (otherIdx < 0) return
94
+ const otherInput = other.inputs[otherIdx]
95
+ if (!otherInput || otherInput.checked) return
96
+ otherInput.checked = true
97
+ other.blocks.forEach((block, j) => {
98
+ block.classList.toggle('active', j === otherIdx)
99
+ })
100
+ })
101
+ })
102
+ }
103
+
104
+ export default {
105
+ extends: DefaultTheme,
106
+ enhanceApp() {
107
+ if (typeof window === 'undefined') return
108
+
109
+ // URL flag wins over any previously stored preference, but we only persist
110
+ // once we've confirmed the value matches a real tab -- typos shouldn't
111
+ // poison localStorage. `pendingUrlLang` is consumed the first time a
112
+ // matching render arrives.
113
+ let pendingUrlLang: string | null = getLanguageFromUrl()
114
+ const consumePendingLang = () => {
115
+ if (!pendingUrlLang) return
116
+ const matches = Array.from(
117
+ document.querySelectorAll<HTMLLabelElement>('.vp-code-group .tabs label')
118
+ ).some((l) => l.textContent?.trim().toLowerCase() === pendingUrlLang)
119
+ if (!matches) return
120
+ localStorage.setItem(STORAGE_KEY, pendingUrlLang)
121
+ pendingUrlLang = null
122
+ }
123
+ window.addEventListener('hashchange', () => {
124
+ pendingUrlLang = getLanguageFromUrl()
125
+ consumePendingLang()
126
+ applyStoredLanguage()
127
+ })
128
+
129
+ observeTabClicks()
130
+
131
+ // Use MutationObserver to apply stored preference after VitePress renders
132
+ const observer = new MutationObserver(() => {
133
+ consumePendingLang()
134
+ applyStoredLanguage()
135
+ })
136
+
137
+ const tryObserve = () => {
138
+ const content = document.querySelector('.VPContent')
139
+ if (content) {
140
+ observer.observe(content, { childList: true, subtree: true })
141
+ consumePendingLang()
142
+ applyStoredLanguage()
143
+ } else {
144
+ requestAnimationFrame(tryObserve)
145
+ }
146
+ }
147
+
148
+ if (document.readyState === 'loading') {
149
+ document.addEventListener('DOMContentLoaded', tryObserve)
150
+ } else {
151
+ tryObserve()
152
+ }
153
+ },
154
+ } satisfies Theme
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Pure helpers for the code-group language URL flag.
3
+ * Extracted from theme/index.ts so they can be unit tested without a DOM.
4
+ */
5
+
6
+ export const STORAGE_KEY = 'dirsql-preferred-lang'
7
+ export const URL_PARAM = 'lang'
8
+
9
+ /**
10
+ * Read a language preference from a URL's search and/or hash components.
11
+ * Accepts the `window.location.search`/`window.location.hash` strings
12
+ * (with or without their leading `?` / `#`). The query form takes
13
+ * precedence over the hash form. Returns the lowercased language name,
14
+ * or null when no flag is present.
15
+ */
16
+ export function parseLanguageFromUrl(
17
+ search: string,
18
+ hash: string
19
+ ): string | null {
20
+ try {
21
+ const query = new URLSearchParams(search).get(URL_PARAM)
22
+ if (query) return query.trim().toLowerCase()
23
+
24
+ const stripped = hash.replace(/^#/, '')
25
+ if (stripped) {
26
+ const fromHash = new URLSearchParams(stripped).get(URL_PARAM)
27
+ if (fromHash) return fromHash.trim().toLowerCase()
28
+ }
29
+ } catch {
30
+ // URL APIs can throw on exotic inputs; fall through to null.
31
+ }
32
+ return null
33
+ }
@@ -0,0 +1,51 @@
1
+ # Documentation Development
2
+
3
+ Instructions for agents working on `dirsql` documentation.
4
+
5
+ ## Stack
6
+
7
+ The docs site uses [VitePress](https://vitepress.dev/). Source files are in `docs/` at the project root.
8
+
9
+ ## Running locally
10
+
11
+ ```bash
12
+ cd docs
13
+ pnpm install
14
+ pnpm dev
15
+ ```
16
+
17
+ This starts a local dev server (default: `http://localhost:5173/dirsql/`). The site hot-reloads on file changes.
18
+
19
+ ## Building
20
+
21
+ ```bash
22
+ cd docs
23
+ pnpm build
24
+ ```
25
+
26
+ The build must succeed before pushing. VitePress will fail on broken links, missing assets, and syntax errors in markdown.
27
+
28
+ ## Testing changes
29
+
30
+ Before pushing any docs changes:
31
+
32
+ 1. Run `pnpm build` in `docs/` and confirm it exits cleanly
33
+ 2. Spot-check the built output with `pnpm preview`
34
+ 3. Verify sidebar navigation, code blocks, and internal links render correctly
35
+
36
+ ## Structure
37
+
38
+ The docs follow the [Diataxis](https://diataxis.fr/) framework:
39
+
40
+ - **Tutorials** (`getting-started.md`) -- learning-oriented, step-by-step
41
+ - **How-to Guides** (`guide/`) -- task-oriented, practical recipes
42
+ - **Reference** (`api/`) -- information-oriented, API details
43
+ - **Explanation** (`architecture.md`) -- understanding-oriented, design decisions
44
+
45
+ ## Conventions
46
+
47
+ - Wrap `dirsql` in backticks in all prose text
48
+ - Use VitePress [code group](https://vitepress.dev/guide/markdown#code-groups) syntax (`::: code-group`) for multi-language examples with `Python`, `Rust`, and `TypeScript` tabs
49
+ - Internal links use relative paths (e.g., `./guide/tables.md`)
50
+ - The VitePress config is at `docs/.vitepress/config.ts`
51
+ - The site is deployed under the `/dirsql/` base path
@@ -0,0 +1,232 @@
1
+ ---
2
+ canonical: https://thekevinscott.github.io/dirsql/api/
3
+ ---
4
+
5
+ # API Reference
6
+
7
+ > Online: <https://thekevinscott.github.io/dirsql/api/>
8
+
9
+ ## DirSQL
10
+
11
+ ### Import
12
+
13
+ ::: code-group
14
+
15
+ ```python [Python]
16
+ from dirsql import DirSQL
17
+ ```
18
+
19
+ ```rust [Rust]
20
+ use dirsql::DirSQL;
21
+ ```
22
+
23
+ ```typescript [TypeScript]
24
+ import { DirSQL } from 'dirsql';
25
+ ```
26
+
27
+ :::
28
+
29
+ ### Constructor
30
+
31
+ ::: code-group
32
+
33
+ ```python [Python]
34
+ DirSQL(
35
+ root: str | None = None,
36
+ *,
37
+ tables: list[Table] | None = None,
38
+ ignore: list[str] | None = None,
39
+ config: str | None = None,
40
+ )
41
+ ```
42
+
43
+ ```rust [Rust]
44
+ DirSQL::builder()
45
+ .root(root) // optional
46
+ .tables(tables) // optional; append with .table(t)
47
+ .ignore(patterns) // optional
48
+ .config(config_toml_path) // optional
49
+ .build() // -> Result<DirSQL>
50
+ ```
51
+
52
+ ```typescript [TypeScript]
53
+ new DirSQL(configPath: string)
54
+ // or
55
+ new DirSQL({
56
+ root?: string,
57
+ tables?: TableDef[],
58
+ ignore?: string[],
59
+ config?: string,
60
+ })
61
+ ```
62
+
63
+ :::
64
+
65
+ Creates an in-memory SQLite index over the given directory. At least one of `root` or `config` must be supplied.
66
+
67
+ When both `root` and `config` are supplied -- or when `config` declares `[dirsql].root` -- the explicit `root` wins and a warning is emitted on stderr. A `[dirsql].root` declared in the config file is resolved relative to the config file's parent directory.
68
+
69
+ In Python, the constructor starts scanning in a background thread and returns immediately. Call `await db.ready()` before querying. In Rust, `.build()` scans synchronously; use `.build_async()` (via `AsyncDirSQL`) for the tokio-driven equivalent. In TypeScript, scanning starts immediately and `db.ready` resolves when the scan finishes.
70
+
71
+ **Parameters:**
72
+
73
+ - `root` -- Path to the directory to index. Optional if `config` is supplied.
74
+ - `tables` -- List of `Table` definitions. Each defines a SQLite table, a glob pattern, and an extract function.
75
+ - `ignore` -- Optional list of glob patterns. Files matching any ignore pattern are skipped regardless of table globs.
76
+ - `config` -- Optional path to a `.dirsql.toml` config file. Its `[[table]]` entries are appended to any programmatic `tables`; its `[dirsql].ignore` patterns are appended to any explicit `ignore`; its optional `[dirsql].root` supplies the root directory when `root` is not passed explicitly.
77
+
78
+ ### Methods
79
+
80
+ #### `ready`
81
+
82
+ ::: code-group
83
+
84
+ ```python [Python]
85
+ await db.ready() -> None
86
+ ```
87
+
88
+ ```rust [Rust]
89
+ db.ready().await -> Result<()>
90
+ ```
91
+
92
+ ```typescript [TypeScript]
93
+ await db.ready // awaitable property
94
+ ```
95
+
96
+ :::
97
+
98
+ Wait for the initial scan to complete. Re-raises any exception from the scan. Safe to call multiple times.
99
+
100
+ #### `query`
101
+
102
+ ::: code-group
103
+
104
+ ```python [Python]
105
+ await db.query(sql: str) -> list[dict]
106
+ ```
107
+
108
+ ```rust [Rust]
109
+ db.query(sql: &str) -> Result<Vec<HashMap<String, Value>>>
110
+ ```
111
+
112
+ ```typescript [TypeScript]
113
+ await db.query(sql: string): Promise<Record<string, unknown>[]>
114
+ ```
115
+
116
+ :::
117
+
118
+ Execute a SQL query against the in-memory database. Returns results keyed by column name. Internal tracking columns (`_dirsql_file_path`, `_dirsql_row_index`) are excluded from results.
119
+
120
+ #### `watch`
121
+
122
+ ::: code-group
123
+
124
+ ```python [Python]
125
+ async for event in db.watch(): # AsyncIterator[RowEvent]
126
+ ...
127
+ ```
128
+
129
+ ```rust [Rust]
130
+ let mut stream = db.watch(); // impl Stream<Item = RowEvent>
131
+ while let Some(event) = stream.next().await { ... }
132
+ ```
133
+
134
+ ```typescript [TypeScript]
135
+ for await (const event of db.watch()) { // AsyncIterable<RowEvent>
136
+ ...
137
+ }
138
+ ```
139
+
140
+ :::
141
+
142
+ Returns an async iterable of `RowEvent` objects. The file watcher starts automatically on first iteration. The iterator never terminates on its own.
143
+
144
+ ---
145
+
146
+ ## Table
147
+
148
+ ### Import
149
+
150
+ ::: code-group
151
+
152
+ ```python [Python]
153
+ from dirsql import Table
154
+ ```
155
+
156
+ ```rust [Rust]
157
+ use dirsql::Table;
158
+ ```
159
+
160
+ ```typescript [TypeScript]
161
+ import { Table } from 'dirsql';
162
+ ```
163
+
164
+ :::
165
+
166
+ ### Constructor
167
+
168
+ ::: code-group
169
+
170
+ ```python [Python]
171
+ Table(*, ddl: str, glob: str, extract: Callable[[str, str], list[dict]])
172
+ ```
173
+
174
+ ```rust [Rust]
175
+ Table::new(ddl: &str, glob: &str, extract: fn(&str, &str) -> Vec<Value>)
176
+ ```
177
+
178
+ ```typescript [TypeScript]
179
+ new Table({ ddl: string, glob: string, extract: (path: string, content: string) => Record<string, unknown>[] })
180
+ ```
181
+
182
+ :::
183
+
184
+ Defines a mapping from files to SQLite table rows.
185
+
186
+ **Parameters:**
187
+
188
+ - `ddl` -- A `CREATE TABLE` statement. The table name is parsed from this DDL.
189
+ - `glob` -- A glob pattern matched against file paths relative to the root directory.
190
+ - `extract` -- A callable `(path, content) -> list[dict]`. Receives the relative file path and file content as strings. Returns a list of dicts/maps mapping column names to values. Return an empty list to skip a file.
191
+
192
+ **Attributes:**
193
+
194
+ - `ddl` -- The DDL string (read-only).
195
+ - `glob` -- The glob pattern (read-only).
196
+
197
+ ---
198
+
199
+ ## RowEvent
200
+
201
+ ### Import
202
+
203
+ ::: code-group
204
+
205
+ ```python [Python]
206
+ from dirsql import RowEvent
207
+ ```
208
+
209
+ ```rust [Rust]
210
+ use dirsql::RowEvent;
211
+ ```
212
+
213
+ ```typescript [TypeScript]
214
+ import { RowEvent } from 'dirsql';
215
+ ```
216
+
217
+ :::
218
+
219
+ Emitted by the watch stream. Represents a change to a row in the database caused by a filesystem event.
220
+
221
+ **Attributes:**
222
+
223
+ | Attribute | Python | Rust | TypeScript |
224
+ |-----------|--------|------|------------|
225
+ | Table name | `table: str` | `table: String` | `table: string` |
226
+ | Action | `action: str` | `action: Action` | `action: string` |
227
+ | Current/new row | `row: dict \| None` | `row: Option<HashMap>` | `row?: Record` |
228
+ | Previous row | `old_row: dict \| None` | `old_row: Option<HashMap>` | `oldRow?: Record` |
229
+ | Error message | `error: str \| None` | `error: Option<String>` | `error?: string` |
230
+ | File path | `file_path: str \| None` | `file_path: Option<String>` | `filePath?: string` |
231
+
232
+ Action values: `"insert"`, `"update"`, `"delete"`, `"error"`.