@@ -48,6 +48,7 @@ namespace {
48
48
using core::Target;
49
49
using model::Document;
50
50
using model::DocumentState;
51
+ using model::FieldTransform;
51
52
using model::FieldValue;
52
53
using model::MaybeDocument;
53
54
using model::Mutation;
@@ -328,11 +329,47 @@ MutationBatch LocalSerializer::DecodeMutationBatch(
328
329
}
329
330
330
331
std::vector<Mutation> mutations;
331
- for (size_t i = 0 ; i < proto.writes_count ; i++) {
332
- mutations.push_back (
333
- rpc_serializer_.DecodeMutation (reader, proto.writes [i]));
332
+
333
+ // Squash old transform mutations into existing patch of set mutations. The
334
+ // replacement of representing `transforms` with `update_transforms` on the
335
+ // SDK means that old `transform` mutations stored in LevelDB need to be
336
+ // updated to `update_transforms`.
337
+ // TODO(b/174608374): Remove this code once we perform a schema migration.
338
+ for (size_t i = proto.writes_count - 1 ; i >= 0 ; --i) {
339
+ _google_firestore_v1_Write mutation = proto.writes [i];
340
+ if (mutation.which_operation == google_firestore_v1_Write_transform_tag) {
341
+ HARD_ASSERT (
342
+ i >= 1 && proto.writes [i - 1 ].which_operation ==
343
+ google_firestore_v1_Write_update_tag,
344
+ " TransformMutation should be preceded by a patch or set mutation" );
345
+ _google_firestore_v1_Write mutation_to_join = proto.writes [i - 1 ];
346
+ _google_firestore_v1_Write new_mutation{mutation_to_join};
347
+ new_mutation.update_transforms_count =
348
+ mutation.transform .field_transforms_count ;
349
+ new_mutation.update_transforms =
350
+ MakeArray<_google_firestore_v1_DocumentTransform_FieldTransform>(
351
+ mutation.transform .field_transforms_count );
352
+ for (size_t j = 0 ; j < mutation.transform .field_transforms_count ; ++j) {
353
+ new_mutation.update_transforms [j] =
354
+ mutation.transform .field_transforms [j];
355
+ }
356
+ mutations.push_back (rpc_serializer_.DecodeMutation (reader, new_mutation));
357
+ --i;
358
+ } else {
359
+ mutations.push_back (rpc_serializer_.DecodeMutation (reader, mutation));
360
+ }
361
+
362
+ // TODO: figure out how to exit the loop without size_t looping around
363
+ if (i == 0 ) {
364
+ break ;
365
+ }
334
366
}
335
367
368
+ // Reverse the mutations to preserve the original ordering since the above
369
+ // for-loop iterates in reverse order. We use reverse() instead of prepending
370
+ // the elements into the mutations array since prepending to a List is O(n).
371
+ std::reverse (mutations.begin (), mutations.end ());
372
+
336
373
return MutationBatch (batch_id, local_write_time, std::move (base_mutations),
337
374
std::move (mutations));
338
375
}
0 commit comments