StormQueries – A Query Builder with ORM Superpowers
Over the years working in web development, I’ve tried countless tools for working with databases.
Most of the time, they fell into one of two categories:
- Query Builders (QB) – lightweight, fast, no schema configuration required. Great for quick queries. The downside? Once you need hierarchical data (1 invoice → many items), you’re on your own.
- ORMs (Object-Relational Mappers) – powerful for handling relationships, but heavy and often require models, annotations, or schema definitions.
And I kept thinking: why isn’t there something in between?
So I built StormQueries 🚀
Why StormQueries?
StormQueries combines the simplicity of a Query Builder with the power of an ORM.
Here’s what it gives you out of the box:
- ✅ Build dynamic queries depending on runtime parameters.
- ✅ Reusable query structures.
- ✅ Hierarchical data fetching (one-to-many).
- ✅ Map results to your own objects without modifying models.
- ✅ Zero schema configuration – just connect to the database.
- ✅ Support for subqueries.
- ✅ Intuitive syntax.
One example:
With StormQueries, you can run an incremental update (field = field + 1
) — something that’s oddly tricky or impossible in many other tools.
Quick examples
Basic CRUD:
$product = $queries->find('products', ['id' => 5]);
$id = $queries->insert('products', [
'name' => 'Golden watch',
'price' => 465
]);
$queries->update('products', ['id' => $id], ['name' => 'Renamed product']);
$queries->delete('products', ['id' => $id]);
Dynamic filtering:
$query = $queries
->select('products')
->join('product_photos', ['product_photos.product_id' => 'products.id'])
->where('is_in_sale', true);
if ($criteria->hasCategory()) {
$query->where('category_id', $criteria->getCategoryId());
}
$products = $query->findAll();
Subqueries:
$queries
->select(SubQuery::create($queries->select('products'), 'p'))
->where('p.product_id', 7)
->find();
ORM-style relationships (without schema config):
$customer = $queries
->select('customers c', Map::select([
'customer_id',
'customer_name'
], Customer::class, classId: 'customer_id'))
->leftJoin('orders o', 'o.customer_id = c.customer_id', Map::many("orders", [
'order_id'
], Order::class, classId: 'order_id'))
->where('c.customer_id', 90)
->find();
foreach ($customer->orders as $order) {
echo $customer->customer_name . " - " . $order->id;
}
How is it different?
- Doctrine / Eloquent (PHP) – require schema definitions and models. StormQueries works right after connecting.
- SQLAlchemy, Hibernate – powerful but heavy, with lots of boilerplate. StormQueries is lightweight and fast.
- Pure Query Builders – flexible, but no hierarchical mapping. StormQueries bridges the gap.
Try it out
🔗 GitHub: storm-php-queries
📖 Docs & examples: stormmoredev.github.io/storm-php-queries
Final thoughts
StormQueries was born out of real-world needs: I wanted the simplicity of Query Builders with the convenience of ORMs, without their usual trade-offs.
If this sounds useful, check it out, give it a ⭐ on GitHub, or drop me some feedback.
Issues, discussions, and pull requests are more than welcome 🙌
This is just the beginning — I’m planning more features inspired by real application use cases. Stay tuned!
Top comments (0)