github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/databases/orm/models_info_m.go (about)

     1  // The original package is migrated from beego and modified, you can find orignal from following link:
     2  //    "github.com/beego/beego/"
     3  //
     4  // Copyright 2023 IAC. All Rights Reserved.
     5  //
     6  // Licensed under the Apache License, Version 2.0 (the "License");
     7  // you may not use this file except in compliance with the License.
     8  // You may obtain a copy of the License at
     9  //
    10  //      http://www.apache.org/licenses/LICENSE-2.0
    11  //
    12  // Unless required by applicable law or agreed to in writing, software
    13  // distributed under the License is distributed on an "AS IS" BASIS,
    14  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15  // See the License for the specific language governing permissions and
    16  // limitations under the License.
    17  
    18  package orm
    19  
    20  import (
    21  	"fmt"
    22  	"os"
    23  	"reflect"
    24  )
    25  
    26  // single model info
    27  type modelInfo struct {
    28  	manual    bool
    29  	isThrough bool
    30  	pkg       string
    31  	name      string
    32  	fullName  string
    33  	table     string
    34  	model     interface{}
    35  	fields    *fields
    36  	addrField reflect.Value // store the original struct value
    37  	uniques   []string
    38  }
    39  
    40  // new model info
    41  func newModelInfo(val reflect.Value) (mi *modelInfo) {
    42  	mi = &modelInfo{}
    43  	mi.fields = newFields()
    44  	ind := reflect.Indirect(val)
    45  	mi.addrField = val
    46  	mi.name = ind.Type().Name()
    47  	mi.fullName = getFullName(ind.Type())
    48  	addModelFields(mi, ind, "", []int{})
    49  	return
    50  }
    51  
    52  // index: FieldByIndex returns the nested field corresponding to index
    53  func addModelFields(mi *modelInfo, ind reflect.Value, mName string, index []int) {
    54  	var (
    55  		err error
    56  		fi  *fieldInfo
    57  		sf  reflect.StructField
    58  	)
    59  
    60  	for i := 0; i < ind.NumField(); i++ {
    61  		field := ind.Field(i)
    62  		sf = ind.Type().Field(i)
    63  		// if the field is unexported skip
    64  		if sf.PkgPath != "" {
    65  			continue
    66  		}
    67  		// add anonymous struct fields
    68  		if sf.Anonymous {
    69  			addModelFields(mi, field, mName+"."+sf.Name, append(index, i))
    70  			continue
    71  		}
    72  
    73  		fi, err = newFieldInfo(mi, field, sf, mName)
    74  		if err == errSkipField {
    75  			err = nil
    76  			continue
    77  		} else if err != nil {
    78  			break
    79  		}
    80  		// record current field index
    81  		fi.fieldIndex = append(fi.fieldIndex, index...)
    82  		fi.fieldIndex = append(fi.fieldIndex, i)
    83  		fi.mi = mi
    84  		fi.inModel = true
    85  		if !mi.fields.Add(fi) {
    86  			err = fmt.Errorf("duplicate column name: %s", fi.column)
    87  			break
    88  		}
    89  		if fi.pk {
    90  			if mi.fields.pk != nil {
    91  				err = fmt.Errorf("one model must have one pk field only")
    92  				break
    93  			} else {
    94  				mi.fields.pk = fi
    95  			}
    96  		}
    97  	}
    98  
    99  	if err != nil {
   100  		fmt.Println(fmt.Errorf("field: %s.%s, %s", ind.Type(), sf.Name, err))
   101  		os.Exit(2)
   102  	}
   103  }
   104  
   105  // combine related model info to new model info.
   106  // prepare for relation models query.
   107  func newM2MModelInfo(m1, m2 *modelInfo) (mi *modelInfo) {
   108  	mi = new(modelInfo)
   109  	mi.fields = newFields()
   110  	mi.table = m1.table + "_" + m2.table + "s"
   111  	mi.name = camelString(mi.table)
   112  	mi.fullName = m1.pkg + "." + mi.name
   113  
   114  	fa := new(fieldInfo) // pk
   115  	f1 := new(fieldInfo) // m1 table RelForeignKey
   116  	f2 := new(fieldInfo) // m2 table RelForeignKey
   117  	fa.fieldType = TypeBigIntegerField
   118  	fa.auto = true
   119  	fa.pk = true
   120  	fa.dbcol = true
   121  	fa.name = "Id"
   122  	fa.column = "id"
   123  	fa.fullName = mi.fullName + "." + fa.name
   124  
   125  	f1.dbcol = true
   126  	f2.dbcol = true
   127  	f1.fieldType = RelForeignKey
   128  	f2.fieldType = RelForeignKey
   129  	f1.name = camelString(m1.table)
   130  	f2.name = camelString(m2.table)
   131  	f1.fullName = mi.fullName + "." + f1.name
   132  	f2.fullName = mi.fullName + "." + f2.name
   133  	f1.column = m1.table + "_id"
   134  	f2.column = m2.table + "_id"
   135  	f1.rel = true
   136  	f2.rel = true
   137  	f1.relTable = m1.table
   138  	f2.relTable = m2.table
   139  	f1.relModelInfo = m1
   140  	f2.relModelInfo = m2
   141  	f1.mi = mi
   142  	f2.mi = mi
   143  
   144  	mi.fields.Add(fa)
   145  	mi.fields.Add(f1)
   146  	mi.fields.Add(f2)
   147  	mi.fields.pk = fa
   148  
   149  	mi.uniques = []string{f1.column, f2.column}
   150  	return
   151  }