github.com/willyham/dosa@v2.3.1-0.20171024181418-1e446d37ee71+incompatible/connectors/random/random.go (about)

     1  // Copyright (c) 2017 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package random
    22  
    23  import (
    24  	"context"
    25  
    26  	"math/rand"
    27  	"time"
    28  
    29  	"github.com/satori/go.uuid"
    30  	"github.com/uber-go/dosa"
    31  )
    32  
    33  const (
    34  	maxBlobSize   = 32
    35  	maxStringSize = 64
    36  )
    37  
    38  // Connector is a connector implementation for testing
    39  type Connector struct{}
    40  
    41  // CreateIfNotExists always succeeds
    42  func (c *Connector) CreateIfNotExists(ctx context.Context, ei *dosa.EntityInfo, values map[string]dosa.FieldValue) error {
    43  	return nil
    44  }
    45  
    46  func randomString(slen int) string {
    47  	var validRunes = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_-+={[}];:,.<>/?")
    48  	str := make([]rune, slen)
    49  	for i := range str {
    50  		str[i] = validRunes[rand.Intn(len(validRunes))]
    51  	}
    52  	return string(str)
    53  }
    54  
    55  // Data generates some random data. Because our test is blackbox in a different package,
    56  // we have to export this
    57  func Data(ei *dosa.EntityInfo, minimumFields []string) map[string]dosa.FieldValue {
    58  	var result = map[string]dosa.FieldValue{}
    59  	for _, field := range minimumFields {
    60  		var v dosa.FieldValue
    61  		cd := ei.Def.FindColumnDefinition(field)
    62  		switch cd.Type {
    63  		case dosa.Int32:
    64  			v = dosa.FieldValue(rand.Int31())
    65  		case dosa.Int64:
    66  			v = dosa.FieldValue(rand.Int63())
    67  		case dosa.Bool:
    68  			if rand.Intn(2) == 0 {
    69  				v = dosa.FieldValue(false)
    70  			} else {
    71  				v = dosa.FieldValue(true)
    72  			}
    73  		case dosa.Blob:
    74  			// Blobs vary in length from 1 to maxBlobSize bytes
    75  			blen := rand.Intn(maxBlobSize-1) + 1
    76  			blob := make([]byte, blen)
    77  			for i := range blob {
    78  				blob[i] = byte(rand.Intn(256))
    79  			}
    80  			v = dosa.FieldValue(blob)
    81  		case dosa.String:
    82  			slen := rand.Intn(maxStringSize) + 1
    83  			v = dosa.FieldValue(randomString(slen))
    84  		case dosa.Double:
    85  			v = dosa.FieldValue(rand.Float64())
    86  		case dosa.Timestamp:
    87  			v = dosa.FieldValue(time.Unix(0, rand.Int63()/2))
    88  		case dosa.TUUID:
    89  			v = dosa.FieldValue(uuid.NewV4())
    90  		default:
    91  			panic("invalid type " + cd.Type.String())
    92  
    93  		}
    94  		result[field] = v
    95  	}
    96  	return result
    97  }
    98  
    99  // Read always returns random data of the type specified
   100  func (c *Connector) Read(ctx context.Context, ei *dosa.EntityInfo, values map[string]dosa.FieldValue, minimumFields []string) (map[string]dosa.FieldValue, error) {
   101  
   102  	return Data(ei, minimumFields), nil
   103  }
   104  
   105  // MultiRead returns a set of random data for each key you specify
   106  func (c *Connector) MultiRead(ctx context.Context, ei *dosa.EntityInfo, values []map[string]dosa.FieldValue, minimumFields []string) ([]*dosa.FieldValuesOrError, error) {
   107  	vals := make([]*dosa.FieldValuesOrError, len(values))
   108  	for inx := range values {
   109  		vals[inx] = &dosa.FieldValuesOrError{
   110  			Values: Data(ei, minimumFields),
   111  		}
   112  	}
   113  	return vals, nil
   114  }
   115  
   116  // Upsert throws away the data you upsert
   117  func (c *Connector) Upsert(ctx context.Context, ei *dosa.EntityInfo, values map[string]dosa.FieldValue) error {
   118  	return nil
   119  }
   120  
   121  // makeErrorSlice is a handy function to make a slice of errors or nil errors
   122  func makeErrorSlice(len int, e error) []error {
   123  	errors := make([]error, len)
   124  	for inx := 0; inx < len; inx = inx + 1 {
   125  		errors[inx] = e
   126  	}
   127  	return errors
   128  }
   129  
   130  // MultiUpsert throws away all the data you upsert, returning a set of no errors
   131  func (c *Connector) MultiUpsert(ctx context.Context, ei *dosa.EntityInfo, values []map[string]dosa.FieldValue) ([]error, error) {
   132  	return makeErrorSlice(len(values), nil), nil
   133  }
   134  
   135  // Remove always returns a not found error
   136  func (c *Connector) Remove(ctx context.Context, ei *dosa.EntityInfo, values map[string]dosa.FieldValue) error {
   137  	return nil
   138  }
   139  
   140  // RemoveRange removes all entities within the range specified by the columnConditions.
   141  func (c *Connector) RemoveRange(ctx context.Context, ei *dosa.EntityInfo, columnConditions map[string][]*dosa.Condition) error {
   142  	return nil
   143  }
   144  
   145  // MultiRemove returns a not found error for each value
   146  func (c *Connector) MultiRemove(ctx context.Context, ei *dosa.EntityInfo, multiValues []map[string]dosa.FieldValue) ([]error, error) {
   147  	return makeErrorSlice(len(multiValues), &dosa.ErrNotFound{}), nil
   148  }
   149  
   150  // Range returns a random set of data, and a random continuation token
   151  func (c *Connector) Range(ctx context.Context, ei *dosa.EntityInfo, columnConditions map[string][]*dosa.Condition, minimumFields []string, token string, limit int) ([]map[string]dosa.FieldValue, string, error) {
   152  	vals := make([]map[string]dosa.FieldValue, limit)
   153  	for inx := range vals {
   154  		vals[inx] = Data(ei, minimumFields)
   155  	}
   156  	return vals, randomString(32), nil
   157  }
   158  
   159  // Scan also returns a random set of data, like Range
   160  func (c *Connector) Scan(ctx context.Context, ei *dosa.EntityInfo, minimumFields []string, token string, limit int) ([]map[string]dosa.FieldValue, string, error) {
   161  	return c.Range(ctx, ei, map[string][]*dosa.Condition{}, minimumFields, token, limit)
   162  }
   163  
   164  // CheckSchema always returns a slice of int32 values that match its index
   165  func (c *Connector) CheckSchema(ctx context.Context, scope, namePrefix string, ed []*dosa.EntityDefinition) (int32, error) {
   166  	return int32(1), nil
   167  }
   168  
   169  // UpsertSchema always returns a slice of int32 values that match its index
   170  func (c *Connector) UpsertSchema(ctx context.Context, scope, namePrefix string, ed []*dosa.EntityDefinition) (*dosa.SchemaStatus, error) {
   171  	return &dosa.SchemaStatus{Version: int32(1), Status: "ACCEPTED"}, nil
   172  }
   173  
   174  // CheckSchemaStatus always returns a schema status with version 1 and ACCEPTED
   175  func (c *Connector) CheckSchemaStatus(ctx context.Context, scope, namePrefix string, version int32) (*dosa.SchemaStatus, error) {
   176  	return &dosa.SchemaStatus{
   177  		Version: int32(1),
   178  		Status:  "ACCEPTED",
   179  	}, nil
   180  }
   181  
   182  // CreateScope returns success
   183  func (c *Connector) CreateScope(ctx context.Context, scope string) error {
   184  	return nil
   185  }
   186  
   187  // TruncateScope returns success
   188  func (c *Connector) TruncateScope(ctx context.Context, scope string) error {
   189  	return nil
   190  }
   191  
   192  // DropScope returns success
   193  func (c *Connector) DropScope(ctx context.Context, scope string) error {
   194  	return nil
   195  }
   196  
   197  // ScopeExists is not implemented yet
   198  func (c *Connector) ScopeExists(ctx context.Context, scope string) (bool, error) {
   199  	return true, nil
   200  }
   201  
   202  // Shutdown always returns nil
   203  func (c *Connector) Shutdown() error {
   204  	return nil
   205  }
   206  
   207  // NewConnector creates a new random connector
   208  func NewConnector() *Connector {
   209  	return &Connector{}
   210  }
   211  
   212  func init() {
   213  	dosa.RegisterConnector("random", func(args dosa.CreationArgs) (dosa.Connector, error) {
   214  		return NewConnector(), nil
   215  	})
   216  }