Skip to content

Commit eb6f182

Browse files
committed
Add support for incomplete entities to Datastore.put (#1040)
Add support for entities with incomplete key to Datastore.put
1 parent d3a49ea commit eb6f182

File tree

9 files changed

+249
-94
lines changed

9 files changed

+249
-94
lines changed

gcloud-java-datastore/src/main/java/com/google/cloud/datastore/BaseDatastoreBatchWriter.java

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,17 +131,65 @@ public final void update(Entity... entities) {
131131
}
132132
}
133133

134-
@SafeVarargs
134+
private void putInternal(FullEntity<Key> entity) {
135+
Key key = entity.key();
136+
toAdd.remove(key);
137+
toUpdate.remove(key);
138+
toDelete.remove(key);
139+
toPut.put(key, entity);
140+
}
141+
135142
@Override
136-
public final void put(Entity... entities) {
143+
public final Entity put(FullEntity<?> entity) {
144+
return DatastoreHelper.put(this, entity);
145+
}
146+
147+
@SuppressWarnings("unchecked")
148+
@Override
149+
public final void putWithDeferredIdAllocation(FullEntity<?>... entities) {
137150
validateActive();
138-
for (Entity entity : entities) {
139-
Key key = entity.key();
140-
toAdd.remove(key);
141-
toUpdate.remove(key);
142-
toDelete.remove(key);
143-
toPut.put(key, entity);
151+
for (FullEntity<?> entity : entities) {
152+
IncompleteKey key = entity.key();
153+
Preconditions.checkArgument(key != null, "Entity must have a key");
154+
if (key instanceof Key) {
155+
putInternal(Entity.convert((FullEntity<Key>) entity));
156+
} else {
157+
toAddAutoId.add((FullEntity<IncompleteKey>) entity);
158+
}
159+
}
160+
}
161+
162+
@SuppressWarnings("unchecked")
163+
@Override
164+
public final List<Entity> put(FullEntity<?>... entities) {
165+
validateActive();
166+
List<IncompleteKey> incompleteKeys = Lists.newArrayListWithExpectedSize(entities.length);
167+
for (FullEntity<?> entity : entities) {
168+
IncompleteKey key = entity.key();
169+
Preconditions.checkArgument(key != null, "Entity must have a key");
170+
if (!(key instanceof Key)) {
171+
incompleteKeys.add(key);
172+
}
144173
}
174+
Iterator<Key> allocated;
175+
if (!incompleteKeys.isEmpty()) {
176+
IncompleteKey[] toAllocate = Iterables.toArray(incompleteKeys, IncompleteKey.class);
177+
allocated = datastore().allocateId(toAllocate).iterator();
178+
} else {
179+
allocated = Collections.emptyIterator();
180+
}
181+
List<Entity> answer = Lists.newArrayListWithExpectedSize(entities.length);
182+
for (FullEntity<?> entity : entities) {
183+
if (entity.key() instanceof Key) {
184+
putInternal((FullEntity<Key>) entity);
185+
answer.add(Entity.convert((FullEntity<Key>) entity));
186+
} else {
187+
Entity entityWithAllocatedId = Entity.builder(allocated.next(), entity).build();
188+
putInternal(entityWithAllocatedId);
189+
answer.add(entityWithAllocatedId);
190+
}
191+
}
192+
return answer;
145193
}
146194

147195
@Override

gcloud-java-datastore/src/main/java/com/google/cloud/datastore/Datastore.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,28 +77,35 @@ interface TransactionCallable<T> {
7777
* @throws DatastoreException upon failure
7878
* @see #allocateId(IncompleteKey)
7979
*/
80-
List<Key> allocateId(IncompleteKey... key);
80+
List<Key> allocateId(IncompleteKey... keys);
8181

8282
/**
8383
* {@inheritDoc}
8484
* @throws DatastoreException upon failure
8585
*/
8686
@Override
87-
void update(Entity... entity);
87+
void update(Entity... entities);
8888

8989
/**
9090
* {@inheritDoc}
9191
* @throws DatastoreException upon failure
9292
*/
9393
@Override
94-
void put(Entity... entity);
94+
Entity put(FullEntity<?> entity);
9595

9696
/**
9797
* {@inheritDoc}
9898
* @throws DatastoreException upon failure
9999
*/
100100
@Override
101-
void delete(Key... key);
101+
List<Entity> put(FullEntity<?>... entities);
102+
103+
/**
104+
* {@inheritDoc}
105+
* @throws DatastoreException upon failure
106+
*/
107+
@Override
108+
void delete(Key... keys);
102109

103110
/**
104111
* Returns a new KeyFactory for this service

gcloud-java-datastore/src/main/java/com/google/cloud/datastore/DatastoreBatchWriter.java

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -19,60 +19,72 @@
1919
import java.util.List;
2020

2121
/**
22-
* An interface to represent a batch of write operations.
23-
* All write operation for a batch writer will be applied to the Datastore in one RPC call.
22+
* An interface to represent a batch of write operations. All write operation for a batch writer
23+
* will be applied to the Datastore in one RPC call.
2424
*/
2525
interface DatastoreBatchWriter extends DatastoreWriter {
2626

2727
/**
28-
* Datastore add operation.
29-
* This method will also allocate id for any entity with an incomplete key.
30-
* As oppose to {@link #add(FullEntity)}, this method will defer any necessary id allocation
28+
* Datastore add operation. This method will also allocate id for any entity with an incomplete
29+
* key. As opposed to {@link #add(FullEntity)}, this method will defer any necessary id allocation
3130
* to submit time.
3231
*
3332
* @throws IllegalArgumentException if any of the given entities is missing a key
34-
* @throws DatastoreException if a given entity with a
35-
* complete key was already added to this writer or if not active
33+
* @throws DatastoreException if a given entity with a complete key was already added to this
34+
* writer or if not active
3635
*/
37-
void addWithDeferredIdAllocation(FullEntity<?>... entity);
36+
void addWithDeferredIdAllocation(FullEntity<?>... entities);
3837

3938
/**
4039
* {@inheritDoc}
4140
* For entities with complete keys that were marked for deletion in this writer the operation
4241
* will be changed to {@link #put}.
43-
* @throws DatastoreException if a given entity with the
44-
* same complete key was already added to this writer, if writer is not active or
45-
* if id allocation for an entity with an incomplete key failed.
42+
*
43+
* @throws DatastoreException if a given entity with the same complete key was already added to
44+
* this writer, if writer is not active or if id allocation for an entity with an incomplete
45+
* key failed.
4646
*/
4747
@Override
48-
List<Entity> add(FullEntity<?>... entity);
48+
List<Entity> add(FullEntity<?>... entities);
4949

5050
/**
5151
* {@inheritDoc}
5252
* This operation will be converted to {@link #put} operation for entities that were already
53-
* added or put in this writer
54-
* @throws DatastoreException if an entity is marked for
55-
* deletion in this writer or if not active
53+
* added or put in this writer.
54+
*
55+
* @throws DatastoreException if an entity is marked for deletion in this writer or if not active
5656
*/
5757
@Override
58-
void update(Entity... entity);
58+
void update(Entity... entities);
5959

6060
/**
6161
* {@inheritDoc}
6262
* This operation will also remove from this batch any prior writes for entities with the same
63-
* keys
63+
* keys
64+
*
6465
* @throws DatastoreException if not active
6566
*/
6667
@Override
67-
void delete(Key... key);
68+
void delete(Key... keys);
69+
70+
/**
71+
* Datastore put operation. This method will also allocate id for any entity with an incomplete
72+
* key. As opposed to {@link #put(FullEntity[])}, this method will defer any necessary id
73+
* allocation to submit time.
74+
*
75+
* @throws IllegalArgumentException if any of the given entities is missing a key
76+
* @throws DatastoreException if not active
77+
*/
78+
void putWithDeferredIdAllocation(FullEntity<?>... entities);
6879

6980
/**
7081
* {@inheritDoc}
7182
* This operation will also remove from this writer any prior writes for the same entities.
83+
*
7284
* @throws DatastoreException if not active
7385
*/
7486
@Override
75-
void put(Entity... entity);
87+
List<Entity> put(FullEntity<?>... entities);
7688

7789
/**
7890
* Returns {@code true} if still active (write operations were not sent to the Datastore).

gcloud-java-datastore/src/main/java/com/google/cloud/datastore/DatastoreHelper.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,10 @@ static Entity add(DatastoreWriter writer, FullEntity<?> entity) {
5151
return writer.add(new FullEntity<?>[] {entity}).get(0);
5252
}
5353

54+
static Entity put(DatastoreWriter writer, FullEntity<?> entity) {
55+
return writer.put(new FullEntity<?>[] {entity}).get(0);
56+
}
57+
5458
static KeyFactory newKeyFactory(DatastoreOptions options) {
5559
return new KeyFactory(options.projectId(), options.namespace());
5660
}

gcloud-java-datastore/src/main/java/com/google/cloud/datastore/DatastoreImpl.java

Lines changed: 57 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,12 @@ com.google.datastore.v1beta3.RunQueryResponse runQuery(
8787
try {
8888
return RetryHelper.runWithRetries(
8989
new Callable<com.google.datastore.v1beta3.RunQueryResponse>() {
90-
@Override public com.google.datastore.v1beta3.RunQueryResponse call()
91-
throws DatastoreException {
92-
return datastoreRpc.runQuery(requestPb);
93-
}
94-
}, retryParams, EXCEPTION_HANDLER, options().clock());
90+
@Override
91+
public com.google.datastore.v1beta3.RunQueryResponse call()
92+
throws DatastoreException {
93+
return datastoreRpc.runQuery(requestPb);
94+
}
95+
}, retryParams, EXCEPTION_HANDLER, options().clock());
9596
} catch (RetryHelperException e) {
9697
throw DatastoreException.translateAndThrow(e);
9798
}
@@ -125,11 +126,12 @@ com.google.datastore.v1beta3.AllocateIdsResponse allocateIds(
125126
try {
126127
return RetryHelper.runWithRetries(
127128
new Callable<com.google.datastore.v1beta3.AllocateIdsResponse>() {
128-
@Override public com.google.datastore.v1beta3.AllocateIdsResponse call()
129-
throws DatastoreException {
130-
return datastoreRpc.allocateIds(requestPb);
131-
}
132-
}, retryParams, EXCEPTION_HANDLER, options().clock());
129+
@Override
130+
public com.google.datastore.v1beta3.AllocateIdsResponse call()
131+
throws DatastoreException {
132+
return datastoreRpc.allocateIds(requestPb);
133+
}
134+
}, retryParams, EXCEPTION_HANDLER, options().clock());
133135
} catch (RetryHelperException e) {
134136
throw DatastoreException.translateAndThrow(e);
135137
}
@@ -166,7 +168,7 @@ public List<Entity> add(FullEntity<?>... entities) {
166168
"Duplicate entity with the key %s", entity.key());
167169
}
168170
} else {
169-
Preconditions.checkArgument(entity.hasKey(), "entity %s is missing a key", entity);
171+
Preconditions.checkArgument(entity.hasKey(), "Entity %s is missing a key", entity);
170172
}
171173
mutationsPb.add(com.google.datastore.v1beta3.Mutation.newBuilder()
172174
.setInsert(entity.toPb()).build());
@@ -281,19 +283,19 @@ com.google.datastore.v1beta3.LookupResponse lookup(
281283
try {
282284
return RetryHelper.runWithRetries(
283285
new Callable<com.google.datastore.v1beta3.LookupResponse>() {
284-
@Override public com.google.datastore.v1beta3.LookupResponse call()
285-
throws DatastoreException {
286-
return datastoreRpc.lookup(requestPb);
287-
}
288-
}, retryParams, EXCEPTION_HANDLER, options().clock());
286+
@Override
287+
public com.google.datastore.v1beta3.LookupResponse call()
288+
throws DatastoreException {
289+
return datastoreRpc.lookup(requestPb);
290+
}
291+
}, retryParams, EXCEPTION_HANDLER, options().clock());
289292
} catch (RetryHelperException e) {
290293
throw DatastoreException.translateAndThrow(e);
291294
}
292295
}
293296

294-
@SafeVarargs
295297
@Override
296-
public final void update(Entity... entities) {
298+
public void update(Entity... entities) {
297299
if (entities.length > 0) {
298300
List<com.google.datastore.v1beta3.Mutation> mutationsPb =
299301
new ArrayList<>();
@@ -309,22 +311,47 @@ public final void update(Entity... entities) {
309311
}
310312
}
311313

312-
@SafeVarargs
313314
@Override
314-
public final void put(Entity... entities) {
315-
if (entities.length > 0) {
316-
List<com.google.datastore.v1beta3.Mutation> mutationsPb =
317-
new ArrayList<>();
318-
Map<Key, Entity> dedupEntities = new LinkedHashMap<>();
319-
for (Entity entity : entities) {
320-
dedupEntities.put(entity.key(), entity);
321-
}
322-
for (Entity e : dedupEntities.values()) {
315+
public Entity put(FullEntity<?> entity) {
316+
return DatastoreHelper.put(this, entity);
317+
}
318+
319+
@SuppressWarnings("unchecked")
320+
@Override
321+
public List<Entity> put(FullEntity<?>... entities) {
322+
if (entities.length == 0) {
323+
return Collections.emptyList();
324+
}
325+
List<com.google.datastore.v1beta3.Mutation> mutationsPb = new ArrayList<>();
326+
Map<Key, Entity> dedupEntities = new LinkedHashMap<>();
327+
for (FullEntity<?> entity : entities) {
328+
Preconditions.checkArgument(entity.hasKey(), "Entity %s is missing a key", entity);
329+
if (entity.key() instanceof Key) {
330+
Entity completeEntity = Entity.convert((FullEntity<Key>) entity);
331+
dedupEntities.put(completeEntity.key(), completeEntity);
332+
} else {
323333
mutationsPb.add(
324-
com.google.datastore.v1beta3.Mutation.newBuilder().setUpsert(e.toPb()).build());
334+
com.google.datastore.v1beta3.Mutation.newBuilder().setUpsert(entity.toPb()).build());
335+
}
336+
}
337+
for (Entity entity : dedupEntities.values()) {
338+
mutationsPb.add(
339+
com.google.datastore.v1beta3.Mutation.newBuilder().setUpsert(entity.toPb()).build());
340+
}
341+
com.google.datastore.v1beta3.CommitResponse commitResponse = commitMutation(mutationsPb);
342+
Iterator<com.google.datastore.v1beta3.MutationResult> mutationResults =
343+
commitResponse.getMutationResultsList().iterator();
344+
ImmutableList.Builder<Entity> responseBuilder = ImmutableList.builder();
345+
for (FullEntity<?> entity : entities) {
346+
Entity completeEntity = dedupEntities.get(entity.key());
347+
if (completeEntity != null) {
348+
responseBuilder.add(completeEntity);
349+
} else {
350+
responseBuilder.add(
351+
Entity.builder(Key.fromPb(mutationResults.next().getKey()), entity).build());
325352
}
326-
commitMutation(mutationsPb);
327353
}
354+
return responseBuilder.build();
328355
}
329356

330357
@Override

gcloud-java-datastore/src/main/java/com/google/cloud/datastore/DatastoreReader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public interface DatastoreReader {
4040
* @throws DatastoreException upon failure
4141
* @see #get(Key)
4242
*/
43-
Iterator<Entity> get(Key... key);
43+
Iterator<Entity> get(Key... keys);
4444

4545
/**
4646
* Returns a list with a value for each given key (ordered by input). {@code null} values are

0 commit comments

Comments
 (0)