github.com/Ali-iotechsys/sqlboiler/v4@v4.0.0-20221208124957-6aec9a5f1f71/boilingcore/text_helpers.go (about)

     1  package boilingcore
     2  
     3  import (
     4  	"strings"
     5  
     6  	"github.com/volatiletech/sqlboiler/v4/drivers"
     7  	"github.com/volatiletech/strmangle"
     8  )
     9  
    10  // txtNameToOne creates the local and foreign function names for
    11  // one-to-many and one-to-one relationships, where local is the side with
    12  // the foreign key.
    13  //
    14  // = many-to-one
    15  // users - videos : user_id
    16  // users - videos : producer_id
    17  //
    18  // fk == table = user.Videos         | video.User
    19  // fk != table = user.ProducerVideos | video.Producer
    20  //
    21  // = many-to-one
    22  // industries - industries : industry_id
    23  // industries - industries : parent_id
    24  //
    25  // fk == table = industry.Industries | industry.Industry
    26  // fk != table = industry.ParentIndustries | industry.Parent
    27  //
    28  // = one-to-one
    29  // users - videos : user_id
    30  // users - videos : producer_id
    31  //
    32  // fk == table = user.Video         | video.User
    33  // fk != table = user.ProducerVideo | video.Producer
    34  //
    35  // = one-to-one
    36  // industries - industries : parent_id
    37  //
    38  // fk == table = industry.Industry | industry.Industry
    39  // fk != table = industry.ParentIndustry | industry.Industry
    40  func txtNameToOne(fk drivers.ForeignKey) (localFn, foreignFn string) {
    41  	fkColumnTrimmedSuffixes := strmangle.Singular(trimSuffixes(fk.Column))
    42  	fkNotTableName := fkColumnTrimmedSuffixes != strmangle.Singular(fk.ForeignTable)
    43  	singularForeignTable := strmangle.Singular(fk.ForeignTable)
    44  
    45  	if fkColumnTrimmedSuffixes == singularForeignTable {
    46  		foreignFn = strmangle.TitleCase(strmangle.Singular(fk.Table) + "_" + fkColumnTrimmedSuffixes)
    47  		if fk.Column != singularForeignTable {
    48  			foreignFn = strmangle.TitleCase(fkColumnTrimmedSuffixes)
    49  		}
    50  	} else if fkColumnTrimmedSuffixes == fk.Column {
    51  		foreignFn = strmangle.TitleCase(fkColumnTrimmedSuffixes + "_" + strmangle.Singular(fk.ForeignTable))
    52  	} else {
    53  		foreignFn = strmangle.TitleCase(fkColumnTrimmedSuffixes)
    54  	}
    55  
    56  	if fkNotTableName {
    57  		localFn = strmangle.TitleCase(fkColumnTrimmedSuffixes)
    58  	}
    59  
    60  	plurality := strmangle.Plural
    61  	if fk.Unique {
    62  		plurality = strmangle.Singular
    63  	}
    64  	localFn += strmangle.TitleCase(plurality(fk.Table))
    65  
    66  	return localFn, foreignFn
    67  }
    68  
    69  // txtNameToMany creates the local and foreign function names for
    70  // many-to-many relationships where there are two foreign keys involved.
    71  //
    72  // The output of the foreign key is the name for that side of the relationship.
    73  //
    74  //   | tags |  | tags_videos      |  | videos |
    75  //   | id   |  | tag_id, video_id |  | id     |
    76  //
    77  // In this setup the lhs is the tag_id foreign key, and so the lhsFn will
    78  // refer to "how to name the lhs" which in this case should be tags. And
    79  // videos for the rhs.
    80  //
    81  // cases:
    82  // sponsors - contests
    83  // sponsor_id contest_id
    84  // fk == table = sponsor.Contests | contest.Sponsors
    85  //
    86  // sponsors - contests
    87  // wiggle_id jiggle_id
    88  // fk != table = sponsor.JiggleSponsors | contest.WiggleContests
    89  //
    90  // industries - industries
    91  // industry_id  mapped_industry_id
    92  // fk == table = industry.Industries
    93  // fk != table = industry.MappedIndustryIndustry
    94  func txtNameToMany(lhs, rhs drivers.ForeignKey) (lhsFn, rhsFn string) {
    95  	lhsKey := strmangle.Singular(trimSuffixes(lhs.Column))
    96  	rhsKey := strmangle.Singular(trimSuffixes(rhs.Column))
    97  
    98  	if lhsKey != strmangle.Singular(lhs.ForeignTable) {
    99  		lhsFn = strmangle.TitleCase(lhsKey)
   100  	}
   101  	lhsFn += strmangle.TitleCase(strmangle.Plural(lhs.ForeignTable))
   102  
   103  	if rhsKey != strmangle.Singular(rhs.ForeignTable) {
   104  		rhsFn = strmangle.TitleCase(rhsKey)
   105  	}
   106  	rhsFn += strmangle.TitleCase(strmangle.Plural(rhs.ForeignTable))
   107  
   108  	return lhsFn, rhsFn
   109  }
   110  
   111  // usesPrimitives checks to see if relationship between two models (ie the foreign key column
   112  // and referred to column) both are primitive Go types we can compare or assign with == and =
   113  // in a template.
   114  func usesPrimitives(tables []drivers.Table, table, column, foreignTable, foreignColumn string) bool {
   115  	local := drivers.GetTable(tables, table)
   116  	foreign := drivers.GetTable(tables, foreignTable)
   117  
   118  	col := local.GetColumn(column)
   119  	foreignCol := foreign.GetColumn(foreignColumn)
   120  
   121  	return isPrimitive(col.Type) && isPrimitive(foreignCol.Type)
   122  }
   123  
   124  var identifierSuffixes = []string{"_id", "_uuid", "_guid", "_oid"}
   125  
   126  // trimSuffixes from the identifier
   127  func trimSuffixes(str string) string {
   128  	ln := len(str)
   129  	for _, s := range identifierSuffixes {
   130  		str = strings.TrimSuffix(str, s)
   131  		if len(str) != ln {
   132  			break
   133  		}
   134  	}
   135  
   136  	return str
   137  }
   138  
   139  func isPrimitive(typ string) bool {
   140  	switch typ {
   141  	// Numeric
   142  	case "int", "int8", "int16", "int32", "int64":
   143  		return true
   144  	case "uint", "uint8", "uint16", "uint32", "uint64":
   145  		return true
   146  	case "float32", "float64":
   147  		return true
   148  	case "byte", "rune", "string":
   149  		return true
   150  	}
   151  
   152  	return false
   153  }
   154  
   155  func isNullPrimitive(typ string) bool {
   156  	switch typ {
   157  	// Numeric
   158  	case "null.Int", "null.Int8", "null.Int16", "null.Int32", "null.Int64":
   159  		return true
   160  	case "null.Uint", "null.Uint8", "null.Uint16", "null.Uint32", "null.Uint64":
   161  		return true
   162  	case "null.Float32", "null.Float64":
   163  		return true
   164  	case "null.Byte", "null.String":
   165  		return true
   166  	}
   167  
   168  	return false
   169  }
   170  
   171  // convertNullToPrimitive takes a type name and returns the underlying primitive type name X if it is a `null.X`,
   172  // otherwise it returns the input value unchanged
   173  func convertNullToPrimitive(typ string) string {
   174  	if isNullPrimitive(typ) {
   175  		return strings.ToLower(strings.Split(typ, ".")[1])
   176  	}
   177  	return typ
   178  }