1package gocb 2 3import "fmt" 4 5// MapGet retrieves a single item from a map document by its key. 6func (b *Bucket) MapGet(key, path string, valuePtr interface{}) (Cas, error) { 7 tracespan := b.startKvOpTrace("MapGet") 8 defer tracespan.Finish() 9 10 frag, err := b.startLookupIn("", key, 0).Get(path).execute(tracespan.Context()) 11 if err != nil { 12 return 0, err 13 } 14 err = frag.ContentByIndex(0, valuePtr) 15 if err != nil { 16 return 0, err 17 } 18 return frag.Cas(), nil 19} 20 21// MapRemove removes a specified key from the specified map document. 22func (b *Bucket) MapRemove(key, path string) (Cas, error) { 23 tracespan := b.startKvOpTrace("MapRemove") 24 defer tracespan.Finish() 25 26 frag, err := b.startMutateIn("", key, 0, 0, 0, 0, 0).Remove(path).execute(tracespan.Context()) 27 if err != nil { 28 return 0, err 29 } 30 return frag.Cas(), nil 31} 32 33// MapSize returns the current number of items in a map document. 34// PERFORMANCE NOTICE: This currently performs a full document fetch... 35func (b *Bucket) MapSize(key string) (uint, Cas, error) { 36 var mapContents map[string]interface{} 37 cas, err := b.Get(key, &mapContents) 38 if err != nil { 39 return 0, 0, err 40 } 41 42 return uint(len(mapContents)), cas, nil 43} 44 45// MapAdd inserts an item to a map document. 46func (b *Bucket) MapAdd(key, path string, value interface{}, createMap bool) (Cas, error) { 47 for { 48 frag, err := b.startMutateIn("MapAdd", key, 0, 0, 0, 0, 0). 49 Insert(path, value, false).Execute() 50 if err != nil { 51 if IsKeyNotFoundError(err) && createMap { 52 data := make(map[string]interface{}) 53 data[path] = value 54 cas, err := b.Insert(key, data, 0) 55 if err != nil { 56 if IsKeyExistsError(err) { 57 continue 58 } 59 60 return 0, err 61 } 62 return cas, nil 63 } 64 return 0, err 65 } 66 return frag.Cas(), nil 67 } 68} 69 70// ListGet retrieves an item from a list document by index. 71func (b *Bucket) ListGet(key string, index uint, valuePtr interface{}) (Cas, error) { 72 frag, err := b.LookupIn(key).Get(fmt.Sprintf("[%d]", index)).Execute() 73 if err != nil { 74 return 0, err 75 } 76 err = frag.ContentByIndex(0, valuePtr) 77 if err != nil { 78 return 0, err 79 } 80 return frag.Cas(), nil 81} 82 83// ListAppend inserts an item to the end of a list document. 84func (b *Bucket) ListAppend(key string, value interface{}, createList bool) (Cas, error) { 85 for { 86 frag, err := b.MutateIn(key, 0, 0).ArrayAppend("", value, false).Execute() 87 if err != nil { 88 if IsKeyNotFoundError(err) && createList { 89 var data []interface{} 90 data = append(data, value) 91 cas, err := b.Insert(key, data, 0) 92 if err != nil { 93 if IsKeyExistsError(err) { 94 continue 95 } 96 97 return 0, err 98 } 99 return cas, nil 100 } 101 return 0, err 102 } 103 return frag.Cas(), nil 104 } 105} 106 107// ListPrepend inserts an item to the beginning of a list document. 108func (b *Bucket) ListPrepend(key string, value interface{}, createList bool) (Cas, error) { 109 for { 110 frag, err := b.MutateIn(key, 0, 0).ArrayPrepend("", value, false).Execute() 111 if err != nil { 112 if IsKeyNotFoundError(err) && createList { 113 var data []interface{} 114 data = append(data, value) 115 cas, err := b.Insert(key, data, 0) 116 if err != nil { 117 if IsKeyExistsError(err) { 118 continue 119 } 120 121 return 0, err 122 } 123 return cas, nil 124 } 125 return 0, err 126 } 127 return frag.Cas(), nil 128 } 129} 130 131// ListRemove removes an item from a list document by its index. 132func (b *Bucket) ListRemove(key string, index uint) (Cas, error) { 133 frag, err := b.MutateIn(key, 0, 0).Remove(fmt.Sprintf("[%d]", index)).Execute() 134 if err != nil { 135 return 0, err 136 } 137 return frag.Cas(), nil 138} 139 140// ListSet replaces the item at a particular index of a list document. 141func (b *Bucket) ListSet(key string, index uint, value interface{}) (Cas, error) { 142 frag, err := b.MutateIn(key, 0, 0).Replace(fmt.Sprintf("[%d]", index), value).Execute() 143 if err != nil { 144 return 0, err 145 } 146 return frag.Cas(), nil 147} 148 149// ListSize returns the current number of items in a list. 150// PERFORMANCE NOTICE: This currently performs a full document fetch... 151func (b *Bucket) ListSize(key string) (uint, Cas, error) { 152 var listContents []interface{} 153 cas, err := b.Get(key, &listContents) 154 if err != nil { 155 return 0, 0, err 156 } 157 158 return uint(len(listContents)), cas, nil 159} 160 161// SetAdd adds a new value to a set document. 162func (b *Bucket) SetAdd(key string, value interface{}, createSet bool) (Cas, error) { 163 for { 164 frag, err := b.MutateIn(key, 0, 0).ArrayAddUnique("", value, false).Execute() 165 if err != nil { 166 if IsKeyNotFoundError(err) && createSet { 167 var data []interface{} 168 data = append(data, value) 169 cas, err := b.Insert(key, data, 0) 170 if err != nil { 171 if IsKeyExistsError(err) { 172 continue 173 } 174 175 return 0, err 176 } 177 return cas, nil 178 } 179 return 0, err 180 } 181 return frag.Cas(), nil 182 } 183} 184 185// SetExists checks if a particular value exists within the specified set document. 186// PERFORMANCE WARNING: This performs a full set fetch and compare. 187func (b *Bucket) SetExists(key string, value interface{}) (bool, Cas, error) { 188 var setContents []interface{} 189 cas, err := b.Get(key, &setContents) 190 if err != nil { 191 return false, 0, err 192 } 193 194 for _, item := range setContents { 195 if item == value { 196 return true, cas, nil 197 } 198 } 199 200 return false, 0, nil 201} 202 203// SetSize returns the current number of values in a set. 204// PERFORMANCE NOTICE: This currently performs a full document fetch... 205func (b *Bucket) SetSize(key string) (uint, Cas, error) { 206 var setContents []interface{} 207 cas, err := b.Get(key, &setContents) 208 if err != nil { 209 return 0, 0, err 210 } 211 212 return uint(len(setContents)), cas, nil 213} 214 215// SetRemove removes a single specified value from the specified set document. 216// WARNING: This relies on Go's interface{} comparison behaviour! 217// PERFORMANCE WARNING: This performs full set fetch, modify, store cycles. 218func (b *Bucket) SetRemove(key string, value interface{}) (Cas, error) { 219 for { 220 var setContents []interface{} 221 cas, err := b.Get(key, &setContents) 222 if err != nil { 223 return 0, err 224 } 225 226 foundItem := false 227 newSetContents := make([]interface{}, 0) 228 for _, item := range setContents { 229 if item == value { 230 foundItem = true 231 } else { 232 newSetContents = append(newSetContents, item) 233 } 234 } 235 236 if !foundItem { 237 return 0, ErrRangeError 238 } 239 240 cas, err = b.Replace(key, newSetContents, cas, 0) 241 if err != nil { 242 if IsKeyExistsError(err) { 243 // If this is just a CAS error, try again! 244 continue 245 } 246 247 return 0, err 248 } 249 250 return cas, nil 251 } 252} 253 254// QueuePush adds a new item to the end of a queue. 255func (b *Bucket) QueuePush(key string, value interface{}, createQueue bool) (Cas, error) { 256 return b.ListPrepend(key, value, createQueue) 257} 258 259// QueuePop pops the oldest item from a queue and returns it. 260func (b *Bucket) QueuePop(key string, valuePtr interface{}) (Cas, error) { 261 for { 262 getFrag, err := b.LookupIn(key).Get("[-1]").Execute() 263 if err != nil { 264 return 0, err 265 } 266 267 rmFrag, err := b.MutateIn(key, getFrag.Cas(), 0).Remove("[-1]").Execute() 268 if err != nil { 269 if IsKeyExistsError(err) { 270 // If this is just a CAS error, try again! 271 continue 272 } 273 274 return 0, err 275 } 276 277 err = getFrag.ContentByIndex(0, valuePtr) 278 if err != nil { 279 return 0, err 280 } 281 282 return rmFrag.Cas(), nil 283 } 284} 285 286// QueueSize returns the current size of a queue. 287func (b *Bucket) QueueSize(key string) (uint, Cas, error) { 288 var queueContents []interface{} 289 cas, err := b.Get(key, &queueContents) 290 if err != nil { 291 return 0, 0, err 292 } 293 294 return uint(len(queueContents)), cas, nil 295} 296