It does complicate the type, and it breaks my nice abstraction. Also
remember that any funny logic will need to be on the server and the
client - and I'd really like the server to be application-agnostic if
possible. That said, the server will probably need
application-specific schema validation & access control code anyway,
so maybe its not a big deal.

Another option is to just do the dangerous thing for objects, but
actively encourage people to use lists instead. If you're inserting
into a list instead of inserting into an object, the semantics are
safe & easy. The final list will just contains both items. For
hierarchal to-do lists, you probably want a children:[] list on your
nodes anyway. Using object-move when the key is either a GUID or a
hash of the data would work fine as well because your keys won't
conflict.

This won't work if you're trying to map a directory structure of files
though. But thats the only bad use case I can think of. Maybe
something as simple as a flag on the move operation saying "in the
case of conflicts, rewrite the destination key to {key}_n". Or we
could just force the IDE to use a list of files, and leave deduping
hacks there.

-J



On Sat, Oct 18, 2014 at 4:44 PM, Ali Lown <a...@lown.me.uk> wrote:
> Hi Joseph,
>
> I think that the only sensible option is to delegate the resolution of
> this action in the case of conflict back into the application, so some
> sort of extension of (4) that allows some arbitrary lambda expression
> to be passed as the onconflict method. (Depending on the situation,
> they might want to 'merge' the two items (if possible), rather than
> moving one into a 'backup' location).
>
> This does complicate the OT type, and does make it more difficult to
> analyse how long certain actions will take to resolve though...
>
> How does this sound?
>
> Ali
>
> On 19 October 2014 00:33, Joseph Gentle <jose...@gmail.com> wrote:
>> I'm (finally!) taking a serious look at making a better version of the
>> JSON OT type. I'm cross-posting this here because it directly effects
>> sharejs & derby users, and I think any serious rewrite of wave will
>> use something like this at the top level to store waves.
>>
>> I have two questions that I would love some input on from the wider 
>> community.
>>
>> We want to add a 'move' action which will let you transplant arbitrary
>> parts of the JSON structure to other places in the tree. This is
>> really useful if, for example, you want a hierarchal to-do list, a
>> tree of source files for your IDE or a tree of blips.
>>
>> But I can't figure out what should happen if two users move different
>> objects to the same place in the tree at the same time.
>>
>> 1. The simplest option is to simply delete one of them. This is really
>> convenient from a programming pov, but I think that would be the worst
>> kind of surprise. {x:1, y:2} -> {z:2}
>> 2. We could try and make one of the moves fail - {x:1, y:2} -> {x:1,
>> z:2}. On the face of it this sounds great, but this is a cascading
>> failure. If (locally) I move x->z then insert some new data at x, what
>> happens to the new data? Does the new data get deleted? Does x get
>> deleted? I can't think of a good answer here which isn't just
>> dangerous in a more complicated way. Making both the moves fail has
>> the same problem.
>> 3. We could pick a winner and then move the loser to some special
>> lost&found bucket or something. So, {x:1, y:2} -> {__recovered_z:1,
>> z:2} But that could play havoc with data bindings, and we'd have to
>> introduce some reserved keys. The other way to do this is to introduce
>> a new top-level structure which contains the data, so it'd be
>> {data:{x:1, y:2}} -> {data:{z:2}, lost:[{z:1}]}.
>> 4. Or we could add the backup location into the move operation itself,
>> so whoever's building on top of this API can make the choice. (They
>> can make a better decision because they know what the data structure
>> looks like). So instead of (move x->z) we'd have (move x->z,
>> onconflict:(move x->__x)) or something.
>>
>> Are there any other choices I'm missing here? I'm edging toward option
>> 4, although it might increase the type's complexity by 50% unless I
>> can think of a clean way to do it.
>>
>> Thanks
>> -J

Reply via email to