1414use Respect \Data \Collections \Filtered ;
1515use Respect \Data \EntityFactory ;
1616use Respect \Data \Hydrator ;
17- use Respect \Relational \Hydrators \FlatNum ;
17+ use Respect \Data \Hydrators \PrestyledAssoc ;
1818use SplObjectStorage ;
1919use Throwable ;
2020
2121use function array_keys ;
22- use function array_merge ;
2322use function array_push ;
2423use function array_values ;
2524use function is_array ;
@@ -32,8 +31,6 @@ final class Mapper extends AbstractMapper
3231{
3332 public readonly Db $ db ;
3433
35- private PDOStatement $ lastStatement ;
36-
3734 /** @var SplObjectStorage<object, true> */
3835 private SplObjectStorage $ persisting ;
3936
@@ -133,7 +130,7 @@ public function flush(): void
133130
134131 protected function defaultHydrator (Collection $ collection ): Hydrator
135132 {
136- return new FlatNum ( $ this -> lastStatement );
133+ return new PrestyledAssoc ( );
137134 }
138135
139136 /** Resolve related entity from relation property or FK field */
@@ -374,48 +371,53 @@ private function buildSelectStatement(Sql $sql, array $collections): Sql
374371 {
375372 $ selectTable = [];
376373 foreach ($ collections as $ tableSpecifier => $ c ) {
377- if ($ c instanceof Composite) {
378- foreach ($ c ->compositions as $ composition => $ columns ) {
379- foreach ($ columns as $ col ) {
380- $ selectTable [] = $ tableSpecifier . '_comp ' . $ composition . '. ' . $ col ;
381- }
382- }
383- }
384-
385374 if ($ c instanceof Filtered) {
386375 $ filters = $ c ->filters ;
387376 if ($ filters ) {
388- $ pkName = $ tableSpecifier . '. ' .
389- $ this ->style ->identifier ($ c ->name );
390-
391- if ($ c ->identifierOnly ) {
392- $ selectColumns = [$ pkName ];
393- } else {
394- $ selectColumns = [
395- $ tableSpecifier . '. ' .
396- $ this ->style ->identifier ($ c ->name ),
397- ];
377+ $ fields = $ this ->entityFactory ->enumerateFields ($ c ->name );
378+ $ pk = $ this ->style ->identifier ($ c ->name );
379+ $ selectTable [] = self ::aliasedColumn ($ tableSpecifier , $ pk , $ fields [$ pk ] ?? $ pk );
380+
381+ if (!$ c ->identifierOnly ) {
398382 foreach ($ filters as $ f ) {
399- $ selectColumns [] = $ tableSpecifier . ' . ' . $ f ;
383+ $ selectTable [] = self :: aliasedColumn ( $ tableSpecifier, $ f , $ fields [ $ f ] ?? $ f) ;
400384 }
401385 }
402386
403387 $ nextName = $ c ->next ?->name;
404388 if ($ nextName !== null ) {
405- $ selectColumns [] = $ tableSpecifier . ' . ' .
406- $ this -> style -> remoteIdentifier ( $ nextName );
389+ $ fk = $ this -> style -> remoteIdentifier ( $ nextName );
390+ $ selectTable [] = self :: aliasedColumn ( $ tableSpecifier , $ fk , $ fields [ $ fk ] ?? $ fk );
407391 }
408-
409- $ selectTable = array_merge ($ selectTable , $ selectColumns );
410392 }
411393 } else {
412- $ selectTable [] = $ tableSpecifier . '.* ' ;
394+ foreach ($ this ->entityFactory ->enumerateFields ($ c ->name ) as $ dbCol => $ styledProp ) {
395+ $ selectTable [] = self ::aliasedColumn ($ tableSpecifier , $ dbCol , $ styledProp );
396+ }
397+ }
398+
399+ // Composition columns come after entity columns so they override on collision
400+ if (!$ c instanceof Composite) {
401+ continue ;
402+ }
403+
404+ foreach ($ c ->compositions as $ composition => $ columns ) {
405+ $ compPrefix = $ tableSpecifier . Composite::COMPOSITION_MARKER . $ composition ;
406+ foreach ($ columns as $ col ) {
407+ $ selectTable [] = self ::aliasedColumn ($ compPrefix , $ col , $ col );
408+ }
413409 }
414410 }
415411
416412 return $ sql ->select (...$ selectTable );
417413 }
418414
415+ /** @return array<string, string> Alias array for Sql::select() */
416+ private static function aliasedColumn (string $ specifier , string $ dbCol , string $ prop ): array
417+ {
418+ return [$ specifier . '__ ' . $ prop => $ specifier . '. ' . $ dbCol ];
419+ }
420+
419421 /** @param array<string, Collection> $collections */
420422 private function buildTables (Sql $ sql , array $ collections ): Sql
421423 {
@@ -466,7 +468,7 @@ private function parseCompositions(Sql $sql, Collection $collection, string $ent
466468 }
467469
468470 foreach (array_keys ($ collection ->compositions ) as $ comp ) {
469- $ alias = $ entity . ' _comp ' . $ comp ;
471+ $ alias = $ entity . Composite:: COMPOSITION_MARKER . $ comp ;
470472 $ sql ->innerJoin ($ comp );
471473 $ sql ->as ($ alias );
472474 $ sql ->on ([
@@ -569,9 +571,8 @@ private function parseHydrated(SplObjectStorage $hydrated): object
569571 /** @return SplObjectStorage<object, Collection>|false */
570572 private function fetchHydrated (Collection $ collection , PDOStatement $ statement ): SplObjectStorage |false
571573 {
572- $ this ->lastStatement = $ statement ;
573574 $ hydrator = $ this ->resolveHydrator ($ collection );
574- $ row = $ statement ->fetch (PDO ::FETCH_NUM );
575+ $ row = $ statement ->fetch (PDO ::FETCH_ASSOC );
575576
576577 return $ hydrator ->hydrate ($ row , $ collection , $ this ->entityFactory );
577578 }
@@ -586,7 +587,7 @@ private function createStatement(
586587 $ query ->concat ($ withExtra );
587588 }
588589
589- $ statement = $ this ->db ->prepare ((string ) $ query , PDO ::FETCH_NUM );
590+ $ statement = $ this ->db ->prepare ((string ) $ query , PDO ::FETCH_ASSOC );
590591 $ statement ->execute ($ query ->params );
591592
592593 return $ statement ;
0 commit comments