@@ -4,7 +4,7 @@ use futures::future::try_join_all;
44use sqlx:: PgPool ;
55use std:: collections:: { HashMap , HashSet } ;
66
7- use super :: db_tracking:: { self , TrackedTargetKey , read_source_tracking_info_for_processing} ;
7+ use super :: db_tracking:: { self , TrackedTargetKeyInfo , read_source_tracking_info_for_processing} ;
88use super :: db_tracking_setup;
99use super :: evaluator:: {
1010 EvaluateSourceEntryOutput , SourceRowEvaluationContext , evaluate_source_entry,
@@ -119,18 +119,24 @@ pub enum SkippedOr<T> {
119119 Skipped ( SourceVersion ) ,
120120}
121121
122+ #[ derive( Debug , Clone , PartialEq , Eq , Hash ) ]
123+ struct TargetKeyPair {
124+ pub key : serde_json:: Value ,
125+ pub additional_key : serde_json:: Value ,
126+ }
127+
122128#[ derive( Default ) ]
123129struct TrackingInfoForTarget < ' a > {
124130 export_op : Option < & ' a AnalyzedExportOp > ,
125131
126132 // Existing keys info. Keyed by target key.
127133 // Will be removed after new rows for the same key are added into `new_staging_keys_info` and `mutation.upserts`,
128134 // hence all remaining ones are to be deleted.
129- existing_staging_keys_info : HashMap < serde_json :: Value , Vec < ( i64 , Option < Fingerprint > ) > > ,
130- existing_keys_info : HashMap < serde_json :: Value , Vec < ( i64 , Option < Fingerprint > ) > > ,
135+ existing_staging_keys_info : HashMap < TargetKeyPair , Vec < ( i64 , Option < Fingerprint > ) > > ,
136+ existing_keys_info : HashMap < TargetKeyPair , Vec < ( i64 , Option < Fingerprint > ) > > ,
131137
132138 // New keys info for staging.
133- new_staging_keys_info : Vec < TrackedTargetKey > ,
139+ new_staging_keys_info : Vec < TrackedTargetKeyInfo > ,
134140
135141 // Mutation to apply to the target storage.
136142 mutation : ExportTargetMutation ,
@@ -208,9 +214,12 @@ async fn precommit_source_tracking_info(
208214 for key_info in keys_info. into_iter ( ) {
209215 target_info
210216 . existing_staging_keys_info
211- . entry ( key_info. 0 )
217+ . entry ( TargetKeyPair {
218+ key : key_info. key ,
219+ additional_key : key_info. additional_key ,
220+ } )
212221 . or_default ( )
213- . push ( ( key_info. 1 , key_info. 2 ) ) ;
222+ . push ( ( key_info. process_ordinal , key_info. fingerprint ) ) ;
214223 }
215224 }
216225
@@ -220,9 +229,12 @@ async fn precommit_source_tracking_info(
220229 for key_info in keys_info. into_iter ( ) {
221230 target_info
222231 . existing_keys_info
223- . entry ( key_info. 0 )
232+ . entry ( TargetKeyPair {
233+ key : key_info. key ,
234+ additional_key : key_info. additional_key ,
235+ } )
224236 . or_default ( )
225- . push ( ( key_info. 1 , key_info. 2 ) ) ;
237+ . push ( ( key_info. process_ordinal , key_info. fingerprint ) ) ;
226238 }
227239 }
228240 }
@@ -249,22 +261,24 @@ async fn precommit_source_tracking_info(
249261 . fields
250262 . push ( value. fields [ * field as usize ] . clone ( ) ) ;
251263 }
252- let existing_target_keys = target_info. existing_keys_info . remove ( & primary_key_json) ;
264+ let additional_key = export_op. export_target_factory . extract_additional_key (
265+ & primary_key,
266+ & field_values,
267+ export_op. export_context . as_ref ( ) ,
268+ ) ?;
269+ let target_key_pair = TargetKeyPair {
270+ key : primary_key_json,
271+ additional_key,
272+ } ;
273+ let existing_target_keys = target_info. existing_keys_info . remove ( & target_key_pair) ;
253274 let existing_staging_target_keys = target_info
254275 . existing_staging_keys_info
255- . remove ( & primary_key_json ) ;
276+ . remove ( & target_key_pair ) ;
256277
257- let upsert_entry = export_op. export_target_factory . prepare_upsert_entry (
258- ExportTargetUpsertEntry {
259- key : primary_key,
260- value : field_values,
261- } ,
262- export_op. export_context . as_ref ( ) ,
263- ) ?;
264278 let curr_fp = if !export_op. value_stable {
265279 Some (
266280 Fingerprinter :: default ( )
267- . with ( & upsert_entry . value ) ?
281+ . with ( & field_values ) ?
268282 . into_fingerprint ( ) ,
269283 )
270284 } else {
@@ -285,16 +299,29 @@ async fn precommit_source_tracking_info(
285299 . into_iter ( )
286300 . next ( )
287301 . ok_or_else ( invariance_violation) ?;
288- keys_info. push ( ( primary_key_json, existing_ordinal, existing_fp) ) ;
302+ keys_info. push ( TrackedTargetKeyInfo {
303+ key : target_key_pair. key ,
304+ additional_key : target_key_pair. additional_key ,
305+ process_ordinal : existing_ordinal,
306+ fingerprint : existing_fp,
307+ } ) ;
289308 } else {
290309 // Entry with new value. Needs to be upserted.
291- target_info . mutation . upserts . push ( upsert_entry ) ;
292- target_info . new_staging_keys_info . push ( (
293- primary_key_json . clone ( ) ,
310+ let tracked_target_key = TrackedTargetKeyInfo {
311+ key : target_key_pair . key . clone ( ) ,
312+ additional_key : target_key_pair . additional_key . clone ( ) ,
294313 process_ordinal,
295- curr_fp,
296- ) ) ;
297- keys_info. push ( ( primary_key_json, process_ordinal, curr_fp) ) ;
314+ fingerprint : curr_fp,
315+ } ;
316+ target_info. mutation . upserts . push ( ExportTargetUpsertEntry {
317+ key : primary_key,
318+ additional_key : target_key_pair. additional_key ,
319+ value : field_values,
320+ } ) ;
321+ target_info
322+ . new_staging_keys_info
323+ . push ( tracked_target_key. clone ( ) ) ;
324+ keys_info. push ( tracked_target_key) ;
298325 }
299326 }
300327 new_target_keys_info. push ( ( export_op. target_id , keys_info) ) ;
@@ -304,32 +331,35 @@ async fn precommit_source_tracking_info(
304331 let mut new_staging_target_keys = db_tracking:: TrackedTargetKeyForSource :: default ( ) ;
305332 let mut target_mutations = HashMap :: with_capacity ( export_ops. len ( ) ) ;
306333 for ( target_id, target_tracking_info) in tracking_info_for_targets. into_iter ( ) {
307- let legacy_keys: HashSet < serde_json :: Value > = target_tracking_info
334+ let legacy_keys: HashSet < TargetKeyPair > = target_tracking_info
308335 . existing_keys_info
309336 . into_keys ( )
310337 . chain ( target_tracking_info. existing_staging_keys_info . into_keys ( ) )
311338 . collect ( ) ;
312339
313340 let mut new_staging_keys_info = target_tracking_info. new_staging_keys_info ;
314341 // Add tracking info for deletions.
315- new_staging_keys_info. extend (
316- legacy_keys
317- . iter ( )
318- . map ( |key| ( ( * key) . clone ( ) , process_ordinal, None ) ) ,
319- ) ;
342+ new_staging_keys_info. extend ( legacy_keys. iter ( ) . map ( |key| TrackedTargetKeyInfo {
343+ key : key. key . clone ( ) ,
344+ additional_key : key. additional_key . clone ( ) ,
345+ process_ordinal,
346+ fingerprint : None ,
347+ } ) ) ;
320348 new_staging_target_keys. push ( ( target_id, new_staging_keys_info) ) ;
321349
322350 if let Some ( export_op) = target_tracking_info. export_op {
323351 let mut mutation = target_tracking_info. mutation ;
324- mutation. delete_keys . reserve ( legacy_keys. len ( ) ) ;
352+ mutation. deletes . reserve ( legacy_keys. len ( ) ) ;
325353 for legacy_key in legacy_keys. into_iter ( ) {
326- mutation. delete_keys . push (
327- value:: Value :: < value:: ScopeValue > :: from_json (
328- legacy_key,
329- & export_op. primary_key_type ,
330- ) ?
331- . as_key ( ) ?,
332- ) ;
354+ let key = value:: Value :: < value:: ScopeValue > :: from_json (
355+ legacy_key. key ,
356+ & export_op. primary_key_type ,
357+ ) ?
358+ . as_key ( ) ?;
359+ mutation. deletes . push ( interface:: ExportTargetDeleteEntry {
360+ key,
361+ additional_key : legacy_key. additional_key ,
362+ } ) ;
333363 }
334364 target_mutations. insert ( target_id, mutation) ;
335365 }
@@ -398,9 +428,10 @@ async fn commit_source_tracking_info(
398428 . filter_map ( |( target_id, target_keys) | {
399429 let cleaned_target_keys: Vec < _ > = target_keys
400430 . into_iter ( )
401- . filter ( |( _, ordinal, _) | {
402- Some ( * ordinal) > precommit_metadata. existing_process_ordinal
403- && * ordinal != precommit_metadata. process_ordinal
431+ . filter ( |key_info| {
432+ Some ( key_info. process_ordinal )
433+ > precommit_metadata. existing_process_ordinal
434+ && key_info. process_ordinal != precommit_metadata. process_ordinal
404435 } )
405436 . collect ( ) ;
406437 if !cleaned_target_keys. is_empty ( ) {
0 commit comments