Design Question/Request: Why do .set() and .add() return OperationResult instead of ValueResult?

Gentlefolk,

When I .get() something from the server I get a ValueResult object. It contains three key items that I will frequently need together: key, value and cas. When I do a .set() or .add(), the client library returns me an OperationResult that only has key and cas.

It would simplify my code if .add() and .set() returned on success a ValueResult with the value property set to the value we just sent to the server. Or, at least, return me a ValueResult object and let me put the value in the property. Otherwise I have to create a property only class or use a cumbersome dictionary. Neither of which are as nice as just being able to get the value out of the .add() or .set() result.

Thank you for considering this request.

Anon,
Andrew

1 Answer

« Back to question.

The Result objects and subclasses contain only the information received from the server wrapped up in a nice object. They are very lightweight objects implemented in pure C, and as such cannot contain extra fields.

For a set and add operation, we naturally don't receive the value we just stored from the server (as it's assumed the actual value is still present) and therefore it would be a performance hit to store the extra data. Consider if the value was particularly large, it would be a significant hit.

Furthermore, the Result object is created only after we receive the result from the server. For a set or add operation, the client at this stage does not keep track of the value in any form.

Would it not be simpler to just make your own application-level object (such as a namedtuple) to set the fields you need?

Mark,

Thank you for replying.

Your answer is what I expected and is a fine answer. My point is that an API is the programmer's user interface to your system. It should make common patterns trivial and complex patterns possible. (Let's also be cognizant of the fact that I am also new to Python and am probably not aware of programming conventions in your world.) For instance, here's my code to get a tweet in my "learn Couchbase" project. It tries to get a tweet and, if it isn't available, create it, a check before create pattern:

def get_status(tw_status):
 
    id_str = tw_status.get('id_str')
 
    if id_str:
 
        key = 'st:' + id_str
 
        result = cb.get(key, quiet=True)
 
        if result.success:
 
            return result
 
        value = {'tw_status': tw_status}
 
        try:
 
            result = cb.add(key, value)
 
            if result.success:
 
                return CBResult(result.key, value, result.cas)
 
        except TemporaryFailError as temp_fail_exception:
 
            return get_status(tw_status)
 
    return None

To do this, I've created a boilerplate class, CBResult, that has a similar interface to your ValueResult. Having a custom property-only class is code noise. There is a fundamental triple tuple for a Couchbase document: key, value and cas. As the cas is critical for trying to write an optimistic locking app for idempotent retries, the API should make it easy for the programmer to maintain this triple at all times. If a get() returns something, then a set()/add()/replace() should return a similar item representing the document.

What should happen in the case of an add_multi(), etc. is up to you but you do have all of the data needed to maintain the triple.

Anon,
Andrew