datastore: commit transactions after queueing modifications

### Do not merge

- [ ] Unit test `commit`
- [ ] Confirm docs build correctly

RE: #300

With this PR, Transaction overrides `save` and `delete`. It wraps the underlying methods, `DatastoreRequest.save` and `DatastoreRequest.delete`, so that we can track what entities are going to be queued for modification when the `done()` callback from a transaction is executed.

As decided in #300, the last modification wins. There are two regression tests that confirm this behavior with a delete before a save and a save before a delete to confirm they are handled properly.

This also makes a big change to how `.save` works. Currently, the callback provided to `save` will receive the same keys it passed in, with any incomplete keys now being made complete. I never found this very practical, as keeping track of the index of my key when I pass it in to then access it again from the callback is unnecessary when I could instead just have one Key object reference that is automatically updated for me.

```js
// Previously

var completeKey = dataset.key(['Company', 'Google']);
var incompleteKey = dataset.key('Company');

dataset.save([
  { key: completeKey, data: {} },
  { key: incompleteKey, data: {} }
], function (err, keys) {
  keys[0] === completeKey // true
  keys[1] === incompleteKey // false
});

// With this PR

dataset.save([
  { key: completeKey, data: {} },
  { key: incompleteKey, data: {} }
], function (err) {
  // incompleteKey has now been given a path with an ID
});
```

As always, (well, most of the time), I tried to leave comments where things could be hard to follow. Even still, if I failed to make things understandable, please just let me know and I will try to correct that.
Even it if is, it's definitely not being converted to -1, which is the less than case. We have to consider that case. You can see for small arrays (length <= 10) we won't see the issue, because it uses insertion sort which never looks for negative values. But larger arrays use quick sort and that's when such a differentiation matters.

Example for proof:
``` js
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].sort(function(a, b) { return a < b })
returns [10, 9, 8, 7, 6, 5, 4, 3, 2, 1 ] (good)

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].sort(function(a, b) { return a < b })
returns [ 7, 12, 11, 10, 9, 8, 6, 5, 4, 3, 2, 1 ] (not so good)
```