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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ print!("{}", out.to_table());

## Documentation

- [Install](https://db.mqlang.org/book/start/install) and [CLI](https://db.mqlang.org/book/start/cli) (`index`, `find`, `lint`, `stats`, `vacuum`, …)
- [Install](https://db.mqlang.org/book/start/install) and [CLI](https://db.mqlang.org/book/start/cli) (`index`, `find`, `stats`, `vacuum`, …)
- [Library API](https://db.mqlang.org/book/start/library), [HTTP server](https://db.mqlang.org/book/start/http-server)
- [SQL schema](https://db.mqlang.org/book/reference/sql-schema), [functions](https://db.mqlang.org/book/reference/sql-functions) and [examples](https://db.mqlang.org/book/reference/sql-examples)
- [Block model](https://db.mqlang.org/book/reference/block-model), [index layers](https://db.mqlang.org/book/reference/index-layers) and [storage format](https://db.mqlang.org/book/reference/storage-format)
Expand Down
2 changes: 0 additions & 2 deletions docs/books/src/reference/index-layers.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ Built once per document and stored in the `.mq-db` file. Checked before any bloc
| `depth = N` (`N > 0`) | `N` exceeds `max_heading_depth` |
| `block_type = 'heading' AND content = 'X'` | `heading_contents` has no case-insensitive match for `X` |

**Via the Rust API**: `store.query().documents(|doc| ...)` lets you filter on *any* zone-map field yourself (`heading_slugs`, `frontmatter_keys`, `title`, `tags`, …), not just the patterns `SqlEngine` recognizes automatically.

## Layer 2: Interval Index (section hierarchy)

Heading hierarchy is encoded as `(pre, post)` pairs via Pre-Post Order (Nested Set) traversal:
Expand Down
16 changes: 0 additions & 16 deletions docs/books/src/start/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,22 +96,6 @@ mq-db repl --db store.mq-db --mode sql

See [REPL](repl.md) for the full command list.

## `lint`

Run structural lint checks (currently: a heading at the given depth immediately followed by a list).

```bash
mq-db lint --db store.mq-db --depth 2
```

```text
✗ 1 violation (H2 immediately followed by list)

file heading
──────────────────────────────────────── ──────────────────────────────
docs/DESIGN.md "Quick Start"
```

## `stats`

Show store-wide statistics: document/block counts, block-type distribution, code-language distribution.
Expand Down
23 changes: 1 addition & 22 deletions docs/books/src/start/library.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,13 @@ mq-db = "0.1"
```

```rust
use mq_db::{DocumentStore, SqlEngine, MqEngine, block::BlockType};
use mq_db::{DocumentStore, SqlEngine, MqEngine};

// Build in memory
let mut store = DocumentStore::new();
store.add_file("docs/DESIGN.md")?;
store.add_str("# Hello\n\n## Architecture\n\nDetails\n")?;

// Chainable query API: zone-map skip + interval scope + block predicates
let chunks = store.query()
.documents(|doc| doc.zone_maps.heading_contents.contains("Architecture"))
.under_heading("Architecture", Some(2))
.filter(|b| matches!(b.block_type, BlockType::Paragraph | BlockType::Code))
.blocks();

// SQL engine (custom sqlparser-based evaluator, no SQLite dependency)
let engine = SqlEngine::new(&store)?;
let out = engine.execute(
Expand All @@ -32,9 +25,6 @@ print!("{}", out.to_table());
// mq engine
let results = MqEngine::eval_store(".h1", &store)?;

// Structural lint
let violations = store.query().lint_heading_followed_by(2, &[BlockType::List]);

// UPDATE/DELETE with write-back: rewrites the affected block's source file
// (heading/paragraph content only), then re-parses it in place
store.execute_sql_mut(
Expand Down Expand Up @@ -66,14 +56,3 @@ let store = DocumentStore::load_catalog_only("store.mq-db")?;
| `DocumentStore::load_catalog_only()` | Catalog only | `list` / `stats`-style metadata commands |

When using `open()`, call `load_all_blocks()` and `load_all_indexes()` before running any `SqlEngine` query.

## Query builder

`store.query()` returns a chainable builder that applies the same three index layers used by the SQL engine, in order:

1. `.documents(|doc| ...)`: zone-map predicate, skips whole documents
2. `.under_heading(title, depth)` / interval-scope helpers: narrows to a `(pre, post)` range
3. `.filter(|block| ...)`: per-block predicate over the remaining candidates
4. `.blocks()`: materializes the final `Vec<&Block>`

See [Index Layers](../reference/index-layers.md) for how each layer works.
48 changes: 0 additions & 48 deletions src/bin/mq-db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -187,17 +187,6 @@ enum Commands {
attach: Vec<String>,
},

/// Run structural lint checks
Lint {
/// Path to .mq-db store file
#[arg(short, long, default_value = "store.mq-db")]
db: PathBuf,

/// Heading depth to check (H1=1 .. H6=6)
#[arg(long, default_value_t = 2)]
depth: u8,
},

/// Show store statistics
Stats {
/// Path to .mq-db store file
Expand Down Expand Up @@ -894,43 +883,6 @@ async fn main() -> anyhow::Result<()> {
run_repl(store, mode, write_back)?;
}

// lint
Commands::Lint { db, depth } => {
let store = load_store(&db)?;
let q = store.query();
let violations = q.lint_heading_followed_by(depth, &[BlockType::List]);
if violations.is_empty() {
println!(
"✓ No violations (H{} must not be immediately followed by a list)",
depth
);
} else {
let n = violations.len();
println!(
"✗ {} violation{} (H{} immediately followed by list)\n",
n,
if n == 1 { "" } else { "s" },
depth
);
println!(" {:<40} heading", "file");
println!(" {} {}", "─".repeat(40), "─".repeat(30));
for v in &violations {
let path = v
.document
.path
.as_ref()
.map(|p| p.to_string_lossy().to_string())
.unwrap_or_else(|| format!("<doc {}>", v.document.id));
let path_display = if path.len() > 40 {
format!("…{}", &path[path.len() - 39..])
} else {
path
};
println!(" {:<40} \"{}\"", path_display, v.heading.content);
}
}
}

// stats
Commands::Stats { db } => {
let store = load_store(&db)?;
Expand Down
34 changes: 7 additions & 27 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,20 @@
//! slugs, code languages, front-matter keys/tags) that let the query
//! engine skip irrelevant documents before scanning their blocks.
//!
//! * **Chainable query API** – document-level and block-level predicates,
//! `UNDER heading` section scoping, built-in linter helpers.
//!
//! ## Quick Start
//!
//! ```rust
//! use mq_db::{DocumentStore, block::BlockType};
//!
//! let mut store = DocumentStore::new();
//! store.add_str("# Hello\n\n## Architecture\n\nDetails\n\n```rust\ncode\n```\n").unwrap();
//!
//! // Extract all content under the "Architecture" H2
//! let chunks = store.query()
//! .under_heading("Architecture", Some(2))
//! .filter(|b| matches!(b.block_type, BlockType::Paragraph | BlockType::Code))
//! .blocks();
//!
//! assert_eq!(chunks.len(), 2);
//! ```
//!
//! ## Structural Linting
//!
//! ```rust
//! use mq_db::{DocumentStore, block::BlockType};
//! use mq_db::{DocumentStore, SqlEngine};
//!
//! let mut store = DocumentStore::new();
//! store.add_str("## Section\n\n- item without intro paragraph\n").unwrap();
//! store.add_str("# Hello\n\n## Architecture\n\nDetails\n").unwrap();
//!
//! let q = store.query();
//! let violations = q.lint_heading_followed_by(2, &[BlockType::List]);
//! let engine = SqlEngine::new(&store).unwrap();
//! let out = engine
//! .execute("SELECT content FROM blocks WHERE block_type = 'heading' ORDER BY pre")
//! .unwrap();
//!
//! assert_eq!(violations.len(), 1);
//! assert_eq!(out.rows.len(), 2);
//! ```

pub mod block;
Expand All @@ -57,7 +39,6 @@ pub mod error;
pub mod index;
pub mod indexes;
pub mod mq_engine;
pub mod query;
pub mod search;
pub mod sql;
pub mod storage;
Expand All @@ -67,7 +48,6 @@ pub mod tui;
pub use document::Document;
pub use error::MqdbError;
pub use mq_engine::MqEngine;
pub use query::{LintViolation, Query, QueryResult};
pub use sql::{QueryOutput, SqlEngine};
pub use storage::Storage;
pub use storage::catalog::CatalogEntry;
Expand Down
Loading
Loading