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

     1  package ravendb
     2  
     3  import "reflect"
     4  
     5  // ConcurrencyCheckMode describes concurrency check
     6  type ConcurrencyCheckMode int
     7  
     8  const (
     9  	// ConcurrencyCheckAuto is automatic optimistic concurrency check depending on UseOptimisticConcurrency setting or provided Change Vector
    10  	ConcurrencyCheckAuto ConcurrencyCheckMode = iota
    11  	// ConcurrencyCheckForced forces optimistic concurrency check even if UseOptimisticConcurrency is not set
    12  	ConcurrencyCheckForced
    13  	// ConcurrencyCheckDisabled disables optimistic concurrency check even if UseOptimisticConcurrency is set
    14  	ConcurrencyCheckDisabled
    15  )
    16  
    17  // documentInfo stores information about entity in a session
    18  // TODO: maybe route all places where we compare enity for equality via
    19  // documentInfo.Equal(other interface{}), so that we can catch
    20  // mismatches of *struct and **struct
    21  type documentInfo struct {
    22  	id                   string
    23  	changeVector         *string
    24  	concurrencyCheckMode ConcurrencyCheckMode
    25  	ignoreChanges        bool
    26  	metadata             map[string]interface{}
    27  	document             map[string]interface{}
    28  	metadataInstance     *MetadataAsDictionary
    29  	entity               interface{}
    30  	newDocument          bool
    31  	collection           string
    32  }
    33  
    34  // we want to route assignments to entity through this functions
    35  // so that we can maintain invariant that entity is *struct (and
    36  // not, e.g., **struct). It's hard to track the difference between
    37  // *struct and **struct otherwise
    38  func (d *documentInfo) setEntity(value interface{}) {
    39  	// TODO: maybe also support value of type *map[string]interface{}?
    40  	if _, ok := value.(map[string]interface{}); ok {
    41  		d.entity = value
    42  		return
    43  	}
    44  
    45  	tp := reflect.TypeOf(value)
    46  	if tp.Kind() == reflect.Struct {
    47  		panicIf(true, "trying to set struct %T", value)
    48  		d.entity = value
    49  	}
    50  
    51  	if tp.Kind() != reflect.Ptr || tp.Elem() == nil {
    52  		panicIf(tp.Kind() != reflect.Ptr || tp.Elem() == nil, "expected value to be *struct or **struct, is %T", value)
    53  		d.entity = value
    54  		return
    55  	}
    56  	tp = tp.Elem()
    57  	if tp.Kind() == reflect.Struct {
    58  		// if it's *struct, just assign
    59  		d.entity = value
    60  		return
    61  	}
    62  	if tp.Kind() != reflect.Ptr || tp.Elem() == nil || tp.Elem().Kind() != reflect.Struct {
    63  		//panicIf(tp.Kind() != reflect.Ptr || tp.Elem() == nil || tp.Elem().Kind() != reflect.Struct, "expected value to be *struct or **struct, is %T", value)
    64  		//TODO: re-enable this panic and fix places that trigger it
    65  		d.entity = value
    66  		return
    67  
    68  	}
    69  	// it's **struct, so extract *struct
    70  	rv := reflect.ValueOf(value)
    71  	rv = rv.Elem() // it's *struct now
    72  	d.entity = rv.Interface()
    73  }
    74  
    75  func getNewDocumentInfo(document map[string]interface{}) *documentInfo {
    76  	metadataV, ok := document[MetadataKey]
    77  	// TODO: maybe convert to errors
    78  	panicIf(!ok, "Document must have a metadata")
    79  	metadata, ok := metadataV.(map[string]interface{})
    80  	panicIf(!ok, "Document metadata is not a valid type %T", metadataV)
    81  
    82  	// TODO: return an error?
    83  
    84  	id, ok := jsonGetAsText(metadata, MetadataID)
    85  	// TODO: return an error?
    86  	panicIf(!ok || id == "", "Document must have an id")
    87  
    88  	changeVector := jsonGetAsTextPointer(metadata, MetadataChangeVector)
    89  	// TODO: return an error?
    90  	panicIf(changeVector == nil, "Document must have a Change Vector")
    91  
    92  	newDocumentInfo := &documentInfo{}
    93  	newDocumentInfo.id = id
    94  	newDocumentInfo.document = document
    95  	newDocumentInfo.metadata = metadata
    96  
    97  	newDocumentInfo.changeVector = changeVector
    98  	return newDocumentInfo
    99  }