@@ -9,6 +9,75 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99
1010--- 
1111
12+ ## [ 2.5.1]  - 2025-10-22 
13+ 
14+ ### Added  
15+ -  ** Db::inc() and Db::dec() support in onDuplicate()** : Now you can use convenient helpers for UPSERT increments
16+   -  Works across all dialects: MySQL, PostgreSQL, SQLite
17+   -  Example: ` ->onDuplicate(['counter' => Db::inc(5)]) ` 
18+   -  Automatically generates dialect-specific SQL (e.g., ` counter = counter + 5 ` )
19+ -  ** CI testing for examples** : All 21 examples now tested in GitHub Actions
20+   -  SQLite: 21/21 examples verified
21+   -  MySQL: 20/20 examples verified (if database available)
22+   -  PostgreSQL: 20/20 examples verified (if database available)
23+ -  ** New tests**  for UPSERT functionality:
24+   -  ` testUpsertWithRawIncrement() `  - tests ` Db::raw('age + 5') `  in onDuplicate
25+   -  ` testUpsertWithIncHelper() `  - tests ` Db::inc(5) `  in onDuplicate
26+   -  ` testGroupByWithQualifiedNames() `  - verifies qualified column names in GROUP BY
27+ 
28+ ### Changed  
29+ -  ** All examples migrated to QueryBuilder API** :
30+   -  Replaced 15+ ` rawQuery() `  calls with fluent QueryBuilder methods
31+   -  ` rawQuery() `  now used ONLY for DDL (CREATE/ALTER/DROP TABLE)
32+   -  Examples demonstrate best practices with ` Db:: `  helpers
33+ -  ** Enhanced buildUpsertClause() signature**  (backwards compatible):
34+   -  Added optional ` $tableName `  parameter for PostgreSQL ambiguous column resolution
35+   -  Enables proper ` Db::inc() `  and ` Db::raw() `  support in UPSERT operations
36+ -  ** Improved test-examples.sh script** :
37+   -  Fixed PostgreSQL port detection in connection checks
38+   -  Now correctly detects all 3 database dialects when available
39+ -  ** JSON column handling** : Examples automatically use JSONB for PostgreSQL, TEXT for MySQL/SQLite
40+ 
41+ ### Fixed  
42+ -  ** CRITICAL: groupBy() and orderBy() with qualified column names**  (` u.id ` , ` t.name ` ):
43+   -  ** Bug** : Qualified names quoted as single identifier ``  `u.id`  ``  instead of ``  `u`.`id`  `` 
44+   -  ** Impact** : Broke on MySQL/PostgreSQL with "Unknown column 'u.id'" error
45+   -  ** Fix** : Changed to use ` quoteQualifiedIdentifier() `  instead of ` quoteIdentifier() ` 
46+   -  ** Tests** : Added ` testGroupByWithQualifiedNames() `  for all 3 dialects
47+ -  ** CRITICAL: Db::inc()/Db::dec() ignored in onDuplicate()** :
48+   -  ** Bug** : Dialects didn't handle ` ['__op' => 'inc'] `  array format in UPSERT
49+   -  ** Impact** : UPSERT replaced value instead of incrementing
50+   -  ** Fix** : Added ` is_array($expr) && isset($expr['__op']) `  handling in all dialects
51+ -  ** PostgreSQL UPSERT "ambiguous column" errors** :
52+   -  ** Bug** : ` Db::raw('age + 5') `  in onDuplicate caused "column reference ambiguous"
53+   -  ** Impact** : PostgreSQL couldn't distinguish old vs new column values
54+   -  ** Fix** : Auto-qualify column references with table name (` user_stats."age" + 5 ` )
55+ -  ** PostgreSQL lastInsertId() exception for non-SERIAL tables** :
56+   -  ** Bug** : Crash when inserting into tables without auto-increment
57+   -  ** Fix** : Added try-catch in ` executeInsert() `  to gracefully handle missing sequence
58+ -  ** String literal quoting in SQL expressions** :
59+   -  Fixed PostgreSQL compatibility (uses ` 'string' `  not ` "string" ` )
60+   -  Fixed CASE WHEN conditions to use single quotes for string literals
61+   -  Examples now properly escape string values in Db::raw() expressions
62+ -  ** Examples multi-dialect compatibility** :
63+   -  JSON columns: Use JSONB for PostgreSQL, TEXT for MySQL/SQLite
64+   -  String concatenation: Dialect-aware (` || `  vs ` CONCAT() ` )
65+   -  Date/time functions: Dialect-specific interval syntax
66+   -  All 21 examples verified on all 3 dialects
67+ 
68+ ### Technical Details  
69+ -  ** All tests passing** : 343 tests, 1544 assertions (up from 334 tests)
70+   -  Added 9 new tests across MySQL, PostgreSQL, SQLite
71+   -  Zero failures, zero errors, zero warnings
72+ -  ** All examples passing** : 61/61 total runs (21 examples × ~ 3 dialects each)
73+   -  SQLite: 21/21 ✅
74+   -  MySQL: 20/20 ✅ (01-connection.php uses SQLite only)
75+   -  PostgreSQL: 20/20 ✅
76+ -  ** PHPStan Level 8** : Zero errors across entire codebase
77+ -  ** Full backwards compatibility** : Optional parameter with default value
78+ 
79+ --- 
80+ 
1281## [ 2.5.0]  - 2025-10-19 
1382
1483### Added  
@@ -308,7 +377,8 @@ Initial tagged release with basic PDO database abstraction functionality.
308377
309378--- 
310379
311- [ Unreleased ] : https://github.com/tommyknocker/pdo-database-class/compare/v2.5.0...HEAD 
380+ [ Unreleased ] : https://github.com/tommyknocker/pdo-database-class/compare/v2.5.1...HEAD 
381+ [ 2.5.1 ] : https://github.com/tommyknocker/pdo-database-class/compare/v2.5.0...v2.5.1 
312382[ 2.5.0 ] : https://github.com/tommyknocker/pdo-database-class/compare/v2.4.3...v2.5.0 
313383[ 2.4.3 ] : https://github.com/tommyknocker/pdo-database-class/compare/v2.4.2...v2.4.3 
314384[ 2.4.2 ] : https://github.com/tommyknocker/pdo-database-class/compare/v2.4.1...v2.4.2 
0 commit comments