Index: lib/src/datastore_impl.dart |
diff --git a/lib/src/datastore_impl.dart b/lib/src/datastore_impl.dart |
index 9229a36fbce4dc13016170ef019f2f4ee9252bc2..edb7e7a5eb2a146cc0141d344c4a0498cccb1459 100644 |
--- a/lib/src/datastore_impl.dart |
+++ b/lib/src/datastore_impl.dart |
@@ -10,7 +10,7 @@ import 'package:http/http.dart' as http; |
import '../datastore.dart' as datastore; |
import '../common.dart' show Page; |
-import 'package:googleapis_beta/datastore/v1beta2.dart' as api; |
+import 'package:googleapis/datastore/v1.dart' as api; |
class TransactionImpl implements datastore.Transaction { |
final String data; |
@@ -20,24 +20,26 @@ class TransactionImpl implements datastore.Transaction { |
class DatastoreImpl implements datastore.Datastore { |
static const List<String> SCOPES = const <String>[ |
api.DatastoreApi.DatastoreScope, |
- api.DatastoreApi.UserinfoEmailScope, |
+ api.DatastoreApi.CloudPlatformScope, |
]; |
final api.DatastoreApi _api; |
final String _project; |
- DatastoreImpl(http.Client client, this._project) |
- : _api = new api.DatastoreApi(client); |
+ /// The [project] parameter is the name of the cloud project (it should not |
+ /// start with a `s~`). |
+ DatastoreImpl(http.Client client, String project) |
+ : _api = new api.DatastoreApi(client), _project = project; |
api.Key _convertDatastore2ApiKey(datastore.Key key, {bool enforceId: true}) { |
var apiKey = new api.Key(); |
apiKey.partitionId = new api.PartitionId() |
- ..datasetId = _project |
- ..namespace = key.partition.namespace; |
+ ..projectId = _project |
+ ..namespaceId = key.partition.namespace; |
apiKey.path = key.elements.map((datastore.KeyElement element) { |
- var part = new api.KeyPathElement(); |
+ var part = new api.PathElement(); |
part.kind = element.kind; |
if (element.id is int) { |
part.id = '${element.id}'; |
@@ -55,7 +57,7 @@ class DatastoreImpl implements datastore.Datastore { |
} |
static datastore.Key _convertApi2DatastoreKey(api.Key key) { |
- var elements = key.path.map((api.KeyPathElement element) { |
+ var elements = key.path.map((api.PathElement element) { |
if (element.id != null) { |
return new datastore.KeyElement(element.kind, int.parse(element.id)); |
} else if (element.name != null) { |
@@ -68,7 +70,7 @@ class DatastoreImpl implements datastore.Datastore { |
var partition; |
if (key.partitionId != null) { |
- partition = new datastore.Partition(key.partitionId.namespace); |
+ partition = new datastore.Partition(key.partitionId.namespaceId); |
// TODO: assert projectId. |
} |
return new datastore.Key(elements, partition: partition); |
@@ -80,8 +82,8 @@ class DatastoreImpl implements datastore.Datastore { |
// FIXME(Issue #2): Is this comparison working correctly? |
if (a.partitionId != null) { |
if (b.partitionId == null) return false; |
- if (a.partitionId.datasetId != b.partitionId.datasetId) return false; |
- if (a.partitionId.namespace != b.partitionId.namespace) return false; |
+ if (a.partitionId.projectId != b.partitionId.projectId) return false; |
+ if (a.partitionId.namespaceId != b.partitionId.namespaceId) return false; |
} else { |
if (b.partitionId != null) return false; |
} |
@@ -94,37 +96,13 @@ class DatastoreImpl implements datastore.Datastore { |
return true; |
} |
- static _convertApi2DatastorePropertyValue(api.Value value) { |
- if (value.booleanValue != null) |
- return value.booleanValue; |
- else if (value.integerValue != null) |
- return int.parse(value.integerValue); |
- else if (value.doubleValue != null) |
- return value.doubleValue; |
- else if (value.stringValue != null) |
- return value.stringValue; |
- else if (value.dateTimeValue != null) |
- return value.dateTimeValue; |
- else if (value.blobValue != null) |
- return new datastore.BlobValue(value.blobValueAsBytes); |
- else if (value.keyValue != null) |
- return _convertApi2DatastoreKey(value.keyValue); |
- else if (value.listValue != null) |
- // FIXME(Issue #3): Consistently handle exceptions. |
- throw new Exception('Cannot have lists inside lists.'); |
- else if (value.blobKeyValue != null) |
- throw new UnsupportedError('Blob keys are not supported.'); |
- else if (value.entityValue != null) |
- throw new UnsupportedError('Entity values are not supported.'); |
- return null; |
- } |
- |
api.Value _convertDatastore2ApiPropertyValue( |
value, bool indexed, {bool lists: true}) { |
var apiValue = new api.Value() |
- ..indexed = indexed; |
+ ..excludeFromIndexes = !indexed; |
if (value == null) { |
- return apiValue; |
+ return apiValue |
+ ..nullValue = "NULL_VALUE"; |
} else if (value is bool) { |
return apiValue |
..booleanValue = value; |
@@ -139,7 +117,7 @@ class DatastoreImpl implements datastore.Datastore { |
..stringValue = value; |
} else if (value is DateTime) { |
return apiValue |
- ..dateTimeValue = value; |
+ ..timestampValue = value.toIso8601String(); |
} else if (value is datastore.BlobValue) { |
return apiValue |
..blobValueAsBytes = value.bytes; |
@@ -155,106 +133,49 @@ class DatastoreImpl implements datastore.Datastore { |
convertItem(i) |
=> _convertDatastore2ApiPropertyValue(i, indexed, lists: false); |
- return new api.Value() |
- ..listValue = value.map(convertItem).toList(); |
+ return new api.Value()..arrayValue = ( |
+ new api.ArrayValue()..values = value.map(convertItem).toList()); |
} else { |
throw new UnsupportedError( |
'Types ${value.runtimeType} cannot be used for serializing.'); |
} |
} |
- static _convertApi2DatastoreProperty(api.Property property) { |
- if (property.booleanValue != null) |
- return property.booleanValue; |
- else if (property.integerValue != null) |
- return int.parse(property.integerValue); |
- else if (property.doubleValue != null) |
- return property.doubleValue; |
- else if (property.stringValue != null) |
- return property.stringValue; |
- else if (property.dateTimeValue != null) |
- return property.dateTimeValue; |
- else if (property.blobValue != null) |
- return new datastore.BlobValue(property.blobValueAsBytes); |
- else if (property.keyValue != null) |
- return _convertApi2DatastoreKey(property.keyValue); |
- else if (property.listValue != null) |
- return |
- property.listValue.map(_convertApi2DatastorePropertyValue).toList(); |
- else if (property.blobKeyValue != null) |
- throw new UnsupportedError('Blob keys are not supported.'); |
- else if (property.entityValue != null) |
+ static dynamic _convertApi2DatastoreProperty(api.Value value) { |
+ if (value.booleanValue != null) |
+ return value.booleanValue; |
+ else if (value.integerValue != null) |
+ return int.parse(value.integerValue); |
+ else if (value.doubleValue != null) |
+ return value.doubleValue; |
+ else if (value.stringValue != null) |
+ return value.stringValue; |
+ else if (value.timestampValue != null) |
+ return DateTime.parse(value.timestampValue); |
+ else if (value.blobValue != null) |
+ return new datastore.BlobValue(value.blobValueAsBytes); |
+ else if (value.keyValue != null) |
+ return _convertApi2DatastoreKey(value.keyValue); |
+ else if (value.arrayValue != null && value.arrayValue.values != null) |
+ return value |
+ .arrayValue.values.map(_convertApi2DatastoreProperty).toList(); |
+ else if (value.entityValue != null) |
throw new UnsupportedError('Entity values are not supported.'); |
+ else if (value.geoPointValue != null) |
+ throw new UnsupportedError('GeoPoint values are not supported.'); |
return null; |
} |
- api.Property _convertDatastore2ApiProperty( |
- value, bool indexed, {bool lists: true}) { |
- var apiProperty = new api.Property() |
- ..indexed = indexed; |
- if (value == null) { |
- return null; |
- } else if (value is bool) { |
- return apiProperty |
- ..booleanValue = value; |
- } else if (value is int) { |
- return apiProperty |
- ..integerValue = '$value'; |
- } else if (value is double) { |
- return apiProperty |
- ..doubleValue = value; |
- } else if (value is String) { |
- return apiProperty |
- ..stringValue = value; |
- } else if (value is DateTime) { |
- return apiProperty |
- ..dateTimeValue = value; |
- } else if (value is datastore.BlobValue) { |
- return apiProperty |
- ..blobValueAsBytes = value.bytes; |
- } else if (value is datastore.Key) { |
- return apiProperty |
- ..keyValue = _convertDatastore2ApiKey(value, enforceId: false); |
- } else if (value is List) { |
- if (!lists) { |
- // FIXME(Issue #3): Consistently handle exceptions. |
- throw new Exception('List values are not allowed.'); |
- } |
- convertItem(i) |
- => _convertDatastore2ApiPropertyValue(i, indexed, lists: false); |
- return new api.Property()..listValue = value.map(convertItem).toList(); |
- } else { |
- throw new UnsupportedError( |
- 'Types ${value.runtimeType} cannot be used for serializing.'); |
- } |
- } |
- |
static datastore.Entity _convertApi2DatastoreEntity(api.Entity entity) { |
var unindexedProperties = new Set(); |
var properties = {}; |
if (entity.properties != null) { |
- entity.properties.forEach((String name, api.Property property) { |
- properties[name] = _convertApi2DatastoreProperty(property); |
- if (property.indexed == false) { |
- // TODO(Issue #$4): Should we support mixed indexed/non-indexed list |
- // values? |
- if (property.listValue != null) { |
- if (property.listValue.length > 0) { |
- var firstIndexed = property.listValue.first.indexed; |
- for (int i = 1; i < property.listValue.length; i++) { |
- if (property.listValue[i].indexed != firstIndexed) { |
- throw new Exception('Some list entries are indexed and some ' |
- 'are not. This is currently not supported.'); |
- } |
- } |
- if (firstIndexed == false) { |
- unindexedProperties.add(name); |
- } |
- } |
- } else { |
- unindexedProperties.add(name); |
- } |
+ entity.properties.forEach((String name, api.Value value) { |
+ properties[name] = _convertApi2DatastoreProperty(value); |
+ if (value.excludeFromIndexes != null && |
+ value.excludeFromIndexes) { |
+ unindexedProperties.add(name); |
} |
}); |
} |
@@ -303,7 +224,7 @@ class DatastoreImpl implements datastore.Datastore { |
if (operator == null) { |
throw new ArgumentError('Unknown filter relation: ${filter.relation}.'); |
} |
- pf.operator = operator; |
+ pf.op = operator; |
pf.property = new api.PropertyReference()..name = filter.name; |
// FIXME(Issue #5): Is this OK? |
@@ -322,7 +243,7 @@ class DatastoreImpl implements datastore.Datastore { |
api.Filter _convertDatastoreAncestorKey2ApiFilter(datastore.Key key) { |
var pf = new api.PropertyFilter(); |
- pf.operator = 'HAS_ANCESTOR'; |
+ pf.op = 'HAS_ANCESTOR'; |
pf.property = new api.PropertyReference()..name = '__key__'; |
pf.value = new api.Value() |
..keyValue = _convertDatastore2ApiKey(key, enforceId: true); |
@@ -347,7 +268,7 @@ class DatastoreImpl implements datastore.Datastore { |
compFilter.filters.add(filter); |
} |
} |
- compFilter.operator = 'AND'; |
+ compFilter.op = 'AND'; |
return new api.Filter()..compositeFilter = compFilter; |
} |
@@ -389,7 +310,7 @@ class DatastoreImpl implements datastore.Datastore { |
request..keys = keys.map((key) { |
return _convertDatastore2ApiKey(key, enforceId: false); |
}).toList(); |
- return _api.datasets.allocateIds(request, _project).then((response) { |
+ return _api.projects.allocateIds(request, _project).then((response) { |
return response.keys.map(_convertApi2DatastoreKey).toList(); |
}, onError: _handleError); |
} |
@@ -397,9 +318,7 @@ class DatastoreImpl implements datastore.Datastore { |
Future<datastore.Transaction> beginTransaction( |
{bool crossEntityGroup: false}) { |
var request = new api.BeginTransactionRequest(); |
- // TODO: Should this be made configurable? |
- request.isolationLevel = 'SERIALIZABLE'; |
- return _api.datasets.beginTransaction(request, _project).then((result) { |
+ return _api.projects.beginTransaction(request, _project).then((result) { |
return new TransactionImpl(result.transaction); |
}, onError: _handleError); |
} |
@@ -417,34 +336,42 @@ class DatastoreImpl implements datastore.Datastore { |
request.mode = 'NON_TRANSACTIONAL'; |
} |
- request.mutation = new api.Mutation(); |
+ var mutations = request.mutations = []; |
if (inserts != null) { |
- request.mutation.upsert = new List(inserts.length); |
for (int i = 0; i < inserts.length; i++) { |
- request.mutation.upsert[i] = _convertDatastore2ApiEntity(inserts[i]); |
+ mutations.add( |
+ new api.Mutation()..upsert = |
+ _convertDatastore2ApiEntity(inserts[i], enforceId: true)); |
} |
} |
+ int autoIdStartIndex = -1; |
if (autoIdInserts != null) { |
- request.mutation.insertAutoId = new List(autoIdInserts.length); |
+ autoIdStartIndex = mutations.length; |
for (int i = 0; i < autoIdInserts.length; i++) { |
- request.mutation.insertAutoId[i] = |
- _convertDatastore2ApiEntity(autoIdInserts[i], enforceId: false); |
+ mutations.add( |
+ new api.Mutation()..insert = |
+ _convertDatastore2ApiEntity(autoIdInserts[i], enforceId: false)); |
} |
} |
if (deletes != null) { |
- request.mutation.delete = new List(deletes.length); |
for (int i = 0; i < deletes.length; i++) { |
- request.mutation.delete[i] = |
- _convertDatastore2ApiKey(deletes[i], enforceId: true); |
+ mutations.add( |
+ new api.Mutation()..delete = |
+ _convertDatastore2ApiKey(deletes[i], enforceId: true)); |
} |
} |
- return _api.datasets.commit(request, _project).then((result) { |
+ return _api.projects.commit(request, _project).then((result) { |
var keys; |
if (autoIdInserts != null && autoIdInserts.length > 0) { |
- keys = result |
- .mutationResult |
- .insertAutoIdKeys |
- .map(_convertApi2DatastoreKey).toList(); |
+ List<api.MutationResult> mutationResults = result.mutationResults; |
+ assert(autoIdStartIndex != -1); |
+ assert(mutationResults.length >= |
+ (autoIdStartIndex + autoIdInserts.length)); |
+ keys = mutationResults |
+ .skip(autoIdStartIndex) |
+ .take(autoIdInserts.length) |
+ .map((api.MutationResult r) => _convertApi2DatastoreKey(r.key)) |
+ .toList(); |
} |
return new datastore.CommitResult(keys); |
}, onError: _handleError); |
@@ -462,7 +389,7 @@ class DatastoreImpl implements datastore.Datastore { |
request.readOptions = new api.ReadOptions(); |
request.readOptions.transaction = (transaction as TransactionImpl).data; |
} |
- return _api.datasets.lookup(request, _project).then((response) { |
+ return _api.projects.lookup(request, _project).then((response) { |
if (response.deferred != null && response.deferred.length > 0) { |
throw new datastore.DatastoreError( |
'Could not successfully look up all keys due to resource ' |
@@ -534,7 +461,7 @@ class DatastoreImpl implements datastore.Datastore { |
..offset = query.offset; |
if (query.kind != null) { |
- apiQuery.kinds = [new api.KindExpression()..name = query.kind]; |
+ apiQuery.kind = [new api.KindExpression()..name = query.kind]; |
} |
var request = new api.RunQueryRequest(); |
@@ -546,7 +473,7 @@ class DatastoreImpl implements datastore.Datastore { |
} |
if (partition != null) { |
request.partitionId = new api.PartitionId() |
- ..namespace = partition.namespace; |
+ ..namespaceId = partition.namespace; |
} |
return QueryPageImpl.runQuery(_api, _project, request, query.limit) |
@@ -557,7 +484,7 @@ class DatastoreImpl implements datastore.Datastore { |
// TODO: Handle [transaction] |
var request = new api.RollbackRequest() |
..transaction = (transaction as TransactionImpl).data; |
- return _api.datasets.rollback(request, _project).catchError(_handleError); |
+ return _api.projects.rollback(request, _project).catchError(_handleError); |
} |
} |
@@ -592,7 +519,7 @@ class QueryPageImpl implements Page<datastore.Entity> { |
request.query.limit = batchLimit; |
- return api.datasets.runQuery(request, project).then((response) { |
+ return api.projects.runQuery(request, project).then((response) { |
var returnedEntities = const []; |
var batch = response.batch; |