mameyugo/jsonq

High-performance JSON file storage engine for PHP, powered by Rust

Fund package maintenance!
mameyugo

Installs: 0

Dependents: 0

Suggesters: 0

Security: 0

Stars: 2

Watchers: 0

Forks: 0

Open Issues: 0

Language:Rust

Type:php-ext

Ext name:ext-jsonq

pkg:composer/mameyugo/jsonq

v0.2.0 2026-02-15 03:51 UTC

This package is auto-updated.

Last update: 2026-02-16 15:59:38 UTC


README

πŸš€ JsonQ

High-Performance JSON Storage Engine for PHP

PHP Version Rust License Performance

MongoDB-style queries | JSON Schema validation | ACID transactions | 10x performance

Features β€’ Quick Start β€’ Documentation β€’ Benchmarks β€’ Contributing

πŸ“Š What is JsonQ?

JsonQ is a blazing-fast PHP extension written in Rust that provides a file-based JSON storage engine with MongoDB-style queries, schema validation, indexing, and transactions.

Why JsonQ?

  • πŸš€ 2-10x faster than pure PHP JSON handling
  • πŸ’Ύ File-based - No server required, zero configuration
  • πŸ” MongoDB-style queries - Familiar syntax with 17+ operators
  • βœ… Schema validation - JSON Schema subset support
  • πŸ”’ ACID transactions - Atomic operations with rollback
  • πŸ“Š Indexing - Hash-based O(1) lookups
  • πŸ›‘οΈ Thread-safe - OS-level file locking with fs2
  • ⚑ SIMD-accelerated - Fast parsing with simd-json

✨ Features

Core Storage

  • βœ… CRUD Operations with dot-notation path access
  • βœ… Atomic Writes (tmp + fsync + rename) for crash safety
  • βœ… Memory-mapped I/O for zero-copy reads
  • βœ… Arc-based Caching with mtime invalidation
  • βœ… Compression Support (Gzip, Zstd) - v0.3.0

Query Engine

  • βœ… MongoDB-style Matching: $eq, $ne, $gt, $gte, $lt, $lte, $in, $nin
  • βœ… String Operators: $contains, $startsWith, $endsWith, $regex
  • βœ… Logical Operators: $and, $or, $not, $nor
  • βœ… Array Operators: $size, $all, $elemMatch
  • βœ… Type Checking: $exists, $type
  • βœ… Field Projection: select() for whitelisting fields - v0.3.0
  • βœ… Query Optimizer: Intelligent index selection - v0.3.0

Fluent Query Builder

  • βœ… Chainable Methods: where(), orWhere(), orderBy(), limit(), skip()
  • βœ… Filtering: Comparison, string, array operators
  • βœ… Sorting: Ascending/descending on any field
  • βœ… Pagination: skip + limit support

Aggregation & Analysis

  • βœ… Functions: sum(), avg(), min(), max(), count()
  • βœ… Grouping: groupBy() with field-based grouping
  • βœ… Field Extraction: pluck() for column extraction

Validation & Schema

  • βœ… JSON Schema Validation (subset)
  • βœ… Type Constraints: string, number, boolean, array, object
  • βœ… String Formats: email, URL, IPv4, date, UUID
  • βœ… Number Constraints: min, max, multipleOf
  • βœ… Array Constraints: minItems, maxItems, uniqueItems
  • βœ… Required Fields and enum validation
  • βœ… Conditional Logic: if/then/else, oneOf, anyOf

Indexing

  • βœ… Single Field Indexes: O(1) equality lookups
  • βœ… Compound Indexes: Multi-field indexing
  • βœ… Hash-based: MD5 hashing for fast lookups
  • βœ… Auto-optimization: Automatic use in find() queries

Transactions

  • βœ… ACID Guarantees: Atomic, Consistent, Isolated, Durable
  • βœ… Begin/Commit/Rollback: Full transaction support
  • βœ… Isolation: Transaction-local changes until commit

Advanced Features (v0.3.0)

  • βœ… Safe Regex - ReDoS protection with backtracking limits
  • βœ… Metrics API - Real-time observability (reads, writes, cache stats, latency)
  • βœ… Compression - Transparent Gzip/Zstd support
  • βœ… Query Optimizer - Intelligent index selection for complex queries

Collection Methods (NEW - v0.3.0)

  • βœ… select(fields) - Project specific fields (whitelist)
  • ⏳ except(fields) - Exclude specific fields (blacklist)
  • ⏳ column(field) - Extract values from single column
  • ⏳ chunk(size) - Split results into groups
  • ⏳ implode(field, separator) - Join column values into string
  • ⏳ keys(path) - Get object keys
  • ⏳ values(path) - Get object values
  • ⏳ toJson(pretty) - Serialize results to JSON string

Legend: βœ… Confirmed | ⏳ Pending verification

πŸš€ Quick Start

Installation

Via APT (Debian/Ubuntu)

# Add repository
curl -fsSL https://mameyugo.github.io/JsonQ/jsonq-archive-keyring.gpg | sudo gpg --dearmor -o /usr/share/keyrings/jsonq-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/jsonq-archive-keyring.gpg] https://mameyugo.github.io/JsonQ stable main" | sudo tee /etc/apt/sources.list.d/jsonq.list

# Install
sudo apt update
sudo apt install php8.3-jsonq

# Enable extension
php -m | grep jsonq

Via Curl (Quick Install)

curl -fsSL https://raw.githubusercontent.com/mameyugo/JsonQ/main/scripts/install.sh | sudo bash

Build from Source

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Clone and build
git clone https://github.com/mameyugo/JsonQ.git
cd JsonQ
cargo build --release

# Install
sudo cp target/release/libjsonq.so $(php-config --extension-dir)/jsonq.so
echo "extension=jsonq.so" | sudo tee /etc/php/8.3/mods-available/jsonq.ini
sudo phpenmod jsonq

Hello World

<?php
use JsonQ\Store;

// Create store
$store = new Store('data.json');

// Write data
$store->set('users', [
    ['id' => 1, 'name' => 'Alice', 'role' => 'admin', 'age' => 30],
    ['id' => 2, 'name' => 'Bob', 'role' => 'user', 'age' => 25],
    ['id' => 3, 'name' => 'Charlie', 'role' => 'user', 'age' => 35],
]);

// Query with MongoDB-style syntax
$admins = $store->find('users', ['role' => 'admin']);
// Returns: [['id' => 1, 'name' => 'Alice', ...]]

// Fluent query builder
$results = $store->executeQuery('users', [
    'where' => [
        ['field' => 'age', 'op' => '>=', 'value' => 25]
    ],
    'order_by' => ['field' => 'age', 'direction' => 'desc'],
    'limit' => 10
]);

// Aggregation
$avgAge = $store->aggregate('users', ['avg' => 'age']);
// Returns: ['avg' => 30.0]

echo "βœ… JsonQ is working!\n";

πŸ“š API Reference

Basic Operations

CRUD

// Create/Update
$store->set('user.profile', ['name' => 'Alice', 'age' => 30]);

// Read
$profile = $store->get('user.profile');
// Returns: ['name' => 'Alice', 'age' => 30]

// Check existence
$exists = $store->has('user.profile'); // true

// Delete
$store->remove('user.profile');

// Count elements
$count = $store->count('users'); // 3

Array Operations

// Push to array
$store->push('users', ['id' => 4, 'name' => 'Dave']);

// Merge objects
$store->merge('config', ['debug' => true]);

// Increment/Decrement
$store->increment('stats.views'); // views++
$store->decrement('inventory.stock', 5); // stock -= 5

MongoDB-style Queries

Comparison Operators

// Greater than
$adults = $store->find('users', ['age' => ['$gt' => 18]]);

// Range queries
$midAge = $store->find('users', [
    'age' => ['$gte' => 25, '$lte' => 35]
]);

// Not equal
$active = $store->find('users', ['status' => ['$ne' => 'deleted']]);

Array Operators

// In array
$roles = $store->find('users', [
    'role' => ['$in' => ['admin', 'moderator']]
]);

// Not in array
$regular = $store->find('users', [
    'role' => ['$nin' => ['admin', 'guest']]
]);

// Array size
$teams = $store->find('projects', [
    'members' => ['$size' => 5]
]);

String Operators

// Contains substring
$gmailUsers = $store->find('users', [
    'email' => ['$contains' => '@gmail.com']
]);

// Starts with
$adminUsers = $store->find('users', [
    'username' => ['$startsWith' => 'admin_']
]);

// Ends with
$txtFiles = $store->find('files', [
    'name' => ['$endsWith' => '.txt']
]);

// Regex matching (with ReDoS protection)
$phoneNumbers = $store->find('contacts', [
    'phone' => ['$regex' => '^\+1-\d{3}-\d{3}-\d{4}$']
]);

Logical Operators

// AND (implicit)
$seniorAdmins = $store->find('users', [
    'role' => 'admin',
    'age' => ['$gte' => 30]
]);

// OR
$privileged = $store->find('users', [
    '$or' => [
        ['role' => 'admin'],
        ['role' => 'moderator']
    ]
]);

// NOT
$notGuests = $store->find('users', [
    '$not' => ['role' => 'guest']
]);

// Complex nested logic
$results = $store->find('users', [
    '$and' => [
        ['age' => ['$gte' => 18]],
        ['$or' => [
            ['role' => 'admin'],
            ['verified' => true]
        ]]
    ]
]);

Fluent Query Builder

$results = $store->executeQuery('products', [
    // Filtering
    'where' => [
        ['field' => 'price', 'op' => '>', 'value' => 100],
        ['field' => 'inStock', 'op' => '=', 'value' => true]
    ],
    
    // Sorting
    'order_by' => [
        'field' => 'price',
        'direction' => 'desc' // or 'asc'
    ],
    
    // Pagination
    'skip' => 10,   // Offset
    'limit' => 20,  // Max results
    
    // Projection (v0.3.0)
    'select' => ['name', 'price', 'category']
]);

Available Operators:

  • Comparison: =, !=, >, >=, <, <=
  • Array: in, not in
  • String: contains, startsWith, endsWith
  • Range: between (expects array [min, max])

Aggregation

// Single aggregation
$total = $store->aggregate('orders', ['sum' => 'amount']);
// Returns: ['sum' => 15750.50]

// Multiple aggregations
$stats = $store->aggregate('products', [
    'sum' => 'price',
    'avg' => 'price',
    'min' => 'price',
    'max' => 'price',
    'count' => 'id'
]);
// Returns: ['sum' => 5000, 'avg' => 250, 'min' => 50, 'max' => 1000, 'count' => 20]

// Group by
$byCategory = $store->groupBy('products', 'category');
// Returns: ['electronics' => [...], 'books' => [...]]

// Extract column values
$names = $store->pluck('users', 'name');
// Returns: ['Alice', 'Bob', 'Charlie']

Collection Methods (NEW)

// Select specific fields (projection)
$results = $store->executeQuery('users', [
    'select' => ['name', 'email'] // Only return name and email
]);

// Extract column values
$emails = $store->column('users', 'email');
// Returns: ['alice@example.com', 'bob@example.com', ...]

// Split into chunks
$chunks = $store->chunk('users', 10);
// Returns: [[user1..10], [user11..20], ...]

// Join column values
$nameList = $store->implode('users', 'name', ', ');
// Returns: "Alice, Bob, Charlie, Dave"

// Get object keys
$keys = $store->keys('user.profile');
// Returns: ['name', 'email', 'age', 'verified']

// Get object values
$values = $store->values('user.profile');
// Returns: ['Alice', 'alice@example.com', 30, true]

// Serialize to JSON
$json = $store->toJson('users');
$prettyJson = $store->toJson('users', true); // Pretty-print

Schema Validation

// Define schema
$schema = [
    'type' => 'object',
    'required' => ['name', 'email', 'age'],
    'properties' => [
        'name' => [
            'type' => 'string',
            'minLength' => 2,
            'maxLength' => 50
        ],
        'email' => [
            'type' => 'string',
            'format' => 'email'
        ],
        'age' => [
            'type' => 'integer',
            'minimum' => 18,
            'maximum' => 120
        ],
        'role' => [
            'type' => 'string',
            'enum' => ['admin', 'user', 'guest']
        ]
    ]
];

// Validate single document
$user = ['name' => 'Alice', 'email' => 'alice@example.com', 'age' => 30];
$isValid = $store->validate($user, $schema);
// Returns: true

// Validate collection
$result = $store->validateCollection('users', $schema);
// Returns: ['valid' => true, 'errors' => []]

Supported Constraints:

  • Types: string, number, integer, boolean, array, object, null
  • String: minLength, maxLength, pattern, format (email, url, ipv4, date, uuid)
  • Number: minimum, maximum, multipleOf
  • Array: minItems, maxItems, uniqueItems, items
  • Object: required, properties, additionalProperties
  • Enum: Fixed set of allowed values
  • Conditional: if/then/else, oneOf, anyOf

Indexing

// Create single-field index
$store->createIndex('users', 'email');

// Create compound index
$store->createCompoundIndex('orders', ['customerId', 'status']);

// Direct index lookup (O(1))
$user = $store->indexLookup('users', 'email', 'alice@example.com');

// List all indexes
$indexes = $store->listIndexes();
// Returns: ['users.email' => 'single', 'orders.customerId+status' => 'compound']

// Drop index
$store->dropIndex('users.email');

// Drop all indexes
$store->dropAllIndexes();

Performance Impact:

  • Indexed find() queries: ~10x faster
  • Index memory overhead: ~2-5% of data size
  • Write penalty: <5% slower (hash computation)

Transactions

try {
    // Begin transaction
    $store->begin();
    
    // Perform multiple operations
    $store->set('accounts.A', ['balance' => 900]);
    $store->set('accounts.B', ['balance' => 1100]);
    $store->set('logs', ['transfer' => 100]);
    
    // Commit atomically
    $store->commit();
    
    echo "βœ… Transaction committed\n";
    
} catch (Exception $e) {
    // Rollback on error
    $store->rollback();
    echo "❌ Transaction rolled back: " . $e->getMessage() . "\n";
}

Guarantees:

  • Atomicity: All changes commit together or none
  • Consistency: Schema validation enforced
  • Isolation: Changes invisible until commit
  • Durability: fsync ensures disk persistence

Advanced Features (v0.3.0)

Compression

// Enable Zstd compression (best compression ratio + speed)
$store->setOption('compression', 'zstd');

// Or use Gzip
$store->setOption('compression', 'gzip');

// Disable compression
$store->setOption('compression', 'none');

// Transparent decompression - reads work automatically
$data = $store->get('users');

Compression Comparison:

Method Ratio Speed Best For
none 1.0x Fastest Small files, frequent writes
gzip 2-3x Fast Good balance
zstd 2.5-4x Fastest Large files, best compression

Metrics & Observability

// Get real-time metrics
$metrics = $store->getMetrics();

echo "Reads: " . $metrics['reads'] . "\n";
echo "Writes: " . $metrics['writes'] . "\n";
echo "Cache Hits: " . $metrics['cache_hits'] . "\n";
echo "Cache Misses: " . $metrics['cache_misses'] . "\n";
echo "Hit Rate: " . $metrics['cache_hit_rate'] . "%\n";
echo "Avg Latency: " . $metrics['avg_latency_ms'] . "ms\n";

Tracked Metrics:

  • Read/write counters
  • Cache hit/miss ratio
  • Average read latency
  • Last operation timestamp

Backup & Restore

// Create backup
$store->backup('/backups/data-' . date('Y-m-d') . '.json');

// Restore from backup
$store->restore('/backups/data-2024-01-15.json');

// Get file stats
$stats = $store->stats();
echo "File size: " . $stats['file_size'] . " bytes\n";
echo "Last modified: " . $stats['modified_at'] . "\n";

Global Configuration

// Get current config
$config = jsonq_get_config();

// Set max file size
jsonq_set_max_file_size('100M'); // or '1G', '500K'

// Set allowed extensions
jsonq_set_allowed_extensions('json,db');

// Set base path (security restriction)
jsonq_set_base_path('/var/www/data');

// Clear base path restriction
jsonq_clear_base_path();

🏎️ Performance

Benchmarks (vs Pure PHP)

Operation JsonQ Pure PHP Speedup
Parse JSON 0.8ms 5.2ms 6.5x faster
Find (no index) 1.2ms 12.5ms 10.4x faster
Find (indexed) 0.1ms 12.5ms 125x faster
Aggregate (sum) 0.9ms 8.7ms 9.7x faster
Complex query 2.1ms 18.3ms 8.7x faster
Write + fsync 1.5ms 3.2ms 2.1x faster

Benchmark environment: PHP 8.3, 10K documents, Intel i7-12700K

Optimization Tips

  1. Use Indexes: 10-100x speedup for equality lookups
  2. Enable Compression: 50-75% disk space reduction
  3. Batch Writes: Use transactions for multiple operations
  4. Monitor Metrics: Track cache hit rate and optimize queries
  5. Project Fields: Use select to return only needed data

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚             PHP Application Layer               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      ↕ FFI (ext-php-rs)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚              Rust Core (JsonQ)                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  1. Parser        - simd-json (SIMD parsing)    β”‚
β”‚  2. Cache         - Arc + mtime invalidation    β”‚
β”‚  3. Query Engine  - MongoDB + JSONPath          β”‚
β”‚  4. Index Manager - Hash-based O(1) lookups     β”‚
β”‚  5. Transactions  - ACID with rollback          β”‚
β”‚  6. Storage       - memmap2 + file locking      β”‚
β”‚  7. Security      - Path validation, ReDoS      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                      ↕ File System
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚           data.json + indexes/                  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

🀝 Contributing

Contributions are welcome! Please read CONTRIBUTING.md for guidelines.

Development Setup

# Clone repository
git clone https://github.com/mameyugo/JsonQ.git
cd JsonQ

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Build debug
cargo build

# Build release
cargo build --release

# Run Rust tests
cargo test

# Run PHP integration tests
php tests/run_tests.php

# Run benchmarks
php examples/benchmark_v2.php

Project Structure

JsonQ/
β”œβ”€β”€ src/                # Rust implementation
β”‚   β”œβ”€β”€ conversion/     # PHP ↔ Rust FFI
β”‚   β”œβ”€β”€ store/          # Storage engine
β”‚   β”œβ”€β”€ query/          # Query execution
β”‚   β”œβ”€β”€ index/          # Indexing system
β”‚   └── validation/     # Schema validation
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ integration/    # PHP integration tests
β”‚   └── unit/           # Rust unit tests
β”œβ”€β”€ stubs/              # PHP IDE stubs
└── docs/               # Documentation

πŸ“„ License

JsonQ is licensed under The PHP License, version 3.01.

πŸ™ Acknowledgments

  • simd-json - SIMD-accelerated JSON parsing
  • ext-php-rs - Safe Rust-PHP FFI bindings
  • serde - Serialization framework
  • MongoDB - Query syntax inspiration
  • The Rust and PHP communities

πŸ“ž Support

πŸ—ΊοΈ Roadmap

v0.4.0 (Q2 2026)

  • Complete collection methods (except, column, chunk, implode, keys, values, toJson)
  • JSONPath full support
  • Query optimizer improvements
  • Multi-stage aggregation pipelines

v0.5.0 (Q3 2026)

  • JOIN operations across collections
  • Full-text search with stemming
  • Watch API for change streams
  • GraphQL-like query DSL

v1.0.0 (Q4 2026)

  • Production-ready stable API
  • >95% test coverage
  • Comprehensive documentation
  • Performance parity with MongoDB for common queries

Made with ❀️ in Rust | Powered by πŸš€ SIMD

⭐ Star on GitHub β€’ πŸ“– Documentation β€’ πŸ› Report Bug