//electValue chooses the best value for the variable in hand. //The preferences goes as // 1. The value read from the environment // 2. The default value // 3. Corresponding zero value if 1 & 2 fails and the variable // is set as optional //Returns error if the value is missing(both in environment //and as default) and the variable is set to mandatory. func (f *fieldMeta) electValue() (string, *models.EnvError) { if f.valueHolder != "" { return f.valueHolder, nil } else if f.defVal != "" { return f.defVal, nil } else if f.mandatory { return "", models.MandatoryValueMissing() } return "", models.OptionalValueMissing() }
//Map performs the mapping of the environment value //to the struct. //source is the structure to which environment values //are to be mapped. func (e EnvToStruct) Map(source interface{}) error { if source == nil { return errors.New("ivalid source;") } rType := reflect.TypeOf(source) if rType.Kind() != reflect.Ptr { return errors.New("Expects pointer to target object") } rType = rType.Elem() if rType.Kind() != reflect.Struct { return errors.New("Expects pointer to struct") } rFieldNum := rType.NumField() metaHolder := make(map[int]fieldMeta, rFieldNum) for i := 0; i < rFieldNum; i++ { rTFi := rType.Field(i) thisMeta := fieldMeta{} thisMeta.position = i rFTag := rTFi.Tag.Get(APP_TAG) tagInfo, tagEr := tagParser(rFTag) if tagEr != nil { return *tagEr } thisMeta.envName = tagInfo.name thisMeta.mandatory = tagInfo.mandatory thisMeta.defVal = tagInfo.deftVal metaHolder[i] = thisMeta } metaHolder = e.envToHolder(e.appName+e.separator, metaHolder) rValue := reflect.ValueOf(source) if rValue.IsNil() { return errors.New("pointer to nil obtained.") } if rValue.Kind() == reflect.Ptr { rValue = rValue.Elem() } for i := 0; i < rFieldNum; i++ { rVFi := rValue.Field(i) rTFi := rType.Field(i) if rVFi.Kind() == reflect.Ptr { rVFi = rVFi.Elem() } if rVFi.CanSet() { thisMeta := metaHolder[i] electedVal, electionError := thisMeta.electValue() if electionError != nil { if *electionError == *models.OptionalValueMissing() { continue } return *electionError.Field(rTFi.Name) } switch rTFi.Type.Kind() { case reflect.Int: intVal, convErr := strconv.Atoi(electedVal) if convErr != nil { return *models.InvalidValue().Field(rTFi.Name) } rVFi.Set(reflect.ValueOf(intVal)) case reflect.String: rVFi.Set(reflect.ValueOf(electedVal)) } } } return nil }