Skip to content

ddbase3/php-struql

Repository files navigation

Struql – Structured Query Logic for PHP

Struql is a modular, extensible, and phase-based query processing framework for PHP. It empowers developers to define, normalize, simplify, and compile structured query logic into executable SQL – all using a clean and extensible handler-based architecture.


🌐 Why Struql?

Struql was designed to solve a recurring problem: building highly dynamic and structured queries without tying your code to SQL strings or rigid query builders. With Struql, you can:

  • Parse structured query inputs from users or APIs
  • Normalize and enrich the query logic
  • Automatically resolve joins and field variants
  • Generate safe and dialect-specific SQL queries

📦 Features

  • Four processing phases: Parse → Normalize → Simplify → Compile
  • Handler architecture: Each transformation is modular and isolated
  • JOIN auto-resolution: Based on smart field inference
  • SQL dialect support: MySQL, MSSQL, PostgreSQL
  • Composable processors: Reusable across contexts
  • Readable, testable, and extendable code

🧱 Architecture Overview

[ Input Query ]
      ↓
[ Parse Phase ]
      ↓
[ Normalize Phase ]
      ↓
[ Simplify Phase ]
      ↓
[ Compile Phase ]
      ↓
[ SQL String ]

Each phase is managed by a Processor, which consists of ordered Handlers. A handler is a class that inspects and transforms the query object for a specific purpose.


🧩 Key Concepts

✅ Processors and Handlers

Each handler must implement:

  • supportedTypes() – which input types it processes
  • run(mixed $input, array &$context): mixed – transformation logic

🧠 Phase Responsibilities

Phase Purpose
parse Parses external input (e.g. query strings) into PHP objects
normalize Expands shorthand field syntax, dollar-fields, top-level filters
simplify Resolves aliases, inferred joins, expands derived objects
compile Transforms the object into executable SQL

🧪 Example Usage

use Struql\Processor\NormalizePhaseProcessor;
use Struql\Processor\CompilePhaseProcessor;
use Struql\Handler\DollarFieldToFieldHandler;
use Struql\Handler\FieldsToWhereHandler;
use Struql\Handler\SqlCompilerHandler;
use Struql\Handler\SqlDialect;

// Normalization
$normalize = new NormalizePhaseProcessor();
$normalize->addHandler(new DollarFieldToFieldHandler());
$normalize->addHandler(new FieldsToWhereHandler());

$query = $normalize->process([
  'type' => 'selectUser',
  '$user!optional.status' => 'active',
  'limit' => 10,
  'offset' => 20,
  'orderBy' => [
    (object)[ 'type' => 'field', 'table' => 'user', 'name' => 'id', 'direction' => 'DESC' ]
  ]
]);

// Compilation
$compile = new CompilePhaseProcessor();
$compile->addHandler(new SqlCompilerHandler(SqlDialect::MySQL));

$sql = $compile->process($query);
echo $sql;

Output SQL:

SELECT `user`.`id`, `user`.`login`, `user`.`name`
FROM `user`
LEFT JOIN `profile` ON `user`.`id` = `profile`.`user_id`
WHERE `user`.`status` = 'active'
ORDER BY `user`.`id` DESC
LIMIT 10 OFFSET 20

🛠️ Built-in Handlers

Normalize Phase

  • DollarFieldToFieldHandler: Converts $table!variant.field to field objects with table, name, and variant
  • FieldsToWhereHandler: Converts top-level field-value pairs to where conditions

Compile Phase

  • SqlCompilerHandler: Converts normalized query objects to SQL strings; supports:

    • Joins (INNER, LEFT)
    • Conditions with AND, OR, NOT
    • ORDER BY, GROUP BY, HAVING, LIMIT, OFFSET
    • Dialect-specific quoting

🔄 Extending Struql

To add a new transformation or compiler step, create a new handler:

class MyCustomHandler extends AbstractHandler {
    public function supportedTypes(): array {
        return ['object'];
    }

    public function run(mixed $input, array &$context): mixed {
        // Transform the $input as needed
        return $input;
    }
}

Register it in your processor:

$normalize->addHandler(new MyCustomHandler());

🚀 Use Cases

  • Backend APIs that accept dynamic filters from users (e.g. dashboards, analytics)
  • Middleware layers that convert API calls to database queries
  • CMS systems with dynamic content filtering
  • Query conversion pipelines for SQL dialect adaptation

📁 File Structure

src/
  Core/
    AbstractHandler.php
    Processor.php
  Handler/
    DollarFieldToFieldHandler.php
    FieldsToWhereHandler.php
    SqlCompilerHandler.php
    SqlDialect.php
  Processor/
    NormalizePhaseProcessor.php
    CompilePhaseProcessor.php

📋 Future Plans

  • ✅ Automatic join resolution via used fields
  • 🔲 Validation layer for input checking before compilation
  • 🔲 Support for INSERT, UPDATE, DELETE queries
  • 🔲 Full support for subqueries and expressions

📃 License

This project is open-source and available under the MIT License.


🤝 Contributing

Contributions are welcome! Create a feature branch and submit a pull request. Please include tests where applicable.


🧠 Summary

Struql is a powerful and extensible query transformation engine. Its handler-based architecture allows developers to fully control and customize every aspect of query interpretation and SQL generation – from API input to final query execution.

Ideal for teams building APIs, dashboards, CMS backends, or data-driven platforms.

About

A PHP implementation of the Struql query language — parse, merge, expand, and translate Struql JSON into SQL.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages