Repository navigation
Description
I'm trying to save a Buffer as a property. From what I can see this should be possibe. In this example the Buffer contains 21 bytes:
dataset.save({
key: dataset.key('Location'),
data: {
id: '113-16',
geometry: new Buffer('010100000000000000000059400000000000006940', 'hex')
}
}, function (err, key) {
console.log(err || key);
});
However when I retrieve the entity I get a Buffer with zero length.
dataset.get(dataset.key([ 'Location', 5707702298738688 ]), function (err, entity) {
console.log(err || entity.data.geometry.length);
});
In your lib/datastore/entity.js, function propertyToValue at line 362 you're creating a Buffer with the property.blob_value as base64:
if (exists(property.blob_value)) {
return new Buffer(property.blob_value, 'base64');
}
When I debugged at this point I found that property.blob_value was a ByteBufferNB object, not a base64 string. I'm wondering if you meant to base64 encode the original value in function valueToProperty at line 430:
if (v instanceof Buffer) {
p.blob_value = v; // should it be v.toString('base64') ?
return p;
}
But that doesn't make sense since the datastore_v1.proto file defines blob_value as bytes not string at line 111:
optional string blob_key_value = 16;
I suppose I could simply store my data directly as a base64-encoded string. But I'd prefer the compactness and efficiency of binary storage if possible.
Activity
ryanseys commentedon Nov 16, 2014
I can reproduce this issue. It appears that the
property.blob_valueis for some reason the entire ByteBuffer object for the entire response. When I decoded the protobuf response and looked for the geometry value, it's set to:This is what
propertyToValuealso sees.property.blob_value instanceof ByteBufferis true in this case.In fact, if you print out the hex value for the entire ByteBuffer, you can see your data is in tact:
Output:
That
010100000000000000000059400000000000006940at the end is your location.But then things get really weird when you decode the original response buffer.
In
datastore/lib/request.js#makeAuthorizedRequest, we get abuffer. We then decode it usingpbResponse.decode(buffer)and get a nice decoded object we can traverse in javascript.If we set that decoded to
var decoded = pbResponse.decode(buffer);and then traverse to the geometry valuedecoded.found[0].entity.property[1].value.blob_valuewe get an ByteBuffer object much like the one at the top of this post. In fact, if we get thebufferproperty in that object, that isdecoded.found[0].entity.property[1].value.blob_value.bufferand compare it to our ORIGINALbufferwe got fresh from the server, they are exactly the same. That is, the decoded buffer contains the original buffer. Recursion is awesome!I don't know enough about protobufs to fix this issue or even to say this is right or wrong but it's blowing my mind. From first glance, it looks like a bug in the protobuf.js library but a second opinion would be great.
pgirard commentedon Nov 16, 2014
Wow, nice job digging into this. Thanks! My whole experience with protocol buffers extends back to just last Wednesday so consider me an interested bystander for now.
ryanseys commentedon Nov 16, 2014
I figured it out! As you can see in the ByteBuffer object above, it has an offset and a limit. So we just need to use that to return the bytes you want! Luckily, ByteBuffer objects have a method to do just that, and viola, a one-line fix :) See 2d76a12
pgirard commentedon Nov 17, 2014
Awesome, thanks so much! Got to love one-line fixes.
build: set AUTOSYNTH_MULTIPLE_COMMITS=true for context aware commits (#…
chore(deps): update dependency @types/sinon to v9 (#301)
chore: release 2.0.0 (#301)
fix(deps): update dependency @google-cloud/common to v3 (#301)
25 remaining items
Release v3.0.1 (#301)
chore(main): release 3.0.0 (#301)
fix(build): fix Kokoro release script (#301)
chore(deps): update dependency eslint-plugin-node to v9 (#301)
Release v3.0.1 (#301)
build: check for 404s when generating docs (#301)
Release v3.0.1 (#301)
build: check for 404s when generating docs (#301)
chore(deps): update dependency @types/node to v18 (#301)
build: check for 404s when generating docs (#301)
Release nodejs-spanner v2.0.0 (#301)
chore(deps): update dependency bignumber.js to v8 (#301)
chore(main): release 3.0.0 (#301)
chore(main): release 3.0.0 (#301)
chore(deps): upgrade @google-cloud/projectify to v0.3.2 (#301)