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

     1  package ravendb
     2  
     3  import (
     4  	"fmt"
     5  	"reflect"
     6  	"strings"
     7  )
     8  
     9  // LoadOperation represents a load operation
    10  type LoadOperation struct {
    11  	session *InMemoryDocumentSessionOperations
    12  
    13  	ids                []string
    14  	includes           []string
    15  	idsToCheckOnServer []string
    16  }
    17  
    18  func NewLoadOperation(session *InMemoryDocumentSessionOperations) *LoadOperation {
    19  	return &LoadOperation{
    20  		session: session,
    21  	}
    22  }
    23  
    24  func (o *LoadOperation) createRequest() (*GetDocumentsCommand, error) {
    25  	if len(o.idsToCheckOnServer) == 0 {
    26  		return nil, nil
    27  	}
    28  
    29  	if o.session.checkIfIdAlreadyIncluded(o.ids, o.includes) {
    30  		return nil, nil
    31  	}
    32  
    33  	if err := o.session.incrementRequestCount(); err != nil {
    34  		return nil, err
    35  	}
    36  
    37  	return NewGetDocumentsCommand(o.idsToCheckOnServer, o.includes, false)
    38  }
    39  
    40  func (o *LoadOperation) byID(id string) *LoadOperation {
    41  	if id == "" {
    42  		return o
    43  	}
    44  
    45  	if o.ids == nil {
    46  		o.ids = []string{id}
    47  	}
    48  
    49  	if o.session.IsLoadedOrDeleted(id) {
    50  		return o
    51  	}
    52  
    53  	o.idsToCheckOnServer = append(o.idsToCheckOnServer, id)
    54  	return o
    55  }
    56  
    57  func (o *LoadOperation) withIncludes(includes []string) *LoadOperation {
    58  	o.includes = includes
    59  	return o
    60  }
    61  
    62  func (o *LoadOperation) byIds(ids []string) *LoadOperation {
    63  	o.ids = stringArrayCopy(ids)
    64  
    65  	seen := map[string]struct{}{}
    66  	for _, id := range ids {
    67  		if id == "" {
    68  			continue
    69  		}
    70  		idl := strings.ToLower(id)
    71  		if _, ok := seen[idl]; ok {
    72  			continue
    73  		}
    74  		seen[idl] = struct{}{}
    75  		o.byID(id)
    76  	}
    77  	return o
    78  }
    79  
    80  func (o *LoadOperation) getDocument(result interface{}) error {
    81  	return o.getDocumentWithID(result, o.ids[0])
    82  }
    83  
    84  func (o *LoadOperation) getDocumentWithID(result interface{}, id string) error {
    85  	if id == "" {
    86  		// TODO: should return default value?
    87  		//return ErrNotFound
    88  		return nil
    89  	}
    90  
    91  	if o.session.IsDeleted(id) {
    92  		// TODO: return ErrDeleted?
    93  		//return ErrNotFound
    94  		return nil
    95  	}
    96  
    97  	doc := o.session.documentsByID.getValue(id)
    98  	if doc == nil {
    99  		doc = o.session.includedDocumentsByID[id]
   100  	}
   101  	if doc == nil {
   102  		//return ErrNotFound
   103  		return nil
   104  	}
   105  
   106  	return o.session.TrackEntityInDocumentInfo(result, doc)
   107  }
   108  
   109  var stringType = reflect.TypeOf("")
   110  
   111  // TODO: also handle a pointer to a map?
   112  func (o *LoadOperation) getDocuments(results interface{}) error {
   113  	// results must be map[string]*struct
   114  	//fmt.Printf("LoadOperation.getDocuments: results type: %T\n", results)
   115  	m := reflect.ValueOf(results)
   116  	if m.Type().Kind() != reflect.Map {
   117  		return fmt.Errorf("results should be a map[string]*struct, is %s. tp: %s", m.Type().String(), m.Type().String())
   118  	}
   119  	mapKeyType := m.Type().Key()
   120  	if mapKeyType != stringType {
   121  		return fmt.Errorf("results should be a map[string]*struct, is %s. tp: %s", m.Type().String(), m.Type().String())
   122  	}
   123  	mapElemPtrType := m.Type().Elem()
   124  	if mapElemPtrType.Kind() != reflect.Ptr {
   125  		return fmt.Errorf("results should be a map[string]*struct, is %s. tp: %s", m.Type().String(), m.Type().String())
   126  	}
   127  	mapElemType := mapElemPtrType.Elem()
   128  	if mapElemType.Kind() != reflect.Struct {
   129  		return fmt.Errorf("results should be a map[string]*struct, is %s. tp: %s", m.Type().String(), m.Type().String())
   130  	}
   131  
   132  	uniqueIds := stringArrayCopy(o.ids)
   133  	stringArrayRemove(&uniqueIds, "")
   134  	uniqueIds = stringArrayRemoveDuplicatesNoCase(uniqueIds)
   135  	for _, id := range uniqueIds {
   136  		v := reflect.New(mapElemPtrType).Interface()
   137  		err := o.getDocumentWithID(v, id)
   138  		if err != nil {
   139  			return err
   140  		}
   141  		key := reflect.ValueOf(id)
   142  		v2 := reflect.ValueOf(v).Elem() // convert *<type> to <type>
   143  		m.SetMapIndex(key, v2)
   144  	}
   145  
   146  	return nil
   147  }
   148  
   149  func (o *LoadOperation) setResult(result *GetDocumentsResult) {
   150  	if result == nil {
   151  		return
   152  	}
   153  
   154  	o.session.registerIncludes(result.Includes)
   155  
   156  	results := result.Results
   157  	for _, document := range results {
   158  		// TODO: Java also does document.isNull()
   159  		if document == nil {
   160  			continue
   161  		}
   162  		newDocumentInfo := getNewDocumentInfo(document)
   163  		o.session.documentsByID.add(newDocumentInfo)
   164  	}
   165  
   166  	o.session.registerMissingIncludes(result.Results, result.Includes, o.includes)
   167  }