github.com/altipla-consulting/ravendb-go-client@v0.1.3/document_conventions.go (about)

     1  package ravendb
     2  
     3  import (
     4  	"reflect"
     5  	"strings"
     6  	"sync"
     7  	"time"
     8  	"unicode"
     9  )
    10  
    11  var (
    12  	// Note: helps find places that in Java code used DocumentConventsion.GetIdentityProperty()
    13  	// if we add support for that
    14  	documentConventionsIdentityPropertyName = "ID"
    15  )
    16  
    17  type DocumentIDGeneratorFunc func(dbName string, entity interface{}) (string, error)
    18  
    19  // DocumentConventions describes document conventions
    20  type DocumentConventions struct {
    21  	frozen                bool
    22  	originalConfiguration *ClientConfiguration
    23  
    24  	MaxNumberOfRequestsPerSession int
    25  	// timeout for wait to server
    26  	Timeout                  time.Duration
    27  	UseOptimisticConcurrency bool
    28  	// JsonDefaultMethod = DocumentConventions.json_default
    29  	MaxLengthOfQueryUsingGetURL int
    30  	IdentityPartsSeparator      string
    31  	disableTopologyUpdates      bool
    32  	// If set to 'true' then it will return an error when any query is performed (in session)
    33  	// without explicit page size set
    34  	RaiseIfQueryPageSizeIsNotSet bool // TODO: rename to ErrorIfQueryPageSizeIsNotSet
    35  
    36  	documentIDGenerator DocumentIDGeneratorFunc
    37  
    38  	// allows overriding entity -> collection name logic
    39  	FindCollectionName func(interface{}) string
    40  
    41  	ReadBalanceBehavior                            ReadBalanceBehavior
    42  	transformClassCollectionNameToDocumentIDPrefix func(string) string
    43  
    44  	// if true, will return error if page size is not set
    45  	ErrorIfQueryPageSizeIsNotSet bool
    46  
    47  	maxHttpCacheSize int
    48  
    49  	// a pointer to silence go vet when copying DocumentConventions wholesale
    50  	mu *sync.Mutex
    51  }
    52  
    53  // Note: Java has it as frozen global variable (possibly for perf) but Go
    54  // has no notion of frozen objects so for safety we create new object
    55  // (avoids accidental modification of shared, global state)
    56  // TODO: replace with direct calls to NewDocumentConventions()
    57  func getDefaultConventions() *DocumentConventions {
    58  	return NewDocumentConventions()
    59  }
    60  
    61  // NewDocumentConventions creates DocumentConventions with default values
    62  func NewDocumentConventions() *DocumentConventions {
    63  	return &DocumentConventions{
    64  		ReadBalanceBehavior:                            ReadBalanceBehaviorNone,
    65  		MaxLengthOfQueryUsingGetURL:                    1024 + 512,
    66  		IdentityPartsSeparator:                         "/",
    67  		disableTopologyUpdates:                         false,
    68  		RaiseIfQueryPageSizeIsNotSet:                   false,
    69  		transformClassCollectionNameToDocumentIDPrefix: getDefaultTransformCollectionNameToDocumentIdPrefix,
    70  		MaxNumberOfRequestsPerSession:                  32,
    71  		maxHttpCacheSize:                               128 * 1024 * 1024,
    72  		mu:                                             &sync.Mutex{},
    73  	}
    74  }
    75  
    76  func (c *DocumentConventions) getMaxHttpCacheSize() int {
    77  	return c.maxHttpCacheSize
    78  }
    79  
    80  func (c *DocumentConventions) Freeze() {
    81  	c.frozen = true
    82  }
    83  
    84  // GetCollectionNameDefault is a default way of
    85  func GetCollectionNameDefault(entityOrType interface{}) string {
    86  	name := getShortTypeNameForEntityOrType(entityOrType)
    87  	return ToPlural(name)
    88  }
    89  
    90  func (c *DocumentConventions) getCollectionName(entityOrType interface{}) string {
    91  	if c.FindCollectionName != nil {
    92  		return c.FindCollectionName(entityOrType)
    93  	}
    94  	return GetCollectionNameDefault(entityOrType)
    95  }
    96  
    97  func getCollectionNameForTypeOrEntity(entityOrType interface{}) string {
    98  	name := getShortTypeNameForEntityOrType(entityOrType)
    99  	return ToPlural(name)
   100  }
   101  
   102  func (c *DocumentConventions) UpdateFrom(configuration *ClientConfiguration) {
   103  	if configuration == nil {
   104  		return
   105  	}
   106  
   107  	c.mu.Lock()
   108  	defer c.mu.Unlock()
   109  
   110  	if configuration.IsDisabled && c.originalConfiguration == nil {
   111  		// nothing to do
   112  		return
   113  	}
   114  
   115  	if configuration.IsDisabled && c.originalConfiguration != nil {
   116  		// need to revert to original values
   117  		c.MaxNumberOfRequestsPerSession = c.originalConfiguration.MaxNumberOfRequestsPerSession
   118  		c.ReadBalanceBehavior = c.originalConfiguration.ReadBalanceBehavior
   119  
   120  		c.originalConfiguration = nil
   121  		return
   122  	}
   123  
   124  	if c.originalConfiguration == nil {
   125  		c.originalConfiguration = &ClientConfiguration{}
   126  		c.originalConfiguration.Etag = -1
   127  		c.originalConfiguration.MaxNumberOfRequestsPerSession = c.MaxNumberOfRequestsPerSession
   128  		c.originalConfiguration.ReadBalanceBehavior = c.ReadBalanceBehavior
   129  	}
   130  
   131  	c.MaxNumberOfRequestsPerSession = firstNonZero(configuration.MaxNumberOfRequestsPerSession, c.originalConfiguration.MaxNumberOfRequestsPerSession)
   132  
   133  	c.ReadBalanceBehavior = firstNonEmptyString(configuration.ReadBalanceBehavior, c.originalConfiguration.ReadBalanceBehavior)
   134  }
   135  
   136  func getDefaultTransformCollectionNameToDocumentIdPrefix(collectionName string) string {
   137  	upperCount := 0
   138  	for _, c := range collectionName {
   139  		if unicode.IsUpper(c) {
   140  			upperCount++
   141  
   142  			// multiple capital letters, so probably something that we want to preserve caps on.
   143  			if upperCount > 1 {
   144  				return collectionName
   145  			}
   146  		}
   147  	}
   148  	if upperCount == 1 {
   149  		return strings.ToLower(collectionName)
   150  	}
   151  	// upperCount must be 0
   152  	return collectionName
   153  }
   154  
   155  func (c *DocumentConventions) Clone() *DocumentConventions {
   156  	res := *c
   157  	// mutex carries its locking state so we need to re-initialize it
   158  	res.mu = &sync.Mutex{}
   159  	return &res
   160  }
   161  
   162  func (c *DocumentConventions) getGoTypeName(entity interface{}) string {
   163  	return getFullTypeName(entity)
   164  }
   165  
   166  // returns "" if no identity property
   167  func (c *DocumentConventions) GetIdentityProperty(clazz reflect.Type) string {
   168  	return getIdentityProperty(clazz)
   169  }
   170  
   171  func (c *DocumentConventions) GetDocumentIDGenerator() DocumentIDGeneratorFunc {
   172  	return c.documentIDGenerator
   173  }
   174  
   175  func (c *DocumentConventions) SetDocumentIDGenerator(documentIDGenerator DocumentIDGeneratorFunc) {
   176  	c.documentIDGenerator = documentIDGenerator
   177  }
   178  
   179  // Generates the document id.
   180  func (c *DocumentConventions) GenerateDocumentID(databaseName string, entity interface{}) (string, error) {
   181  	return c.documentIDGenerator(databaseName, entity)
   182  }
   183  
   184  func (c *DocumentConventions) IsDisableTopologyUpdates() bool {
   185  	return c.disableTopologyUpdates
   186  }
   187  
   188  func (c *DocumentConventions) SetDisableTopologyUpdates(disable bool) {
   189  	c.disableTopologyUpdates = disable
   190  }
   191  
   192  func (c *DocumentConventions) GetIdentityPartsSeparator() string {
   193  	return c.IdentityPartsSeparator
   194  }
   195  
   196  func (c *DocumentConventions) GetTransformClassCollectionNameToDocumentIdPrefix() func(string) string {
   197  	return c.transformClassCollectionNameToDocumentIDPrefix
   198  }
   199  
   200  func (c *DocumentConventions) TryConvertValueForQuery(fieldName string, value interface{}, forRange bool, stringValue *string) bool {
   201  	// TODO: implement me
   202  	// Tested by CustomSerializationTest
   203  	/*
   204  		for (Tuple<Class, IValueForQueryConverter<Object>> queryValueConverter : _listOfQueryValueConverters) {
   205  			if (!queryValueConverter.first.isInstance(value)) {
   206  				continue;
   207  			}
   208  
   209  			return queryValueConverter.second.tryConvertValueForQuery(fieldName, value, forRange, stringValue);
   210  		}
   211  	*/
   212  	*stringValue = ""
   213  	return false
   214  }