@@ -457,9 +457,9 @@ type ForeignKeyRowMapper struct {
457
457
Index sql.Index
458
458
Updater sql.ForeignKeyEditor
459
459
SourceSch sql.Schema
460
- // TargetTypeTransforms are a set of functions to transform the value in the table to the corresponding value in the
460
+ // TargetTypeConversions are a set of functions to transform the value in the table to the corresponding value in the
461
461
// other table. This is required when the types of the two tables are compatible but different (e.g. INT and BIGINT).
462
- TargetTypeTransforms []func ( ctx * sql. Context , val any ) (sql. Type , any , error )
462
+ TargetTypeConversions []ForeignKeyTypeConversionFn
463
463
// IndexPositions hold the mapping between an index's column position and the source row's column position. Given
464
464
// an index (x1, x2) and a source row (y1, y2, y3) and the relation (x1->y3, x2->y1), this slice would contain
465
465
// [2, 0]. The first index column "x1" maps to the third source column "y3" (so position 2 since it's zero-based),
@@ -489,9 +489,9 @@ func (mapper *ForeignKeyRowMapper) GetIter(ctx *sql.Context, row sql.Row, refChe
489
489
490
490
targetType := mapper .SourceSch [rowPos ].Type
491
491
// Transform the type of the value in this row to the one in the other table for the index lookup, if necessary
492
- if mapper .TargetTypeTransforms != nil && mapper .TargetTypeTransforms [rowPos ] != nil {
492
+ if mapper .TargetTypeConversions != nil && mapper .TargetTypeConversions [rowPos ] != nil {
493
493
var err error
494
- targetType , rowVal , err = mapper .TargetTypeTransforms [rowPos ](ctx , rowVal )
494
+ targetType , rowVal , err = mapper .TargetTypeConversions [rowPos ](ctx , rowVal )
495
495
// TODO: possible for this to fail without error, which means the value cannot be found in the other table
496
496
if err != nil {
497
497
return nil , err
@@ -537,26 +537,18 @@ func (mapper *ForeignKeyRowMapper) GetKeyString(row sql.Row) string {
537
537
538
538
// GetChildParentMapping returns a mapping from the foreign key columns of a child schema to the parent schema.
539
539
func GetChildParentMapping (parentSch sql.Schema , childSch sql.Schema , fkDef sql.ForeignKeyConstraint ) (ChildParentMapping , error ) {
540
- parentMap := make (map [string ]int )
541
- for i , col := range parentSch {
542
- parentMap [strings .ToLower (col .Name )] = i
543
- }
544
- childMap := make (map [string ]int )
545
- for i , col := range childSch {
546
- childMap [strings .ToLower (col .Name )] = i
547
- }
548
540
mapping := make (ChildParentMapping , len (childSch ))
549
541
for i := range mapping {
550
542
mapping [i ] = - 1
551
543
}
552
544
for i := range fkDef .Columns {
553
- childIndex , ok := childMap [ strings . ToLower (fkDef .Columns [i ])]
554
- if ! ok {
545
+ childIndex := childSch . IndexOfColName (fkDef .Columns [i ])
546
+ if childIndex < 0 {
555
547
return nil , fmt .Errorf ("foreign key `%s` refers to column `%s` on table `%s` but it could not be found" ,
556
548
fkDef .Name , fkDef .Columns [i ], fkDef .Table )
557
549
}
558
- parentIndex , ok := parentMap [ strings . ToLower (fkDef .ParentColumns [i ])]
559
- if ! ok {
550
+ parentIndex := parentSch . IndexOfColName (fkDef .ParentColumns [i ])
551
+ if parentIndex < 0 {
560
552
return nil , fmt .Errorf ("foreign key `%s` refers to column `%s` on referenced table `%s` but it could not be found" ,
561
553
fkDef .Name , fkDef .ParentColumns [i ], fkDef .ParentTable )
562
554
}
@@ -565,28 +557,37 @@ func GetChildParentMapping(parentSch sql.Schema, childSch sql.Schema, fkDef sql.
565
557
return mapping , nil
566
558
}
567
559
568
- // GetChildParentTypeTransforms returs a set of functions to transform the value in the child table to the
569
- // corresponding type in the parent table, if necessary
570
- func GetChildParentTypeTransforms (parentSch sql.Schema , childSch sql.Schema , fkDef sql.ForeignKeyConstraint ) ([]func (ctx * sql.Context , val any ) (sql.Type , any , error ), error ) {
571
- parentMap := make (map [string ]int )
572
- for i , col := range parentSch {
573
- parentMap [strings .ToLower (col .Name )] = i
574
- }
575
- childMap := make (map [string ]int )
576
- for i , col := range childSch {
577
- childMap [strings .ToLower (col .Name )] = i
578
- }
560
+ // ForeignKeyTypeConversionDirection specifies whether a child column type is being converted to its parent type for
561
+ // constraint enforcement, or vice versa.
562
+ type ForeignKeyTypeConversionDirection byte
563
+ const (
564
+ ChildToParent ForeignKeyTypeConversionDirection = iota
565
+ ParentToChild
566
+ )
579
567
580
- var mapping []func (* sql.Context , any ) (sql.Type , any , error )
568
+ // ForeignKeyTypeConversionFn is a function that transforms a value from one type to another for foreign key constraint
569
+ // enforcement. The target type is returned along with the transformed value, or an error if the transformation fails.
570
+ type ForeignKeyTypeConversionFn func (ctx * sql.Context , val any ) (sql.Type , any , error )
571
+
572
+ // GetForeignKeyTypeConversions returns a set of functions to convert a type in a one foreign key column table to the
573
+ // type in the corresponding table. Specify the schema of both child and parent tables, as well as whether the
574
+ // transformation is from child to parent or vice versa.
575
+ func GetForeignKeyTypeConversions (
576
+ parentSch sql.Schema ,
577
+ childSch sql.Schema ,
578
+ fkDef sql.ForeignKeyConstraint ,
579
+ direction ForeignKeyTypeConversionDirection ,
580
+ ) ([]ForeignKeyTypeConversionFn , error ) {
581
+ var mapping []ForeignKeyTypeConversionFn
581
582
582
583
for i := range fkDef .Columns {
583
- childIndex , ok := childMap [ strings . ToLower (fkDef .Columns [i ])]
584
- if ! ok {
584
+ childIndex := childSch . IndexOfColName (fkDef .Columns [i ])
585
+ if childIndex < 0 {
585
586
return nil , fmt .Errorf ("foreign key `%s` refers to column `%s` on table `%s` but it could not be found" ,
586
587
fkDef .Name , fkDef .Columns [i ], fkDef .Table )
587
588
}
588
- parentIndex , ok := parentMap [ strings . ToLower (fkDef .ParentColumns [i ])]
589
- if ! ok {
589
+ parentIndex := parentSch . IndexOfColName (fkDef .ParentColumns [i ])
590
+ if parentIndex < 0 {
590
591
return nil , fmt .Errorf ("foreign key `%s` refers to column `%s` on referenced table `%s` but it could not be found" ,
591
592
fkDef .Name , fkDef .ParentColumns [i ], fkDef .ParentTable )
592
593
}
@@ -602,12 +603,24 @@ func GetChildParentTypeTransforms(parentSch sql.Schema, childSch sql.Schema, fkD
602
603
603
604
if ! childType .Equals (parentType ) {
604
605
parentExtendedType , _ := parentType .(types.ExtendedType )
606
+ if parentExtendedType == nil {
607
+ // this should be impossible (child and parent should both be extended types), but just in case
608
+ return nil , nil
609
+ }
610
+
611
+ fromType := childExtendedType
612
+ toType := parentExtendedType
613
+ if direction == ParentToChild {
614
+ fromType = parentExtendedType
615
+ toType = childExtendedType
616
+ }
617
+
605
618
if mapping == nil {
606
- mapping = make ([]func ( * sql. Context , any ) (sql. Type , any , error ) , len (childSch ))
619
+ mapping = make ([]ForeignKeyTypeConversionFn , len (childSch ))
607
620
}
608
621
mapping [childIndex ] = func (ctx * sql.Context , val any ) (sql.Type , any , error ) {
609
- convertedVal , err := parentExtendedType .ConvertToType (ctx , childExtendedType , val )
610
- return parentExtendedType , convertedVal , err
622
+ convertedVal , err := toType .ConvertToType (ctx , fromType , val )
623
+ return toType , convertedVal , err
611
624
}
612
625
}
613
626
}
0 commit comments