@Override public Value<FullEntity<?>> saveSafe(final P pojo, final boolean index, final SaveContext ctx, final Path path) throws SkipException { // check if we need to redirect to a different translator if (pojo.getClass() != declaredClass) { // Sometimes generics are more of a hindrance than a help @SuppressWarnings("unchecked") final ClassTranslator<P> translator = (ClassTranslator<P>)byClass.get(pojo.getClass()); if (translator == null) throw new IllegalStateException("Class '" + pojo.getClass() + "' is not a registered @Subclass"); else return translator.save(pojo, index, ctx, path); } else { // This is a normal save final FullEntity.Builder<IncompleteKey> into = FullEntity.newBuilder(); populator.save(pojo, index, ctx, path, into); if (discriminator != null) { into.set(DISCRIMINATOR_PROPERTY, StringValue.newBuilder(discriminator).setExcludeFromIndexes(true).build()); if (!indexedDiscriminators.isEmpty()) into.set(DISCRIMINATOR_INDEX_PROPERTY, ListValue.of(indexedDiscriminators)); } // The question of whether to index this is weird. In order for subthings to be indexed, the entity needs // to be indexed. But then lists with index-heterogeous values (say, nulls) get reordered (!) // by the datastore. So we always index EntityValues and force all the list translators homogenize their lists. // Gross but seems to be the only way. return EntityValue.of(into.build()); } }
/** * Sets the key on a container from the POJO. */ @SuppressWarnings("unchecked") public <K extends IncompleteKey> void setKey(final FullEntity.Builder<K> container, final P pojo) { final IncompleteKey rawKey = getIncompleteKey(pojo); if (!(rawKey instanceof com.google.cloud.datastore.Key)) { // it's incomplete, make sure we can save it Preconditions.checkState(isIdNumeric(), "Cannot save an entity with a null String @Id: %s", pojo); } container.setKey((K)rawKey); }
embeddedMetadata2, embeddedObject); if (embeddedEntityBuilder2 != null) { embeddedEntityBuilder.set(embeddedMetadata2.getMappedName(), embeddedEntityBuilder2.build()); EntityValue.Builder valueBuilder = EntityValue.newBuilder(embeddedEntityBuilder.build()); valueBuilder.setExcludeFromIndexes(!embeddedMetadata.isIndexed()); return valueBuilder;
entityBuilder.set(propertyMetadata.getMappedName(), value); Indexer indexer = propertyMetadata.getSecondaryIndexer(); if (indexer != null) { entityBuilder.set(propertyMetadata.getSecondaryIndexName(), indexer.index(value)); return EntityValue.newBuilder(entityBuilder.build()); } catch (Throwable exp) { throw new MappingException(exp);
this.datastoreEntityConverter.write(probe, probeEntityBuilder); FullEntity<IncompleteKey> probeEntity = probeEntityBuilder.build(); DatastorePersistentEntity<?> persistentEntity = this.datastoreMappingContext.getPersistentEntity(example.getProbeType());
for (Map.Entry<String, ?> entry : map.entrySet()) { String key = entry.getKey(); entityBuilder.set(key, toDatastore(entry.getValue()).build()); builder = EntityValue.newBuilder(entityBuilder.build()); } else { throw new MappingException(String.format("Unsupported type: %s", input.getClass().getName()));
private EntityValue convertOnWriteSingleEmbeddedMap(Object val, String kindName, TypeInformation valueTypeInformation) { return applyEntityValueBuilder(kindName, (builder) -> { Map map = (Map) val; for (Object key : map.keySet()) { String field = convertOnReadSingle(key, ClassTypeInformation.from(String.class)); builder.set(field, convertOnWrite(map.get(key), EmbeddedType.of(valueTypeInformation), field, valueTypeInformation)); } }); }
public static Builder<IncompleteKey> newBuilder() { return new Builder<>(); }
private EntityValue convertOnWriteSingleEmbeddedMap(Object val, String kindName, TypeInformation valueTypeInformation) { return applyEntityValueBuilder(kindName, (builder) -> { Map map = (Map) val; for (Object key : map.keySet()) { String field = convertOnReadSingle(key, ClassTypeInformation.from(String.class)); builder.set(field, convertOnWrite(map.get(key), EmbeddedType.of(valueTypeInformation), field, valueTypeInformation)); } }); }
public static <K extends IncompleteKey> Builder<K> newBuilder(FullEntity<K> copyFrom) { return new Builder<>(copyFrom); }
public static <K extends IncompleteKey> Builder<K> newBuilder(K key) { return new Builder<>(key); }
@SuppressWarnings("unchecked") @Override public ValueBuilder<?, ?, ?> toDatastore(Object input) { if (input == null) { return NullValue.newBuilder(); } Map<String, ?> map = (Map<String, ?>) input; FullEntity.Builder<IncompleteKey> entityBuilder = FullEntity.newBuilder(); for (Map.Entry<String, ?> entry : map.entrySet()) { String key = entry.getKey(); entityBuilder.set(key, valueMapper.toDatastore(entry.getValue()).build()); } return EntityValue.newBuilder(entityBuilder.build()); }
private EntityValue applyEntityValueBuilder(String kindName, Consumer<Builder> consumer) { IncompleteKey key = this.objectToKeyFactory.getIncompleteKey(kindName); FullEntity.Builder<IncompleteKey> builder = FullEntity.newBuilder(key); consumer.accept(builder); return EntityValue.of(builder.build()); }
private EntityValue applyEntityValueBuilder(String kindName, Consumer<Builder> consumer) { IncompleteKey key = this.objectToKeyFactory.getIncompleteKey(kindName); FullEntity.Builder<IncompleteKey> builder = FullEntity.newBuilder(key); consumer.accept(builder); return EntityValue.of(builder.build()); }
/** * Gets the appropriate field value from the pojo and puts it in the container at the appropriate prop name * and with the appropriate indexing. * @param onPojo is the parent pojo which holds the property we represent * @param index is the default state of indexing up to this point * @param containerPath is the path to the container; each property will extend this path. */ @Override public void save(final P onPojo, boolean index, final SaveContext ctx, final Path containerPath, final FullEntity.Builder<?> into) { if (property.isSaved(onPojo)) { // Look for an override on indexing final Boolean propertyIndexInstruction = property.getIndexInstruction(onPojo); if (propertyIndexInstruction != null) index = propertyIndexInstruction; @SuppressWarnings("unchecked") final P value = (P)property.get(onPojo); try { final Path propPath = containerPath.extend(property.getName()); final Value<D> propValue = translator.save(value, index, ctx, propPath); into.set(property.getName(), propValue); } catch (SkipException ex) { // No problem, do nothing } } }
@Override public P loadSafe(final Value<FullEntity<?>> container, final LoadContext ctx, final Path path) throws SkipException { // check if we need to redirect to a different translator final String containerDiscriminator = container.get().contains(DISCRIMINATOR_PROPERTY) ? container.get().getString(DISCRIMINATOR_PROPERTY) : null; // wow no Optional or nullable get if (!Objects.equals(discriminator, containerDiscriminator)) { final ClassTranslator<? extends P> translator = byDiscriminator.get(containerDiscriminator); if (translator == null) { throw new IllegalStateException("Datastore object has discriminator value '" + containerDiscriminator + "' but no relevant @Subclass is registered"); } else { // This fixes alsoLoad names in discriminators by changing the discriminator to what the // translator expects for loading that subclass. Otherwise we'll get the error above since the // translator discriminator and the container discriminator won't match. final StringValue discriminatorValue = StringValue.newBuilder(translator.getDiscriminator()).setExcludeFromIndexes(true).build(); final FullEntity<?> updatedEntity = FullEntity.newBuilder(container.get()).set(DISCRIMINATOR_PROPERTY, discriminatorValue).build(); return translator.load(EntityValue.of(updatedEntity), ctx, path); } } else { // This is a normal load if (log.isTraceEnabled()) log.trace(LogUtils.msg(path, "Instantiating a " + declaredClass.getName())); final P into = forge.construct(declaredClass); populator.load(container.get(), ctx, path, into); return into; } }
@Override public Value<FullEntity<?>> save(final Map<Object, Object> pojo, final boolean index, final SaveContext ctx, final Path path) throws SkipException { // Make this work more like collections than atomic values if (pojo == null || pojo.isEmpty()) throw new SkipException(); final FullEntity.Builder<?> emb = FullEntity.newBuilder(); for (final Map.Entry<Object, Object> entry: pojo.entrySet()) { try { final String key = stringifier.toString(entry.getKey()); if (key == null) path.throwNullPointer("null is not allowed as a map key"); final Path propPath = path.extend(key); final Value<?> value = componentTranslator.save(entry.getValue(), index, ctx, propPath); emb.set(key, value); } catch (SkipException e) { // do nothing } } return EntityValue.of(emb.build()); } };
/** * The problem is ProjectionEntity; there's no way to create an EntityValue with a ProjectionEntity * so we can't use the standard translation system for {@code Value<Entity>}. Instead of making the * translation API really complicated, just convert it to a FullEntity. */ private EntityValue makeLoadEntityValue(final BaseEntity<?> ent) { if (ent instanceof FullEntity<?>) { return EntityValue.of((FullEntity<?>)ent); } else { // Sadly there's no more graceful way of doing this final Builder<?> builder = FullEntity.newBuilder(ent.getKey()); for (final String name : ent.getNames()) { final Value<?> value = ent.getValue(name); builder.set(name, value); } return EntityValue.of(builder.build()); } }
@Override public void run(Transaction tx, Key userKey, String content) { Entity user = tx.get(userKey); if (user == null) { System.out.println("Adding a new user."); user = Entity.newBuilder(userKey).set("count", 1).build(); tx.add(user); } else { user = Entity.newBuilder(user).set("count", user.getLong("count") + 1L).build(); tx.update(user); } IncompleteKey commentKey = IncompleteKey.newBuilder(userKey, COMMENT_KIND).build(); FullEntity<IncompleteKey> comment = FullEntity.newBuilder(commentKey) .set("content", content) .set("timestamp", Timestamp.now()) .build(); tx.addWithDeferredIdAllocation(comment); System.out.printf("Adding a comment to user '%s'.%n", userKey.getName()); }