Declarative Query Engine • Data Mapper • PHP

Describe Data.
Not Execution.

ObjectQuel is a domain-level query engine with integrated ORM capabilities. It lets you describe data relationships and constraints declaratively, while the engine determines optimal execution across SQL, post-processing, and hybrid data sources.

// Declare data ranges
range of p is Product
range of c is Category via p.categories

// Describe what you want
retrieve (p, category_name=c.name)
where p.price < 100
  and c.active = true

Why Ranges Beat Joins

Compare how different approaches express the same data intent.

Doctrine QueryBuilder
Procedural
$qb = $em->createQueryBuilder();
$qb->select('p', 'c.name as category_name')
   ->from(Product::class, 'p')
   ->leftJoin('p.categories', 'c')
   ->where('p.price < :maxPrice')
   ->andWhere('c.active = :active')
   ->setParameter('maxPrice', 100)
   ->setParameter('active', true);

$results = $qb->getQuery()->getResult();

You explicitly define joins, chain conditions, and control execution details.

ObjectQuel
Declarative
$results = $em->executeQuery("
    range of p is Product
    range of c is Category via p.categories
    retrieve (p, category_name=c.name)
    where p.price < :maxPrice
      and c.active = true
", [
    'maxPrice' => 100
]);
    

You declare data ranges and constraints. ObjectQuel analyzes the query and determines execution.

Navigation, Not Configuration

Relationships are paths: via p.categories expresses traversal, not SQL join mechanics.

Smart Query Decomposition

ObjectQuel analyzes ranges and constraints, then generates optimized execution steps automatically.

Composable by Design

Based on tuple relational calculus — QUEL’s declarative model for expressing relational intent.

Choose Your Approach

Simple methods for everyday use, and a query language when relationships and logic grow complex

Simple Methods
// Find by primary key
$user = $em->find(User::class, $id);

// Find by criteria
$posts = $em->findBy(
    Post::class,
    [
        'published' => true,
        'authorId' => 5
    ]
);

Ideal for straightforward lookups and simple filtering

Query Language for Complexity
// Complex relationships and filtering
$results = $em->executeQuery("
    range of p is Product
    range of c is Category via p.categories
    retrieve (p, category_name=c.name)
    where p.price < :maxPrice
      and c.active = true
      and p.name = \"widget*\"
    sort by p.name asc
", ['maxPrice' => 100.00]);

Designed for complex relationships, multistep filtering, and non-trivial queries

When ObjectQuel Shines

Where QUEL's declarative approach delivers the most value

Complex Relationship Navigation

Traverse multiple relationship levels without manual join configuration.

Legacy System Modernization

Adopt gradually alongside existing database code - no big-bang rewrite required.

Hybrid Data Sources

Combine SQL databases and JSON APIs in unified queries.

Secure by Default

All queries use parameterized statements automatically - zero SQL injection risk.

Performance Optimization

The query decomposer analyzes structure and optimizes execution paths automatically.

Canvas Framework Integration

Native integration with Canvas PHP - zero configuration needed when using both together.

Why ObjectQuel Exists

After 25 years writing database queries, I got tired of fighting ORMs that force you to think in SQL joins or drown in method chaining. ObjectQuel brings QUEL’s declarative approach to PHP — declare data ranges and constraints, and let the engine determine execution.

— Floris, Quellabs

How ObjectQuel Works

From query to hydrated entities

Query Processing Pipeline
  • Parse: QUEL syntax into abstract syntax tree
  • Decompose: Break complex queries into optimized subtasks
  • Execute: Fetch from SQL databases and JSON sources
  • Hydrate: Join results and create entity objects

ObjectQuel handles optimization automatically, so you focus on describing data, not execution mechanics.

ObjectQuel Query Flow
QUEL Query range of p is... Parse AST Abstract Syntax Tree Decompose Query Decomposer Optimize & Plan SQL JSON SQL Queries Database Access JSON Data External Sources Join Results Merge Data Hydrate Entity Objects Ready to Use

ObjectQuel handles SQL and JSON sources, then hydrates results into objects

🚀

Get Started in Minutes

Install ObjectQuel via Composer and start querying with objects immediately

# Install via Composer
composer require quellabs/objectquel
Quick Start Example
$config = new Configuration();
$config->setDsn('mysql://user:pass@localhost/db');
$config->setEntityPath(__DIR__ . '/Entities/');

$entityManager = new EntityManager($config);

// Query immediately
$users = $entityManager->find(User::class, 10);
View on GitHub
Repository
View on Packagist
Package
Documentation
Read Docs

Open source and MIT licensed

Ready to Modernize Your Data Layer?

Join developers who've already simplified their database code with ObjectQuel

GitHub Page Get Started Now