Skip to content

Commit 0f68ccd

Browse files
feat(datastore): support setting a property indexed value
By default, property index values are set to `true`, without allowing the user to specify an override. Now, when a user passes in an array to `dataset.save`, they will have the option of setting `true` or `false`. Example: dataset.save({ key: dataset.key('Company'), data: [ name: 'propertyName', value: 'any value type', indexed: false ] }, function(err, keys) {}). Resolves: googleapis#208 Related: http://goo.gl/tKVvhP
1 parent 9f45035 commit 0f68ccd

File tree

5 files changed

+278
-89
lines changed

5 files changed

+278
-89
lines changed

lib/datastore/dataset.js

+27-4
Original file line numberDiff line numberDiff line change
@@ -187,15 +187,25 @@ Dataset.prototype.get = function(key, callback) {
187187
};
188188

189189
/**
190-
* Insert or update the specified object(s) in the current transaction. If a
191-
* key is incomplete, its associated object is inserted and its generated
192-
* identifier is returned to the callback.
190+
* Insert or update the specified object(s) in the current transaction. If a key
191+
* is incomplete, its associated object is inserted and its generated identifier
192+
* is returned to the callback.
193+
*
194+
* This method automatically handles the `upsert`, `insert`, `update`, and
195+
* `insertAutoId` Datastore methods.
196+
*
197+
* By default, properties are set with an `indexed` value of `true`. To override
198+
* this, you must supply an entity's `data` property as an array. See below for
199+
* an example.
193200
*
194201
* @borrows {module:datastore/transaction#save} as save
195202
*
196203
* @param {object|object[]} entities - Datastore key object(s).
197204
* @param {Key} entities.key - Datastore key object.
198-
* @param {object} entities.data - Data to save with the provided key.
205+
* @param {object|object[]} entities.data - Data to save with the provided key.
206+
* If you provide an array of objects, you must use the explicit syntax:
207+
* `name` for the name of the property and `value` for its value. You may
208+
* also specify an `indexed` property, set to `true` or `false`.
199209
* @param {function} callback - The callback function.
200210
*
201211
* @example
@@ -210,6 +220,19 @@ Dataset.prototype.get = function(key, callback) {
210220
* // populated with the complete, generated key.
211221
* });
212222
*
223+
* // To specify an `indexed` value for a Datastore entity, pass in an array for
224+
* // the key's data. The above example would then look like:
225+
* transaction.save({
226+
* key: dataset.key('Company'),
227+
* data: [
228+
* {
229+
* name: 'rating',
230+
* value: '10',
231+
* indexed: false
232+
* }
233+
* ]
234+
* }, function(err, key) {});
235+
*
213236
* // Save multiple entities at once.
214237
* dataset.save([
215238
* {

lib/datastore/entity.js

+16-12
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,7 @@
2121

2222
'use strict';
2323

24-
/**
25-
* @type {object}
26-
*/
24+
/** @type {object} */
2725
var entityMeta = {};
2826

2927
/** @const {regexp} Regular expression to verify a field name. */
@@ -457,6 +455,8 @@ function valueToProperty(v) {
457455
throw new Error('Unsupported field value, ' + v + ', is provided.');
458456
}
459457

458+
module.exports.valueToProperty = valueToProperty;
459+
460460
/**
461461
* Convert an entity object to an entity protocol object.
462462
*
@@ -465,19 +465,23 @@ function valueToProperty(v) {
465465
*
466466
* @example
467467
* entityToEntityProto({
468-
* {
469-
* name: 'Burcu',
470-
* legit: true
471-
* }
468+
* name: 'Burcu',
469+
* legit: true
472470
* });
473471
* // {
474472
* // key: null,
475-
* // properties: {
476-
* // name: {
477-
* // stringValue: 'Burcu'
473+
* // property: [
474+
* // {
475+
* // name: 'name',
476+
* // value: {
477+
* // string_value: 'Burcu'
478+
* // }
478479
* // },
479-
* // legit: {
480-
* // booleanValue: true
480+
* // {
481+
* // name: 'legit',
482+
* // value: {
483+
* // boolean_value: true
484+
* // }
481485
* // }
482486
* // }
483487
* // }

lib/datastore/transaction.js

+40-5
Original file line numberDiff line numberDiff line change
@@ -241,13 +241,23 @@ Transaction.prototype.get = function(keys, callback) {
241241
};
242242

243243
/**
244-
* Insert or update the specified object(s) in the current transaction. If a
245-
* key is incomplete, its associated object is inserted and its generated
246-
* identifier is returned to the callback.
244+
* Insert or update the specified object(s) in the current transaction. If a key
245+
* is incomplete, its associated object is inserted and its generated identifier
246+
* is returned to the callback.
247+
*
248+
* This method automatically handles the `upsert`, `insert`, `update`, and
249+
* `insertAutoId` Datastore methods.
250+
*
251+
* By default, properties are set with an `indexed` value of `true`. To override
252+
* this, you must supply an entity's `data` property as an array. See below for
253+
* an example.
247254
*
248255
* @param {object|object[]} entities - Datastore key object(s).
249256
* @param {Key} entities.key - Datastore key object.
250-
* @param {object} entities.data - Data to save with the provided key.
257+
* @param {object|object[]} entities.data - Data to save with the provided key.
258+
* If you provide an array of objects, you must use the explicit syntax:
259+
* `name` for the name of the property and `value` for its value. You may
260+
* also specify an `indexed` property, set to `true` or `false`.
251261
* @param {function} callback - The callback function.
252262
*
253263
* @example
@@ -264,6 +274,19 @@ Transaction.prototype.get = function(keys, callback) {
264274
* // populated with the complete, generated key.
265275
* });
266276
*
277+
* // To specify an `indexed` value for a Datastore entity, pass in an array for
278+
* // the key's data. The above example would then look like:
279+
* transaction.save({
280+
* key: dataset.key('Company'),
281+
* data: [
282+
* {
283+
* name: 'rating',
284+
* value: '10',
285+
* indexed: false
286+
* }
287+
* ]
288+
* }, function(err, key) {});
289+
*
267290
* // Save multiple entities at once.
268291
* transaction.save([
269292
* {
@@ -290,7 +313,19 @@ Transaction.prototype.save = function(entities, callback) {
290313
var req = {
291314
mode: MODE_NON_TRANSACTIONAL,
292315
mutation: entities.reduce(function(acc, entityObject, index) {
293-
var ent = entity.entityToEntityProto(entityObject.data);
316+
var ent = {};
317+
if (Array.isArray(entityObject.data)) {
318+
ent.property = entityObject.data.map(function(data) {
319+
data.value = entity.valueToProperty(data.value);
320+
if (util.is(data.indexed, 'boolean')) {
321+
data.value.indexed = data.indexed;
322+
delete data.indexed;
323+
}
324+
return data;
325+
});
326+
} else {
327+
ent = entity.entityToEntityProto(entityObject.data);
328+
}
294329
ent.key = entity.keyToKeyProto(entityObject.key);
295330
if (entity.isKeyComplete(entityObject.key)) {
296331
acc.upsert.push(ent);

test/datastore/entity.js

+119-32
Original file line numberDiff line numberDiff line change
@@ -304,39 +304,22 @@ describe('entityFromEntityProto', function() {
304304
});
305305

306306
describe('entityToEntityProto', function() {
307-
it('should support bool, int, double, str, entity & list values', function() {
308-
var now = new Date();
309-
var proto = entity.entityToEntityProto({
310-
name: 'Burcu',
311-
desc: 'Description',
312-
count: new entity.Int(6),
313-
primitiveCount: 6,
314-
legit: true,
315-
date : now,
316-
bytes: new Buffer('Hello'),
317-
list: ['a', new entity.Double(54.7)],
318-
metadata: {
319-
key1: 'value1',
320-
key2: 'value2'
321-
}
307+
it('should format an entity', function() {
308+
var val = entity.entityToEntityProto({
309+
name: 'name'
322310
});
323-
var properties = proto.property;
324-
assert.equal(properties[0].value.string_value, 'Burcu');
325-
assert.equal(properties[1].value.string_value, 'Description');
326-
assert.equal(properties[2].value.integer_value, 6);
327-
assert.equal(properties[3].value.integer_value, 6);
328-
assert.equal(properties[4].value.boolean_value, true);
329-
assert.equal(
330-
properties[5].value.timestamp_microseconds_value, now.getTime() * 1000);
331-
assert.deepEqual(properties[6].value.blob_value, new Buffer('Hello'));
332-
333-
var listValue = properties[7].value.list_value;
334-
assert.equal(listValue[0].string_value, 'a');
335-
assert.equal(listValue[1].double_value, 54.7);
336-
337-
var entityValue = properties[8].value.entity_value;
338-
assert.equal(entityValue.property[0].value.string_value, 'value1');
339-
assert.equal(entityValue.property[1].value.string_value, 'value2');
311+
var expected = {
312+
key: null,
313+
property: [
314+
{
315+
name: 'name',
316+
value: {
317+
string_value: 'name'
318+
}
319+
}
320+
]
321+
};
322+
assert.deepEqual(val, expected);
340323
});
341324
});
342325

@@ -350,3 +333,107 @@ describe('queryToQueryProto', function() {
350333
assert.deepEqual(proto, queryFilterProto);
351334
});
352335
});
336+
337+
describe('valueToProperty', function() {
338+
it('should translate a boolean', function() {
339+
var val = entity.valueToProperty(true);
340+
assert.deepEqual(val, {
341+
boolean_value: true
342+
});
343+
});
344+
345+
it('should translate an int', function() {
346+
var val1 = entity.valueToProperty(new entity.Int(3));
347+
var val2 = entity.valueToProperty(3);
348+
var expected = { integer_value: 3 };
349+
assert.deepEqual(val1, expected);
350+
assert.deepEqual(val2, expected);
351+
});
352+
353+
it('should translate a double', function() {
354+
var val1 = entity.valueToProperty(new entity.Double(3.1));
355+
var val2 = entity.valueToProperty(3.1);
356+
var expected = { double_value: 3.1 };
357+
assert.deepEqual(val1, expected);
358+
assert.deepEqual(val2, expected);
359+
});
360+
361+
it('should translate a date', function() {
362+
var date = new Date();
363+
var val = entity.valueToProperty(date);
364+
var expected = {
365+
timestamp_microseconds_value: date.getTime() * 1000
366+
};
367+
assert.deepEqual(val, expected);
368+
});
369+
370+
it('should translate a string', function() {
371+
var val = entity.valueToProperty('Hi');
372+
var expected = {
373+
string_value: 'Hi'
374+
};
375+
assert.deepEqual(val, expected);
376+
});
377+
378+
it('should translate a buffer', function() {
379+
var buffer = new Buffer('Hi');
380+
var val = entity.valueToProperty(buffer);
381+
var expected = {
382+
blob_value: buffer
383+
};
384+
assert.deepEqual(val, expected);
385+
});
386+
387+
it('should translate an array', function() {
388+
var array = [1, '2', true];
389+
var val = entity.valueToProperty(array);
390+
var expected = {
391+
list_value: [
392+
{ integer_value: 1 },
393+
{ string_value: '2' },
394+
{ boolean_value: true }
395+
]
396+
};
397+
assert.deepEqual(val, expected);
398+
});
399+
400+
it('should translate a Key', function() {
401+
var key = new entity.Key({
402+
namespace: 'ns',
403+
path: ['Kind', 3]
404+
});
405+
var val = entity.valueToProperty(key);
406+
var expected = {
407+
key_value: entity.keyToKeyProto(key)
408+
};
409+
assert.deepEqual(val, expected);
410+
});
411+
412+
describe('objects', function() {
413+
it('should translate an object', function() {
414+
var val = entity.valueToProperty({
415+
name: 'value'
416+
});
417+
var expected = {
418+
entity_value: {
419+
property: [
420+
{
421+
name: 'name',
422+
value: {
423+
string_value: 'value',
424+
}
425+
}
426+
]
427+
},
428+
indexed: false
429+
};
430+
assert.deepEqual(val, expected);
431+
});
432+
433+
it('should not translate a key-less object', function() {
434+
assert.throws(function() {
435+
entity.valueToProperty({});
436+
}, /Unsupported field value/);
437+
});
438+
});
439+
});

0 commit comments

Comments
 (0)