dirsql 0.1.4__tar.gz → 0.1.6__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 (39) hide show
  1. {dirsql-0.1.4 → dirsql-0.1.6}/PKG-INFO +1 -1
  2. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/src/db.rs +69 -2
  3. {dirsql-0.1.4 → dirsql-0.1.6}/pyproject.toml +1 -1
  4. {dirsql-0.1.4 → dirsql-0.1.6}/Cargo.lock +0 -0
  5. {dirsql-0.1.4 → dirsql-0.1.6}/Cargo.toml +0 -0
  6. {dirsql-0.1.4 → dirsql-0.1.6}/README.md +0 -0
  7. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/Cargo.toml +0 -0
  8. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/README.md +0 -0
  9. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/src/lib.rs +0 -0
  10. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/tests/__init__.py +0 -0
  11. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/tests/conftest.py +0 -0
  12. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/tests/integration/__init__.py +0 -0
  13. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/tests/integration/test_async_dirsql.py +0 -0
  14. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/tests/integration/test_binding.py +0 -0
  15. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/tests/integration/test_dirsql.py +0 -0
  16. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/tests/integration/test_docs_examples.py +0 -0
  17. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/tests/integration/test_docs_gaps.py +0 -0
  18. {dirsql-0.1.4 → dirsql-0.1.6}/packages/python/tests/integration/test_from_config.py +0 -0
  19. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/Cargo.toml +0 -0
  20. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/README.md +0 -0
  21. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/benches/db_bench.rs +0 -0
  22. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/benches/differ_bench.rs +0 -0
  23. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/benches/matcher_bench.rs +0 -0
  24. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/benches/scanner_bench.rs +0 -0
  25. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/src/config.rs +0 -0
  26. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/src/differ.rs +0 -0
  27. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/src/lib.rs +0 -0
  28. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/src/matcher.rs +0 -0
  29. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/src/parser.rs +0 -0
  30. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/src/scanner.rs +0 -0
  31. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/src/watcher.rs +0 -0
  32. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/tests/async_sdk.rs +0 -0
  33. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/tests/docs_examples.rs +0 -0
  34. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/tests/docs_gaps.rs +0 -0
  35. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/tests/from_config.rs +0 -0
  36. {dirsql-0.1.4 → dirsql-0.1.6}/packages/rust/tests/sdk.rs +0 -0
  37. {dirsql-0.1.4 → dirsql-0.1.6}/python/dirsql/__init__.py +0 -0
  38. {dirsql-0.1.4 → dirsql-0.1.6}/python/dirsql/_async.py +0 -0
  39. {dirsql-0.1.4 → dirsql-0.1.6}/python/dirsql/test_async.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dirsql
3
- Version: 0.1.4
3
+ Version: 0.1.6
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'
@@ -133,7 +133,11 @@ impl Db {
133
133
  }
134
134
 
135
135
  /// Query the database, returning rows as a list of column-name -> value maps.
136
- /// Internal tracking columns (_dirsql_*) are excluded from results.
136
+ ///
137
+ /// Internal tracking columns (`_dirsql_*`) are excluded from `SELECT *`
138
+ /// results so they don't leak. But if the user names one explicitly in the
139
+ /// projection (e.g. `SELECT _dirsql_file_path FROM t`), it's returned —
140
+ /// users opt into the tracking surface by typing the column name.
137
141
  pub fn query(&self, sql: &str) -> Result<Vec<HashMap<String, Value>>> {
138
142
  let mut stmt = self.conn.prepare(sql)?;
139
143
  let column_names: Vec<String> = stmt.column_names().iter().map(|s| s.to_string()).collect();
@@ -141,7 +145,7 @@ impl Db {
141
145
  let rows = stmt.query_map([], |row| {
142
146
  let mut map = HashMap::new();
143
147
  for (i, name) in column_names.iter().enumerate() {
144
- if name.starts_with("_dirsql_") {
148
+ if name.starts_with("_dirsql_") && !sql.contains(name) {
145
149
  continue;
146
150
  }
147
151
  let val: rusqlite::types::Value = row.get(i)?;
@@ -635,6 +639,69 @@ mod tests {
635
639
  assert!(results[0].contains_key("id"));
636
640
  }
637
641
 
642
+ #[test]
643
+ fn query_honors_explicit_dirsql_file_path() {
644
+ let db = Db::new().unwrap();
645
+ db.create_table("CREATE TABLE t (id TEXT)").unwrap();
646
+ let row = HashMap::from([("id".into(), Value::Text("1".into()))]);
647
+ db.insert_row("t", &row, "file.json", 0).unwrap();
648
+
649
+ let results = db.query("SELECT _dirsql_file_path FROM t").unwrap();
650
+ assert_eq!(results.len(), 1);
651
+ assert_eq!(
652
+ results[0].get("_dirsql_file_path"),
653
+ Some(&Value::Text("file.json".into())),
654
+ );
655
+ }
656
+
657
+ #[test]
658
+ fn query_honors_explicit_dirsql_alongside_user_columns() {
659
+ let db = Db::new().unwrap();
660
+ db.create_table("CREATE TABLE posts (title TEXT)").unwrap();
661
+ let row = HashMap::from([("title".into(), Value::Text("Hello".into()))]);
662
+ db.insert_row("posts", &row, "posts/hello.json", 0).unwrap();
663
+
664
+ let results = db
665
+ .query("SELECT title, _dirsql_file_path FROM posts")
666
+ .unwrap();
667
+ assert_eq!(results.len(), 1);
668
+ assert_eq!(results[0]["title"], Value::Text("Hello".into()));
669
+ assert_eq!(
670
+ results[0]["_dirsql_file_path"],
671
+ Value::Text("posts/hello.json".into()),
672
+ );
673
+ }
674
+
675
+ #[test]
676
+ fn query_honors_explicit_dirsql_row_index() {
677
+ let db = Db::new().unwrap();
678
+ db.create_table("CREATE TABLE t (id TEXT)").unwrap();
679
+ let row = HashMap::from([("id".into(), Value::Text("a".into()))]);
680
+ db.insert_row("t", &row, "f.jsonl", 7).unwrap();
681
+
682
+ let results = db.query("SELECT _dirsql_row_index FROM t").unwrap();
683
+ assert_eq!(results.len(), 1);
684
+ assert_eq!(results[0]["_dirsql_row_index"], Value::Integer(7));
685
+ }
686
+
687
+ #[test]
688
+ fn query_keeps_dirsql_when_filter_references_it_with_star_projection() {
689
+ // Naming `_dirsql_file_path` anywhere in the SQL is treated as
690
+ // "the user is aware of this tracking column", so `SELECT *` with
691
+ // a `_dirsql_*` reference in WHERE returns it.
692
+ let db = Db::new().unwrap();
693
+ db.create_table("CREATE TABLE t (id TEXT)").unwrap();
694
+ let row = HashMap::from([("id".into(), Value::Text("1".into()))]);
695
+ db.insert_row("t", &row, "file.json", 0).unwrap();
696
+
697
+ let results = db
698
+ .query("SELECT * FROM t WHERE _dirsql_file_path = 'file.json'")
699
+ .unwrap();
700
+ assert_eq!(results.len(), 1);
701
+ assert!(results[0].contains_key("id"));
702
+ assert!(results[0].contains_key("_dirsql_file_path"));
703
+ }
704
+
638
705
  // --- Error path: query with invalid SQL ---
639
706
 
640
707
  #[test]
@@ -4,7 +4,7 @@ build-backend = "maturin"
4
4
 
5
5
  [project]
6
6
  name = "dirsql"
7
- version = "0.1.4"
7
+ version = "0.1.6"
8
8
  description = "Ephemeral SQL index over a local directory"
9
9
  license = "MIT"
10
10
  requires-python = ">=3.12"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes