github.com/altipla-consulting/ravendb-go-client@v0.1.3/entity_to_json.go (about) 1 package ravendb 2 3 import ( 4 "errors" 5 "fmt" 6 "reflect" 7 ) 8 9 // TODO: cleanup, possibly rethink entityToJSON 10 11 type entityToJSON struct { 12 session *InMemoryDocumentSessionOperations 13 missingDictionary map[interface{}]map[string]interface{} 14 //private final Map<Object, Map<string, Object>> _missingDictionary = new TreeMap<>((o1, o2) -> o1 == o2 ? 0 : 1); 15 } 16 17 // All the listeners for this session 18 func newEntityToJSON(session *InMemoryDocumentSessionOperations) *entityToJSON { 19 return &entityToJSON{ 20 session: session, 21 } 22 } 23 24 func (e *entityToJSON) getMissingDictionary() map[interface{}]map[string]interface{} { 25 return e.missingDictionary 26 } 27 28 func convertEntityToJSON(entity interface{}, documentInfo *documentInfo) map[string]interface{} { 29 // maybe we don't need to do anything? 30 if v, ok := entity.(map[string]interface{}); ok { 31 return v 32 } 33 jsonNode := structToJSONMap(entity) 34 35 entityToJSONWriteMetadata(jsonNode, documentInfo) 36 37 tryRemoveIdentityProperty(jsonNode) 38 39 return jsonNode 40 } 41 42 // TODO: verify is correct, write a test 43 func isTypeObjectNode(entityType reflect.Type) bool { 44 var v map[string]interface{} 45 typ := reflect.ValueOf(v).Type() 46 return typ.String() == entityType.String() 47 } 48 49 // assumes v is ptr-to-struct and result is ptr-to-ptr-to-struct 50 func setInterfaceToValue(result interface{}, v interface{}) (err error) { 51 52 // this catches a panic that reflect.Value.Set() can produce 53 // and turns it into an error 54 // TODO: a cleaner way would be to check instead suppressing a panic by e.g. 55 // lifting implementation of func directlyAssignable(T, V *rtype) bool { 56 // from reflect package 57 defer func() { 58 if res := recover(); res != nil { 59 fmt.Printf("setInterfaceToValue: panic, res: %v %T\n", res, res) 60 if s, ok := res.(string); ok { 61 err = errors.New(s) 62 } else if panicErr, ok := res.(error); ok { 63 err = panicErr 64 } else { 65 err = fmt.Errorf("%v", res) 66 } 67 } 68 }() 69 70 out := reflect.ValueOf(result) 71 outt := out.Type() 72 if outt.Kind() == reflect.Ptr && out.IsNil() { 73 out.Set(reflect.New(outt.Elem())) 74 } 75 if outt.Kind() == reflect.Ptr { 76 out = out.Elem() 77 //outt = out.Type() 78 //outk = out.Kind() 79 } 80 81 vin := reflect.ValueOf(v) 82 if !out.CanSet() { 83 return fmt.Errorf("cannot set out %s\n", out.String()) 84 } 85 86 out.Set(vin) 87 return 88 } 89 90 // makes a copy of a map and returns a pointer to it 91 func mapDup(m map[string]interface{}) *map[string]interface{} { 92 res := map[string]interface{}{} 93 for k, v := range m { 94 res[k] = v 95 } 96 return &res 97 } 98 99 // ConvertToEntity2 converts document to a value result, matching type of result 100 func (e *entityToJSON) convertToEntity2(result interface{}, id string, document map[string]interface{}) error { 101 if _, ok := result.(**map[string]interface{}); ok { 102 return setInterfaceToValue(result, mapDup(document)) 103 } 104 105 if _, ok := result.(map[string]interface{}); ok { 106 // TODO: is this code path ever executed? 107 return setInterfaceToValue(result, document) 108 } 109 entityType := reflect.TypeOf(result) 110 entity, err := makeStructFromJSONMap(entityType, document) 111 if err != nil { 112 // fmt.Printf("makeStructFromJSONMap() failed with %s\n. Wanted type: %s, document: %v\n", err, entityType, document) 113 return err 114 } 115 trySetIDOnEntity(entity, id) 116 //fmt.Printf("result is: %T, entity is: %T\n", result, entity) 117 if entity == nil { 118 return newIllegalStateError("decoded entity is nil") 119 } 120 return setInterfaceToValue(result, entity) 121 } 122 123 // Converts a json object to an entity. 124 // TODO: remove in favor of entityToJSONConvertToEntity 125 func (e *entityToJSON) convertToEntity(entityType reflect.Type, id string, document map[string]interface{}) (interface{}, error) { 126 if isTypeObjectNode(entityType) { 127 return document, nil 128 } 129 entity, err := makeStructFromJSONMap(entityType, document) 130 if err != nil { 131 return nil, err 132 } 133 trySetIDOnEntity(entity, id) 134 return entity, nil 135 } 136 137 func entityToJSONConvertToEntity(entityType reflect.Type, id string, document map[string]interface{}) (interface{}, error) { 138 if isTypeObjectNode(entityType) { 139 return document, nil 140 } 141 entity, err := makeStructFromJSONMap(entityType, document) 142 if err != nil { 143 return nil, err 144 } 145 trySetIDOnEntity(entity, id) 146 return entity, nil 147 } 148 149 func entityToJSONWriteMetadata(jsonNode map[string]interface{}, documentInfo *documentInfo) { 150 if documentInfo == nil { 151 return 152 } 153 154 setMetadata := false 155 metadataNode := map[string]interface{}{} 156 157 metadata := documentInfo.metadata 158 metadataInstance := documentInfo.metadataInstance 159 if len(metadata) > 0 { 160 setMetadata = true 161 for property, v := range metadata { 162 v = deepCopy(v) 163 metadataNode[property] = v 164 } 165 } else if metadataInstance != nil { 166 setMetadata = true 167 for key, value := range metadataInstance.EntrySet() { 168 metadataNode[key] = value 169 } 170 } 171 172 collection := documentInfo.collection 173 if collection != "" { 174 setMetadata = true 175 176 metadataNode[MetadataCollection] = collection 177 } 178 179 if setMetadata { 180 jsonNode[MetadataKey] = metadataNode 181 } 182 } 183 184 /* 185 //TBD public static object ConvertToEntity(Type entityType, string id, BlittableJsonReaderObject document, DocumentConventions conventions) 186 187 } 188 */ 189 190 func tryRemoveIdentityProperty(document map[string]interface{}) bool { 191 delete(document, IdentityProperty) 192 return true 193 } 194 195 /* 196 public static Object convertToEntity(Class<?> entityClass, String id, ObjectNode document, DocumentConventions conventions) { 197 try { 198 Object defaultValue = InMemoryDocumentSessionOperations.getDefaultValue(entityClass); 199 200 Object entity = defaultValue; 201 202 String documentType = conventions.getJavaClass(id, document); 203 if (documentType != null) { 204 Class<?> clazz = Class.forName(documentType); 205 if (clazz != null && entityClass.isAssignableFrom(clazz)) { 206 entity = conventions.getEntityMapper().treeToValue(document, clazz); 207 } 208 } 209 210 if (entity == null) { 211 entity = conventions.getEntityMapper().treeToValue(document, entityClass); 212 } 213 214 return entity; 215 } catch (Exception e) { 216 throw new IllegalStateException("Could not convert document " + id + " to entity of type " + entityClass); 217 } 218 } 219 */