@@ -22,6 +22,8 @@ import (
22
22
"fmt"
23
23
"testing"
24
24
25
+ "github.com/chenmingyong0423/go-mongox/builder/update"
26
+
25
27
"github.com/chenmingyong0423/go-mongox/internal/pkg/utils"
26
28
27
29
"github.com/chenmingyong0423/go-mongox/callback"
@@ -1091,3 +1093,281 @@ func TestFinder_e2e_DistinctWithParse(t *testing.T) {
1091
1093
require .Error (t , err )
1092
1094
})
1093
1095
}
1096
+
1097
+ func TestFinder_e2e_FindOneAndUpdate (t * testing.T ) {
1098
+ collection := getCollection (t )
1099
+ finder := NewFinder [TestUser ](collection )
1100
+
1101
+ type globalHook struct {
1102
+ opType operation.OpType
1103
+ name string
1104
+ fn callback.CbFn
1105
+ }
1106
+ testCases := []struct {
1107
+ name string
1108
+ before func (ctx context.Context , t * testing.T )
1109
+ after func (ctx context.Context , t * testing.T )
1110
+
1111
+ filter any
1112
+ updates any
1113
+ opts []* options.FindOneAndUpdateOptions
1114
+ globalHook []globalHook
1115
+ beforeHook []beforeHookFn
1116
+ afterHook []afterHookFn [TestUser ]
1117
+
1118
+ ctx context.Context
1119
+ want * TestUser
1120
+ wantErr error
1121
+ }{
1122
+ {
1123
+ name : "nil document" ,
1124
+ before : func (ctx context.Context , t * testing.T ) {
1125
+ insertOneResult , err := collection .InsertOne (ctx , & TestUser {
1126
+ Name : "chenmingyong" ,
1127
+ Age : 24 ,
1128
+ })
1129
+ require .NoError (t , err )
1130
+ require .NotNil (t , insertOneResult .InsertedID )
1131
+ },
1132
+ after : func (ctx context.Context , t * testing.T ) {
1133
+ deleteOneResult , err := collection .DeleteOne (ctx , query .Eq ("name" , "chenmingyong" ))
1134
+ require .NoError (t , err )
1135
+ require .Equal (t , int64 (1 ), deleteOneResult .DeletedCount )
1136
+
1137
+ finder .filter = bson.D {}
1138
+ },
1139
+ filter : query .Eq ("name" , "burt" ),
1140
+ wantErr : mongo .ErrNilDocument ,
1141
+ },
1142
+ {
1143
+ name : "find by name and update age" ,
1144
+ before : func (ctx context.Context , t * testing.T ) {
1145
+ insertOneResult , err := collection .InsertOne (ctx , & TestUser {
1146
+ Name : "chenmingyong" ,
1147
+ Age : 18 ,
1148
+ })
1149
+ require .NoError (t , err )
1150
+ require .NotNil (t , insertOneResult .InsertedID )
1151
+ },
1152
+ after : func (ctx context.Context , t * testing.T ) {
1153
+ deleteOneResult , err := collection .DeleteOne (ctx , query .Eq ("name" , "chenmingyong" ))
1154
+ require .NoError (t , err )
1155
+ require .Equal (t , int64 (1 ), deleteOneResult .DeletedCount )
1156
+
1157
+ finder .filter = bson.D {}
1158
+ },
1159
+ filter : query .Eq ("name" , "chenmingyong" ),
1160
+ updates : update .Set ("age" , 24 ),
1161
+ opts : []* options.FindOneAndUpdateOptions {options .FindOneAndUpdate ().SetReturnDocument (options .After )},
1162
+ want : & TestUser {
1163
+ Name : "chenmingyong" ,
1164
+ Age : 24 ,
1165
+ },
1166
+ },
1167
+ {
1168
+ name : "global before hook error" ,
1169
+ before : func (ctx context.Context , t * testing.T ) {},
1170
+ after : func (ctx context.Context , t * testing.T ) {},
1171
+ filter : query .Eq ("name" , "Mingyong Chen" ),
1172
+ globalHook : []globalHook {
1173
+ {
1174
+ opType : operation .OpTypeBeforeFind ,
1175
+ name : "before hook error" ,
1176
+ fn : func (ctx context.Context , opCtx * operation.OpContext , opts ... any ) error {
1177
+ return errors .New ("global before hook error" )
1178
+ },
1179
+ },
1180
+ },
1181
+ wantErr : errors .New ("global before hook error" ),
1182
+ },
1183
+ {
1184
+ name : "global after hook error" ,
1185
+ before : func (ctx context.Context , t * testing.T ) {
1186
+ insertOneResult , err := collection .InsertOne (ctx , & TestUser {
1187
+ Name : "chenmingyong" ,
1188
+ Age : 18 ,
1189
+ })
1190
+ require .NoError (t , err )
1191
+ require .NotNil (t , insertOneResult .InsertedID )
1192
+ },
1193
+ after : func (ctx context.Context , t * testing.T ) {
1194
+ deleteOneResult , err := collection .DeleteOne (ctx , query .Eq ("name" , "chenmingyong" ))
1195
+ require .NoError (t , err )
1196
+ require .Equal (t , int64 (1 ), deleteOneResult .DeletedCount )
1197
+
1198
+ finder .filter = bson.D {}
1199
+ },
1200
+ filter : query .Eq ("name" , "chenmingyong" ),
1201
+ updates : update .Set ("age" , 24 ),
1202
+ opts : []* options.FindOneAndUpdateOptions {options .FindOneAndUpdate ().SetReturnDocument (options .After )},
1203
+ globalHook : []globalHook {
1204
+ {
1205
+ opType : operation .OpTypeAfterFind ,
1206
+ name : "after hook error" ,
1207
+ fn : func (ctx context.Context , opCtx * operation.OpContext , opts ... any ) error {
1208
+ return errors .New ("global after hook error" )
1209
+ },
1210
+ },
1211
+ },
1212
+ wantErr : errors .New ("global after hook error" ),
1213
+ },
1214
+ {
1215
+ name : "global before and after hook" ,
1216
+ before : func (ctx context.Context , t * testing.T ) {
1217
+ insertOneResult , err := collection .InsertOne (ctx , & TestUser {
1218
+ Name : "chenmingyong" ,
1219
+ Age : 18 ,
1220
+ })
1221
+ require .NoError (t , err )
1222
+ require .NotNil (t , insertOneResult .InsertedID )
1223
+ },
1224
+ after : func (ctx context.Context , t * testing.T ) {
1225
+ deleteOneResult , err := collection .DeleteOne (ctx , query .Eq ("name" , "chenmingyong" ))
1226
+ require .NoError (t , err )
1227
+ require .Equal (t , int64 (1 ), deleteOneResult .DeletedCount )
1228
+
1229
+ finder .filter = bson.D {}
1230
+ },
1231
+ filter : query .Eq ("name" , "chenmingyong" ),
1232
+ updates : update .Set ("age" , 24 ),
1233
+ opts : []* options.FindOneAndUpdateOptions {options .FindOneAndUpdate ().SetReturnDocument (options .After )},
1234
+ globalHook : []globalHook {
1235
+ {
1236
+ opType : operation .OpTypeBeforeFind ,
1237
+ name : "before hook" ,
1238
+ fn : func (ctx context.Context , opCtx * operation.OpContext , opts ... any ) error {
1239
+ if opCtx .Filter .(bson.D )[0 ].Key != "name" || opCtx .Filter .(bson.D )[0 ].Value .(bson.D )[0 ].Value != "chenmingyong" {
1240
+ return errors .New ("filter error" )
1241
+ }
1242
+ if opCtx .Updates .(bson.D )[0 ].Value .(bson.D )[0 ].Key != "age" || opCtx .Updates .(bson.D )[0 ].Value .(bson.D )[0 ].Value != 24 {
1243
+ return errors .New ("updates error" )
1244
+ }
1245
+ return nil
1246
+ },
1247
+ },
1248
+ {
1249
+ opType : operation .OpTypeAfterFind ,
1250
+ name : "after hook" ,
1251
+ fn : func (ctx context.Context , opCtx * operation.OpContext , opts ... any ) error {
1252
+ user := opCtx .Doc .(* TestUser )
1253
+ if user .Name != "chenmingyong" || user .Age != 24 {
1254
+ return errors .New ("result error" )
1255
+ }
1256
+ return nil
1257
+ },
1258
+ },
1259
+ },
1260
+ want : & TestUser {
1261
+ Name : "chenmingyong" ,
1262
+ Age : 24 ,
1263
+ },
1264
+ },
1265
+ {
1266
+ name : "before hook error" ,
1267
+ before : func (ctx context.Context , t * testing.T ) {},
1268
+ after : func (ctx context.Context , t * testing.T ) {},
1269
+ filter : query .Eq ("name" , "chenmingyong" ),
1270
+ beforeHook : []beforeHookFn {
1271
+ func (ctx context.Context , opCtx * OpContext , opts ... any ) error {
1272
+ return errors .New ("before hook error" )
1273
+ },
1274
+ },
1275
+ wantErr : errors .New ("before hook error" ),
1276
+ },
1277
+ {
1278
+ name : "after hook error" ,
1279
+ before : func (ctx context.Context , t * testing.T ) {
1280
+ insertOneResult , err := collection .InsertOne (ctx , & TestUser {
1281
+ Name : "chenmingyong" ,
1282
+ Age : 18 ,
1283
+ })
1284
+ require .NoError (t , err )
1285
+ require .NotNil (t , insertOneResult .InsertedID )
1286
+ },
1287
+ after : func (ctx context.Context , t * testing.T ) {
1288
+ deleteOneResult , err := collection .DeleteOne (ctx , query .Eq ("name" , "chenmingyong" ))
1289
+ require .NoError (t , err )
1290
+ require .Equal (t , int64 (1 ), deleteOneResult .DeletedCount )
1291
+
1292
+ finder .filter = bson.D {}
1293
+ },
1294
+ filter : query .Eq ("name" , "chenmingyong" ),
1295
+ updates : update .Set ("age" , 24 ),
1296
+ opts : []* options.FindOneAndUpdateOptions {options .FindOneAndUpdate ().SetReturnDocument (options .After )},
1297
+ afterHook : []afterHookFn [TestUser ]{
1298
+ func (ctx context.Context , opCtx * AfterOpContext [TestUser ], opts ... any ) error {
1299
+ return errors .New ("after hook error" )
1300
+ },
1301
+ },
1302
+ wantErr : errors .New ("after hook error" ),
1303
+ },
1304
+ {
1305
+ name : "before and after hook" ,
1306
+ before : func (ctx context.Context , t * testing.T ) {
1307
+ insertOneResult , err := collection .InsertOne (ctx , & TestUser {
1308
+ Name : "chenmingyong" ,
1309
+ Age : 18 ,
1310
+ })
1311
+ require .NoError (t , err )
1312
+ require .NotNil (t , insertOneResult .InsertedID )
1313
+ },
1314
+ after : func (ctx context.Context , t * testing.T ) {
1315
+ deleteOneResult , err := collection .DeleteOne (ctx , query .Eq ("name" , "chenmingyong" ))
1316
+ require .NoError (t , err )
1317
+ require .Equal (t , int64 (1 ), deleteOneResult .DeletedCount )
1318
+
1319
+ finder .filter = bson.D {}
1320
+ },
1321
+ filter : query .Eq ("name" , "chenmingyong" ),
1322
+ updates : update .Set ("age" , 24 ),
1323
+ opts : []* options.FindOneAndUpdateOptions {options .FindOneAndUpdate ().SetReturnDocument (options .After )},
1324
+ beforeHook : []beforeHookFn {
1325
+ func (ctx context.Context , opCtx * OpContext , opts ... any ) error {
1326
+ if opCtx .Filter .(bson.D )[0 ].Key != "name" || opCtx .Filter .(bson.D )[0 ].Value .(bson.D )[0 ].Value != "chenmingyong" {
1327
+ return errors .New ("filter error" )
1328
+ }
1329
+ if opCtx .Updates .(bson.D )[0 ].Value .(bson.D )[0 ].Key != "age" || opCtx .Updates .(bson.D )[0 ].Value .(bson.D )[0 ].Value != 24 {
1330
+ return errors .New ("updates error" )
1331
+ }
1332
+ return nil
1333
+ },
1334
+ },
1335
+ afterHook : []afterHookFn [TestUser ]{
1336
+ func (ctx context.Context , opCtx * AfterOpContext [TestUser ], opts ... any ) error {
1337
+ user := opCtx .Doc
1338
+ if user .Name != "chenmingyong" || user .Age != 24 {
1339
+ return errors .New ("after error" )
1340
+ }
1341
+ return nil
1342
+ },
1343
+ },
1344
+ want : & TestUser {
1345
+ Name : "chenmingyong" ,
1346
+ Age : 24 ,
1347
+ },
1348
+ },
1349
+ }
1350
+
1351
+ for _ , tc := range testCases {
1352
+ t .Run (tc .name , func (t * testing.T ) {
1353
+ tc .before (tc .ctx , t )
1354
+ for _ , hook := range tc .globalHook {
1355
+ callback .GetCallback ().Register (hook .opType , hook .name , hook .fn )
1356
+ }
1357
+ user , err := finder .RegisterBeforeHooks (tc .beforeHook ... ).
1358
+ RegisterAfterHooks (tc .afterHook ... ).Filter (tc .filter ).Updates (tc .updates ).
1359
+ FindOneAndUpdate (tc .ctx , tc .opts ... )
1360
+ tc .after (tc .ctx , t )
1361
+ require .Equal (t , tc .wantErr , err )
1362
+ if err == nil {
1363
+ tc .want .ID = user .ID
1364
+ require .Equal (t , tc .want , user )
1365
+ }
1366
+ for _ , hook := range tc .globalHook {
1367
+ callback .GetCallback ().Remove (hook .opType , hook .name )
1368
+ }
1369
+ finder .beforeHooks = nil
1370
+ finder .afterHooks = nil
1371
+ })
1372
+ }
1373
+ }
0 commit comments