Skip to content

Commit 0805c26

Browse files
committed
refactor: rewrite recursive CTE example to use QueryBuilder (no raw SQL); portable path concat via helpers
fix: correct NULL handling and RawValue RHS literalization in ConditionBuilder for WHERE/HAVING (SQLite/PG compatible) chore: update examples to minimize Db::raw usage; all examples and tests pass on MySQL/PG/SQLite
1 parent 9ee0f1f commit 0805c26

File tree

16 files changed

+199
-145
lines changed

16 files changed

+199
-145
lines changed

examples/01-basic/04-insert-update.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@
107107
->where('name', 'page_views')
108108
->update([
109109
'value' => Db::inc(50),
110-
'name' => Db::raw(getCurrentDriver($db) === 'pgsql' ? "name || '_total'" : "CONCAT(name, '_total')"),
110+
// Use helper-based concatenation; quote literal via raw as a minimal fallback
111+
'name' => Db::concat('name', Db::raw("'_total'")),
111112
'updated_at' => Db::now()
112113
]);
113114

examples/01-basic/05-ordering.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@
137137
$byPriority = $db->find()
138138
->from('products')
139139
->select(['name', 'category', 'price'])
140-
->orderBy(Db::raw("CASE WHEN category = 'Electronics' THEN 1 ELSE 2 END"))
140+
->orderBy(Db::case(["category = 'Electronics'" => '1'], '2'))
141141
->orderBy('price', 'DESC')
142142
->get();
143143

examples/03-advanced/02-bulk-operations.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@
4040
echo "✗ Inserted 100 rows in {$elapsed}ms (SLOW)\n\n";
4141

4242
// Clear for comparison
43-
$db->find()->table('users')->where(Db::raw('1=1'))->delete();
43+
$db->find()->table('users')->truncate();
4444

4545
// Example 2: Bulk insert (fast)
4646
echo "2. Bulk insert with insertMulti (RECOMMENDED)...\n";
@@ -62,7 +62,7 @@
6262

6363
// Example 3: Bulk insert in batches
6464
echo "3. Bulk insert in batches (for very large datasets)...\n";
65-
$db->find()->table('users')->where(Db::raw('1=1'))->delete();
65+
$db->find()->table('users')->truncate();
6666

6767
$totalUsers = 1000;
6868
$batchSize = 100;
@@ -95,7 +95,7 @@
9595

9696
// Example 4: Bulk insert with transactions
9797
echo "4. Bulk insert with transaction (even faster)...\n";
98-
$db->find()->table('users')->where(Db::raw('1=1'))->delete();
98+
$db->find()->table('users')->truncate();
9999

100100
$users = [];
101101
for ($i = 1; $i <= 500; $i++) {

examples/03-advanced/03-upsert.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
echo "1. First UPSERT for user 1 (will INSERT)...\n";
3030
$db->find()->table('user_stats')
3131
->onDuplicate([
32-
'login_count' => Db::raw('login_count + 1')
32+
'login_count' => Db::inc(1)
3333
])
3434
->insert([
3535
'user_id' => 1,
@@ -43,7 +43,7 @@
4343
echo "2. Second UPSERT for user 1 (will UPDATE)...\n";
4444
$db->find()->table('user_stats')
4545
->onDuplicate([
46-
'login_count' => Db::raw('login_count + 1')
46+
'login_count' => Db::inc(1)
4747
])
4848
->insert([
4949
'user_id' => 1,
@@ -57,8 +57,8 @@
5757
echo "3. UPSERT with multiple field updates...\n";
5858
$db->find()->table('user_stats')
5959
->onDuplicate([
60-
'login_count' => Db::raw('login_count + 1'),
61-
'total_points' => Db::raw('total_points + 100')
60+
'login_count' => Db::inc(1),
61+
'total_points' => Db::inc(100)
6262
])
6363
->insert([
6464
'user_id' => 1,
@@ -74,8 +74,8 @@
7474
for ($userId = 2; $userId <= 5; $userId++) {
7575
$db->find()->table('user_stats')
7676
->onDuplicate([
77-
'login_count' => Db::raw('login_count + 1'),
78-
'total_points' => Db::raw('total_points + 10')
77+
'login_count' => Db::inc(1),
78+
'total_points' => Db::inc(10)
7979
])
8080
->insert([
8181
'user_id' => $userId,
@@ -94,7 +94,7 @@
9494
foreach ($userIds as $userId) {
9595
$db->find()->table('user_stats')
9696
->onDuplicate([
97-
'login_count' => Db::raw('login_count + 1')
97+
'login_count' => Db::inc(1)
9898
])
9999
->insert([
100100
'user_id' => $userId,
@@ -123,7 +123,9 @@
123123
$db->find()->table('user_stats')
124124
->onDuplicate([
125125
'login_count' => Db::inc(1),
126-
'total_points' => Db::raw('CASE WHEN user_stats.login_count >= 3 THEN user_stats.total_points + 50 ELSE user_stats.total_points + 10 END')
126+
'total_points' => Db::case([
127+
'user_stats.login_count >= 3' => 'user_stats.total_points + 50'
128+
], 'user_stats.total_points + 10')
127129
])
128130
->insert([
129131
'user_id' => 1,

examples/03-advanced/04-subqueries.php

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,16 @@
7171
'name',
7272
'department',
7373
'salary',
74-
'total_orders' => Db::raw('(SELECT COUNT(*) FROM orders WHERE user_id = users.id)'),
75-
'total_amount' => Db::raw('(SELECT COALESCE(SUM(amount), 0) FROM orders WHERE user_id = users.id)')
74+
'total_orders' => function ($q) {
75+
$q->from('orders')
76+
->select([Db::count()])
77+
->where('user_id', Db::raw('users.id'));
78+
},
79+
'total_amount' => function ($q) {
80+
$q->from('orders')
81+
->select([Db::coalesce(Db::sum('amount'), 0)])
82+
->where('user_id', Db::raw('users.id'));
83+
}
7684
])
7785
->get();
7886

@@ -86,7 +94,9 @@
8694
echo "2. Subquery in WHERE...\n";
8795
$results = $db->find()
8896
->from('users')
89-
->where('salary', Db::raw('(SELECT AVG(salary) FROM users)'), '>')
97+
->where('salary', function ($q) {
98+
$q->from('users')->select([Db::avg('salary')]);
99+
}, '>')
90100
->select(['name', 'salary'])
91101
->get();
92102

@@ -113,7 +123,9 @@
113123
echo "4. EXISTS subquery...\n";
114124
$results = $db->find()
115125
->from('users')
116-
->where(Db::raw('EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id)'))
126+
->whereExists(function ($q) {
127+
$q->from('orders')->where('orders.user_id', Db::raw('users.id'));
128+
})
117129
->select(['name', 'department'])
118130
->get();
119131

@@ -127,7 +139,9 @@
127139
echo "5. NOT EXISTS subquery...\n";
128140
$results = $db->find()
129141
->from('users')
130-
->where(Db::raw('NOT EXISTS (SELECT 1 FROM orders WHERE orders.user_id = users.id)'))
142+
->whereNotExists(function ($q) {
143+
$q->from('orders')->where('orders.user_id', Db::raw('users.id'));
144+
})
131145
->select(['name', 'department'])
132146
->get();
133147

@@ -139,11 +153,14 @@
139153

140154
// Example 6: IN subquery
141155
echo "6. IN subquery...\n";
142-
$driver = getCurrentDriver($db);
143-
$quote = $driver === 'pgsql' ? "'" : '"';
144156
$results = $db->find()
145157
->from('users')
146-
->where('id', Db::raw("(SELECT DISTINCT user_id FROM orders WHERE status = {$quote}completed{$quote})"), 'IN')
158+
->whereIn('id', function ($q) {
159+
$q->from('orders')
160+
->select(['user_id'])
161+
->where('status', 'completed')
162+
->groupBy('user_id');
163+
})
147164
->select(['name', 'department'])
148165
->get();
149166

@@ -161,7 +178,11 @@
161178
'name',
162179
'department',
163180
'salary',
164-
'dept_avg_salary' => Db::raw('(SELECT AVG(salary) FROM users u2 WHERE u2.department = users.department)'),
181+
'dept_avg_salary' => function ($q) {
182+
$q->from('users u2')
183+
->select([Db::avg('salary')])
184+
->where('u2.department', Db::raw('users.department'));
185+
},
165186
'salary_vs_dept' => Db::raw('(salary - (SELECT AVG(salary) FROM users u2 WHERE u2.department = users.department))')
166187
])
167188
->get();
@@ -196,10 +217,21 @@
196217
'name',
197218
'department',
198219
'salary',
199-
'salary_rank' => Db::raw('(SELECT COUNT(*) + 1 FROM users u2 WHERE u2.salary > users.salary)'),
200-
'dept_rank' => Db::raw('(SELECT COUNT(*) + 1 FROM users u2 WHERE u2.department = users.department AND u2.salary > users.salary)'),
201-
'total_users' => Db::raw('(SELECT COUNT(*) FROM users)'),
202-
'dept_users' => Db::raw('(SELECT COUNT(*) FROM users u2 WHERE u2.department = users.department)')
220+
'salary_rank' => function ($q) {
221+
$q->from('users u2')->select([Db::raw('COUNT(*) + 1')])->where('u2.salary', Db::raw('users.salary'), '>');
222+
},
223+
'dept_rank' => function ($q) {
224+
$q->from('users u2')
225+
->select([Db::raw('COUNT(*) + 1')])
226+
->where('u2.department', Db::raw('users.department'))
227+
->andWhere('u2.salary', Db::raw('users.salary'), '>');
228+
},
229+
'total_users' => function ($q) {
230+
$q->from('users')->select([Db::count()]);
231+
},
232+
'dept_users' => function ($q) {
233+
$q->from('users u2')->select([Db::count()])->where('u2.department', Db::raw('users.department'));
234+
}
203235
])
204236
->orderBy('salary', 'DESC')
205237
->get();
@@ -239,8 +271,12 @@
239271
WHEN SUM(amount) > 1000 THEN \'Good Performer\'
240272
ELSE \'Average Performer\'
241273
END FROM orders WHERE orders.user_id = users.id)'),
242-
'order_count' => Db::raw('(SELECT COUNT(*) FROM orders WHERE orders.user_id = users.id)'),
243-
'total_revenue' => Db::raw('(SELECT COALESCE(SUM(amount), 0) FROM orders WHERE orders.user_id = users.id)')
274+
'order_count' => function ($q) {
275+
$q->from('orders')->select([Db::count()])->where('orders.user_id', Db::raw('users.id'));
276+
},
277+
'total_revenue' => function ($q) {
278+
$q->from('orders')->select([Db::coalesce(Db::sum('amount'), 0)])->where('orders.user_id', Db::raw('users.id'));
279+
}
244280
])
245281
->get();
246282

examples/05-helpers/03-date-helpers.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -224,8 +224,8 @@
224224
'title',
225225
'event_date',
226226
'event_time',
227-
'date_only' => $driver === 'pgsql' ? Db::raw('created_at::DATE') : Db::date('created_at'),
228-
'time_only' => $driver === 'pgsql' ? Db::raw('created_at::TIME') : Db::time('created_at'),
227+
'date_only' => Db::date('created_at'),
228+
'time_only' => Db::time('created_at'),
229229
])
230230
->get();
231231

examples/06-real-world/02-user-auth.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ function loginUser($db, $username, $password) {
134134
'user_id' => $user['id'],
135135
'ip_address' => '127.0.0.1',
136136
'user_agent' => 'Mozilla/5.0',
137-
'expires_at' => Db::raw(getCurrentDriver($db) === 'mysql' ? 'DATE_ADD(NOW(), INTERVAL 7 DAY)' : (getCurrentDriver($db) === 'pgsql' ? "NOW() + INTERVAL '7 days'" : "DATETIME('now', '+7 days')"))
137+
'expires_at' => Db::now('+7 days')
138138
]);
139139

140140
return [

examples/06-real-world/03-search-filters.php

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -220,23 +220,21 @@ function buildSearchQuery($db, $filters) {
220220
$priceRanges = $db->find()
221221
->from('products')
222222
->select([
223-
'price_range' => Db::raw("CASE
224-
WHEN price < 100 THEN 'Under $100'
225-
WHEN price < 500 THEN '$100-$500'
226-
WHEN price < 1000 THEN '$500-$1000'
227-
WHEN price < 2000 THEN '$1000-$2000'
228-
ELSE 'Over $2000'
229-
END"),
223+
'price_range' => Db::case([
224+
'price < 100' => "'Under $100'",
225+
'price < 500' => "'$100-$500'",
226+
'price < 1000' => "'$500-$1000'",
227+
'price < 2000' => "'$1000-$2000'",
228+
], "'Over $2000'"),
230229
'count' => Db::count(),
231230
'avg_rating' => Db::avg('rating')
232231
])
233-
->groupBy(Db::raw("CASE
234-
WHEN price < 100 THEN 'Under $100'
235-
WHEN price < 500 THEN '$100-$500'
236-
WHEN price < 1000 THEN '$500-$1000'
237-
WHEN price < 2000 THEN '$1000-$2000'
238-
ELSE 'Over $2000'
239-
END"))
232+
->groupBy(Db::case([
233+
'price < 100' => "'Under $100'",
234+
'price < 500' => "'$100-$500'",
235+
'price < 1000' => "'$500-$1000'",
236+
'price < 2000' => "'$1000-$2000'",
237+
], "'Over $2000'"))
240238
->orderBy('count', 'DESC')
241239
->get();
242240

@@ -291,7 +289,7 @@ function buildSearchQuery($db, $filters) {
291289

292290
$withRam = $db->find()
293291
->from('products')
294-
->where(Db::raw("specs LIKE '%\"ram\":\"16GB\"%'"))
292+
->where('specs', '%"ram":"16GB"%', 'LIKE')
295293
->select(['name', 'brand', 'specs'])
296294
->get();
297295

@@ -312,8 +310,8 @@ function buildSearchQuery($db, $filters) {
312310
'type' => Db::raw("'product'"),
313311
'category'
314312
])
315-
->where(Db::raw('LOWER(name) LIKE ' . $db->connection->quote($term)))
316-
->orWhere(Db::raw('LOWER(brand) LIKE ' . $db->connection->quote($term)))
313+
->where(Db::lower('name'), strtolower($term), 'LIKE')
314+
->orWhere(Db::lower('brand'), strtolower($term), 'LIKE')
317315
->limit(5)
318316
->get();
319317

0 commit comments

Comments
 (0)