Skip to content

Instantly share code, notes, and snippets.

@bkerley
Last active December 25, 2015 19:39
Show Gist options
  • Save bkerley/7029427 to your computer and use it in GitHub Desktop.
Save bkerley/7029427 to your computer and use it in GitHub Desktop.
map = @bucket.find_crdt 'my-map-key'
map
# alpha: register
# bravo: set
# charlie: map
# charlie.zulu: map
# charlie.zulu.yankee: counter
# delta: counter
map.registers #=> { :alpha => register("123") }, a Collection<Register> which is a kind of Hash
map.registers[:alpha] #=> register("123")
map.registers[:alpha].set "12345" # immediately issues MapOp(update("alpha", "12345"))
map.sets[:bravo] #=> set("abc", "def", "ghi")
map.sets[:bravo].add "abc" # noop? issue MapOp(update("bravo", SetOp(adds: "abc")))?
map.maps[:charlie].maps[:zulu].counters[:yankee].increment # issue MapOp(update("charlie", MapOp(update("zulu", MapOp(update("yankee", CounterOp(1)))))))
map.batch do |m|
m.counters[:delta].increment # enqueue update("delta", CounterOp(1)) on m (which is map in disguise)
m.maps[:charlie].maps[:zulu].flags[:xray] = true # enqueue add("xray", :flag) and update("xray", FlagOp(:enabled)) on m.charlie.zulu (which is map.charlie.zulu in disguise)
end
# issues enqueued updates in single MapOp
@lenary
Copy link

lenary commented Oct 18, 2013

Yeah, I have some issues I should have raised earlier.

map.charlie.zulu.yankee.increment
# issue MapOp(update("charlie", MapOp(update("zulu", MapOp(update("yankee", CounterOp(1)))))))

This isn't how I see the key names at all. I see them as essentially if you have a map at key "charlie", the whole key you address as "charlie_map" or something.

Yes, working it out from the MapOp might make everything easier, but what if there's both a "charlie_map" and a "charlie_set", and you want to remove the element "foo" from "charlie_set", while keeping the field "foo" in "charlie_map". map.charlie.remove("foo") doesn't really get you anywhere.

But I'm not going to bitch without presenting an alternative:

map.map("charlie").map("zulu").counter("yankee").increment # => issue whatever
map.set("charlie").remove("foo") # => issue whatever
map.map("charlie").remove("foo", :map) # => issue something nicer

Indeed, symbols or strings work for me. So does even something like this:

map.charlie_map.zulu_map.yankee_counter.increment

where those types are defined, and regular ruby methods won't overlap with them.

I like your batch syntax, though I'd also like a blockless way of doing updates, as I had proposed in my gist here: https://gist.github.com/lenary/c054695204152972239e

you might add a method to my thing above like the following:

  def batch!(&blk)
    yield self # or do i instance_eval? I can't remember.
    self.send_operations!
  end

But I dunno.

remember, the interface needs to be the same both
a) whether or not the crdt exists; and
b) even if it does exist, whether or not you've fetched the structure first.

I think we're we're close.

@bkerley
Copy link
Author

bkerley commented Oct 18, 2013

@lenary Super thanks for filling me in that map entries are {name, type} => content and not name => {type, content}, that helps a ton, especially with the case that somebody puts an entry called batch or map or delete in a map.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment