66use Composite \DB \MultiQuery \MultiInsert ;
77use Composite \DB \MultiQuery \MultiSelect ;
88use Composite \Entity \AbstractEntity ;
9+ use Composite \Entity \Columns ;
910use Composite \Entity \Helpers \DateTimeHelper ;
1011use Doctrine \DBAL \Connection ;
12+ use Doctrine \DBAL \ParameterType ;
1113use Ramsey \Uuid \UuidInterface ;
1214
1315abstract class AbstractTable
@@ -52,8 +54,13 @@ public function save(AbstractEntity $entity): void
5254 $ connection = $ this ->getConnection ();
5355 $ this ->checkUpdatedAt ($ entity );
5456
55- $ insertData = $ this ->prepareDataForSql ($ entity ->toArray ());
56- $ this ->getConnection ()->insert ($ this ->getTableName (), $ insertData );
57+ $ insertData = $ entity ->toArray ();
58+ $ preparedInsertData = $ this ->prepareDataForSql ($ insertData );
59+ $ this ->getConnection ()->insert (
60+ table: $ this ->getTableName (),
61+ data: $ preparedInsertData ,
62+ types: $ this ->getDoctrineTypes ($ insertData ),
63+ );
5764
5865 if ($ this ->config ->autoIncrementKey && ($ lastInsertedId = $ connection ->lastInsertId ())) {
5966 $ insertData [$ this ->config ->autoIncrementKey ] = intval ($ lastInsertedId );
@@ -66,7 +73,6 @@ public function save(AbstractEntity $entity): void
6673 if (!$ changedColumns = $ entity ->getChangedColumns ()) {
6774 return ;
6875 }
69- $ changedColumns = $ this ->prepareDataForSql ($ changedColumns );
7076 if ($ this ->config ->hasUpdatedAt () && property_exists ($ entity , 'updated_at ' )) {
7177 $ entity ->updated_at = new \DateTimeImmutable ();
7278 $ changedColumns ['updated_at ' ] = DateTimeHelper::dateTimeToString ($ entity ->updated_at );
@@ -81,10 +87,19 @@ public function save(AbstractEntity $entity): void
8187 }
8288 $ updateString = implode (', ' , array_map (fn ($ key ) => $ this ->escapeIdentifier ($ key ) . "=? " , array_keys ($ changedColumns )));
8389 $ whereString = implode (' AND ' , array_map (fn ($ key ) => $ this ->escapeIdentifier ($ key ) . "=? " , array_keys ($ whereParams )));
90+ $ preparedParams = array_merge (
91+ array_values ($ this ->prepareDataForSql ($ changedColumns )),
92+ array_values ($ this ->prepareDataForSql ($ whereParams )),
93+ );
94+ $ types = array_merge (
95+ $ this ->getDoctrineTypes ($ changedColumns ),
96+ $ this ->getDoctrineTypes ($ whereParams ),
97+ );
8498
8599 $ entityUpdated = (bool )$ this ->getConnection ()->executeStatement (
86100 sql: "UPDATE " . $ this ->escapeIdentifier ($ this ->getTableName ()) . " SET $ updateString WHERE $ whereString; " ,
87- params: array_merge (array_values ($ changedColumns ), array_values ($ whereParams )),
101+ params: $ preparedParams ,
102+ types: $ types ,
88103 );
89104 if ($ this ->config ->hasOptimisticLock () && !$ entityUpdated ) {
90105 throw new Exceptions \LockException ('Failed to update entity version, concurrency modification, rolling back. ' );
@@ -93,6 +108,23 @@ public function save(AbstractEntity $entity): void
93108 }
94109 }
95110
111+ private function getDoctrineTypes (array $ data ): array
112+ {
113+ $ result = [];
114+ foreach ($ data as $ value ) {
115+ if (is_bool ($ value )) {
116+ $ result [] = ParameterType::BOOLEAN ;
117+ } elseif (is_int ($ value )) {
118+ $ result [] = ParameterType::INTEGER ;
119+ } elseif (is_null ($ value )) {
120+ $ result [] = ParameterType::NULL ;
121+ } else {
122+ $ result [] = ParameterType::STRING ;
123+ }
124+ }
125+ return $ result ;
126+ }
127+
96128 /**
97129 * @param AbstractEntity[] $entities
98130 * @throws \Throwable
@@ -124,7 +156,11 @@ public function saveMany(array $entities): void
124156 rows: $ chunk ,
125157 );
126158 if ($ multiInsert ->getSql ()) {
127- $ connection ->executeStatement ($ multiInsert ->getSql (), $ multiInsert ->getParameters ());
159+ $ connection ->executeStatement (
160+ sql: $ multiInsert ->getSql (),
161+ params: $ multiInsert ->getParameters (),
162+ types: $ this ->getDoctrineTypes (array_keys ($ chunk [0 ])),
163+ );
128164 }
129165 }
130166 }
@@ -317,6 +353,9 @@ final protected function createEntities(mixed $data, ?string $keyColumnName = nu
317353 */
318354 protected function getPkCondition (int |string |array |AbstractEntity |UuidInterface $ data ): array
319355 {
356+ if (empty ($ this ->config ->primaryKeys )) {
357+ throw new \Exception ("Primary keys are not defined in ` " . $ this ::class . "` table config " );
358+ }
320359 $ condition = [];
321360 if ($ data instanceof AbstractEntity) {
322361 if ($ data ->isNew ()) {
0 commit comments