github.com/viant/toolbox@v0.34.5/value_provider.go (about) 1 package toolbox 2 3 import ( 4 "bytes" 5 "fmt" 6 "github.com/pkg/errors" 7 "io/ioutil" 8 "os" 9 "strings" 10 "time" 11 ) 12 13 //ValueProvider represents a value provider 14 type ValueProvider interface { 15 //Get returns a value for passed in context and arguments. Context can be used to manage state. 16 Get(context Context, arguments ...interface{}) (interface{}, error) 17 } 18 19 //ValueProviderRegistry registry of value providers 20 type ValueProviderRegistry interface { 21 Register(name string, valueProvider ValueProvider) 22 23 Contains(name string) bool 24 25 Names() []string 26 27 Get(name string) ValueProvider 28 } 29 30 type valueProviderRegistryImpl struct { 31 registry map[string](ValueProvider) 32 } 33 34 func (r valueProviderRegistryImpl) Register(name string, valueProvider ValueProvider) { 35 r.registry[name] = valueProvider 36 } 37 38 func (r valueProviderRegistryImpl) Contains(name string) bool { 39 _, ok := r.registry[name] 40 return ok 41 } 42 43 func (r valueProviderRegistryImpl) Get(name string) ValueProvider { 44 if result, ok := r.registry[name]; ok { 45 return result 46 } 47 panic(fmt.Sprintf("failed to lookup name: %v", name)) 48 } 49 50 func (r valueProviderRegistryImpl) Names() []string { 51 return MapKeysToStringSlice(&r.registry) 52 } 53 54 //NewValueProviderRegistry create new NewValueProviderRegistry 55 func NewValueProviderRegistry() ValueProviderRegistry { 56 var result ValueProviderRegistry = &valueProviderRegistryImpl{ 57 registry: make(map[string]ValueProvider), 58 } 59 return result 60 } 61 62 type envValueProvider struct{} 63 64 func (p envValueProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 65 key := arguments[0].(string) 66 value, found := os.LookupEnv(key) 67 if found { 68 return value, nil 69 } 70 return nil, fmt.Errorf("failed to lookup %v in env", key) 71 } 72 73 //NewEnvValueProvider returns a provider that returns a value of env variables. 74 func NewEnvValueProvider() ValueProvider { 75 var result ValueProvider = &envValueProvider{} 76 return result 77 } 78 79 type dateOfBirthProvider struct{} 80 81 func (p dateOfBirthProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 82 if len(arguments) < 1 { 83 return nil, errors.New("expected <age> | [month], [day], [timeformat]") 84 } 85 now := time.Now() 86 age := AsInt(arguments[0]) 87 var month int = int(now.Month()) 88 var day int = now.Day() 89 var timeFormat = "yyyy-MM-dd" 90 if len(arguments) >= 2 { 91 month = AsInt(arguments[1]) 92 } 93 if len(arguments) >= 3 { 94 day = AsInt(arguments[2]) 95 } 96 if len(arguments) >= 4 { 97 timeFormat = AsString(arguments[3]) 98 } 99 100 dateOfBirthText := fmt.Sprintf("%04d-%02d-%02d", now.Year()-age, month, day) 101 date, err := time.Parse(DateFormatToLayout("yyyy-MM-dd"), dateOfBirthText) 102 if err != nil { 103 return nil, err 104 } 105 return date.Format(DateFormatToLayout(timeFormat)), nil 106 } 107 108 //NewDateOfBirthValueProvider provider for computing date for supplied expected age, month and day 109 func NewDateOfBirthrovider() ValueProvider { 110 return &dateOfBirthProvider{} 111 } 112 113 type castedValueProvider struct{} 114 115 func (p castedValueProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 116 key := arguments[0].(string) 117 if len(arguments) < 2 { 118 return nil, fmt.Errorf("failed to cast to %v due to invalid number of arguments, Wanted 2 but had:%v", key, len(arguments)) 119 } 120 switch key { 121 case "time": 122 if len(arguments) != 3 { 123 return nil, fmt.Errorf("failed to cast to time due to invalid number of arguments expected 2, but had %v", len(arguments)-1) 124 } 125 castedTime, err := ParseTime(AsString(arguments[1]), AsString(arguments[2])) 126 if err != nil { 127 return nil, fmt.Errorf("failed to cast to time %v due to %v", AsString(arguments[1]), err) 128 } 129 return castedTime, nil 130 case "int": 131 return AsInt(arguments[1]), nil 132 case "int32": 133 return int32(AsInt(arguments[1])), nil 134 case "int64": 135 return int64(AsInt(arguments[1])), nil 136 case "float32": 137 return float32(AsFloat(arguments[1])), nil 138 case "float": 139 return AsFloat(arguments[1]), nil 140 case "bool": 141 return AsBoolean(arguments[1]), nil 142 case "string": 143 return AsString(arguments[1]), nil 144 145 } 146 return nil, fmt.Errorf("failed to cast to %v - unsupported type", key) 147 } 148 149 //NewCastedValueProvider return a provider that return casted value type 150 func NewCastedValueProvider() ValueProvider { 151 var result ValueProvider = &castedValueProvider{} 152 return result 153 } 154 155 type currentTimeProvider struct{} 156 157 func (p currentTimeProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 158 return time.Now(), nil 159 } 160 161 //NewCurrentTimeProvider returns a provder that returns time.Now() 162 func NewCurrentTimeProvider() ValueProvider { 163 var result ValueProvider = ¤tTimeProvider{} 164 return result 165 } 166 167 type timeDiffProvider struct{} 168 169 func (p timeDiffProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 170 171 var resultTime time.Time 172 var durationDelta time.Duration 173 var err error 174 if len(arguments) >= 1 { 175 var timeValue *time.Time 176 var timeLiteral = AsString(arguments[0]) 177 if timeValue, err = TimeAt(timeLiteral); err != nil { 178 if timeValue, err = ToTime(arguments[0], ""); err != nil { 179 return nil, err 180 } 181 } 182 resultTime = *timeValue 183 } 184 if len(arguments) >= 3 { 185 var val = AsInt(arguments[1]) 186 var timeUnit = strings.ToLower(AsString(arguments[2])) 187 durationDelta, err = NewDuration(val, timeUnit) 188 if err != nil { 189 return nil, err 190 } 191 } 192 var format = "" 193 if len(arguments) == 4 { 194 format = AsString(arguments[3]) 195 } 196 resultTime = resultTime.Add(durationDelta) 197 switch format { 198 case "unix": 199 return int(resultTime.Unix()+resultTime.UnixNano()) / 1000000000, nil 200 case "timestamp": 201 return int(resultTime.Unix()+resultTime.UnixNano()) / 1000000, nil 202 203 default: 204 if len(format) > 0 { 205 return resultTime.Format(DateFormatToLayout(format)), nil 206 } 207 } 208 return resultTime, nil 209 } 210 211 //NewTimeDiffProvider returns a provider that delta, time unit and optionally format 212 //format as java date format or unix or timestamp 213 func NewTimeDiffProvider() ValueProvider { 214 var result ValueProvider = &timeDiffProvider{} 215 return result 216 } 217 218 type weekdayProvider struct{} 219 220 func (p weekdayProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 221 var now = time.Now() 222 return int(now.Weekday()), nil 223 } 224 225 func NewWeekdayProvider() ValueProvider { 226 return &weekdayProvider{} 227 } 228 229 type nilValueProvider struct{} 230 231 func (p nilValueProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 232 return nil, nil 233 } 234 235 //NewNilValueProvider returns a provider that returns a nil 236 func NewNilValueProvider() ValueProvider { 237 var result ValueProvider = &nilValueProvider{} 238 return result 239 } 240 241 //ConstValueProvider represnet a const value provider 242 type ConstValueProvider struct { 243 Value string 244 } 245 246 //Get return provider value 247 func (p ConstValueProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 248 return p.Value, nil 249 } 250 251 //NewConstValueProvider returns a provider that returns a nil 252 func NewConstValueProvider(value string) ValueProvider { 253 var result ValueProvider = &ConstValueProvider{Value: value} 254 return result 255 } 256 257 type currentDateProvider struct{} 258 259 func (p currentDateProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 260 return time.Now().Local().Format("20060102"), nil 261 } 262 263 //NewCurrentDateProvider returns a provider that returns current date in the format yyyymmdd, i.e. 20170205 264 func NewCurrentDateProvider() ValueProvider { 265 var result ValueProvider = ¤tDateProvider{} 266 return result 267 } 268 269 //Dictionary represents simply lookup interface 270 type Dictionary interface { 271 //Get returns value for passed in key or error 272 Get(key string) (interface{}, error) 273 274 //Exists checks if key exists 275 Exists(key string) bool 276 } 277 278 //MapDictionary alias to map of string and interface{} 279 type MapDictionary map[string]interface{} 280 281 func (d *MapDictionary) Get(name string) (interface{}, error) { 282 if result, found := (*d)[name]; found { 283 return result, nil 284 } 285 return nil, fmt.Errorf("failed to lookup: %v", name) 286 } 287 288 func (d *MapDictionary) Exists(name string) bool { 289 _, found := (*d)[name] 290 return found 291 } 292 293 type dictionaryProvider struct { 294 dictionaryContentKey interface{} 295 } 296 297 func (p dictionaryProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 298 if len(arguments) == 0 { 299 return nil, fmt.Errorf("expected at least one argument but had 0") 300 } 301 var key = AsString(arguments[0]) 302 var dictionary Dictionary 303 context.GetInto(p.dictionaryContentKey, &dictionary) 304 if len(arguments) == 1 && !dictionary.Exists(key) { 305 return nil, nil 306 } 307 return dictionary.Get(key) 308 } 309 310 //NewDictionaryProvider creates a new Dictionary provider, it takes a key context that is a MapDictionary pointer 311 func NewDictionaryProvider(contextKey interface{}) ValueProvider { 312 return &dictionaryProvider{contextKey} 313 } 314 315 type betweenPredicateValueProvider struct{} 316 317 func (p *betweenPredicateValueProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 318 if len(arguments) != 2 { 319 return nil, fmt.Errorf("expected 2 arguments with between predicate but had %v", len(arguments)) 320 } 321 predicate := NewBetweenPredicate(arguments[0], arguments[1]) 322 return &predicate, nil 323 } 324 325 //NewBetweenPredicateValueProvider returns a new between value provider 326 func NewBetweenPredicateValueProvider() ValueProvider { 327 return &betweenPredicateValueProvider{} 328 } 329 330 type withinSecPredicateValueProvider struct{} 331 332 func (p *withinSecPredicateValueProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 333 if len(arguments) != 3 { 334 return nil, fmt.Errorf("expected 3 arguments <ds:within_sec [timestamp, delta, dateFormat]> predicate, but had %v", len(arguments)) 335 } 336 if arguments[0] == "now" { 337 arguments[0] = time.Now() 338 } 339 dateFormat := AsString(arguments[2]) 340 dateLayout := DateFormatToLayout(dateFormat) 341 targetTime := AsTime(arguments[0], dateLayout) 342 if targetTime == nil { 343 return nil, fmt.Errorf("Unable convert %v to time.Time", arguments[0]) 344 } 345 delta := AsInt(arguments[1]) 346 predicate := NewWithinPredicate(*targetTime, delta, dateLayout) 347 return &predicate, nil 348 } 349 350 //NewWithinSecPredicateValueProvider returns a new within second value provider 351 func NewWithinSecPredicateValueProvider() ValueProvider { 352 return &withinSecPredicateValueProvider{} 353 } 354 355 type fileValueProvider struct { 356 trim bool 357 } 358 359 func (p *fileValueProvider) Get(context Context, arguments ...interface{}) (interface{}, error) { 360 filePath := AsString(arguments[0]) 361 fileContent, err := ioutil.ReadFile(filePath) 362 if err != nil { 363 panic(err) 364 } 365 if p.trim { 366 fileContent = bytes.TrimSpace(fileContent) 367 } 368 result := string(fileContent) 369 return result, nil 370 } 371 372 //NewFileValueProvider create new file value provider 373 func NewFileValueProvider(trim bool) ValueProvider { 374 return &fileValueProvider{trim: trim} 375 }