|
1 | 1 | # Derafu: Query - Expressive Path-Based Query Builder for PHP |
2 | 2 |
|
3 | | - |
4 | | - |
5 | | - |
6 | | - |
7 | | - |
8 | | - |
9 | | - |
10 | | -A flexible, intuitive PHP query builder that uses path expressions and configurable operators to simplify complex database queries and relationships. |
11 | | - |
12 | | -## Why Derafu\Query? |
13 | | - |
14 | | -### 🚀 **Intuitive Relationship Navigation** |
15 | | - |
16 | | -Traditional query builders often: |
17 | | - |
18 | | -- Require explicit join definitions. |
19 | | -- Make nested relationship queries verbose. |
20 | | -- Force you to understand the underlying join mechanics. |
21 | | -- Use different filter syntaxes across database engines. |
22 | | - |
23 | | -### 🔥 **What Makes Derafu\Query Unique?** |
24 | | - |
25 | | -| Feature | Derafu\Query | Traditional Query Builders | |
26 | | -|-------------------------------|-----------------|----------------------------| |
27 | | -| **Path-Based Relationships** | ✅ Yes | ❌ No | |
28 | | -| **Automatic Join Resolution** | ✅ Yes | ❌ No | |
29 | | -| **Configurable Operators** | ✅ Yes | ❌ No | |
30 | | -| **Framework Agnostic** | ✅ Yes | ⚠️ Varies | |
31 | | -| **Unified Filter Syntax** | ✅ Yes | ⚠️ Varies | |
32 | | -| **Multi-DB Compatibility** | ✅ Yes | ⚠️ Varies | |
33 | | - |
34 | | -Derafu\Query is **not** a replacement for full-featured ORMs. Instead, it focuses on: |
35 | | - |
36 | | -1. Providing an intuitive way to express complex relationships. |
37 | | -2. Offering a consistent filtering syntax across different backends. |
38 | | -3. Making query building more readable and maintainable. |
39 | | - |
40 | | ---- |
41 | | - |
42 | | -## Features |
43 | | - |
44 | | -- ✅ **Path-Based Relationships** – Express multi-table relationships in a clean, readable format. |
45 | | -- ✅ **Automatic Join Generation** – Let the query builder figure out the join conditions. |
46 | | -- ✅ **Rich Operator System** – 40+ operators for filtering with consistent syntax across databases. |
47 | | -- ✅ **YAML Configuration** – Easily extend and customize operators for your specific needs. |
48 | | -- ✅ **Multiple Backend Support** – Works with SQL databases today, with planned support for Eloquent, Doctrine, and more. |
49 | | -- ✅ **PHP 8+ Optimized** – Takes advantage of modern PHP features. |
50 | | -- ✅ **Framework Independent** – Use it in any PHP project. |
51 | | - |
52 | | ---- |
53 | | - |
54 | | -## Installation |
55 | | - |
56 | | -Install via Composer: |
57 | | - |
58 | | -```bash |
59 | | -composer require derafu/query |
60 | | -``` |
61 | | - |
62 | | -## Basic Usage |
63 | | - |
64 | | -```php |
65 | | -use Derafu\Query\Builder\SqlQueryBuilder; |
66 | | - |
67 | | -// Create a query builder. |
68 | | -$queryBuilder = new SqlQueryBuilder($engine, $expressionParser); |
69 | | - |
70 | | -// Build and execute a query with a simple condition with chained methods. |
71 | | -$result = $queryBuilder |
72 | | - ->table('products') |
73 | | - ->where('price?>1000') // Price greater than 1000. |
74 | | - ->execute(); |
75 | | -``` |
76 | | - |
77 | | -## Path-Based Relationships |
78 | | - |
79 | | -One of the most powerful features of Derafu\Query is the ability to express relationships through paths: |
80 | | - |
81 | | -```php |
82 | | -// Find invoices with customer information. |
83 | | -$result = $queryBuilder |
84 | | - ->where('invoices[alias:i]__customers[on:customer_id=id,alias:c]__name?isnot:null') |
85 | | - ->execute(); |
86 | | -``` |
87 | | - |
88 | | -The path syntax makes it clear which tables are being joined and on what conditions, all in a single expression. |
89 | | - |
90 | | -The main advantage of this syntax is that it can be provided to end users in a simplified version that the backend later completes with the missing data to build filters. This is especially useful for filtering table listings through their columns. |
91 | | - |
92 | | -The simplified filtering example in the invoices table seen above would look like this in the frontend: |
93 | | - |
94 | | -``` |
95 | | -name?isnot:null |
96 | | -``` |
97 | | - |
98 | | -With this filter applied to the invoices table on the customers table, the backend will complete the path with the current table (`invoices`) and the data for the join (`customers` and `customer_id=id`). This allows end users to easily write advanced filters across related tables. |
99 | | - |
100 | | -## Rich Operator System |
101 | | - |
102 | | -Derafu\Query includes a comprehensive set of operators for filtering data: |
103 | | - |
104 | | -```php |
105 | | -// Standard comparison operators. |
106 | | -$queryBuilder->where('price?>500'); // Greater than. |
107 | | -$queryBuilder->where('status?=active'); // Equals. |
108 | | - |
109 | | -// Pattern matching with automatic wildcard generation. |
110 | | -$queryBuilder->where('name?^John'); // Starts with "John". |
111 | | -$queryBuilder->where('email?$*gmail.com'); // Ends with "gmail.com" (case-insensitive). |
112 | | -$queryBuilder->where('description?~~keyword'); // Contains "keyword". |
113 | | - |
114 | | -// List operations. |
115 | | -$queryBuilder->where('status?in:active,pending'); // In list. |
116 | | -$queryBuilder->where('category?notin:archived,deleted'); // Not in list. |
117 | | - |
118 | | -// Range queries. |
119 | | -$queryBuilder->where('price?between:10,50'); // Between 10 and 50. |
120 | | - |
121 | | -// Date operations. |
122 | | -$queryBuilder->where('created_at?date:20240301'); // Specific date. |
123 | | -$queryBuilder->where('created_at?period:202403'); // Month and year. |
124 | | - |
125 | | -// NULL checks. |
126 | | -$queryBuilder->where('deleted_at?is:null'); // Is NULL. |
127 | | -$queryBuilder->where('email?isnot:null'); // Is not NULL. |
128 | | - |
129 | | -// Regular expressions. |
130 | | -$queryBuilder->where('name?~^J.*n$'); // Regex match. |
131 | | - |
132 | | -// Bitwise operations. |
133 | | -$queryBuilder->where('flags?b&1'); // Bitwise AND. |
134 | | -``` |
135 | | - |
136 | | -## Configurable Operators |
137 | | - |
138 | | -All operators are defined in a YAML configuration file, making it easy to extend or customize: |
139 | | - |
140 | | -```yaml |
141 | | -operators: |
142 | | - 'between:': |
143 | | - type: 'range' |
144 | | - name: 'Between' |
145 | | - description: 'Matches values between two specified values (inclusive).' |
146 | | - pattern: '/^[\w\.\-\p{L}\p{M}]+,[\w\.\-\p{L}\p{M}]+$/u' |
147 | | - cast: ['list'] |
148 | | - examples: ['between:1,10', 'between:2024-01-01,2024-12-31'] |
149 | | - sql: '{{column}} BETWEEN {{value_1}} AND {{value_2}}' |
150 | | -``` |
151 | | -
|
152 | | -This allows you to: |
153 | | -
|
154 | | -- Add custom operators specific to your application. |
155 | | -- Adjust SQL templates for different database engines. |
156 | | -- Create aliases for frequently used operations. |
157 | | -- Document operators with examples for your team. |
158 | | -
|
159 | | -## Advanced Usage |
160 | | -
|
161 | | -### Complex Filtering |
162 | | -
|
163 | | -```php |
164 | | -// Find active products with price over 200. |
165 | | -$result = $queryBuilder |
166 | | - ->table('products') |
167 | | - ->where(['flags?b&1', 'price?>200']) |
168 | | - ->execute(); |
169 | | -``` |
170 | | - |
171 | | -### Join with Conditions |
172 | | - |
173 | | -```php |
174 | | -// Find high-value invoices for company customers. |
175 | | -$result = $queryBuilder |
176 | | - ->select('c.name, i.number, i.total') |
177 | | - ->where([ |
178 | | - 'customers[alias:c]__status?=active', |
179 | | - 'customers[alias:c]__invoices[on:id=customer_id,alias:i]__total?>1000' |
180 | | - ]) |
181 | | - ->execute(); |
182 | | -``` |
183 | | - |
184 | | -### Advanced Path Joins |
185 | | - |
186 | | -```php |
187 | | -// Join with OR conditions. |
188 | | -$result = $queryBuilder |
189 | | - $this->select('p.name, i.number') |
190 | | - $this->where('products[alias:p]__category?=electronics') |
191 | | - $this->orWhere('products[alias:p]__category?=software') |
192 | | - $this->andWhere('products[alias:p]__invoice_details[on:id=product_id,alias:id]__invoices[on:invoice_id=id,alias:i]__number?isnot:null') |
193 | | - ->execute(); |
194 | | -``` |
195 | | - |
196 | | -### Cross-Database Compatibility |
197 | | - |
198 | | -The same query syntax works across PostgreSQL, MySQL, SQLite, and other supported databases: |
199 | | - |
200 | | -```php |
201 | | -// The same query syntax works on any database. |
202 | | -$result = $queryBuilder |
203 | | - ->where('products__price?between:100,500') |
204 | | - ->andWhere('products__name?~~*computer') // Case-insensitive contains. |
205 | | - ->andWhere('products__created_at?period:202401') // January 2024. |
206 | | - ->execute(); |
207 | | -``` |
208 | | - |
209 | | -### Declarative Query Configuration |
210 | | - |
211 | | -Beyond the fluent interface, Derafu\Query provides a powerful configuration-based approach to defining queries through the `QueryConfig` class: |
212 | | - |
213 | | -```php |
214 | | -use Derafu\Query\Config\QueryConfig; |
215 | | - |
216 | | -// Define a query using an array configuration. |
217 | | -$config = new QueryConfig([ |
218 | | - 'table' => 'products', |
219 | | - 'select' => 'id, name, price', |
220 | | - 'where' => 'category?=electronics', |
221 | | - 'orderBy' => ['price' => 'DESC'], |
222 | | - 'limit' => 10 |
223 | | -]); |
224 | | - |
225 | | -// Apply the configuration to a query builder. |
226 | | -$result = $config->applyTo($queryBuilder)->execute(); |
227 | | -``` |
228 | | - |
229 | | -## Operator Types |
230 | | - |
231 | | -Derafu\Query includes a wide range of operator types: |
232 | | - |
233 | | -- **Standard** - Direct SQL comparisons (`=`, `!=`, `>`, `<`, etc.). |
234 | | -- **AutoLike** - Automatic pattern generation for LIKE queries (`^`, `~~`, `$`, etc.). |
235 | | -- **Like** - Custom pattern matching (`like:`, `ilike:`). |
236 | | -- **List** - Multiple value operators (`in:`, `notin:`). |
237 | | -- **Range** - Value range operators (`between:`, `notbetween:`). |
238 | | -- **Date** - Date-specific operators (`date:`, `month:`, `year:`, `period:`). |
239 | | -- **Null** - NULL handling operators (`is:null`, `isnot:null`) |
240 | | -- **RegExp** - Regular expression operators (`~`, `~*`, `!~`, `!~*`). |
241 | | -- **Binary** - Bitwise operators (`b&`, `b|`, `b^`, etc.). |
242 | | - |
243 | | -## Roadmap |
244 | | - |
245 | | -- Support for Laravel's Eloquent. |
246 | | -- Integration with Doctrine ORM. |
247 | | -- Query caching mechanisms. |
248 | | -- Expanded filter operations. |
249 | | -- Performance optimizations. |
250 | | - |
251 | | -## Performance Considerations |
252 | | - |
253 | | -- Optimized for readable, maintainable query construction. |
254 | | -- Automatic join generation adds minimal overhead. |
255 | | -- For extremely performance-critical applications, consider pre-optimized raw queries. |
256 | | -- Configurable operators provide a balance between flexibility and performance. |
257 | | - |
258 | | -## Contributing |
259 | | - |
260 | | -Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change. |
261 | | - |
262 | | -## License |
263 | | - |
264 | | -This package is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). |
| 3 | +Please refer to the [documentation](https://www.derafu.dev/docs/data/query) for more information. |
0 commit comments