dirsql 0.3.6__tar.gz → 0.3.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.
- {dirsql-0.3.6 → dirsql-0.3.7}/Cargo.lock +1 -1
- {dirsql-0.3.6 → dirsql-0.3.7}/PKG-INFO +7 -7
- {dirsql-0.3.6/packages/python → dirsql-0.3.7}/README.md +6 -6
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/api/index.md +4 -4
- {dirsql-0.3.6/packages/python → dirsql-0.3.7}/docs/cli/config.md +2 -14
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/cli/index.md +6 -4
- {dirsql-0.3.6/packages/rust → dirsql-0.3.7}/docs/cli/server.md +18 -0
- {dirsql-0.3.6/packages/python → dirsql-0.3.7}/docs/getting-started.md +9 -8
- {dirsql-0.3.6/packages/python → dirsql-0.3.7}/docs/guide/async.md +4 -3
- {dirsql-0.3.6/packages/rust → dirsql-0.3.7}/docs/guide/crdt.md +4 -3
- {dirsql-0.3.6/packages/rust → dirsql-0.3.7}/docs/guide/tables.md +28 -27
- {dirsql-0.3.6/packages/rust → dirsql-0.3.7}/docs/guide/watching.md +4 -3
- {dirsql-0.3.6/packages/rust → dirsql-0.3.7}/docs/index.md +4 -3
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/Cargo.toml +1 -1
- {dirsql-0.3.6 → dirsql-0.3.7/packages/python}/README.md +6 -6
- {dirsql-0.3.6/packages/rust → dirsql-0.3.7/packages/python}/docs/api/index.md +4 -4
- {dirsql-0.3.6 → dirsql-0.3.7/packages/python}/docs/cli/config.md +2 -14
- {dirsql-0.3.6/packages/rust → dirsql-0.3.7/packages/python}/docs/cli/index.md +6 -4
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/cli/server.md +18 -0
- {dirsql-0.3.6 → dirsql-0.3.7/packages/python}/docs/getting-started.md +9 -8
- {dirsql-0.3.6/packages/rust → dirsql-0.3.7/packages/python}/docs/guide/async.md +4 -3
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/guide/crdt.md +4 -3
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/guide/tables.md +28 -27
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/guide/watching.md +4 -3
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/index.md +4 -3
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/src/lib.rs +3 -4
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/tests/integration/test_async_dirsql.py +28 -16
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/tests/integration/test_dirsql.py +59 -34
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/tests/integration/test_docs_examples.py +56 -25
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/tests/integration/test_docs_gaps.py +10 -6
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/tests/integration/test_persist.py +12 -5
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/README.md +4 -1
- {dirsql-0.3.6/packages/python → dirsql-0.3.7/packages/rust}/docs/api/index.md +4 -4
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/docs/cli/config.md +2 -14
- {dirsql-0.3.6/packages/python → dirsql-0.3.7/packages/rust}/docs/cli/index.md +6 -4
- {dirsql-0.3.6 → dirsql-0.3.7/packages/rust}/docs/cli/server.md +18 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/docs/getting-started.md +9 -8
- {dirsql-0.3.6 → dirsql-0.3.7/packages/rust}/docs/guide/async.md +4 -3
- {dirsql-0.3.6 → dirsql-0.3.7/packages/rust}/docs/guide/crdt.md +4 -3
- {dirsql-0.3.6 → dirsql-0.3.7/packages/rust}/docs/guide/tables.md +28 -27
- {dirsql-0.3.6 → dirsql-0.3.7/packages/rust}/docs/guide/watching.md +4 -3
- {dirsql-0.3.6 → dirsql-0.3.7/packages/rust}/docs/index.md +4 -3
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/bin/dirsql.rs +53 -8
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/lib.rs +30 -29
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/persist.rs +6 -6
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/tests/async_sdk.rs +9 -11
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/tests/cli_e2e.rs +45 -5
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/tests/cli_integration.rs +28 -15
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/tests/docs_examples.rs +43 -26
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/tests/docs_gaps.rs +15 -22
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/tests/init_e2e.rs +1 -4
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/tests/persist.rs +11 -13
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/tests/readonly_query.rs +2 -1
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/tests/sdk.rs +65 -40
- {dirsql-0.3.6 → dirsql-0.3.7}/Cargo.toml +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/dirsql/__init__.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/dirsql/_async.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/dirsql/_cli/__init__.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/dirsql/_cli/binary_path.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/dirsql/_cli/is_windows.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/dirsql/_cli/main.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/dirsql/test_async.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/.vitepress/config.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/AGENTS.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/cli/http-api.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/cli/init.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/guide/persistence.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/guide/querying.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/migrations.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/package.json +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/playwright.config.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/docs/vitest.config.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/conftest.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/.claude/CLAUDE.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/.vitepress/config.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/.vitepress/theme/index.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/.vitepress/theme/lang.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/AGENTS.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/cli/http-api.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/cli/init.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/guide/persistence.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/guide/querying.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/migrations.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/package.json +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/playwright.config.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/pnpm-lock.yaml +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/pnpm-workspace.yaml +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/tests/integration/home.spec.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/tests/integration/language-flag.spec.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/tests/unit/config.test.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/tests/unit/lang.test.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/docs/vitest.config.ts +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/tests/__init__.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/tests/conftest.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/tests/e2e/__init__.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/tests/integration/__init__.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/tests/integration/test_binding.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/python/tests/integration/test_from_config.py +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/Cargo.toml +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/benches/db_bench.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/benches/differ_bench.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/benches/matcher_bench.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/benches/scanner_bench.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/docs/cli/http-api.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/docs/cli/init.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/docs/guide/persistence.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/docs/guide/querying.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/docs/migrations.md +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/cli/init.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/cli/mod.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/cli/router.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/cli/serialize.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/cli/server.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/config.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/db.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/differ.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/matcher.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/scanner.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/src/watcher.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/tests/from_config.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/packages/rust/tests/init_integration.rs +0 -0
- {dirsql-0.3.6 → dirsql-0.3.7}/pyproject.toml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dirsql
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.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'
|
|
@@ -64,13 +64,13 @@ async def main():
|
|
|
64
64
|
Table(
|
|
65
65
|
ddl="CREATE TABLE comments (id TEXT, body TEXT, author TEXT)",
|
|
66
66
|
glob="comments/**/index.jsonl",
|
|
67
|
-
extract=lambda path
|
|
67
|
+
extract=lambda path: [
|
|
68
68
|
{
|
|
69
69
|
"id": os.path.basename(os.path.dirname(path)),
|
|
70
70
|
"body": row["body"],
|
|
71
71
|
"author": row["author"],
|
|
72
72
|
}
|
|
73
|
-
for line in
|
|
73
|
+
for line in open(path, encoding="utf-8").read().splitlines()
|
|
74
74
|
for row in [json.loads(line)]
|
|
75
75
|
],
|
|
76
76
|
),
|
|
@@ -94,12 +94,12 @@ db = DirSQL(
|
|
|
94
94
|
Table(
|
|
95
95
|
ddl="CREATE TABLE posts (title TEXT, author_id TEXT)",
|
|
96
96
|
glob="posts/*.json",
|
|
97
|
-
extract=lambda path
|
|
97
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
98
98
|
),
|
|
99
99
|
Table(
|
|
100
100
|
ddl="CREATE TABLE authors (id TEXT, name TEXT)",
|
|
101
101
|
glob="authors/*.json",
|
|
102
|
-
extract=lambda path
|
|
102
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
103
103
|
),
|
|
104
104
|
],
|
|
105
105
|
)
|
|
@@ -139,7 +139,7 @@ async def main():
|
|
|
139
139
|
Table(
|
|
140
140
|
ddl="CREATE TABLE items (name TEXT)",
|
|
141
141
|
glob="**/*.json",
|
|
142
|
-
extract=lambda path
|
|
142
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
143
143
|
),
|
|
144
144
|
],
|
|
145
145
|
)
|
|
@@ -165,7 +165,7 @@ Defines how files map to a SQL table.
|
|
|
165
165
|
|
|
166
166
|
- **`ddl`** (`str`): A `CREATE TABLE` statement defining the schema.
|
|
167
167
|
- **`glob`** (`str`): A glob pattern matched against file paths relative to root.
|
|
168
|
-
- **`extract`** (`Callable[[str
|
|
168
|
+
- **`extract`** (`Callable[[str], list[dict]]`): A function receiving the matched file's absolute filesystem path and returning a list of row dicts. dirsql does not read file contents; a callback that needs the file body reads it itself (e.g. `open(path, encoding="utf-8").read()`). Each dict's keys must match the DDL column names.
|
|
169
169
|
|
|
170
170
|
### `DirSQL(root=None, *, tables=None, ignore=None, config=None)`
|
|
171
171
|
|
|
@@ -47,13 +47,13 @@ async def main():
|
|
|
47
47
|
Table(
|
|
48
48
|
ddl="CREATE TABLE comments (id TEXT, body TEXT, author TEXT)",
|
|
49
49
|
glob="comments/**/index.jsonl",
|
|
50
|
-
extract=lambda path
|
|
50
|
+
extract=lambda path: [
|
|
51
51
|
{
|
|
52
52
|
"id": os.path.basename(os.path.dirname(path)),
|
|
53
53
|
"body": row["body"],
|
|
54
54
|
"author": row["author"],
|
|
55
55
|
}
|
|
56
|
-
for line in
|
|
56
|
+
for line in open(path, encoding="utf-8").read().splitlines()
|
|
57
57
|
for row in [json.loads(line)]
|
|
58
58
|
],
|
|
59
59
|
),
|
|
@@ -77,12 +77,12 @@ db = DirSQL(
|
|
|
77
77
|
Table(
|
|
78
78
|
ddl="CREATE TABLE posts (title TEXT, author_id TEXT)",
|
|
79
79
|
glob="posts/*.json",
|
|
80
|
-
extract=lambda path
|
|
80
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
81
81
|
),
|
|
82
82
|
Table(
|
|
83
83
|
ddl="CREATE TABLE authors (id TEXT, name TEXT)",
|
|
84
84
|
glob="authors/*.json",
|
|
85
|
-
extract=lambda path
|
|
85
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
86
86
|
),
|
|
87
87
|
],
|
|
88
88
|
)
|
|
@@ -122,7 +122,7 @@ async def main():
|
|
|
122
122
|
Table(
|
|
123
123
|
ddl="CREATE TABLE items (name TEXT)",
|
|
124
124
|
glob="**/*.json",
|
|
125
|
-
extract=lambda path
|
|
125
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
126
126
|
),
|
|
127
127
|
],
|
|
128
128
|
)
|
|
@@ -148,7 +148,7 @@ Defines how files map to a SQL table.
|
|
|
148
148
|
|
|
149
149
|
- **`ddl`** (`str`): A `CREATE TABLE` statement defining the schema.
|
|
150
150
|
- **`glob`** (`str`): A glob pattern matched against file paths relative to root.
|
|
151
|
-
- **`extract`** (`Callable[[str
|
|
151
|
+
- **`extract`** (`Callable[[str], list[dict]]`): A function receiving the matched file's absolute filesystem path and returning a list of row dicts. dirsql does not read file contents; a callback that needs the file body reads it itself (e.g. `open(path, encoding="utf-8").read()`). Each dict's keys must match the DDL column names.
|
|
152
152
|
|
|
153
153
|
### `DirSQL(root=None, *, tables=None, ignore=None, config=None)`
|
|
154
154
|
|
|
@@ -168,15 +168,15 @@ import { Table } from 'dirsql';
|
|
|
168
168
|
::: code-group
|
|
169
169
|
|
|
170
170
|
```python [Python]
|
|
171
|
-
Table(*, ddl: str, glob: str, extract: Callable[[str
|
|
171
|
+
Table(*, ddl: str, glob: str, extract: Callable[[str], list[dict]])
|
|
172
172
|
```
|
|
173
173
|
|
|
174
174
|
```rust [Rust]
|
|
175
|
-
Table::new(ddl: &str, glob: &str, extract: fn(&str
|
|
175
|
+
Table::new(ddl: &str, glob: &str, extract: fn(&str) -> Vec<Value>)
|
|
176
176
|
```
|
|
177
177
|
|
|
178
178
|
```typescript [TypeScript]
|
|
179
|
-
new Table({ ddl: string, glob: string, extract: (path: string
|
|
179
|
+
new Table({ ddl: string, glob: string, extract: (path: string) => Record<string, unknown>[] })
|
|
180
180
|
```
|
|
181
181
|
|
|
182
182
|
:::
|
|
@@ -187,7 +187,7 @@ Defines a mapping from files to SQLite table rows.
|
|
|
187
187
|
|
|
188
188
|
- `ddl` -- A `CREATE TABLE` statement. The table name is parsed from this DDL.
|
|
189
189
|
- `glob` -- A glob pattern matched against file paths relative to the root directory.
|
|
190
|
-
- `extract` -- A callable `(path
|
|
190
|
+
- `extract` -- A callable `(path) -> list[dict]`. Receives the absolute filesystem path of the matched file. `dirsql` does not read file contents; a callback that needs the file body reads `path` itself. Returns a list of dicts/maps mapping column names to values. Return an empty list to skip a file.
|
|
191
191
|
|
|
192
192
|
**Attributes:**
|
|
193
193
|
|
|
@@ -6,18 +6,7 @@ canonical: https://thekevinscott.github.io/dirsql/cli/config
|
|
|
6
6
|
|
|
7
7
|
> Online: <https://thekevinscott.github.io/dirsql/cli/config>
|
|
8
8
|
|
|
9
|
-
`dirsql` can be configured with
|
|
10
|
-
way produce **one row per matched file**. Each row's columns come from
|
|
11
|
-
filesystem facts:
|
|
12
|
-
|
|
13
|
-
- **Glob path captures** — named `{placeholder}` segments in the glob.
|
|
14
|
-
- **Stat virtuals** — reserved `_`-prefixed columns for path-derived and
|
|
15
|
-
stat-derived metadata.
|
|
16
|
-
|
|
17
|
-
Content interpretation (parsing JSON, CSV, frontmatter, etc.) is **not**
|
|
18
|
-
configured in `.dirsql.toml`. If you need columns derived from file
|
|
19
|
-
contents, register a programmatic [`Table`](../guide/tables.md) whose `extract`
|
|
20
|
-
function does the parsing in your host language.
|
|
9
|
+
`dirsql` can be configured with an optional `.dirsql.toml` file (if omitted, server falls back to [defaults](./server.md#defaults)). `.dirsql.toml` defines how files are parsed into SQL tables.
|
|
21
10
|
|
|
22
11
|
## Basic Example
|
|
23
12
|
|
|
@@ -30,8 +19,7 @@ ddl = "CREATE TABLE posts (_path TEXT, _basename TEXT, _size INTEGER, _mtime IN
|
|
|
30
19
|
glob = "posts/*.md"
|
|
31
20
|
```
|
|
32
21
|
|
|
33
|
-
Each `posts/*.md` file produces one row
|
|
34
|
-
virtuals are surfaced as SQL columns.
|
|
22
|
+
Each `posts/*.md` file produces one row in the `posts` table.
|
|
35
23
|
|
|
36
24
|
## Loading a Config File
|
|
37
25
|
|
|
@@ -8,16 +8,18 @@ canonical: https://thekevinscott.github.io/dirsql/cli/
|
|
|
8
8
|
|
|
9
9
|
`dirsql` ships a command-line interface that starts an HTTP server exposing
|
|
10
10
|
the same indexing, querying, and watching functionality as the SDK — no host
|
|
11
|
-
language required.
|
|
12
|
-
config
|
|
11
|
+
language required. Run it in any directory to query your files over HTTP:
|
|
12
|
+
with no config it serves a default `files` table, and a
|
|
13
|
+
[`.dirsql.toml`](./config.md) config defines custom tables.
|
|
13
14
|
|
|
14
15
|
Everything you need to run `dirsql` as a CLI lives in this section:
|
|
15
16
|
|
|
16
17
|
- **[Installation](#installation)** — get the `dirsql` binary.
|
|
17
18
|
- **[Running the Server](./server.md)** — subcommands and flags.
|
|
18
19
|
- **[Generating a Config (`init`)](./init.md)** — scaffold a `.dirsql.toml`.
|
|
19
|
-
- **[Configuration File](./config.md)** — the `.dirsql.toml` format.
|
|
20
|
-
|
|
20
|
+
- **[Configuration File](./config.md)** — the `.dirsql.toml` format. Custom
|
|
21
|
+
tables are defined exclusively through this file; without it, the server
|
|
22
|
+
runs in [zero-config mode](./server.md#zero-config-mode).
|
|
21
23
|
- **[HTTP API](./http-api.md)** — the `POST /query` and `GET /events`
|
|
22
24
|
endpoints, status codes, and event streaming.
|
|
23
25
|
|
|
@@ -29,6 +29,24 @@ $ Running at localhost:7117
|
|
|
29
29
|
The server reads tables from a [`.dirsql.toml`](./config.md) config file. By
|
|
30
30
|
default it looks for `./.dirsql.toml`; override the path with `--config`.
|
|
31
31
|
|
|
32
|
+
## Defaults
|
|
33
|
+
|
|
34
|
+
If no config file is found, `dirsql` serves a single table named `files`, with one row per file under the directory
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
cd ~/some/directory # no .dirsql.toml here
|
|
38
|
+
dirsql
|
|
39
|
+
|
|
40
|
+
$ Running at localhost:7117
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
curl -s localhost:7117/query -H 'content-type: application/json' \
|
|
45
|
+
-d '{"sql":"SELECT _basename, _size FROM files ORDER BY _size DESC LIMIT 5"}'
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
A `.dirsql.toml` file will override the default.
|
|
49
|
+
|
|
32
50
|
## Flags
|
|
33
51
|
|
|
34
52
|
| Flag | Default | Description |
|
|
@@ -63,12 +63,12 @@ async def main():
|
|
|
63
63
|
Table(
|
|
64
64
|
ddl="CREATE TABLE posts (title TEXT, author TEXT)",
|
|
65
65
|
glob="posts/*.json",
|
|
66
|
-
extract=lambda path
|
|
66
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
67
67
|
),
|
|
68
68
|
Table(
|
|
69
69
|
ddl="CREATE TABLE authors (id TEXT, name TEXT)",
|
|
70
70
|
glob="authors/*.json",
|
|
71
|
-
extract=lambda path
|
|
71
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
72
72
|
),
|
|
73
73
|
],
|
|
74
74
|
)
|
|
@@ -120,12 +120,12 @@ let db = DirSQL::new(
|
|
|
120
120
|
Table::new(
|
|
121
121
|
"CREATE TABLE posts (title TEXT, author TEXT)",
|
|
122
122
|
"posts/*.json",
|
|
123
|
-
|
|
|
123
|
+
|path| vec![row_from_json(&std::fs::read_to_string(path).unwrap())],
|
|
124
124
|
),
|
|
125
125
|
Table::new(
|
|
126
126
|
"CREATE TABLE authors (id TEXT, name TEXT)",
|
|
127
127
|
"authors/*.json",
|
|
128
|
-
|
|
|
128
|
+
|path| vec![row_from_json(&std::fs::read_to_string(path).unwrap())],
|
|
129
129
|
),
|
|
130
130
|
],
|
|
131
131
|
)?;
|
|
@@ -139,18 +139,19 @@ let results = db.query(
|
|
|
139
139
|
```
|
|
140
140
|
|
|
141
141
|
```typescript [TypeScript]
|
|
142
|
+
import { readFileSync } from 'node:fs';
|
|
142
143
|
import { DirSQL, type TableDef } from 'dirsql';
|
|
143
144
|
|
|
144
145
|
const tables: TableDef[] = [
|
|
145
146
|
{
|
|
146
147
|
ddl: 'CREATE TABLE posts (title TEXT, author TEXT)',
|
|
147
148
|
glob: 'posts/*.json',
|
|
148
|
-
extract: (
|
|
149
|
+
extract: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
|
|
149
150
|
},
|
|
150
151
|
{
|
|
151
152
|
ddl: 'CREATE TABLE authors (id TEXT, name TEXT)',
|
|
152
153
|
glob: 'authors/*.json',
|
|
153
|
-
extract: (
|
|
154
|
+
extract: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
|
|
154
155
|
},
|
|
155
156
|
];
|
|
156
157
|
|
|
@@ -169,8 +170,8 @@ const results = await db.query(`
|
|
|
169
170
|
## What happens at startup
|
|
170
171
|
|
|
171
172
|
1. `dirsql` walks the directory tree
|
|
172
|
-
2. Files matching each table's glob pattern are
|
|
173
|
-
3. The `extract` function
|
|
173
|
+
2. Files matching each table's glob pattern are identified
|
|
174
|
+
3. The `extract` function receives each matched file's absolute path and returns rows
|
|
174
175
|
4. Rows are inserted into an in-memory SQLite database
|
|
175
176
|
5. SQL queries run against that database
|
|
176
177
|
|
|
@@ -24,7 +24,7 @@ async def main():
|
|
|
24
24
|
Table(
|
|
25
25
|
ddl="CREATE TABLE items (name TEXT, value INTEGER)",
|
|
26
26
|
glob="data/*.json",
|
|
27
|
-
extract=lambda path
|
|
27
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
28
28
|
),
|
|
29
29
|
],
|
|
30
30
|
)
|
|
@@ -47,7 +47,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
47
47
|
Table::new(
|
|
48
48
|
"CREATE TABLE items (name TEXT, value INTEGER)",
|
|
49
49
|
"data/*.json",
|
|
50
|
-
|
|
|
50
|
+
|path| vec![serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap()],
|
|
51
51
|
),
|
|
52
52
|
],
|
|
53
53
|
)?;
|
|
@@ -59,6 +59,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|
|
59
59
|
```
|
|
60
60
|
|
|
61
61
|
```typescript [TypeScript]
|
|
62
|
+
import { readFileSync } from 'node:fs';
|
|
62
63
|
import { DirSQL, Table } from 'dirsql';
|
|
63
64
|
|
|
64
65
|
const db = new DirSQL({
|
|
@@ -67,7 +68,7 @@ const db = new DirSQL({
|
|
|
67
68
|
new Table({
|
|
68
69
|
ddl: 'CREATE TABLE items (name TEXT, value INTEGER)',
|
|
69
70
|
glob: 'data/*.json',
|
|
70
|
-
extract: (
|
|
71
|
+
extract: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
|
|
71
72
|
}),
|
|
72
73
|
],
|
|
73
74
|
});
|
|
@@ -60,7 +60,7 @@ db = DirSQL(
|
|
|
60
60
|
ddl="CREATE TABLE posts (id TEXT, title TEXT, body TEXT, updated INTEGER)",
|
|
61
61
|
# Match the JSON view, not the raw CRDT binary.
|
|
62
62
|
glob="posts/*/view.json",
|
|
63
|
-
extract=lambda path
|
|
63
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
64
64
|
),
|
|
65
65
|
],
|
|
66
66
|
)
|
|
@@ -76,20 +76,21 @@ let db = DirSQL::new(
|
|
|
76
76
|
Table::new(
|
|
77
77
|
"CREATE TABLE posts (id TEXT, title TEXT, body TEXT, updated INTEGER)",
|
|
78
78
|
"posts/*/view.json",
|
|
79
|
-
|
|
|
79
|
+
|path| vec![row_from_json(&std::fs::read_to_string(path).unwrap())],
|
|
80
80
|
),
|
|
81
81
|
],
|
|
82
82
|
)?;
|
|
83
83
|
```
|
|
84
84
|
|
|
85
85
|
```typescript [TypeScript]
|
|
86
|
+
import { readFileSync } from 'node:fs';
|
|
86
87
|
import { DirSQL, type TableDef } from 'dirsql';
|
|
87
88
|
|
|
88
89
|
const tables: TableDef[] = [
|
|
89
90
|
{
|
|
90
91
|
ddl: 'CREATE TABLE posts (id TEXT, title TEXT, body TEXT, updated INTEGER)',
|
|
91
92
|
glob: 'posts/*/view.json',
|
|
92
|
-
extract: (
|
|
93
|
+
extract: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
|
|
93
94
|
},
|
|
94
95
|
];
|
|
95
96
|
|
|
@@ -18,7 +18,7 @@ from dirsql import Table
|
|
|
18
18
|
table = Table(
|
|
19
19
|
ddl="CREATE TABLE comments (id TEXT, body TEXT, author TEXT)",
|
|
20
20
|
glob="comments/**/index.jsonl",
|
|
21
|
-
extract=lambda path
|
|
21
|
+
extract=lambda path: [
|
|
22
22
|
{"id": "...", "body": "...", "author": "..."}
|
|
23
23
|
],
|
|
24
24
|
)
|
|
@@ -31,7 +31,7 @@ use std::collections::HashMap;
|
|
|
31
31
|
let table = Table::new(
|
|
32
32
|
"CREATE TABLE comments (id TEXT, body TEXT, author TEXT)",
|
|
33
33
|
"comments/**/index.jsonl",
|
|
34
|
-
|_path
|
|
34
|
+
|_path| {
|
|
35
35
|
let mut row: HashMap<String, Value> = HashMap::new();
|
|
36
36
|
row.insert("id".into(), Value::Text("...".into()));
|
|
37
37
|
row.insert("body".into(), Value::Text("...".into()));
|
|
@@ -47,7 +47,7 @@ import type { TableDef } from 'dirsql';
|
|
|
47
47
|
const table: TableDef = {
|
|
48
48
|
ddl: 'CREATE TABLE comments (id TEXT, body TEXT, author TEXT)',
|
|
49
49
|
glob: 'comments/**/index.jsonl',
|
|
50
|
-
extract: (_path
|
|
50
|
+
extract: (_path) => [
|
|
51
51
|
{ id: '...', body: '...', author: '...' },
|
|
52
52
|
],
|
|
53
53
|
};
|
|
@@ -89,38 +89,38 @@ Glob syntax follows standard Unix globbing rules. `**` matches any number of dir
|
|
|
89
89
|
|
|
90
90
|
### `extract`
|
|
91
91
|
|
|
92
|
-
A callable `(path: str
|
|
92
|
+
A callable `(path: str) -> list[dict]` that converts a file into rows.
|
|
93
93
|
|
|
94
|
-
- `path` is the
|
|
95
|
-
- `content` is the file content as a string
|
|
94
|
+
- `path` is the **absolute filesystem path** of the matched file
|
|
96
95
|
- Return a list of dicts, where each dict maps column names to values
|
|
97
96
|
- Return an empty list to skip a file
|
|
98
97
|
|
|
98
|
+
`dirsql` does not read file contents for you. If your extract needs the file
|
|
99
|
+
body, read it inside the callback using `path`. Callbacks that derive columns
|
|
100
|
+
only from the path (or that rely solely on the auto-injected filesystem-fact
|
|
101
|
+
columns) never touch the file at all.
|
|
102
|
+
|
|
99
103
|
```python
|
|
100
104
|
import json
|
|
101
105
|
|
|
102
106
|
# Single-object JSON files: one row per file
|
|
103
|
-
extract
|
|
107
|
+
def extract(path):
|
|
108
|
+
with open(path, encoding="utf-8") as f:
|
|
109
|
+
return [json.loads(f.read())]
|
|
104
110
|
|
|
105
111
|
# JSONL files: one row per line
|
|
106
|
-
extract
|
|
107
|
-
|
|
108
|
-
]
|
|
112
|
+
def extract(path):
|
|
113
|
+
with open(path, encoding="utf-8") as f:
|
|
114
|
+
return [json.loads(line) for line in f]
|
|
109
115
|
|
|
110
|
-
# Derive
|
|
116
|
+
# Derive a value from the file path alone -- no file read
|
|
111
117
|
import os
|
|
112
|
-
extract=lambda path
|
|
113
|
-
{
|
|
114
|
-
"id": os.path.basename(os.path.dirname(path)),
|
|
115
|
-
"body": json.loads(line)["body"],
|
|
116
|
-
}
|
|
117
|
-
for line in content.splitlines()
|
|
118
|
-
for _ in [json.loads(line)]
|
|
119
|
-
]
|
|
118
|
+
extract = lambda path: [{"id": os.path.basename(os.path.dirname(path))}]
|
|
120
119
|
|
|
121
120
|
# Conditionally skip files
|
|
122
|
-
def extract(path
|
|
123
|
-
|
|
121
|
+
def extract(path):
|
|
122
|
+
with open(path, encoding="utf-8") as f:
|
|
123
|
+
data = json.loads(f.read())
|
|
124
124
|
if data.get("draft"):
|
|
125
125
|
return []
|
|
126
126
|
return [data]
|
|
@@ -142,12 +142,12 @@ db = DirSQL(
|
|
|
142
142
|
Table(
|
|
143
143
|
ddl="CREATE TABLE posts (title TEXT, author_id TEXT)",
|
|
144
144
|
glob="posts/*.json",
|
|
145
|
-
extract=lambda path
|
|
145
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
146
146
|
),
|
|
147
147
|
Table(
|
|
148
148
|
ddl="CREATE TABLE authors (id TEXT, name TEXT)",
|
|
149
149
|
glob="authors/*.json",
|
|
150
|
-
extract=lambda path
|
|
150
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
151
151
|
),
|
|
152
152
|
],
|
|
153
153
|
)
|
|
@@ -184,12 +184,12 @@ let db = DirSQL::new(
|
|
|
184
184
|
Table::new(
|
|
185
185
|
"CREATE TABLE posts (title TEXT, author_id TEXT)",
|
|
186
186
|
"posts/*.json",
|
|
187
|
-
|
|
|
187
|
+
|path| vec![row_from_json(&std::fs::read_to_string(path).unwrap())],
|
|
188
188
|
),
|
|
189
189
|
Table::new(
|
|
190
190
|
"CREATE TABLE authors (id TEXT, name TEXT)",
|
|
191
191
|
"authors/*.json",
|
|
192
|
-
|
|
|
192
|
+
|path| vec![row_from_json(&std::fs::read_to_string(path).unwrap())],
|
|
193
193
|
),
|
|
194
194
|
],
|
|
195
195
|
)?;
|
|
@@ -197,17 +197,18 @@ let db = DirSQL::new(
|
|
|
197
197
|
|
|
198
198
|
```typescript [TypeScript]
|
|
199
199
|
import { DirSQL, type TableDef } from 'dirsql';
|
|
200
|
+
import { readFileSync } from 'node:fs';
|
|
200
201
|
|
|
201
202
|
const tables: TableDef[] = [
|
|
202
203
|
{
|
|
203
204
|
ddl: 'CREATE TABLE posts (title TEXT, author_id TEXT)',
|
|
204
205
|
glob: 'posts/*.json',
|
|
205
|
-
extract: (
|
|
206
|
+
extract: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
|
|
206
207
|
},
|
|
207
208
|
{
|
|
208
209
|
ddl: 'CREATE TABLE authors (id TEXT, name TEXT)',
|
|
209
210
|
glob: 'authors/*.json',
|
|
210
|
-
extract: (
|
|
211
|
+
extract: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
|
|
211
212
|
},
|
|
212
213
|
];
|
|
213
214
|
|
|
@@ -26,7 +26,7 @@ db = DirSQL(
|
|
|
26
26
|
Table(
|
|
27
27
|
ddl="CREATE TABLE comments (id TEXT, body TEXT, author TEXT)",
|
|
28
28
|
glob="comments/**/*.json",
|
|
29
|
-
extract=lambda path
|
|
29
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
30
30
|
),
|
|
31
31
|
],
|
|
32
32
|
)
|
|
@@ -67,7 +67,7 @@ let db = DirSQL::new(
|
|
|
67
67
|
Table::new(
|
|
68
68
|
"CREATE TABLE comments (id TEXT, body TEXT, author TEXT)",
|
|
69
69
|
"comments/**/*.json",
|
|
70
|
-
|
|
|
70
|
+
|path| vec![row_from_json(&std::fs::read_to_string(path).unwrap())],
|
|
71
71
|
),
|
|
72
72
|
],
|
|
73
73
|
)?;
|
|
@@ -92,13 +92,14 @@ while let Some(event) = stream.next().await {
|
|
|
92
92
|
```
|
|
93
93
|
|
|
94
94
|
```typescript [TypeScript]
|
|
95
|
+
import { readFileSync } from 'node:fs';
|
|
95
96
|
import { DirSQL, type TableDef } from 'dirsql';
|
|
96
97
|
|
|
97
98
|
const tables: TableDef[] = [
|
|
98
99
|
{
|
|
99
100
|
ddl: 'CREATE TABLE comments (id TEXT, body TEXT, author TEXT)',
|
|
100
101
|
glob: 'comments/**/*.json',
|
|
101
|
-
extract: (
|
|
102
|
+
extract: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
|
|
102
103
|
},
|
|
103
104
|
];
|
|
104
105
|
|
|
@@ -35,7 +35,7 @@ db = DirSQL(
|
|
|
35
35
|
Table(
|
|
36
36
|
ddl="CREATE TABLE files (name TEXT, size INTEGER, type TEXT)",
|
|
37
37
|
glob="data/*.json",
|
|
38
|
-
extract=lambda path
|
|
38
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
39
39
|
),
|
|
40
40
|
],
|
|
41
41
|
)
|
|
@@ -53,7 +53,7 @@ let db = DirSQL::new(
|
|
|
53
53
|
Table::new(
|
|
54
54
|
"CREATE TABLE files (name TEXT, size INTEGER, type TEXT)",
|
|
55
55
|
"data/*.json",
|
|
56
|
-
|
|
|
56
|
+
|path| vec![serde_json::from_str(&std::fs::read_to_string(path).unwrap()).unwrap()],
|
|
57
57
|
),
|
|
58
58
|
],
|
|
59
59
|
)?;
|
|
@@ -62,6 +62,7 @@ let large = db.query("SELECT * FROM files WHERE size > 1000")?;
|
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
```typescript [TypeScript]
|
|
65
|
+
import { readFileSync } from 'node:fs';
|
|
65
66
|
import { DirSQL, Table } from 'dirsql';
|
|
66
67
|
|
|
67
68
|
const db = new DirSQL({
|
|
@@ -70,7 +71,7 @@ const db = new DirSQL({
|
|
|
70
71
|
new Table({
|
|
71
72
|
ddl: 'CREATE TABLE files (name TEXT, size INTEGER, type TEXT)',
|
|
72
73
|
glob: 'data/*.json',
|
|
73
|
-
extract: (
|
|
74
|
+
extract: (path) => [JSON.parse(readFileSync(path, 'utf8'))],
|
|
74
75
|
}),
|
|
75
76
|
],
|
|
76
77
|
});
|
|
@@ -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.7"
|
|
8
8
|
edition.workspace = true
|
|
9
9
|
publish = false
|
|
10
10
|
readme = "README.md"
|
|
@@ -47,13 +47,13 @@ async def main():
|
|
|
47
47
|
Table(
|
|
48
48
|
ddl="CREATE TABLE comments (id TEXT, body TEXT, author TEXT)",
|
|
49
49
|
glob="comments/**/index.jsonl",
|
|
50
|
-
extract=lambda path
|
|
50
|
+
extract=lambda path: [
|
|
51
51
|
{
|
|
52
52
|
"id": os.path.basename(os.path.dirname(path)),
|
|
53
53
|
"body": row["body"],
|
|
54
54
|
"author": row["author"],
|
|
55
55
|
}
|
|
56
|
-
for line in
|
|
56
|
+
for line in open(path, encoding="utf-8").read().splitlines()
|
|
57
57
|
for row in [json.loads(line)]
|
|
58
58
|
],
|
|
59
59
|
),
|
|
@@ -77,12 +77,12 @@ db = DirSQL(
|
|
|
77
77
|
Table(
|
|
78
78
|
ddl="CREATE TABLE posts (title TEXT, author_id TEXT)",
|
|
79
79
|
glob="posts/*.json",
|
|
80
|
-
extract=lambda path
|
|
80
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
81
81
|
),
|
|
82
82
|
Table(
|
|
83
83
|
ddl="CREATE TABLE authors (id TEXT, name TEXT)",
|
|
84
84
|
glob="authors/*.json",
|
|
85
|
-
extract=lambda path
|
|
85
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
86
86
|
),
|
|
87
87
|
],
|
|
88
88
|
)
|
|
@@ -122,7 +122,7 @@ async def main():
|
|
|
122
122
|
Table(
|
|
123
123
|
ddl="CREATE TABLE items (name TEXT)",
|
|
124
124
|
glob="**/*.json",
|
|
125
|
-
extract=lambda path
|
|
125
|
+
extract=lambda path: [json.loads(open(path, encoding="utf-8").read())],
|
|
126
126
|
),
|
|
127
127
|
],
|
|
128
128
|
)
|
|
@@ -148,7 +148,7 @@ Defines how files map to a SQL table.
|
|
|
148
148
|
|
|
149
149
|
- **`ddl`** (`str`): A `CREATE TABLE` statement defining the schema.
|
|
150
150
|
- **`glob`** (`str`): A glob pattern matched against file paths relative to root.
|
|
151
|
-
- **`extract`** (`Callable[[str
|
|
151
|
+
- **`extract`** (`Callable[[str], list[dict]]`): A function receiving the matched file's absolute filesystem path and returning a list of row dicts. dirsql does not read file contents; a callback that needs the file body reads it itself (e.g. `open(path, encoding="utf-8").read()`). Each dict's keys must match the DDL column names.
|
|
152
152
|
|
|
153
153
|
### `DirSQL(root=None, *, tables=None, ignore=None, config=None)`
|
|
154
154
|
|
|
@@ -168,15 +168,15 @@ import { Table } from 'dirsql';
|
|
|
168
168
|
::: code-group
|
|
169
169
|
|
|
170
170
|
```python [Python]
|
|
171
|
-
Table(*, ddl: str, glob: str, extract: Callable[[str
|
|
171
|
+
Table(*, ddl: str, glob: str, extract: Callable[[str], list[dict]])
|
|
172
172
|
```
|
|
173
173
|
|
|
174
174
|
```rust [Rust]
|
|
175
|
-
Table::new(ddl: &str, glob: &str, extract: fn(&str
|
|
175
|
+
Table::new(ddl: &str, glob: &str, extract: fn(&str) -> Vec<Value>)
|
|
176
176
|
```
|
|
177
177
|
|
|
178
178
|
```typescript [TypeScript]
|
|
179
|
-
new Table({ ddl: string, glob: string, extract: (path: string
|
|
179
|
+
new Table({ ddl: string, glob: string, extract: (path: string) => Record<string, unknown>[] })
|
|
180
180
|
```
|
|
181
181
|
|
|
182
182
|
:::
|
|
@@ -187,7 +187,7 @@ Defines a mapping from files to SQLite table rows.
|
|
|
187
187
|
|
|
188
188
|
- `ddl` -- A `CREATE TABLE` statement. The table name is parsed from this DDL.
|
|
189
189
|
- `glob` -- A glob pattern matched against file paths relative to the root directory.
|
|
190
|
-
- `extract` -- A callable `(path
|
|
190
|
+
- `extract` -- A callable `(path) -> list[dict]`. Receives the absolute filesystem path of the matched file. `dirsql` does not read file contents; a callback that needs the file body reads `path` itself. Returns a list of dicts/maps mapping column names to values. Return an empty list to skip a file.
|
|
191
191
|
|
|
192
192
|
**Attributes:**
|
|
193
193
|
|