Skip to content

Commit a78eb0c

Browse files
committed
feat: add enhanced WHERE condition methods with AND/OR variants
- Add whereNull, whereNotNull, whereBetween, whereNotBetween, whereColumn methods - Update whereIn/whereNotIn to support arrays in addition to subqueries - Add AND variants: andWhereNull, andWhereNotNull, andWhereBetween, andWhereNotBetween, andWhereIn, andWhereNotIn, andWhereColumn - Add OR variants: orWhereNull, orWhereNotNull, orWhereBetween, orWhereNotBetween, orWhereIn, orWhereNotIn, orWhereColumn - Update ConditionBuilder, QueryBuilder, and all related interfaces - Add comprehensive tests (27 tests, 66 assertions) in WhereConditionMethodsTests - Update documentation with new methods and examples - Update examples/01-basic/03-where-conditions.php with new functionality - Update README.md with enhanced WHERE methods reference Improves developer experience by providing fluent methods instead of requiring helper functions for common WHERE patterns.
1 parent 94f95df commit a78eb0c

File tree

8 files changed

+1723
-47
lines changed

8 files changed

+1723
-47
lines changed

README.md

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1414,7 +1414,13 @@ $users = $db->find()
14141414
})
14151415
->get();
14161416

1417-
// IN condition
1417+
// IN condition (with array)
1418+
$users = $db->find()
1419+
->from('users')
1420+
->whereIn('id', [1, 2, 3, 4, 5])
1421+
->get();
1422+
1423+
// You can also use the helper function
14181424
$users = $db->find()
14191425
->from('users')
14201426
->where(Db::in('id', [1, 2, 3, 4, 5]))
@@ -1423,14 +1429,30 @@ $users = $db->find()
14231429
// BETWEEN
14241430
$users = $db->find()
14251431
->from('users')
1426-
->where(Db::between('age', 18, 65))
1432+
->whereBetween('age', 18, 65)
14271433
->get();
14281434

14291435
// IS NULL / IS NOT NULL
14301436
$users = $db->find()
14311437
->from('users')
1432-
->where(Db::isNull('deleted_at'))
1433-
->andWhere(Db::isNotNull('email'))
1438+
->whereNull('deleted_at')
1439+
->andWhereNotNull('email')
1440+
->get();
1441+
1442+
// Column comparison
1443+
$products = $db->find()
1444+
->from('products')
1445+
->whereColumn('quantity', '<=', 'threshold')
1446+
->get();
1447+
1448+
// AND/OR variants
1449+
$users = $db->find()
1450+
->from('users')
1451+
->where('active', 1)
1452+
->andWhereNull('deleted_at')
1453+
->andWhereBetween('age', 18, 65)
1454+
->andWhereIn('status', ['active', 'pending'])
1455+
->orWhereNotNull('verified_at')
14341456
->get();
14351457
```
14361458

@@ -3084,7 +3106,17 @@ $constraints = $db->constraints('users');
30843106
| Method | Description |
30853107
|--------|-------------|
30863108
| `where(...)` / `andWhere(...)` / `orWhere(...)` | Add WHERE conditions |
3087-
| `whereIn(column, callable\|QueryBuilder)` / `whereNotIn(column, callable\|QueryBuilder)` | Add WHERE IN/NOT IN with subquery |
3109+
| `whereNull(column, boolean='AND')` / `whereNotNull(column, boolean='AND')` | WHERE column IS NULL / IS NOT NULL |
3110+
| `andWhereNull(column)` / `andWhereNotNull(column)` | AND variants for NULL checks |
3111+
| `orWhereNull(column)` / `orWhereNotNull(column)` | OR variants for NULL checks |
3112+
| `whereBetween(column, min, max, boolean='AND')` / `whereNotBetween(column, min, max, boolean='AND')` | WHERE column BETWEEN / NOT BETWEEN |
3113+
| `andWhereBetween(column, min, max)` / `andWhereNotBetween(column, min, max)` | AND variants for BETWEEN |
3114+
| `orWhereBetween(column, min, max)` / `orWhereNotBetween(column, min, max)` | OR variants for BETWEEN |
3115+
| `whereIn(column, array\|callable, boolean='AND')` / `whereNotIn(column, array\|callable, boolean='AND')` | WHERE column IN / NOT IN (supports arrays and subqueries) |
3116+
| `andWhereIn(column, array\|callable)` / `andWhereNotIn(column, array\|callable)` | AND variants for IN |
3117+
| `orWhereIn(column, array\|callable)` / `orWhereNotIn(column, array\|callable)` | OR variants for IN |
3118+
| `whereColumn(first, operator, second, boolean='AND')` | Compare two columns |
3119+
| `andWhereColumn(first, operator, second)` / `orWhereColumn(first, operator, second)` | AND/OR variants for column comparison |
30883120
| `whereExists(callable\|QueryBuilder)` / `whereNotExists(callable\|QueryBuilder)` | Add WHERE EXISTS/NOT EXISTS with subquery |
30893121
| `where(column, QueryBuilder, operator)` | Add WHERE condition with QueryBuilder subquery |
30903122
| `join(...)` / `leftJoin(...)` / `rightJoin(...)` / `innerJoin(...)` | Add JOIN clauses |

documentation/03-query-builder/filtering-conditions.md

Lines changed: 131 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,16 @@ $users = $db->find()
8888

8989
## IN and NOT IN
9090

91-
### Basic IN
91+
### Basic IN with Array
92+
93+
```php
94+
$users = $db->find()
95+
->from('users')
96+
->whereIn('status', ['active', 'pending'])
97+
->get();
98+
```
99+
100+
You can also use the helper function:
92101

93102
```php
94103
use tommyknocker\pdodb\helpers\Db;
@@ -99,19 +108,46 @@ $users = $db->find()
99108
->get();
100109
```
101110

102-
### NOT IN
111+
### NOT IN with Array
112+
113+
```php
114+
$users = $db->find()
115+
->from('users')
116+
->whereNotIn('status', ['banned', 'deleted'])
117+
->get();
118+
```
119+
120+
### AND/OR Variants
103121

104122
```php
123+
// AND variants
105124
$users = $db->find()
106125
->from('users')
107-
->where(Db::notIn('status', ['banned', 'deleted']))
126+
->where('active', 1)
127+
->andWhereIn('status', ['active', 'pending'])
128+
->get();
129+
130+
// OR variants
131+
$users = $db->find()
132+
->from('users')
133+
->where('active', 1)
134+
->orWhereIn('status', ['pending', 'suspended'])
108135
->get();
109136
```
110137

111138
## BETWEEN
112139

113140
### Value Range
114141

142+
```php
143+
$users = $db->find()
144+
->from('users')
145+
->whereBetween('age', 18, 65)
146+
->get();
147+
```
148+
149+
You can also use the helper function:
150+
115151
```php
116152
use tommyknocker\pdodb\helpers\Db;
117153

@@ -126,14 +162,41 @@ $users = $db->find()
126162
```php
127163
$users = $db->find()
128164
->from('users')
129-
->where(Db::notBetween('age', 0, 17))
165+
->whereNotBetween('age', 0, 17)
166+
->get();
167+
```
168+
169+
### AND/OR Variants
170+
171+
```php
172+
// AND variants
173+
$users = $db->find()
174+
->from('users')
175+
->where('active', 1)
176+
->andWhereBetween('age', 18, 65)
177+
->get();
178+
179+
// OR variants
180+
$users = $db->find()
181+
->from('users')
182+
->where('active', 1)
183+
->orWhereBetween('age', 18, 65)
130184
->get();
131185
```
132186

133187
## NULL Handling
134188

135189
### IS NULL
136190

191+
```php
192+
$users = $db->find()
193+
->from('users')
194+
->whereNull('deleted_at')
195+
->get();
196+
```
197+
198+
You can also use the helper function:
199+
137200
```php
138201
use tommyknocker\pdodb\helpers\Db;
139202

@@ -148,7 +211,68 @@ $users = $db->find()
148211
```php
149212
$users = $db->find()
150213
->from('users')
151-
->where(Db::isNotNull('email'))
214+
->whereNotNull('email')
215+
->get();
216+
```
217+
218+
### AND/OR Variants
219+
220+
```php
221+
// AND variants
222+
$users = $db->find()
223+
->from('users')
224+
->where('active', 1)
225+
->andWhereNull('deleted_at')
226+
->get();
227+
228+
$users = $db->find()
229+
->from('users')
230+
->where('active', 1)
231+
->andWhereNotNull('email')
232+
->get();
233+
234+
// OR variants
235+
$users = $db->find()
236+
->from('users')
237+
->where('active', 1)
238+
->orWhereNull('deleted_at')
239+
->get();
240+
241+
$users = $db->find()
242+
->from('users')
243+
->where('active', 1)
244+
->orWhereNotNull('email')
245+
->get();
246+
```
247+
248+
## Column Comparison
249+
250+
### Compare Columns
251+
252+
```php
253+
// Compare two columns
254+
$products = $db->find()
255+
->from('products')
256+
->whereColumn('quantity', '=', 'threshold')
257+
->get();
258+
259+
// Use different operators
260+
$products = $db->find()
261+
->from('products')
262+
->whereColumn('price', '>', 'cost')
263+
->get();
264+
265+
// AND/OR variants
266+
$products = $db->find()
267+
->from('products')
268+
->where('active', 1)
269+
->andWhereColumn('quantity', '>', 'threshold')
270+
->get();
271+
272+
$products = $db->find()
273+
->from('products')
274+
->where('active', 1)
275+
->orWhereColumn('price', '<', 'cost')
152276
->get();
153277
```
154278

@@ -179,6 +303,8 @@ $users = $db->find()
179303
->get();
180304
```
181305

306+
Note: `whereIn` and `whereNotIn` support both arrays and subqueries.
307+
182308
### WHERE EXISTS
183309

184310
```php

examples/01-basic/03-where-conditions.php

Lines changed: 79 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,16 @@
2222
'category' => 'TEXT',
2323
'price' => 'REAL',
2424
'stock' => 'INTEGER',
25-
'active' => 'INTEGER DEFAULT 1'
25+
'active' => 'INTEGER DEFAULT 1',
26+
'threshold' => 'INTEGER DEFAULT 10'
2627
]);
2728

2829
$products = [
29-
['name' => 'Laptop', 'category' => 'Electronics', 'price' => 999.99, 'stock' => 15, 'active' => 1],
30-
['name' => 'Mouse', 'category' => 'Electronics', 'price' => 29.99, 'stock' => 50, 'active' => 1],
31-
['name' => 'Keyboard', 'category' => 'Electronics', 'price' => 79.99, 'stock' => 30, 'active' => 1],
32-
['name' => 'Desk', 'category' => 'Furniture', 'price' => 299.99, 'stock' => 5, 'active' => 1],
33-
['name' => 'Chair', 'category' => 'Furniture', 'price' => 199.99, 'stock' => 0, 'active' => 0],
30+
['name' => 'Laptop', 'category' => 'Electronics', 'price' => 999.99, 'stock' => 15, 'active' => 1, 'threshold' => 20],
31+
['name' => 'Mouse', 'category' => 'Electronics', 'price' => 29.99, 'stock' => 50, 'active' => 1, 'threshold' => 30],
32+
['name' => 'Keyboard', 'category' => 'Electronics', 'price' => 79.99, 'stock' => 30, 'active' => 1, 'threshold' => 10],
33+
['name' => 'Desk', 'category' => 'Furniture', 'price' => 299.99, 'stock' => 5, 'active' => 1, 'threshold' => 10],
34+
['name' => 'Chair', 'category' => 'Furniture', 'price' => 199.99, 'stock' => 0, 'active' => 0, 'threshold' => 10],
3435
];
3536

3637
$db->find()->table('products')->insertMulti($products);
@@ -70,22 +71,36 @@
7071
->get();
7172
echo " Found " . count($lowStockOrInactive) . " products (low stock OR inactive)\n\n";
7273

73-
// Example 5: IN operator
74-
echo "5. IN operator...\n";
74+
// Example 5: IN operator (with array)
75+
echo "5. IN operator (with array)...\n";
7576
$specific = $db->find()
7677
->from('products')
77-
->where(Db::in('name', ['Laptop', 'Mouse', 'Keyboard']))
78+
->whereIn('name', ['Laptop', 'Mouse', 'Keyboard'])
7879
->get();
7980
echo " Found " . count($specific) . " specific products\n\n";
8081

82+
// You can also use the helper function
83+
$specific2 = $db->find()
84+
->from('products')
85+
->where(Db::in('name', ['Laptop', 'Mouse', 'Keyboard']))
86+
->get();
87+
echo " (Helper function result: " . count($specific2) . " products)\n\n";
88+
8189
// Example 6: BETWEEN operator
8290
echo "6. BETWEEN operator...\n";
8391
$midRange = $db->find()
8492
->from('products')
85-
->where(Db::between('price', 50, 300))
93+
->whereBetween('price', 50, 300)
8694
->get();
8795
echo " Found " . count($midRange) . " mid-range products ($50-$300)\n\n";
8896

97+
// You can also use the helper function
98+
$midRange2 = $db->find()
99+
->from('products')
100+
->where(Db::between('price', 50, 300))
101+
->get();
102+
echo " (Helper function result: " . count($midRange2) . " products)\n\n";
103+
89104
// Example 7: LIKE pattern matching
90105
echo "7. LIKE pattern matching...\n";
91106
$matching = $db->find()
@@ -98,11 +113,19 @@
98113
echo "8. IS NULL / IS NOT NULL...\n";
99114
$hasStock = $db->find()
100115
->from('products')
101-
->where(Db::isNotNull('stock'))
116+
->whereNotNull('stock')
102117
->andWhere('stock', 0, '>')
103118
->get();
104119
echo " Found " . count($hasStock) . " products in stock\n\n";
105120

121+
// You can also use the helper function
122+
$hasStock2 = $db->find()
123+
->from('products')
124+
->where(Db::isNotNull('stock'))
125+
->andWhere('stock', 0, '>')
126+
->get();
127+
echo " (Helper function result: " . count($hasStock2) . " products)\n\n";
128+
106129
// Example 9: NOT operator
107130
echo "9. NOT operator...\n";
108131
$notElectronics = $db->find()
@@ -125,5 +148,50 @@
125148
echo "{$p['name']}: \${$p['price']} (stock: {$p['stock']})\n";
126149
}
127150

151+
// Example 11: Enhanced WHERE methods (AND variants)
152+
echo "\n11. Enhanced WHERE methods (AND variants)...\n";
153+
$activeAndInStock = $db->find()
154+
->from('products')
155+
->where('active', 1)
156+
->andWhereNotNull('stock')
157+
->andWhereBetween('price', 50, 300)
158+
->andWhereIn('category', ['Electronics', 'Furniture'])
159+
->get();
160+
echo " Found " . count($activeAndInStock) . " active products with stock in price range\n\n";
161+
162+
// Example 12: Enhanced WHERE methods (OR variants)
163+
echo "12. Enhanced WHERE methods (OR variants)...\n";
164+
$mixedConditions = $db->find()
165+
->from('products')
166+
->where('active', 1)
167+
->orWhereNull('stock')
168+
->orWhereBetween('price', 200, 500)
169+
->orWhereIn('name', ['Laptop', 'Desk'])
170+
->get();
171+
echo " Found " . count($mixedConditions) . " products matching OR conditions\n\n";
172+
173+
// Example 13: Column comparison
174+
echo "13. Column comparison...\n";
175+
$needsRestock = $db->find()
176+
->from('products')
177+
->whereColumn('stock', '<=', 'threshold')
178+
->get();
179+
echo " Found " . count($needsRestock) . " products that need restocking (stock <= threshold)\n\n";
180+
181+
$profitable = $db->find()
182+
->from('products')
183+
->whereColumn('price', '>', 'threshold')
184+
->get();
185+
echo " Found " . count($profitable) . " products with price > threshold\n\n";
186+
187+
// Example 14: AND/OR with column comparison
188+
echo "14. AND/OR with column comparison...\n";
189+
$complex = $db->find()
190+
->from('products')
191+
->where('active', 1)
192+
->andWhereColumn('stock', '>', 'threshold')
193+
->get();
194+
echo " Found " . count($complex) . " active products with stock > threshold\n\n";
195+
128196
echo "\nAll WHERE examples completed!\n";
129197

0 commit comments

Comments
 (0)