github.com/ravendb/ravendb-go-client@v0.0.0-20240229102137-4474ee7aa0fa/subscription_batch.go (about) 1 package ravendb 2 3 import ( 4 "log" 5 "reflect" 6 ) 7 8 // SubscriptionBatchItem describes a single result from subscription 9 type SubscriptionBatchItem struct { 10 Result interface{} 11 ErrorMessage string 12 ID string 13 ChangeVector string 14 15 RawResult map[string]interface{} 16 RawMetadata map[string]interface{} 17 Metadata *MetadataAsDictionary 18 } 19 20 func (i *SubscriptionBatchItem) throwItemProcessException() error { 21 return newIllegalStateError("Failed to process document " + i.ID + " with Change Vector " + i.ChangeVector + " because: \n" + i.ErrorMessage) 22 } 23 24 // GetResult sets result to to the value of that batch item 25 func (i *SubscriptionBatchItem) GetResult(result interface{}) error { 26 if i.ErrorMessage != "" { 27 return i.throwItemProcessException() 28 } 29 if v, ok := result.(*map[string]interface{}); ok { 30 *v = i.RawResult 31 return nil 32 } 33 if err := checkValidLoadArg(result, "result"); err != nil { 34 return err 35 } 36 return setInterfaceToValue(result, i.Result) 37 } 38 39 func (i *SubscriptionBatchItem) GetMetadata() *MetadataAsDictionary { 40 if i.Metadata == nil { 41 i.Metadata = NewMetadataAsDictionary(i.RawMetadata, nil, "") 42 } 43 44 return i.Metadata 45 } 46 47 // SubscriptionBatch describes a bunch of results for subscription 48 type SubscriptionBatch struct { 49 clazz reflect.Type 50 revisions bool 51 requestExecutor *RequestExecutor 52 store *DocumentStore 53 dbName string 54 55 logger *log.Logger 56 generateEntityIdOnTheClient *generateEntityIDOnTheClient 57 58 Items []*SubscriptionBatchItem 59 } 60 61 func (b *SubscriptionBatch) OpenSession() (*DocumentSession, error) { 62 sessionOptions := &SessionOptions{ 63 Database: b.dbName, 64 RequestExecutor: b.requestExecutor, 65 } 66 return b.store.OpenSessionWithOptions(sessionOptions) 67 } 68 69 func newSubscriptionBatch(clazz reflect.Type, revisions bool, requestExecutor *RequestExecutor, store *DocumentStore, dbName string, logger *log.Logger) *SubscriptionBatch { 70 res := &SubscriptionBatch{ 71 clazz: clazz, 72 revisions: revisions, 73 requestExecutor: requestExecutor, 74 store: store, 75 dbName: dbName, 76 logger: logger, 77 } 78 79 fn := func(entity interface{}) (string, error) { 80 panic("Shouldn't be generating new ids here") 81 } 82 c := res.requestExecutor.GetConventions() 83 res.generateEntityIdOnTheClient = newGenerateEntityIDOnTheClient(c, fn) 84 return res 85 } 86 87 func (b *SubscriptionBatch) initialize(batch []*subscriptionConnectionServerMessage) (string, error) { 88 b.Items = nil 89 90 lastReceivedChangeVector := "" 91 92 for _, item := range batch { 93 curDoc := item.Data 94 metadataI, ok := curDoc[MetadataKey] 95 if !ok { 96 return "", throwRequired("@metadata field") 97 } 98 99 metadata := metadataI.(map[string]interface{}) 100 id, ok := jsonGetAsText(metadata, MetadataID) 101 if !ok { 102 return "", throwRequired("@id field") 103 } 104 changeVector, ok := jsonGetAsText(metadata, MetadataChangeVector) 105 if !ok { 106 return "", throwRequired("@change-vector field") 107 } 108 lastReceivedChangeVector = changeVector 109 if b.logger != nil { 110 b.logger.Printf("Got %s (change vector: [%s], size: %d)", id, lastReceivedChangeVector, len(curDoc)) 111 } 112 var instance interface{} 113 114 if item.Exception == "" { 115 if b.clazz == reflect.TypeOf(map[string]interface{}{}) { 116 instance = curDoc 117 } else { 118 if b.revisions { 119 // parse outer object manually as Previous/Current has PascalCase 120 previous := curDoc["Previous"] 121 current := curDoc["Current"] 122 revision := &Revision{} 123 //c := b._requestExecutor.GetConventions() 124 if current != nil { 125 doc := current.(map[string]interface{}) 126 v, err := entityToJSONConvertToEntity(b.clazz, id, doc) 127 if err != nil { 128 return "", err 129 } 130 revision.Current = v 131 } 132 if previous != nil { 133 doc := previous.(map[string]interface{}) 134 v, err := entityToJSONConvertToEntity(b.clazz, id, doc) 135 if err != nil { 136 return "", err 137 } 138 revision.Previous = v 139 } 140 instance = revision 141 } else { 142 var err error 143 instance, err = entityToJSONConvertToEntity(b.clazz, id, curDoc) 144 if err != nil { 145 return "", err 146 } 147 } 148 } 149 150 if stringIsNotEmpty(id) { 151 b.generateEntityIdOnTheClient.trySetIdentity(instance, id) 152 } 153 } 154 itemToAdd := &SubscriptionBatchItem{ 155 ChangeVector: changeVector, 156 ID: id, 157 RawResult: curDoc, 158 RawMetadata: metadata, 159 Result: instance, 160 ErrorMessage: item.Exception, 161 } 162 b.Items = append(b.Items, itemToAdd) 163 } 164 return lastReceivedChangeVector, nil 165 } 166 167 func throwRequired(name string) error { 168 return newIllegalStateError("Document must have a " + name) 169 }