Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions packages/python/changelog.d/2026-10-06-one-glob-compiler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**Changed** A declared `[[table]] glob` is compiled by the same glob compiler
as a path-table, so brace ranges such as `f{1..3}.md` and the other bash brace
rules now read the same on both surfaces.
7 changes: 7 additions & 0 deletions packages/python/e2e-attestations/claude-1258-one-pattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"command": "uv run python -m pytest tests/e2e/capture_collision_test.py tests/e2e/declared_table_name_test.py tests/e2e/extension_package_test.py tests/e2e/query_contract_test.py tests/e2e/plugin_discovery_test.py tests/e2e/sigint_interrupt_test.py tests/e2e/fanout_test.py tests/e2e/use_case_transcripts_test.py tests/e2e/plugin_extension_discovery_test.py -x -q",
"ran_at": 1791301900,
"exit_code": 0,
"commit": "14d2a11edd69bb0715bbffdb085b1d6582728dd8",
"branch": "claude/1258-one-pattern"
}
28 changes: 28 additions & 0 deletions packages/python/migrations.d/2026-10-06-one-glob-compiler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
### Config table globs share the path-table glob compiler

#### Summary

A declared `[[table]] glob` is now compiled by the same compiler as a
path-table. A brace range such as `f{1..3}.md` expands as in bash instead of
matching nothing. Nothing else changes.

#### Required changes

_None._

#### Deprecations removed

_None._

#### Behavior changes without code changes

- `glob = "f{1..3}.md"` matches `f1.md`, `f2.md` and `f3.md`.

#### Verification

```bash
cd "$(mktemp -d)"
touch f1.md f2.md f3.md f4.md
dirsql query "SELECT path FROM './f{1..3}.md' ORDER BY path"
# expected: [{"path":"f1.md"},{"path":"f2.md"},{"path":"f3.md"}]
```
3 changes: 3 additions & 0 deletions packages/rust/changelog.d/2026-10-06-one-glob-compiler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**Changed** A declared `[[table]] glob` is compiled by the same glob compiler
as a path-table, so brace ranges such as `f{1..3}.md` and the other bash brace
rules now read the same on both surfaces.
28 changes: 28 additions & 0 deletions packages/rust/migrations.d/2026-10-06-one-glob-compiler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
### Config table globs share the path-table glob compiler

#### Summary

A declared `[[table]] glob` is now compiled by the same compiler as a
path-table. A brace range such as `f{1..3}.md` expands as in bash instead of
matching nothing. Nothing else changes.

#### Required changes

_None._

#### Deprecations removed

_None._

#### Behavior changes without code changes

- `glob = "f{1..3}.md"` matches `f1.md`, `f2.md` and `f3.md`.

#### Verification

```bash
cd "$(mktemp -d)"
touch f1.md f2.md f3.md f4.md
dirsql query "SELECT path FROM './f{1..3}.md' ORDER BY path"
# expected: [{"path":"f1.md"},{"path":"f2.md"},{"path":"f3.md"}]
```
5 changes: 3 additions & 2 deletions packages/rust/src/matcher.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::posix_class::expand_posix_classes;
use crate::scanner::{PathGlob, compile_glob};
use globset::GlobBuilder;
use regex::{Regex, RegexBuilder};
use std::path::Path;
Expand Down Expand Up @@ -81,7 +82,7 @@ pub struct MatchResult {
/// A compiled glob pattern. `{name}` placeholders are rewritten to `*` before
/// compilation, so they are pure match wildcards.
struct PatternEntry {
pattern: Pattern,
pattern: PathGlob,
table_name: String,
}

Expand Down Expand Up @@ -161,7 +162,7 @@ impl TableMatcher {
let mut entries = Vec::new();
for (pattern, table_name) in mappings {
entries.push(PatternEntry {
pattern: Pattern::new(&glob_with_placeholders_as_star(pattern))?,
pattern: compile_glob(&glob_with_placeholders_as_star(pattern))?,
table_name: table_name.to_string(),
});
}
Expand Down
62 changes: 62 additions & 0 deletions packages/rust/tests/config_glob_parity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//! A config `[[table]] glob` reads exactly as the same string written after
//! `FROM './`: both surfaces run one pattern implementation. Real filesystem,
//! real SQLite, SDK public API.

use std::collections::HashMap;
use std::fs;
use std::path::Path;

use dirsql::{DirSQL, Table, Value};
use tempfile::TempDir;

fn tree(files: &[&str]) -> TempDir {
let root = TempDir::new().unwrap();
for file in files {
let at = root.path().join(file);
fs::create_dir_all(at.parent().unwrap()).unwrap();
fs::write(at, "x").unwrap();
}
root
}

fn config_paths(root: &Path, glob: &str) -> Vec<String> {
let base = root.to_path_buf();
let table = Table::new("t", "CREATE TABLE t (p TEXT)", glob, move |path| {
let rel = Path::new(path)
.strip_prefix(&base)
.unwrap_or(Path::new(path));
vec![HashMap::from([(
"p".to_string(),
Value::Text(rel.to_string_lossy().replace('\\', "/")),
)])]
});
let db = DirSQL::new(root, vec![table]).unwrap();
texts(&db, "SELECT p FROM t", "p")
}

fn path_table_paths(root: &Path, glob: &str) -> Vec<String> {
let db = DirSQL::new(root, vec![]).unwrap();
texts(&db, &format!("SELECT path FROM './{glob}'"), "path")
}

fn texts(db: &DirSQL, sql: &str, column: &str) -> Vec<String> {
let mut out: Vec<String> = db
.query(sql)
.unwrap()
.iter()
.map(|r| match r.get(column) {
Some(Value::Text(s)) => s.clone(),
other => panic!("{column} was not text: {other:?}"),
})
.collect();
out.sort();
out
}

#[test]
fn a_brace_range_expands_as_it_does_in_a_path_table() {
let root = tree(&["f1.md", "f2.md", "f3.md", "f4.md"]);
let expected = vec!["f1.md", "f2.md", "f3.md"];
assert_eq!(path_table_paths(root.path(), "f{1..3}.md"), expected);
assert_eq!(config_paths(root.path(), "f{1..3}.md"), expected);
}
3 changes: 3 additions & 0 deletions packages/ts/changelog.d/2026-10-06-one-glob-compiler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
**Changed** A declared `[[table]] glob` is compiled by the same glob compiler
as a path-table, so brace ranges such as `f{1..3}.md` and the other bash brace
rules now read the same on both surfaces.
7 changes: 7 additions & 0 deletions packages/ts/e2e-attestations/claude-1258-one-pattern.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"command": "pnpm test:e2e",
"ran_at": 1791249711,
"exit_code": 0,
"commit": "c846339f5451e9d133220ee0a8d20706473ef82e",
"branch": "claude/1258-one-pattern"
}
28 changes: 28 additions & 0 deletions packages/ts/migrations.d/2026-10-06-one-glob-compiler.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
### Config table globs share the path-table glob compiler

#### Summary

A declared `[[table]] glob` is now compiled by the same compiler as a
path-table. A brace range such as `f{1..3}.md` expands as in bash instead of
matching nothing. Nothing else changes.

#### Required changes

_None._

#### Deprecations removed

_None._

#### Behavior changes without code changes

- `glob = "f{1..3}.md"` matches `f1.md`, `f2.md` and `f3.md`.

#### Verification

```bash
cd "$(mktemp -d)"
touch f1.md f2.md f3.md f4.md
dirsql query "SELECT path FROM './f{1..3}.md' ORDER BY path"
# expected: [{"path":"f1.md"},{"path":"f2.md"},{"path":"f3.md"}]
```
Loading