diff --git a/ARCHITECTURAL_GUARDRAILS.md b/ARCHITECTURAL_GUARDRAILS.md
index 7a9b6bfe..8540f6b4 100644
--- a/ARCHITECTURAL_GUARDRAILS.md
+++ b/ARCHITECTURAL_GUARDRAILS.md
@@ -38,7 +38,7 @@ The project is organized as a Cargo workspace with the following crates:
| `sensibledb-cli` | `sensibledb-cli/` | CLI tool for project management and query deployment |
| `sensibledb-explorer` | `sensibledb-explorer/` | Web-based data explorer UI |
| `metrics` | `metrics/` | Observability and metrics collection |
-| `nql-tests` | `nql-tests/` | SensibleQL query language test suite |
+| `sensibleql-tests` | `sensibleql-tests/` | SensibleQL query language test suite |
---
@@ -118,7 +118,7 @@ The project is organized as a Cargo workspace with the following crates:
## 8. Testing Guardrails
- **Unit tests**: Co-located with source in each crate
-- **Query tests**: `nql-tests/` crate for SensibleQL validation
+- **Query tests**: `sensibleql-tests/` crate for SensibleQL validation
- **E2E tests**: Playwright-based in `e2e/` directory
- **Metrics**: Collected via `metrics/` crate
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index a1ff4343..dfa7673a 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -126,7 +126,7 @@ The heart of SensibleDB containing all database functionality.
- `analyzer/` - Type checking, validation, and diagnostics
- `generator/` - Rust code generation from parsed queries
-- **`grammar.pest`** - 295-line Pest grammar defining NQL syntax
+- **`grammar.pest`** - 295-line Pest grammar defining SensibleQL syntax
- **`protocol/`** - Wire protocol and data types
@@ -232,8 +232,8 @@ sensibledb-cli/
#### `/sensibledb-macros/` - Procedural Macros
Procedural macros for SensibleDB including route registration and code generation utilities.
-#### `/nql-tests/` - NQL Test Suite
-Test files for the Nexus Query Language (NQL).
+#### `/sensibleql-tests/` - SensibleQL Test Suite
+Test files for the Nexus Query Language (SensibleQL).
#### `/metrics/` - Performance Metrics
Performance benchmarking and metrics collection.
@@ -284,7 +284,7 @@ Run Clippy to check code quality:
The `clippy_check.sh` script at the repository root runs clippy with project-specific rules:
- Treats warnings as errors
-- Excludes `nql-tests` crate
+- Excludes `sensibleql-tests` crate
- Can run in dashboard mode with additional features
### Testing
@@ -308,8 +308,8 @@ SensibleDB has a comprehensive test suite organized across multiple levels:
- `init_tests.rs` - Project initialization
- `project_tests.rs` - Project management
-**NQL End-to-End Tests**
-- `/nql-tests/tests/` - 54+ test directories covering:
+**SensibleQL End-to-End Tests**
+- `/sensibleql-tests/tests/` - 54+ test directories covering:
- Graph operations (add_n, add_e, traversals)
- Vector search (search_v_with_embed)
- Text search (search_bm25)
@@ -334,8 +334,8 @@ cargo test --workspace
cargo test -p sensibledb-db
cargo test -p sensibledb-cli
-# Run NQL tests
-cd nql-tests
+# Run SensibleQL tests
+cd sensibleql-tests
./test.sh
# Run benchmarks
diff --git a/Cargo.lock b/Cargo.lock
index ed133eea..1e32ab0f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3421,7 +3421,7 @@ dependencies = [
]
[[package]]
-name = "nql-tests"
+name = "sensibleql-tests"
version = "0.1.0"
dependencies = [
"anyhow",
diff --git a/Cargo.toml b/Cargo.toml
index f31f02e0..883e5d7c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -4,7 +4,7 @@ members = [
"sensibledb-container",
"sensibledb-macros",
"sensibledb-cli",
- "nql-tests",
+ "sensibleql-tests",
"metrics",
"sensibledb-explorer",
]
diff --git a/README.md b/README.md
index 28da134b..afa9ad41 100644
--- a/README.md
+++ b/README.md
@@ -166,7 +166,7 @@ SensibleDB/
├── sensibledb-container/ # Docker container deployment
├── sensibledb-macros/ # Procedural macros for SensibleQL
├── metrics/ # Telemetry and metrics
-├── nql-tests/ # Query language test suite
+├── sensibleql-tests/ # Query language test suite
├── e2e/ # Playwright E2E tests (65 tests)
└── docs/ # Documentation source
```
diff --git a/assets/sensible-db-logo.svg b/assets/sensible-db-logo.svg
index 9a46efca..f2bda0bc 100644
--- a/assets/sensible-db-logo.svg
+++ b/assets/sensible-db-logo.svg
@@ -29,6 +29,6 @@
SensibleDB
- EXPLORE YOUR DATA'S CONNECTIONS
+ EXPLORE YOUR DATA
diff --git a/clippy_check.sh b/clippy_check.sh
index c4123082..88c36cd2 100755
--- a/clippy_check.sh
+++ b/clippy_check.sh
@@ -1,5 +1,5 @@
-# cargo clippy --workspace --locked --exclude nql-tests --exclude metrics -- -D warnings -A clippy::too_many_arguments -A clippy::let-and-return -A clippy::module-inception -A clippy::new-ret-no-self -A clippy::wrong-self-convention -A clippy::large-enum-variant -A clippy::inherent-to-string -A clippy::inherent_to_string_shadow_display -D clippy::unwrap_used
+# cargo clippy --workspace --locked --exclude sensibleql-tests --exclude metrics -- -D warnings -A clippy::too_many_arguments -A clippy::let-and-return -A clippy::module-inception -A clippy::new-ret-no-self -A clippy::wrong-self-convention -A clippy::large-enum-variant -A clippy::inherent-to-string -A clippy::inherent_to_string_shadow_display -D clippy::unwrap_used
if [ "$1" = "dashboard" ]; then
cargo clippy -p sensibledb-container --features dev \
@@ -14,7 +14,7 @@ if [ "$1" = "dashboard" ]; then
-A clippy::inherent_to_string_shadow_display
fi
-cargo clippy --workspace --locked --exclude nql-tests --exclude sensibledb-cli --exclude sensibledb-explorer \
+cargo clippy --workspace --locked --exclude sensibleql-tests --exclude sensibledb-cli --exclude sensibledb-explorer \
-- -D warnings \
-A clippy::too_many_arguments \
-A clippy::let-and-return \
diff --git a/docs/INDEX.md b/docs/INDEX.md
index 975a4cb9..9a489f18 100644
--- a/docs/INDEX.md
+++ b/docs/INDEX.md
@@ -1,449 +1,143 @@
-# SensibleDB Documentation
-
-## Table of Contents
-
-- [Getting Started](#getting-started)
- - [Overview](#overview)
- - [Installation](#installation)
-- [SensibleQL Query Language](#sensibleql-query-language)
- - [Overview](#sensibleql-overview)
- - [Schema Definition](#schema-definition)
- - [CRUD Operations](#crud-operations)
- - [Graph Traversals](#graph-traversals)
- - [Vector Operations](#vector-operations)
-- [CLI Reference](#cli-reference)
-- [SDKs](#sdks)
-- [Features](#features)
+# SensibleDB
----
-
-## Getting Started
-
-### Overview
-
-SensibleDB is a high-performance **graph-vector database** built from scratch in Rust, with its own query language designed for traversing and manipulating graph and vector data efficiently.
+**Embedded Graph-Vector Database for AI Applications**
-SensibleDB makes it easy to build all components needed for an AI application in a single platform. You no longer need a separate application DB, vector DB, graph DB, or application layers. Just use SensibleDB.
+SensibleDB is a unified database that makes it easy to build all the components needed for an AI application in a single platform. You no longer need a separate application DB, vector DB, graph DB, or application layers managing multiple storage locations.
-#### Key Features
+Built in Rust with LMDB as its storage engine — like SQLite for knowledge graphs.
-- **Built-in MCP Tools** — AI agents can discover data and walk the graph autonomously
-- **Built-in Embeddings** — Use `Embed()` to vectorize text directly in queries
-- **RAG Tooling** — Vector search, keyword search (BM25), and graph traversals
-- **Secure by Default** — Private by default, accessible only through compiled queries
-- **Ultra-Low Latency** — Rust + LMDB for near-zero overhead access
-- **Type-Safe Queries** — 100% type-safe with compile-time validation
-
-#### Multi-Model Support
+---
-| Model | Description | Use Case |
-|-------|-------------|----------|
-| **Graph** | Native node/edge with traversals | Knowledge graphs, social networks |
-| **Vector** | Cosine similarity with embeddings | Semantic search, RAG |
-| **KV** | Simple key-value lookups | Caching, configuration |
-| **Document** | Flexible schema documents | Content management |
-| **Relational** | Table-based queries with joins | Traditional data relationships |
+## Why SensibleDB?
-### Installation
+| Before SensibleDB | With SensibleDB |
+|---|---|
+| PostgreSQL for app data | **One database** handles everything |
+| Pinecone / Weaviate for vectors | Graph + vector + embedded in a single engine |
+| Neo4j for graph relationships | Type-safe queries with compile-time validation |
+| Custom auth & access layers | Secure by default — access only through compiled SensibleQL |
-#### Prerequisites
+## Key Features
-- **Rust** 1.75.0 or higher
-- **Docker Desktop** (for local development)
-- **LMDB** system library
+- **Built-in MCP Tools** — AI agents discover data and walk the graph instead of generating SQL
+- **Built-in Embeddings** — Vectorize text directly in queries with `Embed()`
+- **RAG Tooling** — Vector search, keyword search, and graph traversals out of the box
+- **Secure by Default** — Private by default; access only through compiled SensibleQL queries
+- **Ultra-Low Latency** — Rust + LMDB storage engine for extreme performance
+- **Type-Safe Queries** — SensibleQL is 100% type-safe, catch errors at compile time
+- **Embedded Mode** — Zero external dependencies, use directly in Rust applications
+- **Visual Explorer** — Interactive graph visualization, natural language chat, and report generation
-```bash
-# Install Rust
-curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
+---
-# Install LMDB
-brew install lmdb # macOS
-apt install liblmdb-dev # Ubuntu/Debian
-pacman -S lmdb # Arch Linux
-```
+## Quick Start
-#### Step 1: Install NexusCLI
+### 1. Install the CLI
```bash
curl -sSL "https://install.sensibledb-db.com" | bash
-nexus --version
```
-#### Step 2: Initialize a Project
+### 2. Initialize a Project
```bash
mkdir my-project && cd my-project
-nexus init
+sensibledb init
```
-Creates:
-```
-my-project/
-├── sensibledb.toml # Project configuration
-├── db/
-│ ├── schema.hx # Schema definitions
-│ └── queries.hx # Query definitions
-└── .sensibledb/ # Build artifacts
-```
+### 3. Write Your Schema & Queries
-#### Step 3: Write Schema and Queries
+Open the generated `.hx` file and define your schema:
-**schema.hx:**
-```nql
+```sensibleql
N::User {
INDEX name: String,
- email: String,
- created_at: Date DEFAULT NOW
+ age: U32
}
-E::Follows {
- From: User,
- To: User,
- Properties: {
- since: Date
- }
+E::FRIENDS {
+ from: User,
+ to: User
}
-```
-**queries.hx:**
-```nql
-QUERY createUser(name: String, email: String) =>
- user <- AddN({name: name, email: email})
+QUERY getUser(user_name: String) =>
+ user <- N({name: user_name})
RETURN user
-QUERY getUser(name: String) =>
- user <- N({name: name})
- RETURN user
-
-QUERY getUserFollowers(user_id: ID) =>
- followers <- N(user_id)::In
- RETURN followers
+QUERY getFriends(user_id: U64) =>
+ user <- N({id: user_id})
+ friends <- TRAVERSE user -[FRIENDS]-> friend
+ RETURN friend
```
-#### Step 4: Check and Deploy
+### 4. Deploy
```bash
-nexus check # Validate compilation
-nexus push dev # Deploy locally
+sensibledb push dev
```
-#### Step 5: Test
+### 5. Use in Your Application
-```bash
-curl -X POST http://localhost:6969/createUser \
- -H 'Content-Type: application/json' \
- -d '{"name": "John", "email": "john@example.com"}'
-
-curl -X POST http://localhost:6969/getUser \
- -H 'Content-Type: application/json' \
- -d '{"name": "John"}'
-```
-
----
-
-## SensibleQL Query Language
-
-### Overview
-
-SensibleQL is a **strongly typed, compiled query language** for SensibleDB that combines the best features of Gremlin, Cypher, and Rust.
-
-#### Why SensibleQL?
-
-| Feature | SensibleQL | Gremlin | Cypher |
-|---------|---------|---------|--------|
-| Type Safety | Compile-time | Runtime | Runtime |
-| Syntax | Clean, concise | Verbose | Readable |
-| Performance | Compiled | Interpreted | Interpreted |
-| IDE Support | Autocomplete | Limited | Limited |
-| Vector Support | Built-in | External | External |
-
-#### Query Structure
-
-```nql
-QUERY QueryName(param1: Type, param2: Type) =>
- result <- traversal_expression
- RETURN result
-```
-
-| Component | Description |
-|-----------|-------------|
-| `QUERY` | Start query definition |
-| `QueryName` | Query identifier (becomes API endpoint) |
-| `param: Type` | Typed input parameters |
-| `=>` | Separates header from body |
-| `<-` | Assignment operator |
-| `RETURN` | Output values |
-
-### Schema Definition
-
-#### Node Schema
-
-```nql
-N::User {
- INDEX name: String,
- email: String,
- age: U32,
- created_at: Date DEFAULT NOW
-}
-```
-
-#### Edge Schema
-
-```nql
-E::Follows {
- From: User,
- To: User,
- Properties: {
- since: Date
- }
-}
-```
-
-#### Supported Types
-
-| Type | Description | Example |
-|------|-------------|---------|
-| `String` | UTF-8 text | `"hello"` |
-| `I32`, `I64` | Signed integers | `42` |
-| `U8`, `U32`, `U64` | Unsigned integers | `42` |
-| `F32`, `F64` | Floating point | `3.14` |
-| `Boolean` | True/false | `true` |
-| `Date` | Timestamp | `NOW` |
-| `ID` | Unique identifier | Auto-generated |
-| `Vector` | Float array | `[0.1, 0.2, ...]` |
-
-### CRUD Operations
-
-#### Create
-
-```nql
-QUERY createUser(name: String, email: String) =>
- user <- AddN({name: name, email: email})
- RETURN user
-
-QUERY followUser(from_id: ID, to_id: ID, since: Date) =>
- edge <- AddE({since: since})::From(from_id)::To(to_id)
- RETURN edge
-```
-
-#### Read
-
-```nql
-QUERY getUser(name: String) =>
- user <- N({name: name})
- RETURN user
-
-QUERY getAllUsers() =>
- users <- N()
- RETURN users
-```
-
-#### Update
-
-```nql
-QUERY updateUserEmail(user_id: ID, email: String) =>
- updated <- N(user_id)::Update({email: email})
- RETURN updated
-```
-
-#### Delete
-
-```nql
-QUERY deleteUser(user_id: ID) =>
- N(user_id)::Drop
- RETURN "Deleted"
-```
-
-### Graph Traversals
-
-#### `::Out` — Outgoing Nodes
-
-```nql
-QUERY GetUserFollowing(user_id: ID) =>
- following <- N(user_id)::Out
- RETURN following
-```
-
-#### `::In` — Incoming Nodes
-
-```nql
-QUERY GetUserFollowers(user_id: ID) =>
- followers <- N(user_id)::In
- RETURN followers
-```
-
-#### `::OutE` — Outgoing Edges
-
-```nql
-QUERY GetFollowingEdges(user_id: ID) =>
- edges <- N(user_id)::OutE
- RETURN edges
-```
-
-#### `::InE` — Incoming Edges
-
-```nql
-QUERY GetFollowerEdges(user_id: ID) =>
- edges <- N(user_id)::InE
- RETURN edges
-```
-
-#### Chaining Traversals
-
-```nql
-QUERY GetFriendsOfFriends(user_id: ID) =>
- fof <- N(user_id)::Out::Out
- RETURN fof
-```
-
-#### Shortest Path
-
-```nql
-QUERY FindPath(from_id: ID, to_id: ID) =>
- path <- N(from_id)::ShortestPath(to_id)>
- RETURN path
-```
-
-### Vector Operations
-
-#### Vector Similarity Search
-
-```nql
-QUERY searchSimilar(query_vec: [F32], limit: U32) =>
- results <- SearchV({vector: query_vec, limit: limit})
- RETURN results
-```
-
-#### Automatic Embeddings
-
-```nql
-QUERY searchArticles(query: String) =>
- results <- SearchV({vector: Embed(query), limit: 10})
- RETURN results
-```
-
-#### Keyword Search (BM25)
-
-```nql
-QUERY keywordSearch(query: String) =>
- results <- SearchBM25({fields: ["title", "content"], query: query})
- RETURN results
-```
-
-#### Hybrid Search with RRF
-
-```nql
-QUERY hybridSearch(query: String) =>
- vector_results <- SearchV({vector: Embed(query), limit: 20})
- keyword_results <- SearchBM25({fields: ["title"], query: query})
- combined <- vector_results::RRF(keyword_results)
- RETURN combined
-```
-
-#### MMR Reranking
-
-```nql
-QUERY diverseResults(query: String) =>
- results <- SearchV({vector: Embed(query), limit: 50})
- diverse <- results::MMR({diversity: 0.5, limit: 10})
- RETURN diverse
-```
-
----
-
-## CLI Reference
-
-### Commands
-
-| Command | Description |
-|---------|-------------|
-| `nexus init` | Initialize a new project |
-| `nexus check` | Validate schema and queries |
-| `nexus push dev` | Deploy to local instance |
-| `nexus status` | Show instance status |
-| `nexus start ` | Start an instance |
-| `nexus stop ` | Stop an instance |
-| `nexus logs` | Stream instance logs |
-| `nexus prune` | Clean up unused resources |
-| `nexus update` | Update CLI to latest version |
-
-### Configuration (sensibledb.toml)
-
-```toml
-[project]
-name = "my-project"
-build_mode = "debug"
-
-[vector]
-dimensions = 384
-metric = "cosine"
-
-[instance]
-name = "dev-instance"
-port = 6969
-```
-
----
-
-## SDKs
-
-### TypeScript
-
-```bash
-npm install sensible-ts
-```
+**TypeScript:**
```typescript
import SensibleDB from "sensible-ts";
+
const client = new SensibleDB();
-const user = await client.query("getUser", { name: "John" });
-```
-### Python
+// Create a user
+await client.query("addUser", { name: "John", age: 30 });
-```bash
-pip install sensible-py
+// Query with type safety
+const user = await client.query("getUser", { user_name: "John" });
```
+**Python:**
+
```python
-from nexus import Client
-client = Client(local=True, port=6969)
-user = client.query("getUser", {"name": "John"})
-```
+from sensibledb import SensibleDB
-### Rust (Embedded)
+client = SensibleDB()
-```toml
-[dependencies]
-sensibledb-db = { version = "1.3", features = ["embedded"] }
+# Query the database
+user = client.query("getUser", user_name="John")
+print(user)
```
+**Rust (Embedded):**
+
```rust
use sensibledb_db::embedded::{Database, Node};
+
let db = Database::open("./my_db")?;
+let mut tx = db.write_transaction()?;
+
+tx.put_node(Node {
+ id: 1,
+ label: "User".into(),
+})?;
+
+tx.commit()?;
```
---
-## Features
-
-### Built-in MCP Tools
-AI agents can discover data and walk the graph autonomously, constructing queries based on graph topology.
+## Documentation
-### Built-in Embeddings
-Use `Embed()` directly in queries — no external embedding service needed.
+| Section | Description |
+|---|---|
+| [Getting Started](getting-started/intro.md) | Installation and setup |
+| [SensibleQL](sensibleql/overview.md) | Query language reference |
+| [CLI](cli/getting-started.md) | Command-line tool guide |
+| [SDKs](sdks/overview.md) | TypeScript, Python, and Rust SDKs |
+| [Features](features/overview.md) | Full feature overview |
-### RAG Tooling
-Vector search, BM25 keyword search, graph traversals, hybrid search with RRF, and MMR reranking.
+---
-### Security
-Private by default. Data accessible only through compiled SensibleQL queries. Type-safe queries prevent injection attacks.
+## License
-### Ultra-Low Latency
-Rust + LMDB memory-mapped B-trees for near-zero overhead access.
+SensibleDB is licensed under the AGPL (Affero General Public License).
-### Type-Safe Queries
-Compile-time validation catches errors before production. IDE support with autocomplete.
+## Commercial Support
-### Multi-Model
-Graph, vector, KV, document, and relational — all in one database.
+SensibleDB is available as a managed service for selected users. For enterprise support or managed deployment, [contact us](mailto:founders@sensibledb-db.com).
diff --git a/docs/architecture/diagrams/system-context.mmd b/docs/architecture/diagrams/system-context.mmd
index 2fe3ef01..0656cf1a 100644
--- a/docs/architecture/diagrams/system-context.mmd
+++ b/docs/architecture/diagrams/system-context.mmd
@@ -4,7 +4,7 @@ title: SensibleDB - System Context Diagram (C4 Level 1)
graph TB
subgraph External["External Systems"]
- Developer["👤 Developer
Writes NexusQL schemas & queries"]
+ Developer["👤 Developer
Writes SensibleQL schemas & queries"]
AIApp["🤖 AI Application
RAG, Agents, LLM Apps"]
MCPClient["🔧 MCP Client
AI Agent Tool Discovery"]
end
diff --git a/docs/design/explorer-redesign.md b/docs/design/explorer-redesign.md
index 125f1d0d..a62d2f78 100644
--- a/docs/design/explorer-redesign.md
+++ b/docs/design/explorer-redesign.md
@@ -415,7 +415,7 @@ Step 4: Processing
| Label/Type | Type | "What kind of item this is" |
| Vector Embedding | Similarity | "Items that are alike are grouped together" |
| Graph Traversal | Follow connections | "Starting from one item, see what it connects to" |
-| NQL Query | Ask a question | "A way to ask your data questions" |
+| SensibleQL Query | Ask a question | "A way to ask your data questions" |
| Schema | Structure | "The blueprint of how your data is organized" |
### 6.2 Contextual Tooltips
@@ -539,7 +539,7 @@ Every technical term gets a `?` icon that shows:
### Phase 1: Foundation (Week 1)
- [ ] Design system tokens (CSS variables) ✅ started
- [ ] Consistent component styles (buttons, inputs, cards)
-- [ ] Fix NQL query execution (camelCase params) ✅ done
+- [ ] Fix SensibleQL query execution (camelCase params) ✅ done
- [ ] Graph interaction (zoom, pan, drag, select) ✅ done
### Phase 2: Home & Onboarding (Week 2)
@@ -550,7 +550,7 @@ Every technical term gets a `?` icon that shows:
### Phase 3: Chat Interface (Week 3)
- [ ] Chat view with conversation history
-- [ ] Natural language to NQL translation (local)
+- [ ] Natural language to SensibleQL translation (local)
- [ ] Streaming response display
- [ ] Follow-up question suggestions
@@ -585,4 +585,4 @@ Every technical term gets a `?` icon that shows:
| Query success rate | > 90% | % of queries that return results vs errors |
| User retention (7-day) | > 60% | Analytics: returning users / total users |
| Support tickets | < 5/week | Track user-reported issues |
-| NQL usage vs Chat | < 30% NQL | Migration to natural language interface |
+| SensibleQL usage vs Chat | < 30% SensibleQL | Migration to natural language interface |
diff --git a/docs/getting-started/installation.md b/docs/getting-started/installation.md
index d5674c2e..a53cb7bd 100644
--- a/docs/getting-started/installation.md
+++ b/docs/getting-started/installation.md
@@ -25,7 +25,7 @@ nexus init
### 3. Write Schema and Queries
**schema.hx:**
-```nql
+```sensibleql
N::User {
INDEX name: String,
email: String,
@@ -40,7 +40,7 @@ E::Follows {
```
**queries.hx:**
-```nql
+```sensibleql
QUERY createUser(name: String, email: String) =>
user <- AddN({name: name, email: email})
RETURN user
diff --git a/docs/nexusql/crud-operations.md b/docs/sensibleql/crud-operations.md
similarity index 91%
rename from docs/nexusql/crud-operations.md
rename to docs/sensibleql/crud-operations.md
index 52351ceb..09cc18e4 100644
--- a/docs/nexusql/crud-operations.md
+++ b/docs/sensibleql/crud-operations.md
@@ -2,7 +2,7 @@
## Create
-```nql
+```sensibleql
QUERY createUser(name: String, email: String) =>
user <- AddN({name: name, email: email})
RETURN user
@@ -14,7 +14,7 @@ QUERY followUser(from_id: ID, to_id: ID, since: Date) =>
## Read
-```nql
+```sensibleql
QUERY getUser(name: String) =>
user <- N({name: name})
RETURN user
@@ -22,7 +22,7 @@ QUERY getUser(name: String) =>
## Update
-```nql
+```sensibleql
QUERY updateUserEmail(user_id: ID, email: String) =>
updated <- N(user_id)::Update({email: email})
RETURN updated
@@ -30,7 +30,7 @@ QUERY updateUserEmail(user_id: ID, email: String) =>
## Delete
-```nql
+```sensibleql
QUERY deleteUser(user_id: ID) =>
N(user_id)::Drop
RETURN "Deleted"
diff --git a/docs/nexusql/overview.md b/docs/sensibleql/overview.md
similarity index 96%
rename from docs/nexusql/overview.md
rename to docs/sensibleql/overview.md
index 755f9a97..48617f3f 100644
--- a/docs/nexusql/overview.md
+++ b/docs/sensibleql/overview.md
@@ -12,7 +12,7 @@ SensibleQL is a **strongly typed, compiled query language** for SensibleDB.
## Query Structure
-```nql
+```sensibleql
QUERY QueryName(param1: Type, param2: Type) =>
result <- traversal_expression
RETURN result
@@ -20,7 +20,7 @@ QUERY QueryName(param1: Type, param2: Type) =>
## Example
-```nql
+```sensibleql
N::User {
INDEX name: String,
age: U32
diff --git a/docs/nexusql/schema-definition.md b/docs/sensibleql/schema-definition.md
similarity index 95%
rename from docs/nexusql/schema-definition.md
rename to docs/sensibleql/schema-definition.md
index 88dabd7e..420320d5 100644
--- a/docs/nexusql/schema-definition.md
+++ b/docs/sensibleql/schema-definition.md
@@ -2,7 +2,7 @@
## Node Schema
-```nql
+```sensibleql
N::User {
INDEX name: String,
email: String,
@@ -13,7 +13,7 @@ N::User {
## Edge Schema
-```nql
+```sensibleql
E::Follows {
From: User,
To: User,
diff --git a/docs/nexusql/traversals.md b/docs/sensibleql/traversals.md
similarity index 90%
rename from docs/nexusql/traversals.md
rename to docs/sensibleql/traversals.md
index 75cbccb9..5ce5018c 100644
--- a/docs/nexusql/traversals.md
+++ b/docs/sensibleql/traversals.md
@@ -2,7 +2,7 @@
## Out - Outgoing Nodes
-```nql
+```sensibleql
QUERY GetUserFollowing(user_id: ID) =>
following <- N(user_id)::Out
RETURN following
@@ -10,7 +10,7 @@ QUERY GetUserFollowing(user_id: ID) =>
## In - Incoming Nodes
-```nql
+```sensibleql
QUERY GetUserFollowers(user_id: ID) =>
followers <- N(user_id)::In
RETURN followers
@@ -18,7 +18,7 @@ QUERY GetUserFollowers(user_id: ID) =>
## OutE - Outgoing Edges
-```nql
+```sensibleql
QUERY GetFollowingEdges(user_id: ID) =>
edges <- N(user_id)::OutE
RETURN edges
@@ -26,7 +26,7 @@ QUERY GetFollowingEdges(user_id: ID) =>
## InE - Incoming Edges
-```nql
+```sensibleql
QUERY GetFollowerEdges(user_id: ID) =>
edges <- N(user_id)::InE
RETURN edges
@@ -34,7 +34,7 @@ QUERY GetFollowerEdges(user_id: ID) =>
## Chaining
-```nql
+```sensibleql
QUERY GetFriendsOfFriends(user_id: ID) =>
fof <- N(user_id)::Out::Out
RETURN fof
@@ -42,7 +42,7 @@ QUERY GetFriendsOfFriends(user_id: ID) =>
## Shortest Path
-```nql
+```sensibleql
QUERY FindPath(from_id: ID, to_id: ID) =>
path <- N(from_id)::ShortestPath(to_id)>
RETURN path
diff --git a/docs/nexusql/vector-operations.md b/docs/sensibleql/vector-operations.md
similarity index 93%
rename from docs/nexusql/vector-operations.md
rename to docs/sensibleql/vector-operations.md
index 30d2dd9c..e79ae656 100644
--- a/docs/nexusql/vector-operations.md
+++ b/docs/sensibleql/vector-operations.md
@@ -2,7 +2,7 @@
## Vector Similarity Search
-```nql
+```sensibleql
QUERY searchSimilar(query_vec: [F32], limit: U32) =>
results <- SearchV({vector: query_vec, limit: limit})
RETURN results
@@ -10,7 +10,7 @@ QUERY searchSimilar(query_vec: [F32], limit: U32) =>
## Automatic Embeddings
-```nql
+```sensibleql
QUERY searchArticles(query: String) =>
results <- SearchV({vector: Embed(query), limit: 10})
RETURN results
@@ -18,7 +18,7 @@ QUERY searchArticles(query: String) =>
## Keyword Search (BM25)
-```nql
+```sensibleql
QUERY keywordSearch(query: String) =>
results <- SearchBM25({fields: ["title", "content"], query: query})
RETURN results
@@ -26,7 +26,7 @@ QUERY keywordSearch(query: String) =>
## Hybrid Search with RRF
-```nql
+```sensibleql
QUERY hybridSearch(query: String) =>
vector_results <- SearchV({vector: Embed(query), limit: 20})
keyword_results <- SearchBM25({fields: ["title"], query: query})
diff --git a/e2e/chat-view.spec.ts b/e2e/chat-view.spec.ts
index f605eb9a..e1ced9dd 100644
--- a/e2e/chat-view.spec.ts
+++ b/e2e/chat-view.spec.ts
@@ -59,12 +59,12 @@ test.describe('Chat Interface', () => {
await expect(page.locator('.follow-up-chips')).toBeVisible();
});
- test('"How did I get this?" expandable shows NQL query', async ({ page }) => {
+ test('"How did I get this?" expandable shows SensibleQL query', async ({ page }) => {
const input = page.locator('.chat-input-area input');
await input.fill('What data do I have?');
await page.getByRole('button', { name: 'Send' }).click();
await expect(page.locator('.chat-message.assistant').last()).toBeVisible({ timeout: 5000 });
- const nqlToggle = page.locator('.nql-toggle-btn');
- await expect(nqlToggle).toBeVisible();
+ const sensibleqlToggle = page.locator('.sensibleql-toggle-btn');
+ await expect(sensibleqlToggle).toBeVisible();
});
});
diff --git a/e2e/fixtures.ts b/e2e/fixtures.ts
index 3cabfb2e..d7ac189d 100644
--- a/e2e/fixtures.ts
+++ b/e2e/fixtures.ts
@@ -83,7 +83,7 @@ export async function injectTauriMock(page: Page) {
return 'deleted';
case 'schema_get':
return mockData.schema;
- case 'nql_execute': {
+ case 'sensibleql_execute': {
const query = (args?.query || '').trim().toUpperCase();
if (query.includes('COUNT') && query.includes('NODE')) {
return { success: true, message: `Found ${mockData.nodes.length} nodes`, data: { nodes: mockData.nodes, edges: [] } };
diff --git a/e2e/onboarding-and-polish.spec.ts b/e2e/onboarding-and-polish.spec.ts
index 57bf1082..1ce4c295 100644
--- a/e2e/onboarding-and-polish.spec.ts
+++ b/e2e/onboarding-and-polish.spec.ts
@@ -71,15 +71,15 @@ test.describe('Design System', () => {
});
});
-test.describe('NQL Editor', () => {
+test.describe('SensibleQL Editor', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/');
- await page.getByRole('button', { name: 'NQL Editor' }).first().click();
+ await page.getByRole('button', { name: 'SensibleQL Editor' }).first().click();
await page.waitForTimeout(500);
});
- test('renders NQL editor', async ({ page }) => {
- await expect(page.locator('.nql-editor')).toBeVisible();
+ test('renders SensibleQL editor', async ({ page }) => {
+ await expect(page.locator('.sensibleql-editor')).toBeVisible();
});
test('displays sample queries', async ({ page }) => {
diff --git a/mkdocs.yml b/mkdocs.yml
index 12f2f7a9..52d95f2b 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -43,6 +43,7 @@ markdown_extensions:
- pymdownx.details
nav:
+ - Home: index.md
- Getting Started:
- Overview: getting-started/intro.md
- Installation: getting-started/installation.md
diff --git a/sensibledb-cli/src/github_issue.rs b/sensibledb-cli/src/github_issue.rs
index 2237b551..1c26e43e 100644
--- a/sensibledb-cli/src/github_issue.rs
+++ b/sensibledb-cli/src/github_issue.rs
@@ -53,8 +53,8 @@ impl GitHubIssueBuilder {
/// Build the GitHub issue URL with query parameters.
pub fn build_url(&self) -> String {
let title = match &self.first_error {
- Some(error) => format!("bug (nql): rust generation failure - {}", error),
- None => "bug (nql): rust generation failure".to_string(),
+ Some(error) => format!("bug (sensibleql): rust generation failure - {}", error),
+ None => "bug (sensibleql): rust generation failure".to_string(),
};
// URL encode the fixed parameters
diff --git a/sensibledb-db/src/sensibledbc/generator/queries.rs b/sensibledb-db/src/sensibledbc/generator/queries.rs
index d07482c7..30601075 100644
--- a/sensibledb-db/src/sensibledbc/generator/queries.rs
+++ b/sensibledb-db/src/sensibledbc/generator/queries.rs
@@ -300,7 +300,7 @@ impl Query {
}
} else if struct_def.is_collection {
// Collection - generate mapping code
- // Use NQL closure param name if available, otherwise fall back to singular form
+ // Use SensibleQL closure param name if available, otherwise fall back to singular form
let singular_var = struct_def
.closure_param_name
.as_deref()
@@ -1310,7 +1310,7 @@ impl Query {
)?;
} else if struct_def.is_collection {
// Collection - generate mapping code
- // Use NQL closure param name if available, otherwise fall back to singular form
+ // Use SensibleQL closure param name if available, otherwise fall back to singular form
let singular_var = struct_def
.closure_param_name
.as_deref()
diff --git a/sensibledb-db/src/sensibledbc/generator/return_values.rs b/sensibledb-db/src/sensibledbc/generator/return_values.rs
index 2f10c2d4..4e066b29 100644
--- a/sensibledb-db/src/sensibledbc/generator/return_values.rs
+++ b/sensibledb-db/src/sensibledbc/generator/return_values.rs
@@ -53,7 +53,7 @@ pub struct ReturnValueStruct {
pub field_infos: Vec, // Original field info for nested struct generation
pub aggregate_properties: Vec, // Properties to group by (for closure-style aggregates)
pub is_count_aggregate: bool, // True for COUNT mode aggregates
- pub closure_param_name: Option, // NQL closure parameter name (e.g., "e" from entries::|e|)
+ pub closure_param_name: Option, // SensibleQL closure parameter name (e.g., "e" from entries::|e|)
pub is_primitive: bool, // True for Count/Boolean/Scalar - emit variable directly
pub primitive_literal_value: Option>, // For primitives with field access (e.g., user::ID)
}
diff --git a/sensibledb-db/src/sensibledbc/generator/traversal_steps.rs b/sensibledb-db/src/sensibledbc/generator/traversal_steps.rs
index e85950a2..5d859658 100644
--- a/sensibledb-db/src/sensibledbc/generator/traversal_steps.rs
+++ b/sensibledb-db/src/sensibledbc/generator/traversal_steps.rs
@@ -140,7 +140,7 @@ pub struct Traversal {
pub excluded_fields: Vec,
pub nested_traversals: std::collections::HashMap,
pub is_reused_variable: bool,
- pub closure_param_name: Option, // NQL closure parameter name (e.g., "e" from entries::|e|)
+ pub closure_param_name: Option, // SensibleQL closure parameter name (e.g., "e" from entries::|e|)
/// Maps output field name -> source property name for renamed fields
/// e.g., "post" -> "content" for `post: content`, "file_id" -> "ID"
pub field_name_mappings: std::collections::HashMap,
diff --git a/sensibledb-db/src/sensibledbc/parser/README.md b/sensibledb-db/src/sensibledbc/parser/README.md
index b10640d8..ebb75b6f 100644
--- a/sensibledb-db/src/sensibledbc/parser/README.md
+++ b/sensibledb-db/src/sensibledbc/parser/README.md
@@ -7,7 +7,7 @@ The parser module transforms SensibleQL source code into an Abstract Syntax Tree
### Core Components
- **`mod.rs`** - Main parser entry point, orchestrates parsing of schemas, queries, and migrations
-- **`grammar.pest`** - Pest grammar defining NQL syntax rules
+- **`grammar.pest`** - Pest grammar defining SensibleQL syntax rules
- **`types.rs`** - AST node definitions and data structures
- **`location.rs`** - Location tracking for error reporting
@@ -24,7 +24,7 @@ The parser module transforms SensibleQL source code into an Abstract Syntax Tree
## Parsing Flow
-1. **Input**: NQL files containing schemas, queries, and migrations
+1. **Input**: SensibleQL files containing schemas, queries, and migrations
2. **Lexing**: Pest tokenizes input according to `grammar.pest` rules
3. **AST Construction**:
- Schemas parsed first (establishing type definitions)
diff --git a/sensibledb-explorer/icons/128x128.png b/sensibledb-explorer/icons/128x128.png
index 2243a781..ff158536 100644
Binary files a/sensibledb-explorer/icons/128x128.png and b/sensibledb-explorer/icons/128x128.png differ
diff --git a/sensibledb-explorer/icons/128x128@2x.png b/sensibledb-explorer/icons/128x128@2x.png
index dbd4d907..3e087d83 100644
Binary files a/sensibledb-explorer/icons/128x128@2x.png and b/sensibledb-explorer/icons/128x128@2x.png differ
diff --git a/sensibledb-explorer/icons/32x32.png b/sensibledb-explorer/icons/32x32.png
index 3731e51a..5098faf4 100644
Binary files a/sensibledb-explorer/icons/32x32.png and b/sensibledb-explorer/icons/32x32.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_1024x1024.png b/sensibledb-explorer/icons/app.iconset/icon_1024x1024.png
new file mode 100644
index 00000000..14853cbe
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_1024x1024.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_128x128.png b/sensibledb-explorer/icons/app.iconset/icon_128x128.png
new file mode 100644
index 00000000..ff158536
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_128x128.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_128x128@2x.png b/sensibledb-explorer/icons/app.iconset/icon_128x128@2x.png
new file mode 100644
index 00000000..3e087d83
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_128x128@2x.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_16x16.png b/sensibledb-explorer/icons/app.iconset/icon_16x16.png
new file mode 100644
index 00000000..e4429d76
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_16x16.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_16x16@2x.png b/sensibledb-explorer/icons/app.iconset/icon_16x16@2x.png
new file mode 100644
index 00000000..5098faf4
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_16x16@2x.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_256x256.png b/sensibledb-explorer/icons/app.iconset/icon_256x256.png
new file mode 100644
index 00000000..3e087d83
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_256x256.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_256x256@2x.png b/sensibledb-explorer/icons/app.iconset/icon_256x256@2x.png
new file mode 100644
index 00000000..3ade7091
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_256x256@2x.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_32x32.png b/sensibledb-explorer/icons/app.iconset/icon_32x32.png
new file mode 100644
index 00000000..5098faf4
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_32x32.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_32x32@2x.png b/sensibledb-explorer/icons/app.iconset/icon_32x32@2x.png
new file mode 100644
index 00000000..2e77b984
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_32x32@2x.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_512x512.png b/sensibledb-explorer/icons/app.iconset/icon_512x512.png
new file mode 100644
index 00000000..3ade7091
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_512x512.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_512x512@2x.png b/sensibledb-explorer/icons/app.iconset/icon_512x512@2x.png
new file mode 100644
index 00000000..14853cbe
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_512x512@2x.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_64x64.png b/sensibledb-explorer/icons/app.iconset/icon_64x64.png
new file mode 100644
index 00000000..2e77b984
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_64x64.png differ
diff --git a/sensibledb-explorer/icons/app.iconset/icon_64x64@2x.png b/sensibledb-explorer/icons/app.iconset/icon_64x64@2x.png
new file mode 100644
index 00000000..ff158536
Binary files /dev/null and b/sensibledb-explorer/icons/app.iconset/icon_64x64@2x.png differ
diff --git a/sensibledb-explorer/icons/icon.icns b/sensibledb-explorer/icons/icon.icns
index dbd4d907..cb2a23dc 100644
Binary files a/sensibledb-explorer/icons/icon.icns and b/sensibledb-explorer/icons/icon.icns differ
diff --git a/sensibledb-explorer/icons/icon.ico b/sensibledb-explorer/icons/icon.ico
new file mode 100644
index 00000000..c535f9ed
Binary files /dev/null and b/sensibledb-explorer/icons/icon.ico differ
diff --git a/sensibledb-explorer/src/commands/database.rs b/sensibledb-explorer/src/commands/database.rs
index e3a217a7..69f22aa9 100644
--- a/sensibledb-explorer/src/commands/database.rs
+++ b/sensibledb-explorer/src/commands/database.rs
@@ -56,13 +56,25 @@ pub fn db_close(state: tauri::State, name: String) -> Result) -> Result, String> {
let dbs = state.databases.lock().map_err(|e| e.to_string())?;
let keys: Vec = dbs.keys().cloned().collect();
- let msg = format!("[DB_LIST] Returning {} databases: {:?}
-", keys.len(), keys);
+ let msg = format!(
+ "[DB_LIST] Returning {} databases: {:?}
+",
+ keys.len(),
+ keys
+ );
eprint!("{}", msg);
- std::fs::write("/tmp/sensibledb-explorer.log", format!("{}
+ std::fs::write(
+ "/tmp/sensibledb-explorer.log",
+ format!(
+ "{}
[DB_LIST] Returning {} databases: {:?}
-",
- std::fs::read_to_string("/tmp/sensibledb-explorer.log").unwrap_or_default(), keys.len(), keys)).ok();
+",
+ std::fs::read_to_string("/tmp/sensibledb-explorer.log").unwrap_or_default(),
+ keys.len(),
+ keys
+ ),
+ )
+ .ok();
Ok(keys)
}
@@ -112,10 +124,13 @@ pub fn db_create_demo_internal(state: &AppState) -> Result<(), String> {
#[tauri::command]
pub fn db_create_demo(state: tauri::State) -> Result {
- db_create_demo_internal(&state).map(|_| "Demo databases ready: health-patterns, project-management".to_string())
+ db_create_demo_internal(&state)
+ .map(|_| "Demo databases ready: health-patterns, project-management".to_string())
}
-fn populate_health_patterns(db: &sensibledb_db::embedded::database::Database) -> Result<(), String> {
+fn populate_health_patterns(
+ db: &sensibledb_db::embedded::database::Database,
+) -> Result<(), String> {
db.put_node(Node {
id: 1,
label: "Person:Alex".to_string(),
@@ -291,64 +306,236 @@ fn populate_health_patterns(db: &sensibledb_db::embedded::database::Database) ->
#[tauri::command]
pub fn log_error(msg: String) {
eprintln!("[FRONTEND_ERROR] {}", msg);
- let _ = std::fs::write("/tmp/sensibledb-explorer.log", format!("{}
+ let _ = std::fs::write(
+ "/tmp/sensibledb-explorer.log",
+ format!(
+ "{}
[FRONTEND_ERROR] {}
-",
- std::fs::read_to_string("/tmp/sensibledb-explorer.log").unwrap_or_default(), msg));
+",
+ std::fs::read_to_string("/tmp/sensibledb-explorer.log").unwrap_or_default(),
+ msg
+ ),
+ );
}
-fn populate_project_management(db: &sensibledb_db::embedded::database::Database) -> Result<(), String> {
+fn populate_project_management(
+ db: &sensibledb_db::embedded::database::Database,
+) -> Result<(), String> {
// Team Members
- db.put_node(Node { id: 1, label: "Person:Alice".to_string() }).map_err(|e| e.to_string())?;
- db.put_node(Node { id: 2, label: "Person:Bob".to_string() }).map_err(|e| e.to_string())?;
- db.put_node(Node { id: 3, label: "Person:Carol".to_string() }).map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 1,
+ label: "Person:Alice".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 2,
+ label: "Person:Bob".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 3,
+ label: "Person:Carol".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
// Projects
- db.put_node(Node { id: 10, label: "Project:WebsiteRedesign".to_string() }).map_err(|e| e.to_string())?;
- db.put_node(Node { id: 11, label: "Project:MobileApp".to_string() }).map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 10,
+ label: "Project:WebsiteRedesign".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 11,
+ label: "Project:MobileApp".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
// Tasks
- db.put_node(Node { id: 20, label: "Task:DesignMockups".to_string() }).map_err(|e| e.to_string())?;
- db.put_node(Node { id: 21, label: "Task:FrontendDev".to_string() }).map_err(|e| e.to_string())?;
- db.put_node(Node { id: 22, label: "Task:BackendAPI".to_string() }).map_err(|e| e.to_string())?;
- db.put_node(Node { id: 23, label: "Task:Testing".to_string() }).map_err(|e| e.to_string())?;
- db.put_node(Node { id: 24, label: "Task:Deployment".to_string() }).map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 20,
+ label: "Task:DesignMockups".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 21,
+ label: "Task:FrontendDev".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 22,
+ label: "Task:BackendAPI".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 23,
+ label: "Task:Testing".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 24,
+ label: "Task:Deployment".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
// Tools
- db.put_node(Node { id: 30, label: "Tool:Figma".to_string() }).map_err(|e| e.to_string())?;
- db.put_node(Node { id: 31, label: "Tool:GitHub".to_string() }).map_err(|e| e.to_string())?;
- db.put_node(Node { id: 32, label: "Tool:AWS".to_string() }).map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 30,
+ label: "Tool:Figma".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 31,
+ label: "Tool:GitHub".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_node(Node {
+ id: 32,
+ label: "Tool:AWS".to_string(),
+ })
+ .map_err(|e| e.to_string())?;
// Assignments: Person -> Project
- db.put_edge(Edge { id: 100, label: "ASSIGNED_TO".to_string(), from: 1, to: 10 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 101, label: "ASSIGNED_TO".to_string(), from: 2, to: 10 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 102, label: "ASSIGNED_TO".to_string(), from: 3, to: 11 }).map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 100,
+ label: "ASSIGNED_TO".to_string(),
+ from: 1,
+ to: 10,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 101,
+ label: "ASSIGNED_TO".to_string(),
+ from: 2,
+ to: 10,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 102,
+ label: "ASSIGNED_TO".to_string(),
+ from: 3,
+ to: 11,
+ })
+ .map_err(|e| e.to_string())?;
// Tasks belong to projects
- db.put_edge(Edge { id: 110, label: "PART_OF".to_string(), from: 20, to: 10 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 111, label: "PART_OF".to_string(), from: 21, to: 10 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 112, label: "PART_OF".to_string(), from: 22, to: 11 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 113, label: "PART_OF".to_string(), from: 23, to: 11 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 114, label: "PART_OF".to_string(), from: 24, to: 11 }).map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 110,
+ label: "PART_OF".to_string(),
+ from: 20,
+ to: 10,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 111,
+ label: "PART_OF".to_string(),
+ from: 21,
+ to: 10,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 112,
+ label: "PART_OF".to_string(),
+ from: 22,
+ to: 11,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 113,
+ label: "PART_OF".to_string(),
+ from: 23,
+ to: 11,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 114,
+ label: "PART_OF".to_string(),
+ from: 24,
+ to: 11,
+ })
+ .map_err(|e| e.to_string())?;
// Task dependencies
- db.put_edge(Edge { id: 120, label: "BLOCKS".to_string(), from: 20, to: 21 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 121, label: "BLOCKS".to_string(), from: 21, to: 23 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 122, label: "BLOCKS".to_string(), from: 22, to: 23 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 123, label: "BLOCKS".to_string(), from: 23, to: 24 }).map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 120,
+ label: "BLOCKS".to_string(),
+ from: 20,
+ to: 21,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 121,
+ label: "BLOCKS".to_string(),
+ from: 21,
+ to: 23,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 122,
+ label: "BLOCKS".to_string(),
+ from: 22,
+ to: 23,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 123,
+ label: "BLOCKS".to_string(),
+ from: 23,
+ to: 24,
+ })
+ .map_err(|e| e.to_string())?;
// Tasks use tools
- db.put_edge(Edge { id: 130, label: "USES".to_string(), from: 20, to: 30 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 131, label: "USES".to_string(), from: 21, to: 31 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 132, label: "USES".to_string(), from: 22, to: 31 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 133, label: "USES".to_string(), from: 24, to: 32 }).map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 130,
+ label: "USES".to_string(),
+ from: 20,
+ to: 30,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 131,
+ label: "USES".to_string(),
+ from: 21,
+ to: 31,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 132,
+ label: "USES".to_string(),
+ from: 22,
+ to: 31,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 133,
+ label: "USES".to_string(),
+ from: 24,
+ to: 32,
+ })
+ .map_err(|e| e.to_string())?;
// Person owns tasks
- db.put_edge(Edge { id: 140, label: "OWNS".to_string(), from: 1, to: 20 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 141, label: "OWNS".to_string(), from: 2, to: 21 }).map_err(|e| e.to_string())?;
- db.put_edge(Edge { id: 142, label: "OWNS".to_string(), from: 3, to: 22 }).map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 140,
+ label: "OWNS".to_string(),
+ from: 1,
+ to: 20,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 141,
+ label: "OWNS".to_string(),
+ from: 2,
+ to: 21,
+ })
+ .map_err(|e| e.to_string())?;
+ db.put_edge(Edge {
+ id: 142,
+ label: "OWNS".to_string(),
+ from: 3,
+ to: 22,
+ })
+ .map_err(|e| e.to_string())?;
Ok(())
}
-
-
diff --git a/sensibledb-explorer/src/commands/mod.rs b/sensibledb-explorer/src/commands/mod.rs
index 7d6b6af7..f17eaac0 100644
--- a/sensibledb-explorer/src/commands/mod.rs
+++ b/sensibledb-explorer/src/commands/mod.rs
@@ -1,11 +1,11 @@
pub mod database;
pub mod edges;
pub mod nodes;
-pub mod nql;
pub mod schema;
+pub mod sensibleql;
pub use database::*;
pub use edges::*;
pub use nodes::*;
-pub use nql::*;
pub use schema::*;
+pub use sensibleql::*;
diff --git a/sensibledb-explorer/src/commands/nodes.rs b/sensibledb-explorer/src/commands/nodes.rs
index bbf2d99b..03d2bc3a 100644
--- a/sensibledb-explorer/src/commands/nodes.rs
+++ b/sensibledb-explorer/src/commands/nodes.rs
@@ -87,25 +87,51 @@ pub fn node_delete(
#[tauri::command]
pub fn node_list(state: tauri::State, db_name: String) -> Result, String> {
- let log_msg = format!("[NODE_LIST] Called with db_name={}
-", db_name);
+ let log_msg = format!(
+ "[NODE_LIST] Called with db_name={}
+",
+ db_name
+ );
eprint!("{}", log_msg);
- let _ = std::fs::write("/tmp/sensibledb-explorer.log", format!("{}
-{}",
- std::fs::read_to_string("/tmp/sensibledb-explorer.log").unwrap_or_default(), log_msg));
+ let _ = std::fs::write(
+ "/tmp/sensibledb-explorer.log",
+ format!(
+ "{}
+{}",
+ std::fs::read_to_string("/tmp/sensibledb-explorer.log").unwrap_or_default(),
+ log_msg
+ ),
+ );
let dbs = state.databases.lock().map_err(|e| e.to_string())?;
- eprintln!("[NODE_LIST] Available DBs: {:?}", dbs.keys().collect::>());
- let db = dbs
- .get(&db_name)
- .ok_or_else(|| format!("Database '{}' not found. Available: {:?}", db_name, dbs.keys().collect::>()))?;
+ eprintln!(
+ "[NODE_LIST] Available DBs: {:?}",
+ dbs.keys().collect::>()
+ );
+ let db = dbs.get(&db_name).ok_or_else(|| {
+ format!(
+ "Database '{}' not found. Available: {:?}",
+ db_name,
+ dbs.keys().collect::>()
+ )
+ })?;
let tx = db.read_transaction().map_err(|e| e.to_string())?;
let nodes = tx.scan_nodes().map_err(|e| e.to_string())?;
- let log_msg2 = format!("[NODE_LIST] db={} found {} nodes
-", db_name, nodes.len());
+ let log_msg2 = format!(
+ "[NODE_LIST] db={} found {} nodes
+",
+ db_name,
+ nodes.len()
+ );
eprint!("{}", log_msg2);
- let _ = std::fs::write("/tmp/sensibledb-explorer.log", format!("{}
-{}",
- std::fs::read_to_string("/tmp/sensibledb-explorer.log").unwrap_or_default(), log_msg2));
+ let _ = std::fs::write(
+ "/tmp/sensibledb-explorer.log",
+ format!(
+ "{}
+{}",
+ std::fs::read_to_string("/tmp/sensibledb-explorer.log").unwrap_or_default(),
+ log_msg2
+ ),
+ );
Ok(nodes
.into_iter()
.map(|n| NodeDto {
diff --git a/sensibledb-explorer/src/commands/nql.rs b/sensibledb-explorer/src/commands/sensibleql.rs
similarity index 59%
rename from sensibledb-explorer/src/commands/nql.rs
rename to sensibledb-explorer/src/commands/sensibleql.rs
index 2a725038..c90ac362 100644
--- a/sensibledb-explorer/src/commands/nql.rs
+++ b/sensibledb-explorer/src/commands/sensibleql.rs
@@ -3,13 +3,13 @@ use sensibledb_db::embedded::transaction::{Edge, Node, ReadTransaction};
use serde::{Deserialize, Serialize};
#[derive(Deserialize)]
-pub struct NqlRequest {
+pub struct SensibleqlRequest {
pub db_name: String,
pub query: String,
}
#[derive(Serialize, Deserialize)]
-pub struct NqlResult {
+pub struct SensibleqlResult {
pub success: bool,
pub message: String,
pub data: Option,
@@ -37,11 +37,11 @@ struct QResult {
}
#[tauri::command(rename_all = "camelCase")]
-pub fn nql_execute(
+pub fn sensibleql_execute(
state: tauri::State,
db_name: String,
query: String,
-) -> Result {
+) -> Result {
let dbs = state.databases.lock().map_err(|e| e.to_string())?;
let db = dbs
.get(&db_name)
@@ -61,49 +61,105 @@ pub fn nql_execute(
do_count(&q, &all_nodes, &all_edges)?
} else {
QResult {
- nodes: all_nodes.iter().map(|n| QNode { id: n.id, label: n.label.clone() }).collect(),
- edges: all_edges.iter().map(|e| QEdge { id: e.id, label: e.label.clone(), from: e.from, to: e.to }).collect(),
+ nodes: all_nodes
+ .iter()
+ .map(|n| QNode {
+ id: n.id,
+ label: n.label.clone(),
+ })
+ .collect(),
+ edges: all_edges
+ .iter()
+ .map(|e| QEdge {
+ id: e.id,
+ label: e.label.clone(),
+ from: e.from,
+ to: e.to,
+ })
+ .collect(),
count: all_nodes.len(),
}
};
- Ok(NqlResult {
+ Ok(SensibleqlResult {
success: true,
- message: format!("Query returned {} nodes and {} edges", result.nodes.len(), result.edges.len()),
+ message: format!(
+ "Query returned {} nodes and {} edges",
+ result.nodes.len(),
+ result.edges.len()
+ ),
data: Some(serde_json::to_value(&result).map_err(|e| e.to_string())?),
})
}
fn do_match(q: &str, nodes: &[Node], edges: &[Edge]) -> Result {
let label = pick_label(q);
- let matched: Vec = nodes.iter()
- .filter(|n| label.as_ref().map_or(true, |l| n.label.to_lowercase().contains(l)))
- .map(|n| QNode { id: n.id, label: n.label.clone() })
+ let matched: Vec = nodes
+ .iter()
+ .filter(|n| {
+ label
+ .as_ref()
+ .map_or(true, |l| n.label.to_lowercase().contains(l))
+ })
+ .map(|n| QNode {
+ id: n.id,
+ label: n.label.clone(),
+ })
.collect();
let matched_edges: Vec = if q.contains(")-[") || q.contains("]->") {
let el = pick_edge_label(q);
- edges.iter()
+ edges
+ .iter()
.filter(|e| {
let nm = matched.iter().any(|n| n.id == e.from || n.id == e.to);
- el.as_ref().map_or(nm, |x| e.label.to_lowercase().contains(x) && nm)
+ el.as_ref()
+ .map_or(nm, |x| e.label.to_lowercase().contains(x) && nm)
+ })
+ .map(|e| QEdge {
+ id: e.id,
+ label: e.label.clone(),
+ from: e.from,
+ to: e.to,
})
- .map(|e| QEdge { id: e.id, label: e.label.clone(), from: e.from, to: e.to })
.collect()
- } else { vec![] };
- Ok(QResult { nodes: matched.clone(), edges: matched_edges, count: matched.len() })
+ } else {
+ vec![]
+ };
+ Ok(QResult {
+ nodes: matched.clone(),
+ edges: matched_edges,
+ count: matched.len(),
+ })
}
fn do_get(q: &str, nodes: &[Node], edges: &[Edge]) -> Result {
let term = pick_search(q);
- let matched: Vec = nodes.iter()
- .filter(|n| term.as_ref().map_or(true, |s| n.label.to_lowercase().contains(s)))
- .map(|n| QNode { id: n.id, label: n.label.clone() })
+ let matched: Vec = nodes
+ .iter()
+ .filter(|n| {
+ term.as_ref()
+ .map_or(true, |s| n.label.to_lowercase().contains(s))
+ })
+ .map(|n| QNode {
+ id: n.id,
+ label: n.label.clone(),
+ })
.collect();
- let matched_edges: Vec = edges.iter()
+ let matched_edges: Vec = edges
+ .iter()
.filter(|e| matched.iter().any(|n| n.id == e.from || n.id == e.to))
- .map(|e| QEdge { id: e.id, label: e.label.clone(), from: e.from, to: e.to })
+ .map(|e| QEdge {
+ id: e.id,
+ label: e.label.clone(),
+ from: e.from,
+ to: e.to,
+ })
.collect();
- Ok(QResult { nodes: matched.clone(), edges: matched_edges, count: matched.len() })
+ Ok(QResult {
+ nodes: matched.clone(),
+ edges: matched_edges,
+ count: matched.len(),
+ })
}
fn do_count(q: &str, nodes: &[Node], edges: &[Edge]) -> Result {
@@ -111,9 +167,20 @@ fn do_count(q: &str, nodes: &[Node], edges: &[Edge]) -> Result
let count = if q.contains("edge") || q.contains("relationship") {
edges.len()
} else {
- nodes.iter().filter(|n| label.as_ref().map_or(true, |l| n.label.to_lowercase().contains(l))).count()
+ nodes
+ .iter()
+ .filter(|n| {
+ label
+ .as_ref()
+ .map_or(true, |l| n.label.to_lowercase().contains(l))
+ })
+ .count()
};
- Ok(QResult { nodes: vec![], edges: vec![], count })
+ Ok(QResult {
+ nodes: vec![],
+ edges: vec![],
+ count,
+ })
}
fn pick_label(q: &str) -> Option {
@@ -127,7 +194,9 @@ fn pick_label(q: &str) -> Option {
// Node pattern: single letter variable like (n:Label)
if between.len() <= 2 && between.chars().all(|c| c.is_alphabetic()) {
let after = &q[i + 1..];
- let end = after.find(|c: char| !c.is_alphanumeric() && c != '_').unwrap_or(after.len());
+ let end = after
+ .find(|c: char| !c.is_alphanumeric() && c != '_')
+ .unwrap_or(after.len());
if end > 0 {
return Some(after[..end].to_string());
}
@@ -143,7 +212,11 @@ fn pick_edge_label(q: &str) -> Option {
let colon = rest.find(':')?;
let after = &rest[colon + 1..];
let end = after.find(']')?;
- if end > 0 { Some(after[..end].to_string()) } else { None }
+ if end > 0 {
+ Some(after[..end].to_string())
+ } else {
+ None
+ }
}
fn pick_search(q: &str) -> Option {
diff --git a/sensibledb-explorer/src/frontend/src/App.css b/sensibledb-explorer/src/frontend/src/App.css
index 641b491f..b4ff01f5 100644
--- a/sensibledb-explorer/src/frontend/src/App.css
+++ b/sensibledb-explorer/src/frontend/src/App.css
@@ -13,8 +13,9 @@
border-bottom: 1px solid var(--border);
display: flex;
align-items: center;
+ justify-content: center;
padding: 0 var(--space-lg);
- gap: var(--space-lg);
+ position: relative;
flex-shrink: 0;
}
@@ -22,6 +23,9 @@
display: flex;
align-items: center;
gap: var(--space-sm);
+ position: absolute;
+ left: 50%;
+ transform: translateX(-50%);
}
.header-logo {
@@ -35,16 +39,19 @@
}
.header-accent {
- color: #6366f1;
+ color: var(--accent)6366f1;
}
.header-db-selector {
- flex: 1;
+ position: absolute;
+ left: var(--space-lg);
display: flex;
align-items: center;
}
.header-actions {
+ position: absolute;
+ right: var(--space-lg);
display: flex;
gap: var(--space-sm);
}
diff --git a/sensibledb-explorer/src/frontend/src/App.tsx b/sensibledb-explorer/src/frontend/src/App.tsx
index cd4f857c..f3743213 100644
--- a/sensibledb-explorer/src/frontend/src/App.tsx
+++ b/sensibledb-explorer/src/frontend/src/App.tsx
@@ -5,7 +5,7 @@ import GraphView from "./components/graph/GraphView";
import NodeList from "./components/entities/NodeList";
import EdgeList from "./components/entities/EdgeList";
import SchemaBrowser from "./components/sidebar/SchemaBrowser";
-import NqlEditor from "./components/editor/NqlEditor";
+import SensibleQLEditor from "./components/editor/SensibleQLEditor";
import HomeView from "./components/home/HomeView";
import ChatView from "./components/chat/ChatView";
import ReportView from "./components/report/ReportView";
@@ -61,7 +61,7 @@ const App: Component = () => {
else if (e.key === "5") setActiveView("nodes");
else if (e.key === "6") setActiveView("edges");
else if (e.key === "7") setActiveView("schema");
- else if (e.key === "8") setActiveView("nql");
+ else if (e.key === "8") setActiveView("sensibleql");
else if (e.key === "Escape") {
if (selectedNode()) setSelectedNode(null);
else setActiveView("home");
@@ -135,8 +135,8 @@ const App: Component = () => {
-
-
+
+
-
-
+
+
-
-
{msg.nql}
+
+ {msg.sensibleql}
diff --git a/sensibledb-explorer/src/frontend/src/components/editor/NqlEditor.css b/sensibledb-explorer/src/frontend/src/components/editor/SensibleQLEditor.css
similarity index 94%
rename from sensibledb-explorer/src/frontend/src/components/editor/NqlEditor.css
rename to sensibledb-explorer/src/frontend/src/components/editor/SensibleQLEditor.css
index 944548ab..ed5b8dc5 100644
--- a/sensibledb-explorer/src/frontend/src/components/editor/NqlEditor.css
+++ b/sensibledb-explorer/src/frontend/src/components/editor/SensibleQLEditor.css
@@ -1,4 +1,4 @@
-.nql-editor {
+.sensibleql-editor {
display: flex;
flex-direction: column;
height: 100%;
@@ -84,12 +84,12 @@
}
.result-header .success {
- color: #22c55e;
+ color: var(--accent)22c55e;
font-weight: 500;
}
.result-header .error {
- color: #ef4444;
+ color: var(--accent)ef4444;
font-weight: 500;
}
@@ -135,11 +135,11 @@
}
.result-header .success {
- color: #22c55e;
+ color: var(--accent)22c55e;
font-weight: 500;
}
.result-header .error {
- color: #ef4444;
+ color: var(--accent)ef4444;
font-weight: 500;
}
diff --git a/sensibledb-explorer/src/frontend/src/components/editor/NqlEditor.tsx b/sensibledb-explorer/src/frontend/src/components/editor/SensibleQLEditor.tsx
similarity index 87%
rename from sensibledb-explorer/src/frontend/src/components/editor/NqlEditor.tsx
rename to sensibledb-explorer/src/frontend/src/components/editor/SensibleQLEditor.tsx
index efe01fb6..5a344d7f 100644
--- a/sensibledb-explorer/src/frontend/src/components/editor/NqlEditor.tsx
+++ b/sensibledb-explorer/src/frontend/src/components/editor/SensibleQLEditor.tsx
@@ -1,10 +1,10 @@
import { Component, createSignal, onMount, Show, For } from "solid-js";
import { EditorView, basicSetup } from "codemirror";
import { EditorState } from "@codemirror/state";
-import { nqlExecute } from "../../lib/api";
+import { sensibleqlExecute } from "../../lib/api";
import { activeDb } from "../../stores/app";
-import type { NqlResult } from "../../types";
-import "./NqlEditor.css";
+import type { SensibleqlResult } from "../../types";
+import "./SensibleQLEditor.css";
interface SampleQuery {
label: string;
@@ -26,10 +26,10 @@ const sampleQueries: SampleQuery[] = [
{ label: "Tools Used", tooltip: "Find all tools", query: "MATCH (n:Tool) RETURN n" },
];
-const NqlEditor: Component = () => {
+const SensibleQLEditor: Component = () => {
let editorRef: HTMLDivElement | undefined;
const [query, setQuery] = createSignal("");
- const [result, setResult] = createSignal(null);
+ const [result, setResult] = createSignal(null);
const [isRunning, setIsRunning] = createSignal(false);
let editor: EditorView | undefined;
@@ -42,8 +42,8 @@ const NqlEditor: Component = () => {
basicSetup,
EditorView.theme({
"&": { fontSize: "14px" },
- ".cm-editor": { background: "#1e293b" },
- ".cm-gutters": { background: "#0f172a", border: "none" },
+ ".cm-editor": { background: "#f8fafc" },
+ ".cm-gutters": { background: "#f1f5f9", border: "none" },
}),
EditorView.updateListener.of((update) => {
if (update.docChanged) {
@@ -60,7 +60,7 @@ const NqlEditor: Component = () => {
if (!activeDb() || !query()) return;
setIsRunning(true);
try {
- const res = await nqlExecute(activeDb()!, query());
+ const res = await sensibleqlExecute(activeDb()!, query());
setResult(res);
} catch (e: any) {
setResult({ success: false, message: String(e), data: null });
@@ -80,9 +80,9 @@ const NqlEditor: Component = () => {
};
return (
-