1010use Bow \Support \Str ;
1111use JsonSerializable ;
1212use PDO ;
13+ use PDOException ;
1314use PDOStatement ;
1415
1516class QueryBuilder implements JsonSerializable
@@ -112,6 +113,13 @@ class QueryBuilder implements JsonSerializable
112113 */
113114 protected string $ adapter = '' ;
114115
116+ /**
117+ * Determine the last sql query
118+ *
119+ * @var string|null
120+ */
121+ protected ?string $ last_query = null ;
122+
115123 /**
116124 * QueryBuilder Constructor
117125 *
@@ -170,16 +178,21 @@ public function as(string $as): QueryBuilder
170178 * WHERE column1 $comparator $value|column
171179 *
172180 * @param string $where
181+ * @param array $data
173182 * @return QueryBuilder
174183 */
175- public function whereRaw (string $ where ): QueryBuilder
184+ public function whereRaw (string $ where, array $ data = [] ): QueryBuilder
176185 {
177186 if ($ this ->where == null ) {
178187 $ this ->where = $ where ;
179188 } else {
180189 $ this ->where .= ' and ' . $ where ;
181190 }
182191
192+ if (!empty ($ data )) {
193+ $ this ->where_data_binding = array_merge (array_values ($ data ), $ this ->where_data_binding );
194+ }
195+
183196 return $ this ;
184197 }
185198
@@ -189,16 +202,21 @@ public function whereRaw(string $where): QueryBuilder
189202 * WHERE column1 $comparator $value|column
190203 *
191204 * @param string $where
205+ * @param array $data
192206 * @return QueryBuilder
193207 */
194- public function orWhereRaw (string $ where ): QueryBuilder
208+ public function orWhereRaw (string $ where, array $ data = [] ): QueryBuilder
195209 {
196210 if ($ this ->where == null ) {
197211 $ this ->where = $ where ;
198212 } else {
199213 $ this ->where .= ' or ' . $ where ;
200214 }
201215
216+ if (!empty ($ data )) {
217+ $ this ->where_data_binding = array_merge (array_values ($ data ), $ this ->where_data_binding );
218+ }
219+
202220 return $ this ;
203221 }
204222
@@ -217,8 +235,7 @@ public function orWhere(string $column, mixed $comparator = '=', mixed $value =
217235 {
218236 if (is_null ($ this ->where )) {
219237 throw new QueryBuilderException (
220- 'This function can not be used without a where before. ' ,
221- E_ERROR
238+ 'This function can not be used without a where before. '
222239 );
223240 }
224241
@@ -252,13 +269,12 @@ public function where(
252269 }
253270
254271 if ($ value === null ) {
255- throw new QueryBuilderException ('Unresolved comparison value ' , E_ERROR );
272+ throw new QueryBuilderException ('Unresolved comparison value ' );
256273 }
257274
258275 if (!in_array (Str::lower ($ boolean ), ['and ' , 'or ' ])) {
259276 throw new QueryBuilderException (
260- 'The bool ' . $ boolean . ' not accepted ' ,
261- E_ERROR
277+ 'The bool ' . $ boolean . ' not accepted '
262278 );
263279 }
264280
@@ -719,8 +735,7 @@ public function andOn(string $first, $comparator = '=', $second = null): QueryBu
719735 {
720736 if (is_null ($ this ->join )) {
721737 throw new QueryBuilderException (
722- 'The inner join clause is already initialized. ' ,
723- E_ERROR
738+ 'The inner join clause is already initialized. '
724739 );
725740 }
726741
@@ -750,7 +765,6 @@ public function orOn(string $first, $comparator = '=', $second = null): QueryBui
750765 if (is_null ($ this ->join )) {
751766 throw new QueryBuilderException (
752767 'The inner join clause is already initialized. ' ,
753- E_ERROR
754768 );
755769 }
756770
@@ -889,13 +903,8 @@ private function aggregate($aggregate, $column): mixed
889903 }
890904 }
891905
892- $ statement = $ this ->connection ->prepare ($ sql );
893-
894- $ this ->bind ($ statement , $ this ->where_data_binding );
906+ $ statement = $ this ->execute ($ sql , $ this ->where_data_binding );
895907
896- $ statement ->execute ();
897-
898- $ this ->triggerQueryEvent ($ sql , $ this ->where_data_binding );
899908 $ this ->where_data_binding = [];
900909
901910 if ($ statement ->rowCount () > 1 ) {
@@ -926,7 +935,9 @@ private function bind(PDOStatement $pdo_statement, array $bindings = []): void
926935 // Named placeholders
927936 foreach ($ bindings as $ key => $ value ) {
928937 $ param = PDO ::PARAM_STR ;
929- if (is_null ($ value ) || strtolower ((string ) $ value ) === 'null ' ) {
938+ if (is_array ($ value ) || is_object ($ value )) {
939+ $ value = json_encode ($ value );
940+ } elseif (is_null ($ value ) || strtolower ((string ) $ value ) === 'null ' ) {
930941 $ param = PDO ::PARAM_NULL ;
931942 } elseif (is_int ($ value )) {
932943 $ param = PDO ::PARAM_INT ;
@@ -945,7 +956,9 @@ private function bind(PDOStatement $pdo_statement, array $bindings = []): void
945956 $ i = 1 ;
946957 foreach ($ bindings as $ value ) {
947958 $ param = PDO ::PARAM_STR ;
948- if (is_null ($ value ) || strtolower ((string ) $ value ) === 'null ' ) {
959+ if (is_array ($ value ) || is_object ($ value )) {
960+ $ value = json_encode ($ value );
961+ } elseif (is_null ($ value ) || strtolower ((string ) $ value ) === 'null ' ) {
949962 $ param = PDO ::PARAM_NULL ;
950963 } elseif (is_int ($ value )) {
951964 $ param = PDO ::PARAM_INT ;
@@ -1110,17 +1123,12 @@ public function get(array $columns = []): array|object|null
11101123 // Execution of request.
11111124 $ sql = $ this ->toSql ();
11121125
1113- $ statement = $ this ->connection ->prepare ($ sql );
1114-
1115- $ this ->bind ($ statement , $ this ->where_data_binding );
1116-
1117- $ statement ->execute ();
1126+ $ statement = $ this ->execute ($ sql , $ this ->where_data_binding );
11181127
11191128 $ data = $ statement ->fetchAll ();
11201129
11211130 $ statement ->closeCursor ();
11221131
1123- $ this ->triggerQueryEvent ($ sql , $ this ->where_data_binding );
11241132 $ this ->where_data_binding = [];
11251133
11261134 if (!$ this ->first ) {
@@ -1215,20 +1223,14 @@ public function update(array $data = []): int
12151223 $ sql .= ' where ' . $ this ->where ;
12161224
12171225 $ this ->where = null ;
1218-
1219- $ this ->where_data_binding = array_merge (array_values ($ data ), $ this ->where_data_binding );
12201226 }
12211227
1222- $ statement = $ this ->connection -> prepare ( $ sql );
1228+ $ this -> where_data_binding = array_merge ( array_values ( $ data ), $ this ->where_data_binding );
12231229
1224- $ this ->bind ($ statement , $ this ->where_data_binding );
1225-
1226- // Execution of the request
1227- $ statement ->execute ();
1230+ $ statement = $ this ->execute ($ sql , $ this ->where_data_binding );
12281231
12291232 $ result = $ statement ->rowCount ();
12301233
1231- $ this ->triggerQueryEvent ($ sql , $ this ->where_data_binding );
12321234 $ this ->where_data_binding = [];
12331235
12341236 return (int ) $ result ;
@@ -1265,15 +1267,10 @@ public function delete(): int
12651267 $ this ->where = null ;
12661268 }
12671269
1268- $ statement = $ this ->connection ->prepare ($ sql );
1269-
1270- $ this ->bind ($ statement , $ this ->where_data_binding );
1271-
1272- $ statement ->execute ();
1270+ $ statement = $ this ->execute ($ sql , $ this ->where_data_binding );
12731271
12741272 $ result = $ statement ->rowCount ();
12751273
1276- $ this ->triggerQueryEvent ($ sql , $ this ->where_data_binding );
12771274 $ this ->where_data_binding = [];
12781275
12791276 return (int ) $ result ;
@@ -1292,6 +1289,18 @@ public function increment(string $column, int $step = 1): int
12921289 return $ this ->incrementAction ($ column , $ step );
12931290 }
12941291
1292+ /**
1293+ * Decrement column
1294+ *
1295+ * @param string $column
1296+ * @param int $step
1297+ * @return int
1298+ */
1299+ public function decrement (string $ column , int $ step = 1 ): int
1300+ {
1301+ return $ this ->incrementAction ($ column , $ step , '- ' );
1302+ }
1303+
12951304 /**
12961305 * Method to customize the increment and decrement methods
12971306 *
@@ -1310,27 +1319,11 @@ private function incrementAction(string $column, int $step = 1, string $directio
13101319 $ this ->where = null ;
13111320 }
13121321
1313- $ statement = $ this ->connection ->prepare ($ sql );
1314-
1315- $ this ->bind ($ statement , $ this ->where_data_binding );
1316-
1317- $ statement ->execute ();
1322+ $ statement = $ this ->execute ($ sql , $ this ->where_data_binding );
13181323
13191324 return (int )$ statement ->rowCount ();
13201325 }
13211326
1322- /**
1323- * Decrement column
1324- *
1325- * @param string $column
1326- * @param int $step
1327- * @return int
1328- */
1329- public function decrement (string $ column , int $ step = 1 ): int
1330- {
1331- return $ this ->incrementAction ($ column , $ step , '- ' );
1332- }
1333-
13341327 /**
13351328 * Allows a query with the DISTINCT clause
13361329 *
@@ -1371,10 +1364,14 @@ public function truncate(): bool
13711364 $ sql = 'truncate table ' . $ this ->table . '; ' ;
13721365 }
13731366
1367+ $ this ->last_query = $ sql ;
1368+
13741369 $ result = (bool ) $ this ->connection ->exec ($ sql );
13751370
13761371 $ this ->triggerQueryEvent ($ sql , []);
13771372
1373+ $ this ->last_query = $ sql ;
1374+
13781375 return $ result ;
13791376 }
13801377
@@ -1422,7 +1419,6 @@ public function insert(array $values): int
14221419 if ($ single_item_structure_detected && $ mixture_item_structure_detected ) {
14231420 throw new QueryBuilderException (
14241421 'Mixed structure detected in insert data. Cannot mix single and multiple row inserts. ' ,
1425- E_ERROR
14261422 );
14271423 }
14281424
@@ -1455,15 +1451,39 @@ private function insertOne(array $values): int
14551451
14561452 $ sql .= '( ' . implode (', ' , $ this ->add2points ($ fields , true )) . '); ' ;
14571453
1454+ $ statement = $ this ->execute ($ sql , $ values );
1455+
1456+ return (int ) $ statement ->rowCount ();
1457+ }
1458+
1459+ /**
1460+ * Execute statement
1461+ *
1462+ * @param string $sql
1463+ * @param array $bindings
1464+ * @return PDOStatement
1465+ */
1466+ private function execute (string $ sql , array $ bindings = []): PDOStatement
1467+ {
1468+ $ this ->last_query = $ sql ;
1469+
14581470 $ statement = $ this ->connection ->prepare ($ sql );
14591471
1460- $ this ->bind ($ statement , $ values );
1472+ $ this ->bind ($ statement , $ bindings );
14611473
1462- $ statement ->execute ();
1474+ try {
1475+ $ statement ->execute ();
14631476
1464- $ this ->triggerQueryEvent ($ sql , $ values );
1477+ $ this ->triggerQueryEvent ($ sql , $ bindings );
1478+ } catch (\Exception $ e ) {
1479+ throw new QueryBuilderException (
1480+ 'Error executing query: ' . $ e ->getMessage (),
1481+ $ this ->last_query ,
1482+ E_ERROR ,
1483+ );
1484+ }
14651485
1466- return ( int ) $ statement-> rowCount () ;
1486+ return $ statement ;
14671487 }
14681488
14691489 /**
@@ -1475,6 +1495,8 @@ public function drop(): bool
14751495 {
14761496 $ sql = 'drop table ' . $ this ->table ;
14771497
1498+ $ this ->last_query = $ sql ;
1499+
14781500 $ result = (bool ) $ this ->connection ->exec ($ sql );
14791501
14801502 $ this ->triggerQueryEvent ($ sql , []);
0 commit comments