File tree Expand file tree Collapse file tree 2 files changed +55
-4
lines changed
packages/database/src/Mappers
tests/Integration/Database/Builder Expand file tree Collapse file tree 2 files changed +55
-4
lines changed Original file line number Diff line number Diff line change 22
33namespace Tempest \Database \Mappers ;
44
5- use Exception ;
65use Tempest \Database \BelongsTo ;
76use Tempest \Database \Builder \ModelInspector ;
8- use Tempest \Database \Exceptions \ModelDidNotHavePrimaryColumn ;
97use Tempest \Database \HasMany ;
108use Tempest \Database \HasOne ;
119use Tempest \Discovery \SkipDiscovery ;
@@ -35,7 +33,31 @@ public function map(mixed $from, mixed $to): array
3533 ->map (fn (array $ rows ) => $ this ->normalizeFields ($ model , $ rows ))
3634 ->values ();
3735
38- return map ($ parsed ->toArray ())->collection ()->to ($ to );
36+ $ objects = map ($ parsed ->toArray ())->collection ()->to ($ to );
37+
38+ foreach ($ objects as $ i => $ object ) {
39+ foreach ($ model ->getRelations () as $ relation ) {
40+ // When a nullable BelongsTo relation wasn't loaded, we need to make sure to unset it if it has a default value.
41+ // If we wouldn't do this, the default value would overwrite the "unloaded" value on the next time saving the model
42+ if (! $ relation instanceof BelongsTo) {
43+ continue ;
44+ }
45+
46+ if (! $ relation ->property ->isNullable ()) {
47+ continue ;
48+ }
49+
50+ if (! $ relation ->property ->hasDefaultValue ()) {
51+ continue ;
52+ }
53+
54+ if (! array_key_exists ($ relation ->name , $ parsed [$ i ] ?? [])) {
55+ $ relation ->property ->unset ($ object );
56+ }
57+ }
58+ }
59+
60+ return $ objects ;
3961 }
4062
4163 private function normalizeFields (ModelInspector $ model , array $ rows ): array
Original file line number Diff line number Diff line change @@ -626,12 +626,38 @@ public function test_nullable_relations(): void
626626 CreateANullableTable::class,
627627 );
628628
629- $ a = ANullableModel::create ();
629+ $ a = ANullableModel::create (
630+ name: 'a ' ,
631+ );
630632
631633 $ a ->load ('b ' );
632634
633635 $ this ->assertNull ($ a ->b );
634636 }
637+
638+ public function test_nullable_relation_save (): void
639+ {
640+ $ this ->migrate (
641+ CreateMigrationsTable::class,
642+ CreateBNullableTable::class,
643+ CreateANullableTable::class,
644+ );
645+
646+ ANullableModel::create (
647+ name: 'a ' ,
648+ b: BNullableModel::new (
649+ name: 'b ' ,
650+ ),
651+ );
652+
653+ $ a = ANullableModel::select ()->first ();
654+ $ a ->save ();
655+
656+ $ a = ANullableModel::select ()->with ('b ' )->first ();
657+
658+ $ this ->assertNotNull ($ a ->b );
659+ $ this ->assertSame ('b ' , $ a ->b ->name );
660+ }
635661}
636662
637663final class Foo
@@ -987,6 +1013,7 @@ public function up(): QueryStatement
9871013 {
9881014 return new CreateTableStatement ('a ' )
9891015 ->primary ()
1016+ ->string ('name ' )
9901017 ->belongsTo ('a.b_id ' , 'b.id ' , nullable: true );
9911018 }
9921019}
@@ -1009,6 +1036,8 @@ final class ANullableModel
10091036 use IsDatabaseModel;
10101037
10111038 public ?BNullableModel $ b = null ;
1039+
1040+ public string $ name ;
10121041}
10131042
10141043#[Table('b ' )]
You can’t perform that action at this time.
0 commit comments