@@ -32,19 +32,25 @@ func newTestServerWithCMV(t *testing.T, configs []CMVConfig) *server {
3232}
3333
3434func TestCMVTransformKey (t * testing.T ) {
35+ // Mirrors the production CMV config: key_mapping [3,4,1,2,0] + append_source_key.
36+ // SELECT SPLIT(_key,'#')[SAFE_OFFSET(3)] AS provider_id, ..., _key AS source_key
37+ // ORDER BY provider_id, client_id, rev_ts, event_category, bitlink_id, source_key
38+ // CMV key = provider_id#client_id#rev_ts#event_category#bitlink_id#<full_source_key>
3539 inst := & cmvInstance {
3640 config : CMVConfig {
3741 SourceTable : "attributions_conversion_events" ,
3842 ViewID : "attributions_conversion_events_by_client" ,
3943 KeySeparator : "#" ,
40- KeyMapping : []int {3 , 4 , 1 , 2 , 0 , 5 },
44+ KeyMapping : []int {3 , 4 , 1 , 2 , 0 },
4145 AppendSourceKey : true ,
4246 },
4347 }
4448
4549 sourceKey := "bitlink123#9999999999#order#shopify#myshop.myshopify.com#01HWXYZ"
4650 got := inst .transformKey (sourceKey )
47- want := "shopify#myshop.myshopify.com#9999999999#order#bitlink123#01HWXYZ#bitlink123#9999999999#order#shopify#myshop.myshopify.com#01HWXYZ"
51+ // parts: [0]bitlink123 [1]9999999999 [2]order [3]shopify [4]myshop.myshopify.com [5]01HWXYZ
52+ // mapped: parts[3]#parts[4]#parts[1]#parts[2]#parts[0] + full source key
53+ want := "shopify#myshop.myshopify.com#9999999999#order#bitlink123#bitlink123#9999999999#order#shopify#myshop.myshopify.com#01HWXYZ"
4854 assert .Equal (t , want , got )
4955}
5056
@@ -261,7 +267,7 @@ func TestLoadCMVConfigs(t *testing.T) {
261267 "source_table": "attributions_conversion_events",
262268 "view_id": "attributions_conversion_events_by_client",
263269 "key_separator": "#",
264- "key_mapping": [3, 4, 1, 2, 0, 5 ],
270+ "key_mapping": [3, 4, 1, 2, 0],
265271 "include_families": ["cr", "d", "m"],
266272 "append_source_key": true
267273 }
@@ -276,34 +282,100 @@ func TestLoadCMVConfigs(t *testing.T) {
276282 assert .Equal (t , "attributions_conversion_events" , configs [0 ].SourceTable )
277283 assert .Equal (t , "attributions_conversion_events_by_client" , configs [0 ].ViewID )
278284 assert .Equal (t , "#" , configs [0 ].KeySeparator )
279- assert .Equal (t , []int {3 , 4 , 1 , 2 , 0 , 5 }, configs [0 ].KeyMapping )
285+ assert .Equal (t , []int {3 , 4 , 1 , 2 , 0 }, configs [0 ].KeyMapping )
280286 assert .Equal (t , []string {"cr" , "d" , "m" }, configs [0 ].IncludeFamilies )
281287 assert .True (t , configs [0 ].AppendSourceKey )
282288}
283289
284290func TestParseCMVConfigFromSQL (t * testing.T ) {
291+ // Mirrors the production Terraform CMV SQL exactly: no CAST, _key aliased as
292+ // source_key, attribution_source_id is embedded in source_key not a separate component.
285293 query := `SELECT
286- CAST(SPLIT(_key, '#')[SAFE_OFFSET(3)] AS STRING) AS provider_id,
287- CAST(SPLIT(_key, '#')[SAFE_OFFSET(4)] AS STRING) AS client_id,
288- CAST(SPLIT(_key, '#')[SAFE_OFFSET(1)] AS STRING) AS rev_ts,
289- CAST(SPLIT(_key, '#')[SAFE_OFFSET(2)] AS STRING) AS conversion_type,
290- CAST(SPLIT(_key, '#')[SAFE_OFFSET(0)] AS STRING) AS bitlink_id,
291- CAST(SPLIT(_key, '#')[SAFE_OFFSET(5)] AS STRING) AS attribution_source_id,
292- _key,
294+ SPLIT(_key, '#')[SAFE_OFFSET(3)] AS provider_id,
295+ SPLIT(_key, '#')[SAFE_OFFSET(4)] AS client_id,
296+ SPLIT(_key, '#')[SAFE_OFFSET(1)] AS rev_ts,
297+ SPLIT(_key, '#')[SAFE_OFFSET(2)] AS event_category,
298+ SPLIT(_key, '#')[SAFE_OFFSET(0)] AS bitlink_id,
299+ _key AS source_key,
293300 cr AS cr,
294301 d AS d,
295302 m AS m
296303FROM ` + "`attributions_conversion_events`" + `
297- ORDER BY provider_id, client_id, rev_ts, conversion_type , bitlink_id, attribution_source_id, _key `
304+ ORDER BY provider_id, client_id, rev_ts, event_category , bitlink_id, source_key `
298305
299306 cfg , err := ParseCMVConfigFromSQL ("attributions_conversion_events_by_client" , query )
300307 require .NoError (t , err )
301308 assert .Equal (t , "attributions_conversion_events" , cfg .SourceTable )
302309 assert .Equal (t , "attributions_conversion_events_by_client" , cfg .ViewID )
303310 assert .Equal (t , "#" , cfg .KeySeparator )
304- assert .Equal (t , []int {3 , 4 , 1 , 2 , 0 , 5 }, cfg .KeyMapping )
311+ assert .Equal (t , []int {3 , 4 , 1 , 2 , 0 }, cfg .KeyMapping )
305312 assert .True (t , cfg .AppendSourceKey )
306313 assert .Contains (t , cfg .IncludeFamilies , "cr" )
307314 assert .Contains (t , cfg .IncludeFamilies , "d" )
308315 assert .Contains (t , cfg .IncludeFamilies , "m" )
309316}
317+
318+ func TestCMVDropRowRangePrefix (t * testing.T ) {
319+ ctx := context .Background ()
320+ // Key mapping [1,0]: CMV key = source[1]#source[0] (swap two components).
321+ configs := []CMVConfig {{
322+ SourceTable : "src_table" ,
323+ ViewID : "src_cmv" ,
324+ KeySeparator : "#" ,
325+ KeyMapping : []int {1 , 0 },
326+ }}
327+ s := newTestServerWithCMV (t , configs )
328+
329+ parent := "projects/test/instances/test"
330+ fqSrc := parent + "/tables/src_table"
331+ fqCMV := parent + "/tables/src_cmv"
332+
333+ _ , err := s .CreateTable (ctx , & btapb.CreateTableRequest {
334+ Parent : parent ,
335+ TableId : "src_table" ,
336+ Table : & btapb.Table {
337+ ColumnFamilies : map [string ]* btapb.ColumnFamily {
338+ "cf1" : {},
339+ },
340+ },
341+ })
342+ require .NoError (t , err )
343+
344+ // Write three rows: two share the prefix "alpha#" and one does not.
345+ for _ , key := range []string {"alpha#one" , "alpha#two" , "beta#three" } {
346+ _ , err = s .MutateRow (ctx , & btpb.MutateRowRequest {
347+ TableName : fqSrc ,
348+ RowKey : []byte (key ),
349+ Mutations : []* btpb.Mutation {{
350+ Mutation : & btpb.Mutation_SetCell_ {
351+ SetCell : & btpb.Mutation_SetCell {
352+ FamilyName : "cf1" ,
353+ ColumnQualifier : []byte ("c" ),
354+ TimestampMicros : 1000 ,
355+ Value : []byte ("v" ),
356+ },
357+ },
358+ }},
359+ })
360+ require .NoError (t , err )
361+ }
362+
363+ s .mu .Lock ()
364+ cmvTbl := s .tables [fqCMV ]
365+ s .mu .Unlock ()
366+ require .NotNil (t , cmvTbl )
367+ assert .Equal (t , 3 , cmvTbl .rows .Len ())
368+
369+ // Drop source rows with prefix "alpha#".
370+ _ , err = s .DropRowRange (ctx , & btapb.DropRowRangeRequest {
371+ Name : fqSrc ,
372+ Target : & btapb.DropRowRangeRequest_RowKeyPrefix {RowKeyPrefix : []byte ("alpha#" )},
373+ })
374+ require .NoError (t , err )
375+
376+ // CMV should now have only 1 row: "three#beta" (from "beta#three").
377+ assert .Equal (t , 1 , cmvTbl .rows .Len ())
378+ // The remaining CMV row should be the transformed "beta#three" → "three#beta".
379+ cmvRow := cmvTbl .rows .Get (btreeKey ("three#beta" ))
380+ assert .NotNil (t , cmvRow , "CMV row for non-deleted source should still exist" )
381+ }
0 commit comments