π Enterprise-grade ORM features in a single PHP file. Zero dependencies. Maximum power.
ProQuery is a comprehensive SQLite ORM that delivers Laravel Eloquent-style functionality without the framework overhead. Perfect for projects that need powerful database abstraction without complex dependency management.
- π¦ Single-file distribution - Just drop and use
- π₯ Zero dependencies - Pure PHP, no Composer required
- π¨ Eloquent-style syntax - Familiar and intuitive API
- β‘ Optimized for SQLite - WAL mode, memory temp storage, smart caching
- π‘οΈ Production-ready - Battle-tested patterns and error handling
- β Full relationship support - HasOne, HasMany, BelongsTo, BelongsToMany
- β Advanced relationships - HasManyThrough, HasOneThrough
- β Polymorphic relations - MorphTo, MorphOne, MorphMany, MorphToMany
- β
 Eager loading - Prevent N+1 queries with with()method
- β Lazy loading - Load relationships on-demand
- π Schema builder - Fluent table creation and modification
- π Migration system - Version control for your database
- π± Database seeding - Populate your database with test data
- π Query builder - Powerful, chainable query construction
- π Aggregates - COUNT, SUM, AVG, MIN, MAX support
- π Pagination - Built-in pagination with helpers
- πΎ Query caching - Cache frequently used queries
- π Query logging - Track and analyze all queries
- π Debug helpers - dd()anddump()methods
- π― Chunk processing - Handle large datasets efficiently
- β‘ Optimized eager loading - Smart batching of related queries
wget https://raw.githubusercontent.com/nadermkhan/ProQuery/main/ProQuery.phpgit clone https://github.com/nadermkhan/ProQuery.gitcomposer require nadermkhan/proquery<?php
require_once 'ProQuery.php';
// Initialize database
ProQuery::init('database.db');
// Define your model
class User extends Model {
    protected static $table = 'users';
    protected static $fillable = ['name', 'email', 'password'];
    
    public function posts() {
        return $this->hasMany(Post::class);
    }
}
// Create the table
Schema::create('users', function(Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->string('password');
    $table->timestamps();
});
// Create a user
$user = User::create([
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'password' => password_hash('secret', PASSWORD_DEFAULT)
]);
// Query users
$users = User::where('created_at', '>', '2024-01-01')
             ->orderBy('name')
             ->limit(10)
             ->get();
// Eager load relationships
$users = User::with('posts')->get();Initialize ProQuery with your database:
// File-based database
ProQuery::init('path/to/database.db');
// In-memory database (great for testing)
ProQuery::init(':memory:');
// Enable query logging
ProQuery::getInstance()->enableQueryLog();Define models by extending the base Model class:
class Post extends Model {
    // Table name (optional, defaults to lowercase plural of class name)
    protected static $table = 'posts';
    
    // Mass assignable attributes
    protected static $fillable = ['title', 'content', 'user_id'];
    
    // Hidden attributes (excluded from JSON/array)
    protected static $hidden = ['internal_notes'];
    
    // Attribute casting
    protected static $casts = [
        'published' => 'boolean',
        'metadata' => 'json',
        'published_at' => 'datetime'
    ];
    
    // Enable/disable timestamps
    protected static $timestamps = true;
}// Retrieve all records
$users = User::all();
// Find by primary key
$user = User::find(1);
$user = User::findOrFail(1); // Throws exception if not found
// Where clauses
$users = User::where('status', 'active')->get();
$users = User::where('age', '>', 18)->get();
$users = User::whereIn('role', ['admin', 'moderator'])->get();
$users = User::whereBetween('age', [18, 65])->get();
$users = User::whereNull('deleted_at')->get();
// Ordering
$users = User::orderBy('name', 'ASC')->get();
$users = User::latest()->get(); // Order by created_at DESC
$users = User::oldest()->get(); // Order by created_at ASC
// Limiting
$users = User::limit(10)->offset(20)->get();
$users = User::take(5)->skip(10)->get();// Aggregates
$count = User::count();
$sum = Order::sum('total');
$avg = Product::avg('price');
$min = Product::min('price');
$max = Product::max('price');
// Exists checks
if (User::where('email', 'test@example.com')->exists()) {
    // User exists
}
// Joins
$users = User::query()
    ->join('posts', 'users.id', '=', 'posts.user_id')
    ->select('users.*', 'posts.title')
    ->get();
// Raw expressions
$users = User::query()
    ->select(raw('COUNT(*) as post_count'))
    ->groupBy('status')
    ->get();class User extends Model {
    // One-to-One
    public function profile() {
        return $this->hasOne(Profile::class);
    }
    
    // One-to-Many
    public function posts() {
        return $this->hasMany(Post::class);
    }
    
    // Belongs To
    public function company() {
        return $this->belongsTo(Company::class);
    }
    
    // Many-to-Many
    public function roles() {
        return $this->belongsToMany(Role::class, 'user_roles')
                    ->withPivot(['expires_at'])
                    ->withTimestamps();
    }
    
    // Has Many Through
    public function comments() {
        return $this->hasManyThrough(Comment::class, Post::class);
    }
    
    // Polymorphic Relations
    public function images() {
        return $this->morphMany(Image::class, 'imageable');
    }
}// Eager loading (prevents N+1 queries)
$users = User::with(['posts', 'roles'])->get();
$users = User::with('posts.comments')->get(); // Nested
// Lazy loading
$user = User::find(1);
$posts = $user->posts; // Loads on access
// Relationship operations
$user->roles()->attach($roleId);
$user->roles()->detach($roleId);
$user->roles()->sync([1, 2, 3]);
$user->posts()->create(['title' => 'New Post']);// Create table
Schema::create('products', function(Blueprint $table) {
    $table->id();
    $table->string('name', 100);
    $table->text('description')->nullable();
    $table->decimal('price', 10, 2);
    $table->integer('stock')->default(0);
    $table->boolean('active')->default(true);
    $table->json('metadata')->nullable();
    $table->timestamps();
    
    $table->index('name');
    $table->unique('sku');
});
// Modify table
Schema::table('products', function(Blueprint $table) {
    $table->string('sku', 50)->unique();
    $table->foreign('category_id')->references('id')->on('categories');
});
// Drop table
Schema::dropIfExists('products');
// Check existence
if (Schema::hasTable('products')) {
    // Table exists
}// Create a migration
class CreateProductsTable extends Migration {
    public function up() {
        Schema::create('products', function(Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->decimal('price', 10, 2);
            $table->timestamps();
        });
    }
    
    public function down() {
        Schema::drop('products');
    }
}
// Run migrations
$migrator = new Migrator('./migrations');
$migrator->run();
// Rollback
$migrator->rollback();
$migrator->rollback(3); // Rollback 3 batches
// Reset and refresh
$migrator->reset();
$migrator->refresh();$users = User::paginate(15); // 15 per page
// Access pagination data
$users->items();        // Current page items
$users->total();        // Total items
$users->currentPage();  // Current page number
$users->lastPage();     // Last page number
$users->hasMorePages(); // Check if more pages exist
// Render links
echo $users->links();// Process large datasets efficiently
User::chunk(100, function($users) {
    foreach ($users as $user) {
        // Process user
    }
});// Dump and die
User::where('status', 'active')->dd();
// Dump and continue
User::where('status', 'active')->dump()->get();
// Get SQL
$sql = User::where('status', 'active')->toSql();
// Query log
$queries = ProQuery::getInstance()->getQueryLog();<?php
require_once 'ProQuery.php';
// Initialize
ProQuery::init('blog.db');
// Models
class User extends Model {
    protected static $fillable = ['name', 'email', 'password'];
    
    public function posts() {
        return $this->hasMany(Post::class);
    }
    
    public function comments() {
        return $this->hasMany(Comment::class);
    }
}
class Post extends Model {
    protected static $fillable = ['title', 'content', 'user_id', 'published'];
    protected static $casts = ['published' => 'boolean'];
    
    public function user() {
        return $this->belongsTo(User::class);
    }
    
    public function comments() {
        return $this->hasMany(Comment::class);
    }
    
    public function tags() {
        return $this->belongsToMany(Tag::class);
    }
}
// Create schema
Schema::create('users', function($table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->string('password');
    $table->timestamps();
});
Schema::create('posts', function($table) {
    $table->id();
    $table->string('title');
    $table->text('content');
    $table->integer('user_id');
    $table->boolean('published')->default(false);
    $table->timestamps();
    $table->foreign('user_id')->references('id')->on('users');
});
// Usage
$user = User::create([
    'name' => 'Jane Doe',
    'email' => 'jane@example.com',
    'password' => password_hash('secret', PASSWORD_DEFAULT)
]);
$post = $user->posts()->create([
    'title' => 'Getting Started with ProQuery',
    'content' => 'ProQuery makes database operations simple...',
    'published' => true
]);
// Complex query
$popularPosts = Post::with(['user', 'comments'])
    ->where('published', true)
    ->where('created_at', '>', date('Y-m-d', strtotime('-7 days')))
    ->orderBy('views', 'DESC')
    ->limit(10)
    ->get();Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (git checkout -b feature/AmazingFeature)
- Commit your changes (git commit -m 'Add some AmazingFeature')
- Push to the branch (git push origin feature/AmazingFeature)
- Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Inspired by Laravel Eloquent
- Built for the PHP community that values simplicity and power
- π§ Email: nadermkhan@gmail.com
- π Issues: GitHub Issues
- π‘ Discussions: GitHub Discussions
Built with β€οΈ by Nader Mahbub Khan
If you find ProQuery useful, please β star this repository!
This README provides a comprehensive overview of ProQuery with clear examples, making it easy for developers to understand and start using the framework immediately. The documentation is structured, professional, and highlights all the powerful features while maintaining the simplicity that makes ProQuery special.