anchor.diff:        ).then((_) => _release_locks()).then((_) => nextVersion);
     }
   
  +  Future writeOperation(String _id, String author, String action, Map newData,
  +                        {upsert: false}) {
  +    cache.invalidate();
  +    num nextVersion;
  +    return _get_locks().then((_) => collection.findOne({"_id" : _id}))
  +      .then((Map oldData) {
  +
  +        if (oldData == null) oldData = {};
  +        // check that current db state is consistent with required action
  +        var inferredAction;
  +        if (oldData.isNotEmpty && newData.isEmpty) inferredAction = 'remove';
  +        else if (oldData.isEmpty && newData.isNotEmpty) inferredAction = 'add';
  +        else if (oldData.isNotEmpty && newData.isNotEmpty) inferredAction = 'change';
  +        else throw true;
  +
  +        if (action != inferredAction) {
  +          if (!(action == 'change' &&
  +                inferredAction == 'add' &&
  +                upsert == true))
  +            throw true;
  +        }
  +
  +        if (!newData.isEmpty && newData['_id'] != _id) {
  +          throw new MongoException(null,
  +              'New document id ${newData['_id']} should be same as old one $_id.');
  +        } else {
  +          return _maxVersion.then((version) {
  +            nextVersion = version + 1;
  +            if (inferredAction == 'remove' ){
  +              return collection.remove({'_id': _id});
  +            } else {
  +              newData[VERSION_FIELD_NAME] = nextVersion;
  +              if (inferredAction == 'add') {
  +                return collection.insert(newData);
  +              } else {
  +                return collection.save(newData);
  +              }
  +            }
  +          }).then((_) =>
  +            _collectionHistory.insert({
  +              "before" : oldData,
  +              "after" : newData,
  +              "action" : inferredAction,
  +              "author" : author,
  +              "version" : nextVersion
  +            }));
  +        }
  +      }).then((_) => _release_locks()).then((_) => nextVersion)
  +      .catchError((e) => _release_locks().then((_) {
  +        if (e is! Exception){
  +          return e;
  +        } else {
  +          throw e;
  +        }
  +      }));
  +  }
  +
  +  Future change(String _id, Map newData, String author, {upsert: false}) {
  +    return writeOperation(_id, author, 'change', newData, upsert: upsert);
  +  }
  +
  +  Future add(Map data, String author) {
  +    return writeOperation(data['_id'], author, 'add', data);
  +  }
  +
  +  Future remove(String _id, String author) {
  +    return writeOperation(_id, author, 'remove', {});
  +  }
  +
  +  //TODO:
  +  //findOne, depr_change, map
  +
     /**
      * Changes document with id [_id] to [newData]. If such document does not
      * exist, nothing happens and [true] is returned.
      */
  -  Future change(String _id, Map newData, String author) {
  +  Future __change(String _id, Map newData, String author) {
       cache.invalidate();
       num nextVersion;
       Map newRecord;
  
positive.code:               return _limitedDiffFromVersion(diff);
              }
  
              return pretify(diff);
      }).catchError((e){
       if (e is List) {
         return e;
  
negative.code:       ).then((_) => _release_locks()).then((_) => nextVersion);
    }
  
    Future<Map> diffFromVersion(num version) {
      return cache.putIfAbsent('version ${collection.collectionName}', () => _maxVersion)
        .then((maxVer) {
  