github.com/unigraph-dev/dgraph@v1.1.1-0.20200923154953-8b52b426f765/types/value.go (about) 1 /* 2 * Copyright 2018 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package types 18 19 import ( 20 "strconv" 21 "strings" 22 ) 23 24 // TypeForValue tries to determine the most likely type based on a value. We only want to use this 25 // function when there's no schema type and no suggested storage type. 26 // Returns the guessed type or DefaultID if it couldn't be determined. 27 // If retval is non-nil, the parsed value is returned, useful in conjunction with ObjectValue(). 28 func TypeForValue(v []byte) (TypeID, interface{}) { 29 s := string(v) 30 switch { 31 case v == nil || s == "": 32 break 33 34 // Possible boolean. Specific to "true" or "false". 35 case s[0] == 't', s[0] == 'T', s[0] == 'f', s[0] == 'F': 36 var b bool 37 // XXX: we dont use ParseBool here because it considers 't' and 'f' as values. 38 switch s { 39 case "true", "TRUE", "True": 40 b = true 41 return BoolID, b 42 case "false", "FALSE", "False": 43 return BoolID, b 44 } 45 46 // Possible datetime. Unfortunately, year-only value will fallthrough as int. 47 case checkDateTime(s): 48 if t, err := ParseTime(s); err == nil { 49 return DateTimeID, t 50 } 51 52 // Possible int. 53 case checkInt(s): 54 if i, err := strconv.ParseInt(s, 10, 64); err == nil { 55 return IntID, i 56 } 57 58 // Possible float. 59 case checkFloat(s): 60 if f, err := strconv.ParseFloat(s, 64); err == nil { 61 return FloatID, f 62 } 63 } 64 return DefaultID, nil 65 } 66 67 func isSign(d byte) bool { 68 return d == '-' || d == '+' 69 } 70 71 func isDigit(d byte) bool { 72 return d >= '0' && d <= '9' 73 } 74 75 func checkInt(s string) bool { 76 if isSign(s[0]) && len(s) > 1 { 77 s = s[1:] 78 } 79 return isDigit(s[0]) && !strings.ContainsAny(s[1:], ".Ee") 80 } 81 82 func checkFloat(s string) bool { 83 if isSign(s[0]) && len(s) > 1 { 84 s = s[1:] 85 } 86 if s[0] == '.' && len(s) > 1 { 87 // .012 is totally legit 88 return isDigit(s[1]) 89 } 90 return isDigit(s[0]) && strings.ContainsAny(s[1:], ".Ee") 91 } 92 93 func checkDateTime(s string) bool { 94 if len(s) < 5 { 95 return false 96 } 97 return isDigit(s[0]) && isDigit(s[1]) && isDigit(s[2]) && isDigit(s[3]) && s[4] == '-' 98 }