github.com/altipla-consulting/ravendb-go-client@v0.1.3/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  */