cypher-guard


Namecypher-guard JSON
Version 0.1.11 PyPI version JSON
download
home_pageNone
SummaryPython bindings for Cypher Guard - A Rust library for parsing and validating Cypher queries against a user-defined schema
upload_time2025-07-20 19:30:56
maintainerNeo4j Field Team
docs_urlNone
authorNeo4j Field Team
requires_python>=3.9.0
licenseMIT
keywords cypher neo4j validation parser graph database
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # cypher-guard

![Cypher Guard Banner](assets/cypher-guard-banner.png)

## Introduction

Cypher Guard is an open-source Rust library for parsing and validating [Cypher](https://neo4j.com/developer/cypher/) queries against a user-defined schema. It provides robust, schema-aware validation for graph queries, with bindings for Python and TypeScript/JavaScript. The Python and TypeScript/JS bindings expose a simple API in those languages, but leverage the full performance and safety of Rust under the hood. Cypher Guard is designed for use in developer tools, CI pipelines, and anywhere you need to ensure Cypher query correctness.

---

## Quickstart

### Rust

```sh
cargo build --release
```

### Python

```sh
# Install uv (if not already)
pip install uv

# Build and install Python bindings
make build-python
```

### TypeScript/JavaScript

```sh
make build-js
```

---

## Usage

### Rust Library

```rust
use cypher_guard::{validate_cypher_with_schema, DbSchema};

// Load your schema
let schema_json = r#"{
    "node_props": {
        "Person": [
            {"name": "name", "neo4j_type": "STRING"},
            {"name": "age", "neo4j_type": "INTEGER"}
        ]
    },
    "rel_props": {
        "KNOWS": [
            {"name": "since", "neo4j_type": "DateTime"}
        ]
    },
    "relationships": [
        {"start": "Person", "end": "Person", "rel_type": "KNOWS"}
    ],
    "metadata": {"index": [], "constraint": []}
}"#;

let schema = DbSchema::from_json_string(schema_json).unwrap();
let query = "MATCH (a:Person)-[r:KNOWS]->(b:Person) RETURN a.name, r.since";

match validate_cypher_with_schema(query, &schema) {
    Ok(true) => println!("Query is valid!"),
    Ok(false) => println!("Query is invalid"),
    Err(e) => println!("Error: {}", e),
}
```

### Python API

```python
from cypher_guard import validate_cypher, get_validation_errors, parse_query

schema_json = '''{
    "node_props": {
        "Person": [
            {"name": "name", "neo4j_type": "STRING"},
            {"name": "age", "neo4j_type": "INTEGER"}
        ]
    },
    "rel_props": {
        "KNOWS": [
            {"name": "since", "neo4j_type": "DateTime"}
        ]
    },
    "relationships": [
        {"start": "Person", "end": "Person", "rel_type": "KNOWS"}
    ],
    "metadata": {"index": [], "constraint": []}
}'''

query = "MATCH (a:Person)-[r:KNOWS]->(b:Person) RETURN a.name, r.since"

# Validate query
try:
    is_valid = validate_cypher(query, schema_json)
    print(f"Query is valid: {is_valid}")
except Exception as e:
    print(f"Validation error: {e}")

# Get all validation errors
errors = get_validation_errors(query, schema_json)
for error in errors:
    print(f"Error: {error}")

# Parse query (returns AST as dict)
ast = parse_query(query)
print(f"Parsed AST: {ast}")
```

### TypeScript/JavaScript API

```typescript
import { validateCypher, getValidationErrors } from "cypher-guard";

const schemaJson = `{
    "node_props": {
        "Person": [
            {"name": "name", "neo4j_type": "STRING"},
            {"name": "age", "neo4j_type": "INTEGER"}
        ]
    },
    "rel_props": {
        "KNOWS": [
            {"name": "since", "neo4j_type": "DateTime"}
        ]
    },
    "relationships": [
        {"start": "Person", "end": "Person", "rel_type": "KNOWS"}
    ],
    "metadata": {"index": [], "constraint": []}
}`;

const query = "MATCH (a:Person)-[r:KNOWS]->(b:Person) RETURN a.name, r.since";

try {
    const isValid = validateCypher(query, schemaJson);
    console.log(`Query is valid: ${isValid}`);
} catch (error) {
    console.log(`Validation error: ${error}`);
}

const errors = getValidationErrors(query, schemaJson);
errors.forEach(error => console.log(`Error: ${error}`));
```

---

## Makefile Commands

The Makefile provides convenient shortcuts for building, testing, and linting across Rust, Python, and JavaScript/TypeScript bindings.

| Command         | Description                                                                 |
|-----------------|-----------------------------------------------------------------------------|
| `make` or `make build`         | Build and install the Python extension using uv and maturin.      |
| `make build-python`            | Build and install the Python extension (`uv run maturin develop`). |
| `make test-python`             | Run the Python test suite with pytest.                                |
| `make build-js`                | Install and build the JS/TS bindings (`npm install && npm run build`).|
| `make test-js`                 | Run the JS/TS test suite (`npm test`).                                |
| `make build-rust`              | Build the Rust library (`cargo build`).                               |
| `make test-rust`               | Run Rust tests, formatting, and clippy lints.                        |
| `make fmt`                     | Check Rust code formatting (`cargo fmt --all -- --check`).            |
| `make clippy`                  | Run clippy linter on the main Rust crate.                             |
| `make clippy-all`              | Run clippy linter on all Rust crates.                                 |
| `make clean`                   | Remove build artifacts, Python caches, and node modules.              |
| `make install`                 | Alias for `make build`.                                               |

**Note:** Most commands are cross-platform and will set up all dependencies for you.

---

## How It Works: Parsing & Validation Flow

Cypher Guard separates query validation into three phases:

1. **Parsing**: Uses the [`nom`](https://docs.rs/nom) parser combinator library to convert Cypher into an Abstract Syntax Tree (AST). If parsing fails, you get a syntax error.
2. **Element Extraction**: Traverses the AST to extract all elements that need validation (node labels, relationship types, properties, variables, etc.).
3. **Schema Validation**: Validates the extracted elements against your schema, returning specific error types for different validation failures.

### Project Structure

```
rust/
├── cypher_guard/           # Main Rust library
│   ├── src/
│   │   ├── lib.rs          # Public API
│   │   ├── parser/         # Cypher parsing modules
│   │   │   ├── ast.rs      # Abstract Syntax Tree definitions
│   │   │   ├── clauses.rs  # Top-level clause parsing (MATCH, RETURN, etc.)
│   │   │   ├── patterns.rs # Node/relationship pattern parsing
│   │   │   ├── components.rs # Expression and component parsing
│   │   │   └── utils.rs    # Parser utilities
│   │   ├── schema.rs       # Schema structure and JSON parsing
│   │   ├── validation.rs   # Query element extraction and validation
│   │   └── errors.rs       # Error types and conversion
│   └── Cargo.toml
├── python_bindings/        # Python bindings using PyO3
│   ├── src/lib.rs          # Python API and exception handling
│   ├── tests/              # Python test suite
│   └── pyproject.toml
└── js_bindings/           # TypeScript/JavaScript bindings using napi-rs
    ├── src/lib.rs         # JS/TS API
    ├── test.ts            # JS/TS tests
    └── package.json
```

### Validation Flow

1. **Query Input**: Cypher query string
2. **Parsing**: `parse_query()` → AST
3. **Element Extraction**: `extract_query_elements()` → QueryElements
4. **Schema Validation**: `validate_query_elements()` → Validation Errors
5. **Error Conversion**: Rust errors → Language-specific exceptions

---

## Features

### Core Functionality
- **Full Cypher parsing**: MATCH, OPTIONAL MATCH, RETURN, WITH, WHERE, CREATE, MERGE, SET
- **Schema-aware validation**: Labels, relationship types, properties, type checking
- **Custom error types**: Specific exceptions for different validation failures
- **Multi-language bindings**: Rust, Python, and TypeScript/JavaScript APIs

### Supported Cypher Features

#### Clauses
- `MATCH`, `OPTIONAL MATCH`
- `RETURN`
- `WITH` (aliases, property access, function calls, wildcards)
- `WHERE` (complex conditions, logical operators, parentheses)
- `CREATE`
- `MERGE` (with `ON CREATE` and `ON MATCH`)
- `SET`

#### Node Patterns
- Basic nodes: `(n)`
- Labeled nodes: `(n:Person)`
- Nodes with properties: `(n:Person {name: 'Alice', age: 30})`
- Nodes with variables: `(person:Person)`

#### Relationship Patterns
- Basic: `(a)-[r]->(b)`
- Typed: `(a)-[r:KNOWS]->(b)`
- With properties: `(a)-[r:KNOWS {since: '2020'}]->(b)`
- Variable length: `(a)-[r:KNOWS*1..5]->(b)`
- Optional: `(a)-[r:KNOWS?]->(b)`
- Undirected: `(a)-[r:KNOWS]-(b)`
- Multiple types: `(a)-[r:KNOWS|FRIENDS]->(b)`

#### Quantified Path Patterns (QPP)
- Basic: `((a)-[r:KNOWS]->(b)){1,5}`
- With WHERE: `((a)-[r:KNOWS]->(b) WHERE r.since > '2020'){1,5}`
- With path variables: `p = ((a)-[r:KNOWS]->(b)){1,5}`

#### WHERE Conditions
- Property comparisons: `n.name = 'Alice'`, `n.age > 30`
- Boolean: `n.active = true`, `n.name IS NULL`
- Function calls: `length(n.name) > 5`
- Path properties: `p.length > 2`
- Logical: `AND`, `OR`, `NOT`
- Parenthesized: `(n.age > 30 AND n.active = true)`

#### Property Values
- Strings: `'Alice'`
- Numbers: `30`, `3.14`
- Booleans: `true`, `false`
- NULL: `NULL`
- Lists: `[1, 2, 3]`
- Maps: `{name: 'Alice', age: 30}`
- Function calls: `timestamp()`

#### Function Calls
- Basic: `length(n.name)`
- Nested: `substring(n.name, 0, 5)`
- Multiple arguments: `coalesce(n.name, 'Unknown')`

#### Quantifiers
- Zero or more: `*`
- One or more: `+`
- Exact: `{5}`
- Range: `{1,5}`
- Optional: `?`

#### Path Variables
- Assignment: `p = (a)-[r:KNOWS]->(b)`
- Path properties: `p.length`, `p.nodes`, `p.relationships`

### Error Types

The library provides specific error types for different validation failures:

#### Python Exceptions
- `CypherValidationError` - Base class for all validation errors
- `InvalidNodeLabel` - Invalid node label in schema
- `InvalidRelationshipType` - Invalid relationship type in schema
- `InvalidNodeProperty` - Invalid property on node label
- `InvalidRelationshipProperty` - Invalid property on relationship type
- `InvalidPropertyAccess` - Invalid property access in query
- `InvalidPropertyName` - Invalid property name
- `UndefinedVariable` - Variable referenced but not defined
- `TypeMismatch` - Type mismatch in property values
- `InvalidRelationship` - Invalid relationship pattern
- `InvalidLabel` - Invalid label usage

#### Rust Error Types
- `CypherGuardError` - Main error enum
- `CypherGuardParsingError` - Parsing-specific errors
- `CypherGuardValidationError` - Validation-specific errors
- `CypherGuardSchemaError` - Schema-related errors

---

## Schema Format

Cypher Guard uses a JSON schema format to define your graph structure:

```json
{
    "node_props": {
        "Person": [
            {"name": "name", "neo4j_type": "STRING"},
            {"name": "age", "neo4j_type": "INTEGER"},
            {"name": "active", "neo4j_type": "BOOLEAN"}
        ],
        "Movie": [
            {"name": "title", "neo4j_type": "STRING"},
            {"name": "year", "neo4j_type": "INTEGER"}
        ]
    },
    "rel_props": {
        "KNOWS": [
            {"name": "since", "neo4j_type": "DateTime"}
        ],
        "ACTED_IN": [
            {"name": "role", "neo4j_type": "STRING"}
        ]
    },
    "relationships": [
        {"start": "Person", "end": "Person", "rel_type": "KNOWS"},
        {"start": "Person", "end": "Movie", "rel_type": "ACTED_IN"}
    ],
    "metadata": {
        "index": [],
        "constraint": []
    }
}
```

### Schema Components

- **node_props**: Node labels and their properties with Neo4j types
- **rel_props**: Relationship types and their properties
- **relationships**: Valid relationship patterns between node labels
- **metadata**: Indexes and constraints (future use)

---

## Test Coverage

- **Rust**: 190+ tests covering parsing, validation, error handling, and edge cases
- **Python**: Unit tests for valid/invalid queries, schema validation, and error reporting (`rust/python_bindings/tests/unit/`)
- **TypeScript/JS**: Tests for JS/TS bindings (`rust/js_bindings/test.ts`)

Current test status: **73 passed, 26 failed** (mostly test expectation mismatches, core functionality working)

---

## Documentation

- **[Releases](docs/RELEASES.md)** - Download latest releases and view changelog
- **[Versioning Guide](docs/VERSIONING.md)** - Release management and versioning
- **[API Reference](docs/API.md)** - Complete API documentation
- **[Schema Format](docs/SCHEMA.md)** - Schema definition guide

---

## Contributing

This project is open source and welcomes contributions! Please open issues or submit pull requests for improvements or bug fixes.

### Development Setup

1. Clone the repository
2. Install dependencies: `make uv-install`
3. Build: `make build-python`
4. Test: `make test-python`

---

## License

MIT

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "cypher-guard",
    "maintainer": "Neo4j Field Team",
    "docs_url": null,
    "requires_python": ">=3.9.0",
    "maintainer_email": null,
    "keywords": "cypher, neo4j, validation, parser, graph, database",
    "author": "Neo4j Field Team",
    "author_email": null,
    "download_url": null,
    "platform": null,
    "description": "# cypher-guard\n\n![Cypher Guard Banner](assets/cypher-guard-banner.png)\n\n## Introduction\n\nCypher Guard is an open-source Rust library for parsing and validating [Cypher](https://neo4j.com/developer/cypher/) queries against a user-defined schema. It provides robust, schema-aware validation for graph queries, with bindings for Python and TypeScript/JavaScript. The Python and TypeScript/JS bindings expose a simple API in those languages, but leverage the full performance and safety of Rust under the hood. Cypher Guard is designed for use in developer tools, CI pipelines, and anywhere you need to ensure Cypher query correctness.\n\n---\n\n## Quickstart\n\n### Rust\n\n```sh\ncargo build --release\n```\n\n### Python\n\n```sh\n# Install uv (if not already)\npip install uv\n\n# Build and install Python bindings\nmake build-python\n```\n\n### TypeScript/JavaScript\n\n```sh\nmake build-js\n```\n\n---\n\n## Usage\n\n### Rust Library\n\n```rust\nuse cypher_guard::{validate_cypher_with_schema, DbSchema};\n\n// Load your schema\nlet schema_json = r#\"{\n    \"node_props\": {\n        \"Person\": [\n            {\"name\": \"name\", \"neo4j_type\": \"STRING\"},\n            {\"name\": \"age\", \"neo4j_type\": \"INTEGER\"}\n        ]\n    },\n    \"rel_props\": {\n        \"KNOWS\": [\n            {\"name\": \"since\", \"neo4j_type\": \"DateTime\"}\n        ]\n    },\n    \"relationships\": [\n        {\"start\": \"Person\", \"end\": \"Person\", \"rel_type\": \"KNOWS\"}\n    ],\n    \"metadata\": {\"index\": [], \"constraint\": []}\n}\"#;\n\nlet schema = DbSchema::from_json_string(schema_json).unwrap();\nlet query = \"MATCH (a:Person)-[r:KNOWS]->(b:Person) RETURN a.name, r.since\";\n\nmatch validate_cypher_with_schema(query, &schema) {\n    Ok(true) => println!(\"Query is valid!\"),\n    Ok(false) => println!(\"Query is invalid\"),\n    Err(e) => println!(\"Error: {}\", e),\n}\n```\n\n### Python API\n\n```python\nfrom cypher_guard import validate_cypher, get_validation_errors, parse_query\n\nschema_json = '''{\n    \"node_props\": {\n        \"Person\": [\n            {\"name\": \"name\", \"neo4j_type\": \"STRING\"},\n            {\"name\": \"age\", \"neo4j_type\": \"INTEGER\"}\n        ]\n    },\n    \"rel_props\": {\n        \"KNOWS\": [\n            {\"name\": \"since\", \"neo4j_type\": \"DateTime\"}\n        ]\n    },\n    \"relationships\": [\n        {\"start\": \"Person\", \"end\": \"Person\", \"rel_type\": \"KNOWS\"}\n    ],\n    \"metadata\": {\"index\": [], \"constraint\": []}\n}'''\n\nquery = \"MATCH (a:Person)-[r:KNOWS]->(b:Person) RETURN a.name, r.since\"\n\n# Validate query\ntry:\n    is_valid = validate_cypher(query, schema_json)\n    print(f\"Query is valid: {is_valid}\")\nexcept Exception as e:\n    print(f\"Validation error: {e}\")\n\n# Get all validation errors\nerrors = get_validation_errors(query, schema_json)\nfor error in errors:\n    print(f\"Error: {error}\")\n\n# Parse query (returns AST as dict)\nast = parse_query(query)\nprint(f\"Parsed AST: {ast}\")\n```\n\n### TypeScript/JavaScript API\n\n```typescript\nimport { validateCypher, getValidationErrors } from \"cypher-guard\";\n\nconst schemaJson = `{\n    \"node_props\": {\n        \"Person\": [\n            {\"name\": \"name\", \"neo4j_type\": \"STRING\"},\n            {\"name\": \"age\", \"neo4j_type\": \"INTEGER\"}\n        ]\n    },\n    \"rel_props\": {\n        \"KNOWS\": [\n            {\"name\": \"since\", \"neo4j_type\": \"DateTime\"}\n        ]\n    },\n    \"relationships\": [\n        {\"start\": \"Person\", \"end\": \"Person\", \"rel_type\": \"KNOWS\"}\n    ],\n    \"metadata\": {\"index\": [], \"constraint\": []}\n}`;\n\nconst query = \"MATCH (a:Person)-[r:KNOWS]->(b:Person) RETURN a.name, r.since\";\n\ntry {\n    const isValid = validateCypher(query, schemaJson);\n    console.log(`Query is valid: ${isValid}`);\n} catch (error) {\n    console.log(`Validation error: ${error}`);\n}\n\nconst errors = getValidationErrors(query, schemaJson);\nerrors.forEach(error => console.log(`Error: ${error}`));\n```\n\n---\n\n## Makefile Commands\n\nThe Makefile provides convenient shortcuts for building, testing, and linting across Rust, Python, and JavaScript/TypeScript bindings.\n\n| Command         | Description                                                                 |\n|-----------------|-----------------------------------------------------------------------------|\n| `make` or `make build`         | Build and install the Python extension using uv and maturin.      |\n| `make build-python`            | Build and install the Python extension (`uv run maturin develop`). |\n| `make test-python`             | Run the Python test suite with pytest.                                |\n| `make build-js`                | Install and build the JS/TS bindings (`npm install && npm run build`).|\n| `make test-js`                 | Run the JS/TS test suite (`npm test`).                                |\n| `make build-rust`              | Build the Rust library (`cargo build`).                               |\n| `make test-rust`               | Run Rust tests, formatting, and clippy lints.                        |\n| `make fmt`                     | Check Rust code formatting (`cargo fmt --all -- --check`).            |\n| `make clippy`                  | Run clippy linter on the main Rust crate.                             |\n| `make clippy-all`              | Run clippy linter on all Rust crates.                                 |\n| `make clean`                   | Remove build artifacts, Python caches, and node modules.              |\n| `make install`                 | Alias for `make build`.                                               |\n\n**Note:** Most commands are cross-platform and will set up all dependencies for you.\n\n---\n\n## How It Works: Parsing & Validation Flow\n\nCypher Guard separates query validation into three phases:\n\n1. **Parsing**: Uses the [`nom`](https://docs.rs/nom) parser combinator library to convert Cypher into an Abstract Syntax Tree (AST). If parsing fails, you get a syntax error.\n2. **Element Extraction**: Traverses the AST to extract all elements that need validation (node labels, relationship types, properties, variables, etc.).\n3. **Schema Validation**: Validates the extracted elements against your schema, returning specific error types for different validation failures.\n\n### Project Structure\n\n```\nrust/\n\u251c\u2500\u2500 cypher_guard/           # Main Rust library\n\u2502   \u251c\u2500\u2500 src/\n\u2502   \u2502   \u251c\u2500\u2500 lib.rs          # Public API\n\u2502   \u2502   \u251c\u2500\u2500 parser/         # Cypher parsing modules\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 ast.rs      # Abstract Syntax Tree definitions\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 clauses.rs  # Top-level clause parsing (MATCH, RETURN, etc.)\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 patterns.rs # Node/relationship pattern parsing\n\u2502   \u2502   \u2502   \u251c\u2500\u2500 components.rs # Expression and component parsing\n\u2502   \u2502   \u2502   \u2514\u2500\u2500 utils.rs    # Parser utilities\n\u2502   \u2502   \u251c\u2500\u2500 schema.rs       # Schema structure and JSON parsing\n\u2502   \u2502   \u251c\u2500\u2500 validation.rs   # Query element extraction and validation\n\u2502   \u2502   \u2514\u2500\u2500 errors.rs       # Error types and conversion\n\u2502   \u2514\u2500\u2500 Cargo.toml\n\u251c\u2500\u2500 python_bindings/        # Python bindings using PyO3\n\u2502   \u251c\u2500\u2500 src/lib.rs          # Python API and exception handling\n\u2502   \u251c\u2500\u2500 tests/              # Python test suite\n\u2502   \u2514\u2500\u2500 pyproject.toml\n\u2514\u2500\u2500 js_bindings/           # TypeScript/JavaScript bindings using napi-rs\n    \u251c\u2500\u2500 src/lib.rs         # JS/TS API\n    \u251c\u2500\u2500 test.ts            # JS/TS tests\n    \u2514\u2500\u2500 package.json\n```\n\n### Validation Flow\n\n1. **Query Input**: Cypher query string\n2. **Parsing**: `parse_query()` \u2192 AST\n3. **Element Extraction**: `extract_query_elements()` \u2192 QueryElements\n4. **Schema Validation**: `validate_query_elements()` \u2192 Validation Errors\n5. **Error Conversion**: Rust errors \u2192 Language-specific exceptions\n\n---\n\n## Features\n\n### Core Functionality\n- **Full Cypher parsing**: MATCH, OPTIONAL MATCH, RETURN, WITH, WHERE, CREATE, MERGE, SET\n- **Schema-aware validation**: Labels, relationship types, properties, type checking\n- **Custom error types**: Specific exceptions for different validation failures\n- **Multi-language bindings**: Rust, Python, and TypeScript/JavaScript APIs\n\n### Supported Cypher Features\n\n#### Clauses\n- `MATCH`, `OPTIONAL MATCH`\n- `RETURN`\n- `WITH` (aliases, property access, function calls, wildcards)\n- `WHERE` (complex conditions, logical operators, parentheses)\n- `CREATE`\n- `MERGE` (with `ON CREATE` and `ON MATCH`)\n- `SET`\n\n#### Node Patterns\n- Basic nodes: `(n)`\n- Labeled nodes: `(n:Person)`\n- Nodes with properties: `(n:Person {name: 'Alice', age: 30})`\n- Nodes with variables: `(person:Person)`\n\n#### Relationship Patterns\n- Basic: `(a)-[r]->(b)`\n- Typed: `(a)-[r:KNOWS]->(b)`\n- With properties: `(a)-[r:KNOWS {since: '2020'}]->(b)`\n- Variable length: `(a)-[r:KNOWS*1..5]->(b)`\n- Optional: `(a)-[r:KNOWS?]->(b)`\n- Undirected: `(a)-[r:KNOWS]-(b)`\n- Multiple types: `(a)-[r:KNOWS|FRIENDS]->(b)`\n\n#### Quantified Path Patterns (QPP)\n- Basic: `((a)-[r:KNOWS]->(b)){1,5}`\n- With WHERE: `((a)-[r:KNOWS]->(b) WHERE r.since > '2020'){1,5}`\n- With path variables: `p = ((a)-[r:KNOWS]->(b)){1,5}`\n\n#### WHERE Conditions\n- Property comparisons: `n.name = 'Alice'`, `n.age > 30`\n- Boolean: `n.active = true`, `n.name IS NULL`\n- Function calls: `length(n.name) > 5`\n- Path properties: `p.length > 2`\n- Logical: `AND`, `OR`, `NOT`\n- Parenthesized: `(n.age > 30 AND n.active = true)`\n\n#### Property Values\n- Strings: `'Alice'`\n- Numbers: `30`, `3.14`\n- Booleans: `true`, `false`\n- NULL: `NULL`\n- Lists: `[1, 2, 3]`\n- Maps: `{name: 'Alice', age: 30}`\n- Function calls: `timestamp()`\n\n#### Function Calls\n- Basic: `length(n.name)`\n- Nested: `substring(n.name, 0, 5)`\n- Multiple arguments: `coalesce(n.name, 'Unknown')`\n\n#### Quantifiers\n- Zero or more: `*`\n- One or more: `+`\n- Exact: `{5}`\n- Range: `{1,5}`\n- Optional: `?`\n\n#### Path Variables\n- Assignment: `p = (a)-[r:KNOWS]->(b)`\n- Path properties: `p.length`, `p.nodes`, `p.relationships`\n\n### Error Types\n\nThe library provides specific error types for different validation failures:\n\n#### Python Exceptions\n- `CypherValidationError` - Base class for all validation errors\n- `InvalidNodeLabel` - Invalid node label in schema\n- `InvalidRelationshipType` - Invalid relationship type in schema\n- `InvalidNodeProperty` - Invalid property on node label\n- `InvalidRelationshipProperty` - Invalid property on relationship type\n- `InvalidPropertyAccess` - Invalid property access in query\n- `InvalidPropertyName` - Invalid property name\n- `UndefinedVariable` - Variable referenced but not defined\n- `TypeMismatch` - Type mismatch in property values\n- `InvalidRelationship` - Invalid relationship pattern\n- `InvalidLabel` - Invalid label usage\n\n#### Rust Error Types\n- `CypherGuardError` - Main error enum\n- `CypherGuardParsingError` - Parsing-specific errors\n- `CypherGuardValidationError` - Validation-specific errors\n- `CypherGuardSchemaError` - Schema-related errors\n\n---\n\n## Schema Format\n\nCypher Guard uses a JSON schema format to define your graph structure:\n\n```json\n{\n    \"node_props\": {\n        \"Person\": [\n            {\"name\": \"name\", \"neo4j_type\": \"STRING\"},\n            {\"name\": \"age\", \"neo4j_type\": \"INTEGER\"},\n            {\"name\": \"active\", \"neo4j_type\": \"BOOLEAN\"}\n        ],\n        \"Movie\": [\n            {\"name\": \"title\", \"neo4j_type\": \"STRING\"},\n            {\"name\": \"year\", \"neo4j_type\": \"INTEGER\"}\n        ]\n    },\n    \"rel_props\": {\n        \"KNOWS\": [\n            {\"name\": \"since\", \"neo4j_type\": \"DateTime\"}\n        ],\n        \"ACTED_IN\": [\n            {\"name\": \"role\", \"neo4j_type\": \"STRING\"}\n        ]\n    },\n    \"relationships\": [\n        {\"start\": \"Person\", \"end\": \"Person\", \"rel_type\": \"KNOWS\"},\n        {\"start\": \"Person\", \"end\": \"Movie\", \"rel_type\": \"ACTED_IN\"}\n    ],\n    \"metadata\": {\n        \"index\": [],\n        \"constraint\": []\n    }\n}\n```\n\n### Schema Components\n\n- **node_props**: Node labels and their properties with Neo4j types\n- **rel_props**: Relationship types and their properties\n- **relationships**: Valid relationship patterns between node labels\n- **metadata**: Indexes and constraints (future use)\n\n---\n\n## Test Coverage\n\n- **Rust**: 190+ tests covering parsing, validation, error handling, and edge cases\n- **Python**: Unit tests for valid/invalid queries, schema validation, and error reporting (`rust/python_bindings/tests/unit/`)\n- **TypeScript/JS**: Tests for JS/TS bindings (`rust/js_bindings/test.ts`)\n\nCurrent test status: **73 passed, 26 failed** (mostly test expectation mismatches, core functionality working)\n\n---\n\n## Documentation\n\n- **[Releases](docs/RELEASES.md)** - Download latest releases and view changelog\n- **[Versioning Guide](docs/VERSIONING.md)** - Release management and versioning\n- **[API Reference](docs/API.md)** - Complete API documentation\n- **[Schema Format](docs/SCHEMA.md)** - Schema definition guide\n\n---\n\n## Contributing\n\nThis project is open source and welcomes contributions! Please open issues or submit pull requests for improvements or bug fixes.\n\n### Development Setup\n\n1. Clone the repository\n2. Install dependencies: `make uv-install`\n3. Build: `make build-python`\n4. Test: `make test-python`\n\n---\n\n## License\n\nMIT\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Python bindings for Cypher Guard - A Rust library for parsing and validating Cypher queries against a user-defined schema",
    "version": "0.1.11",
    "project_urls": {
        "Documentation": "https://github.com/neo4j-field/cypher-guard#readme",
        "Homepage": "https://github.com/neo4j-field/cypher-guard",
        "Issues": "https://github.com/neo4j-field/cypher-guard/issues",
        "Repository": "https://github.com/neo4j-field/cypher-guard"
    },
    "split_keywords": [
        "cypher",
        " neo4j",
        " validation",
        " parser",
        " graph",
        " database"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "645dd56977b61456b8f15e3e7a1791125d5e41af031815cc14c7911988f1fd23",
                "md5": "8d6bac23172d98dcd4f0593648adc627",
                "sha256": "445974f6254a936c76c4220e574bce39fd9c80e503b6d79b5fb53629092c86e3"
            },
            "downloads": -1,
            "filename": "cypher_guard-0.1.11-cp311-cp311-manylinux_2_34_x86_64.whl",
            "has_sig": false,
            "md5_digest": "8d6bac23172d98dcd4f0593648adc627",
            "packagetype": "bdist_wheel",
            "python_version": "cp311",
            "requires_python": ">=3.9.0",
            "size": 3425148,
            "upload_time": "2025-07-20T19:30:56",
            "upload_time_iso_8601": "2025-07-20T19:30:56.774538Z",
            "url": "https://files.pythonhosted.org/packages/64/5d/d56977b61456b8f15e3e7a1791125d5e41af031815cc14c7911988f1fd23/cypher_guard-0.1.11-cp311-cp311-manylinux_2_34_x86_64.whl",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-07-20 19:30:56",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "neo4j-field",
    "github_project": "cypher-guard#readme",
    "github_not_found": true,
    "lcname": "cypher-guard"
}
        
Elapsed time: 1.01273s