@@ -964,4 +964,228 @@ public function testSchemalessInternalAttributes(): void
964964 $ database ->deleteCollection ($ col );
965965 Authorization::cleanRoles ();
966966 }
967+
968+ public function testSchemalessDates (): void
969+ {
970+ /** @var Database $database */
971+ $ database = static ::getDatabase ();
972+
973+ if ($ database ->getAdapter ()->getSupportForAttributes ()) {
974+ $ this ->expectNotToPerformAssertions ();
975+ return ;
976+ }
977+
978+ $ col = uniqid ('sl_dates ' );
979+ $ database ->createCollection ($ col );
980+
981+ $ permissions = [
982+ Permission::read (Role::any ()),
983+ Permission::write (Role::any ()),
984+ Permission::update (Role::any ()),
985+ Permission::delete (Role::any ())
986+ ];
987+
988+ // Seed deterministic date strings
989+ $ createdAt1 = '2000-01-01T10:00:00.000+00:00 ' ;
990+ $ updatedAt1 = '2000-01-02T11:11:11.000+00:00 ' ;
991+ $ curDate1 = '2000-01-05T05:05:05.000+00:00 ' ;
992+
993+ // createDocument with preserved dates
994+ $ doc1 = $ database ->withPreserveDates (function () use ($ database , $ col , $ permissions , $ createdAt1 , $ updatedAt1 , $ curDate1 ) {
995+ return $ database ->createDocument ($ col , new Document ([
996+ '$id ' => 'd1 ' ,
997+ '$permissions ' => $ permissions ,
998+ '$createdAt ' => $ createdAt1 ,
999+ '$updatedAt ' => $ updatedAt1 ,
1000+ 'curDate ' => $ curDate1 ,
1001+ 'counter ' => 0 ,
1002+ ]));
1003+ });
1004+
1005+ $ this ->assertEquals ('d1 ' , $ doc1 ->getId ());
1006+ $ this ->assertTrue (is_string ($ doc1 ->getAttribute ('curDate ' )));
1007+ $ this ->assertEquals ($ curDate1 , $ doc1 ->getAttribute ('curDate ' ));
1008+ $ this ->assertTrue (is_string ($ doc1 ->getAttribute ('$createdAt ' )));
1009+ $ this ->assertTrue (is_string ($ doc1 ->getAttribute ('$updatedAt ' )));
1010+ $ this ->assertEquals ($ createdAt1 , $ doc1 ->getAttribute ('$createdAt ' ));
1011+ $ this ->assertEquals ($ updatedAt1 , $ doc1 ->getAttribute ('$updatedAt ' ));
1012+
1013+ $ fetched1 = $ database ->getDocument ($ col , 'd1 ' );
1014+ $ this ->assertEquals ($ curDate1 , $ fetched1 ->getAttribute ('curDate ' ));
1015+ $ this ->assertTrue (is_string ($ fetched1 ->getAttribute ('curDate ' )));
1016+ $ this ->assertTrue (is_string ($ fetched1 ->getAttribute ('$createdAt ' )));
1017+ $ this ->assertTrue (is_string ($ fetched1 ->getAttribute ('$updatedAt ' )));
1018+ $ this ->assertEquals ($ createdAt1 , $ fetched1 ->getAttribute ('$createdAt ' ));
1019+ $ this ->assertEquals ($ updatedAt1 , $ fetched1 ->getAttribute ('$updatedAt ' ));
1020+
1021+ // createDocuments with preserved dates
1022+ $ createdAt2 = '2001-02-03T04:05:06.000+00:00 ' ;
1023+ $ updatedAt2 = '2001-02-04T04:05:07.000+00:00 ' ;
1024+ $ curDate2 = '2001-02-05T06:07:08.000+00:00 ' ;
1025+
1026+ $ createdAt3 = '2002-03-04T05:06:07.000+00:00 ' ;
1027+ $ updatedAt3 = '2002-03-05T05:06:08.000+00:00 ' ;
1028+ $ curDate3 = '2002-03-06T07:08:09.000+00:00 ' ;
1029+
1030+ $ countCreated = $ database ->withPreserveDates (function () use ($ database , $ col , $ permissions , $ createdAt2 , $ updatedAt2 , $ curDate2 , $ createdAt3 , $ updatedAt3 , $ curDate3 ) {
1031+ return $ database ->createDocuments ($ col , [
1032+ new Document ([
1033+ '$id ' => 'd2 ' ,
1034+ '$permissions ' => $ permissions ,
1035+ '$createdAt ' => $ createdAt2 ,
1036+ '$updatedAt ' => $ updatedAt2 ,
1037+ 'curDate ' => $ curDate2 ,
1038+ ]),
1039+ new Document ([
1040+ '$id ' => 'd3 ' ,
1041+ '$permissions ' => $ permissions ,
1042+ '$createdAt ' => $ createdAt3 ,
1043+ '$updatedAt ' => $ updatedAt3 ,
1044+ 'curDate ' => $ curDate3 ,
1045+ ]),
1046+ ]);
1047+ });
1048+ $ this ->assertEquals (2 , $ countCreated );
1049+
1050+ $ fetched2 = $ database ->getDocument ($ col , 'd2 ' );
1051+ $ this ->assertEquals ($ curDate2 , $ fetched2 ->getAttribute ('curDate ' ));
1052+ $ this ->assertEquals ($ createdAt2 , $ fetched2 ->getAttribute ('$createdAt ' ));
1053+ $ this ->assertEquals ($ updatedAt2 , $ fetched2 ->getAttribute ('$updatedAt ' ));
1054+
1055+ $ fetched3 = $ database ->getDocument ($ col , 'd3 ' );
1056+ $ this ->assertEquals ($ curDate3 , $ fetched3 ->getAttribute ('curDate ' ));
1057+ $ this ->assertEquals ($ createdAt3 , $ fetched3 ->getAttribute ('$createdAt ' ));
1058+ $ this ->assertEquals ($ updatedAt3 , $ fetched3 ->getAttribute ('$updatedAt ' ));
1059+
1060+ // updateDocument with preserved $updatedAt and custom date field
1061+ $ newCurDate1 = '2000-02-01T00:00:00.000+00:00 ' ;
1062+ $ newUpdatedAt1 = '2000-02-02T02:02:02.000+00:00 ' ;
1063+ $ updated1 = $ database ->withPreserveDates (function () use ($ database , $ col , $ newCurDate1 , $ newUpdatedAt1 ) {
1064+ return $ database ->updateDocument ($ col , 'd1 ' , new Document ([
1065+ 'curDate ' => $ newCurDate1 ,
1066+ '$updatedAt ' => $ newUpdatedAt1 ,
1067+ ]));
1068+ });
1069+ $ this ->assertEquals ($ newCurDate1 , $ updated1 ->getAttribute ('curDate ' ));
1070+ $ this ->assertEquals ($ newUpdatedAt1 , $ updated1 ->getAttribute ('$updatedAt ' ));
1071+ $ refetched1 = $ database ->getDocument ($ col , 'd1 ' );
1072+ $ this ->assertEquals ($ newCurDate1 , $ refetched1 ->getAttribute ('curDate ' ));
1073+ $ this ->assertEquals ($ newUpdatedAt1 , $ refetched1 ->getAttribute ('$updatedAt ' ));
1074+
1075+ // updateDocuments with preserved $updatedAt over a subset
1076+ $ bulkCurDate = '2001-01-01T00:00:00.000+00:00 ' ;
1077+ $ bulkUpdatedAt = '2001-01-02T00:00:00.000+00:00 ' ;
1078+ $ updatedCount = $ database ->withPreserveDates (function () use ($ database , $ col , $ bulkCurDate , $ bulkUpdatedAt ) {
1079+ return $ database ->updateDocuments (
1080+ $ col ,
1081+ new Document ([
1082+ 'curDate ' => $ bulkCurDate ,
1083+ '$updatedAt ' => $ bulkUpdatedAt ,
1084+ ]),
1085+ [Query::equal ('$id ' , ['d2 ' , 'd3 ' ])]
1086+ );
1087+ });
1088+ $ this ->assertEquals (2 , $ updatedCount );
1089+ $ afterBulk2 = $ database ->getDocument ($ col , 'd2 ' );
1090+ $ afterBulk3 = $ database ->getDocument ($ col , 'd3 ' );
1091+ $ this ->assertEquals ($ bulkCurDate , $ afterBulk2 ->getAttribute ('curDate ' ));
1092+ $ this ->assertEquals ($ bulkUpdatedAt , $ afterBulk2 ->getAttribute ('$updatedAt ' ));
1093+ $ this ->assertEquals ($ bulkCurDate , $ afterBulk3 ->getAttribute ('curDate ' ));
1094+ $ this ->assertEquals ($ bulkUpdatedAt , $ afterBulk3 ->getAttribute ('$updatedAt ' ));
1095+
1096+ // upsertDocument: create new then update existing with preserved dates
1097+ $ createdAt4 = '2003-03-03T03:03:03.000+00:00 ' ;
1098+ $ updatedAt4 = '2003-03-04T04:04:04.000+00:00 ' ;
1099+ $ curDate4 = '2003-03-05T05:05:05.000+00:00 ' ;
1100+ $ up1 = $ database ->withPreserveDates (function () use ($ database , $ col , $ permissions , $ createdAt4 , $ updatedAt4 , $ curDate4 ) {
1101+ return $ database ->upsertDocument ($ col , new Document ([
1102+ '$id ' => 'd4 ' ,
1103+ '$permissions ' => $ permissions ,
1104+ '$createdAt ' => $ createdAt4 ,
1105+ '$updatedAt ' => $ updatedAt4 ,
1106+ 'curDate ' => $ curDate4 ,
1107+ ]));
1108+ });
1109+ $ this ->assertEquals ('d4 ' , $ up1 ->getId ());
1110+ $ this ->assertEquals ($ curDate4 , $ up1 ->getAttribute ('curDate ' ));
1111+ $ this ->assertEquals ($ createdAt4 , $ up1 ->getAttribute ('$createdAt ' ));
1112+ $ this ->assertEquals ($ updatedAt4 , $ up1 ->getAttribute ('$updatedAt ' ));
1113+
1114+ $ updatedAt4b = '2003-03-06T06:06:06.000+00:00 ' ;
1115+ $ curDate4b = '2003-03-07T07:07:07.000+00:00 ' ;
1116+ $ up2 = $ database ->withPreserveDates (function () use ($ database , $ col , $ updatedAt4b , $ curDate4b ) {
1117+ return $ database ->upsertDocument ($ col , new Document ([
1118+ '$id ' => 'd4 ' ,
1119+ 'curDate ' => $ curDate4b ,
1120+ '$updatedAt ' => $ updatedAt4b ,
1121+ ]));
1122+ });
1123+ $ this ->assertEquals ($ curDate4b , $ up2 ->getAttribute ('curDate ' ));
1124+ $ this ->assertEquals ($ updatedAt4b , $ up2 ->getAttribute ('$updatedAt ' ));
1125+ $ refetched4 = $ database ->getDocument ($ col , 'd4 ' );
1126+ $ this ->assertEquals ($ curDate4b , $ refetched4 ->getAttribute ('curDate ' ));
1127+ $ this ->assertEquals ($ updatedAt4b , $ refetched4 ->getAttribute ('$updatedAt ' ));
1128+
1129+ // upsertDocuments: mix create and update with preserved dates
1130+ $ createdAt5 = '2004-04-01T01:01:01.000+00:00 ' ;
1131+ $ updatedAt5 = '2004-04-02T02:02:02.000+00:00 ' ;
1132+ $ curDate5 = '2004-04-03T03:03:03.000+00:00 ' ;
1133+ $ updatedAt2b = '2001-02-08T08:08:08.000+00:00 ' ;
1134+ $ curDate2b = '2001-02-09T09:09:09.000+00:00 ' ;
1135+
1136+ $ upCount = $ database ->withPreserveDates (function () use ($ database , $ col , $ permissions , $ createdAt5 , $ updatedAt5 , $ curDate5 , $ updatedAt2b , $ curDate2b ) {
1137+ return $ database ->upsertDocuments ($ col , [
1138+ new Document ([
1139+ '$id ' => 'd5 ' ,
1140+ '$permissions ' => $ permissions ,
1141+ '$createdAt ' => $ createdAt5 ,
1142+ '$updatedAt ' => $ updatedAt5 ,
1143+ 'curDate ' => $ curDate5 ,
1144+ ]),
1145+ new Document ([
1146+ '$id ' => 'd2 ' ,
1147+ '$updatedAt ' => $ updatedAt2b ,
1148+ 'curDate ' => $ curDate2b ,
1149+ ]),
1150+ ]);
1151+ });
1152+ $ this ->assertEquals (2 , $ upCount );
1153+
1154+ $ fetched5 = $ database ->getDocument ($ col , 'd5 ' );
1155+ $ this ->assertEquals ($ curDate5 , $ fetched5 ->getAttribute ('curDate ' ));
1156+ $ this ->assertEquals ($ createdAt5 , $ fetched5 ->getAttribute ('$createdAt ' ));
1157+ $ this ->assertEquals ($ updatedAt5 , $ fetched5 ->getAttribute ('$updatedAt ' ));
1158+
1159+ $ fetched2b = $ database ->getDocument ($ col , 'd2 ' );
1160+ $ this ->assertEquals ($ curDate2b , $ fetched2b ->getAttribute ('curDate ' ));
1161+ $ this ->assertEquals ($ updatedAt2b , $ fetched2b ->getAttribute ('$updatedAt ' ));
1162+
1163+ // increase/decrease should not affect date types; ensure they remain strings
1164+ $ afterInc = $ database ->increaseDocumentAttribute ($ col , 'd1 ' , 'counter ' , 5 );
1165+ $ this ->assertEquals (5 , $ afterInc ->getAttribute ('counter ' ));
1166+ $ this ->assertTrue (is_string ($ afterInc ->getAttribute ('curDate ' )));
1167+ $ this ->assertTrue (is_string ($ afterInc ->getAttribute ('$createdAt ' )));
1168+ $ this ->assertTrue (is_string ($ afterInc ->getAttribute ('$updatedAt ' )));
1169+
1170+ $ afterIncFetched = $ database ->getDocument ($ col , 'd1 ' );
1171+ $ this ->assertEquals (5 , $ afterIncFetched ->getAttribute ('counter ' ));
1172+ $ this ->assertTrue (is_string ($ afterIncFetched ->getAttribute ('curDate ' )));
1173+ $ this ->assertTrue (is_string ($ afterIncFetched ->getAttribute ('$createdAt ' )));
1174+ $ this ->assertTrue (is_string ($ afterIncFetched ->getAttribute ('$updatedAt ' )));
1175+
1176+ $ afterDec = $ database ->decreaseDocumentAttribute ($ col , 'd1 ' , 'counter ' , 2 );
1177+ $ this ->assertEquals (3 , $ afterDec ->getAttribute ('counter ' ));
1178+ $ this ->assertTrue (is_string ($ afterDec ->getAttribute ('curDate ' )));
1179+ $ this ->assertTrue (is_string ($ afterDec ->getAttribute ('$createdAt ' )));
1180+ $ this ->assertTrue (is_string ($ afterDec ->getAttribute ('$updatedAt ' )));
1181+
1182+ $ afterDecFetched = $ database ->getDocument ($ col , 'd1 ' );
1183+ $ this ->assertEquals (3 , $ afterDecFetched ->getAttribute ('counter ' ));
1184+ $ this ->assertTrue (is_string ($ afterDecFetched ->getAttribute ('curDate ' )));
1185+ $ this ->assertTrue (is_string ($ afterDecFetched ->getAttribute ('$createdAt ' )));
1186+ $ this ->assertTrue (is_string ($ afterDecFetched ->getAttribute ('$updatedAt ' )));
1187+
1188+ $ database ->deleteCollection ($ col );
1189+ }
1190+
9671191}
0 commit comments