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 = &currentTimeProvider{}
   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 = &currentDateProvider{}
   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  }