github.com/ravendb/ravendb-go-client@v0.0.0-20240229102137-4474ee7aa0fa/metadata_as_dictionary.go (about) 1 package ravendb 2 3 // Note: Java has IMetadataAsDictionary which is not needed in Go 4 // so we use concrete type MetadataAsDictionary 5 6 // MetadataAsDictionary describes metadata for a document 7 type MetadataAsDictionary struct { 8 parent *MetadataAsDictionary 9 parentKey string 10 11 // the actual metadata 12 metadata map[string]interface{} 13 source map[string]interface{} 14 15 dirty bool 16 } 17 18 // NewMetadataAsDictionaryWithSource returns MetadataAsDictionary based on a given source 19 func NewMetadataAsDictionaryWithSource(metadata map[string]interface{}) *MetadataAsDictionary { 20 return &MetadataAsDictionary{ 21 source: metadata, 22 } 23 } 24 25 // NewMetadataAsDictionaryWithMetadata returns MetadataAsDictionary based on a given metadata 26 func NewMetadataAsDictionaryWithMetadata(metadata map[string]interface{}) *MetadataAsDictionary { 27 return &MetadataAsDictionary{ 28 metadata: metadata, 29 } 30 } 31 32 // NewMetadataAsDictionary returns MetadataAsDictionary based on a given metadata and parent 33 func NewMetadataAsDictionary(metadata map[string]interface{}, parent *MetadataAsDictionary, parentKey string) *MetadataAsDictionary { 34 panicIf(parent == nil, "Parent cannot be null") 35 panicIf(parentKey == "", "ParentKey cannot be empty") 36 return &MetadataAsDictionary{ 37 source: metadata, 38 parent: parent, 39 parentKey: parentKey, 40 } 41 } 42 43 // MarkDirty marks us as dirty 44 func (d *MetadataAsDictionary) MarkDirty() { 45 d.dirty = true 46 } 47 48 // IsDirty returns if we're dirty 49 func (d *MetadataAsDictionary) IsDirty() bool { 50 return d.dirty 51 } 52 53 // KeySet returns all keys 54 func (d *MetadataAsDictionary) KeySet() []string { 55 if d.metadata == nil { 56 d.Init() 57 } 58 // TODO: pre-allocate res 59 var res []string 60 for k := range d.metadata { 61 res = append(res, k) 62 } 63 return res 64 } 65 66 // Init initializes metadata 67 func (d *MetadataAsDictionary) Init() { 68 d.dirty = true 69 d.metadata = map[string]interface{}{} 70 71 for k, v := range d.source { 72 val := d.ConvertValue(k, v) 73 d.metadata[k] = val 74 } 75 76 if d.parent != nil { 77 d.parent.Put(d.parentKey, d) 78 } 79 } 80 81 // Put inserts a given value with a given key 82 func (d *MetadataAsDictionary) Put(key string, value interface{}) interface{} { 83 if d.metadata == nil { 84 d.Init() 85 } 86 d.dirty = true 87 88 d.metadata[key] = value 89 return value 90 } 91 92 // ConvertValue converts value with a given key to a desired type 93 func (d *MetadataAsDictionary) ConvertValue(key string, value interface{}) interface{} { 94 if value == nil { 95 return nil 96 } 97 98 switch v := value.(type) { 99 case int, bool, string, float32, float64: // TODO: more int types? 100 return value 101 case map[string]interface{}: 102 // TODO: not sure what to do here. Relevant test case: TestRavenDB10641 103 //return NewMetadataAsDictionary(v, d, key) 104 return v 105 case []interface{}: 106 n := len(v) 107 res := make([]interface{}, n) 108 for i, el := range v { 109 newEl := d.ConvertValue(key, el) 110 res[i] = newEl 111 } 112 return res 113 default: 114 panicIf(true, "unsuppoted type %T", value) 115 } 116 117 return nil 118 } 119 120 // Clear removes all metadata 121 func (d *MetadataAsDictionary) Clear() { 122 if d.metadata == nil { 123 d.Init() 124 } 125 d.dirty = true 126 127 d.metadata = map[string]interface{}{} // TODO: can it be nil? 128 } 129 130 // Get returns metadata value with a given key 131 func (d *MetadataAsDictionary) Get(key string) (interface{}, bool) { 132 if d.metadata != nil { 133 v, ok := d.metadata[key] 134 return v, ok 135 } 136 137 v, ok := d.source[key] 138 if !ok { 139 return v, ok 140 } 141 return d.ConvertValue(key, v), ok 142 } 143 144 // EntrySet returns metadata as map[string]interface{} 145 func (d *MetadataAsDictionary) EntrySet() map[string]interface{} { 146 if d.metadata == nil { 147 d.Init() 148 } 149 150 return d.metadata 151 } 152 153 // ContainsKey returns true if we have metadata value with a given key 154 func (d *MetadataAsDictionary) ContainsKey(key string) bool { 155 if d.metadata != nil { 156 _, ok := d.metadata[key] 157 return ok 158 } 159 160 _, ok := d.source[key] 161 return ok 162 } 163 164 // GetObjects returns metadata info for a given key 165 // TODO: return an error instead of panicking on cast failures? 166 func (d *MetadataAsDictionary) GetObjects(key string) []*MetadataAsDictionary { 167 objI, ok := d.Get(key) 168 if !ok || objI == nil { 169 return nil 170 } 171 obj := objI.([]interface{}) 172 n := len(obj) 173 if n == 0 { 174 return nil 175 } 176 list := make([]*MetadataAsDictionary, n) 177 for i := 0; i < n; i++ { 178 if d, ok := obj[i].(map[string]interface{}); ok { 179 list[i] = NewMetadataAsDictionaryWithMetadata(d) 180 continue 181 } 182 v := obj[i].(*MetadataAsDictionary) 183 list[i] = v 184 } 185 return list 186 } 187 188 // Size returns number of metadata items 189 func (d *MetadataAsDictionary) Size() int { 190 if d.metadata != nil { 191 return len(d.metadata) 192 } 193 194 return len(d.source) 195 } 196 197 func (d *MetadataAsDictionary) IsEmpty() bool { 198 return d.Size() == 0 199 } 200 201 func (d *MetadataAsDictionary) Remove(key string) { 202 if d.metadata == nil { 203 return 204 } 205 d.dirty = true 206 207 delete(d.metadata, key) 208 } 209 210 /* 211 @Override 212 public void putAll(Map<? extends string, ?> m) { 213 if (_metadata == null) { 214 init(); 215 } 216 dirty = true; 217 218 _metadata.putAll(m); 219 } 220 221 @Override 222 public boolean containsValue(Object value) { 223 if (_metadata == null) { 224 init(); 225 } 226 227 return _metadata.containsValue(value); 228 } 229 230 @Override 231 public Collection<Object> values() { 232 if (_metadata == null) { 233 init(); 234 } 235 236 return _metadata.values(); 237 } 238 239 @Override 240 241 } 242 */