diff --git a/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java b/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java index 6d2121021..b514c2e57 100644 --- a/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java +++ b/core/src/main/java/google/registry/flows/domain/DomainCreateFlow.java @@ -110,7 +110,6 @@ import google.registry.model.reporting.DomainTransactionRecord; import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField; import google.registry.model.reporting.HistoryEntry; import google.registry.model.reporting.IcannReportingTypes.ActivityReportField; -import google.registry.persistence.DomainHistoryVKey; import google.registry.persistence.VKey; import google.registry.tmch.LordnTaskUtils; import java.util.Optional; @@ -372,7 +371,7 @@ public class DomainCreateFlow implements TransactionalFlow { && TokenType.SINGLE_USE.equals(allocationToken.get().getTokenType())) { entitiesToSave.add( allocationTokenFlowUtils.redeemToken( - allocationToken.get(), DomainHistoryVKey.create(Key.create(historyEntry)))); + allocationToken.get(), HistoryEntry.createVKey(Key.create(historyEntry)))); } enqueueTasks(newDomain, hasSignedMarks, hasClaimsNotice); diff --git a/core/src/main/java/google/registry/flows/domain/token/AllocationTokenFlowUtils.java b/core/src/main/java/google/registry/flows/domain/token/AllocationTokenFlowUtils.java index a041c88a4..5af042884 100644 --- a/core/src/main/java/google/registry/flows/domain/token/AllocationTokenFlowUtils.java +++ b/core/src/main/java/google/registry/flows/domain/token/AllocationTokenFlowUtils.java @@ -32,7 +32,8 @@ import google.registry.model.domain.token.AllocationToken; import google.registry.model.domain.token.AllocationToken.TokenStatus; import google.registry.model.domain.token.AllocationToken.TokenType; import google.registry.model.registry.Registry; -import google.registry.persistence.DomainHistoryVKey; +import google.registry.model.reporting.HistoryEntry; +import google.registry.persistence.VKey; import java.util.List; import java.util.Optional; import javax.inject.Inject; @@ -107,7 +108,7 @@ public class AllocationTokenFlowUtils { /** Redeems a SINGLE_USE {@link AllocationToken}, returning the redeemed copy. */ public AllocationToken redeemToken( - AllocationToken token, DomainHistoryVKey redemptionHistoryEntry) { + AllocationToken token, VKey redemptionHistoryEntry) { checkArgument( TokenType.SINGLE_USE.equals(token.getTokenType()), "Only SINGLE_USE tokens can be marked as redeemed"); diff --git a/core/src/main/java/google/registry/model/domain/GracePeriod.java b/core/src/main/java/google/registry/model/domain/GracePeriod.java index e9c860f91..a85fa308d 100644 --- a/core/src/main/java/google/registry/model/domain/GracePeriod.java +++ b/core/src/main/java/google/registry/model/domain/GracePeriod.java @@ -23,6 +23,8 @@ import google.registry.model.billing.BillingEvent; import google.registry.model.billing.BillingEvent.Recurring; import google.registry.model.domain.rgp.GracePeriodStatus; import google.registry.model.ofy.ObjectifyService; +import google.registry.persistence.BillingVKey.BillingEventVKey; +import google.registry.persistence.BillingVKey.BillingRecurrenceVKey; import google.registry.persistence.VKey; import google.registry.schema.replay.DatastoreAndSqlEntity; import javax.annotation.Nullable; @@ -82,10 +84,8 @@ public class GracePeriod extends GracePeriodBase implements DatastoreAndSqlEntit instance.domainRepoId = checkArgumentNotNull(domainRepoId); instance.expirationTime = checkArgumentNotNull(expirationTime); instance.clientId = checkArgumentNotNull(clientId); - instance.billingEventOneTime = billingEventOneTime; - instance.billingEventOneTimeHistoryId = DomainBase.getHistoryId(billingEventOneTime); - instance.billingEventRecurring = billingEventRecurring; - instance.billingEventRecurringHistoryId = DomainBase.getHistoryId(billingEventRecurring); + instance.billingEventOneTime = BillingEventVKey.create(billingEventOneTime); + instance.billingEventRecurring = BillingRecurrenceVKey.create(billingEventRecurring); return instance; } @@ -178,7 +178,6 @@ public class GracePeriod extends GracePeriodBase implements DatastoreAndSqlEntit public GracePeriod cloneAfterOfyLoad(String domainRepoId) { GracePeriod clone = clone(this); clone.domainRepoId = checkArgumentNotNull(domainRepoId); - clone.restoreHistoryIds(); return clone; } @@ -190,7 +189,7 @@ public class GracePeriod extends GracePeriodBase implements DatastoreAndSqlEntit */ public GracePeriod cloneWithRecurringBillingEvent(VKey recurring) { GracePeriod clone = clone(this); - clone.billingEventRecurring = recurring; + clone.billingEventRecurring = BillingRecurrenceVKey.create(recurring); return clone; } @@ -232,9 +231,7 @@ public class GracePeriod extends GracePeriodBase implements DatastoreAndSqlEntit instance.expirationTime = gracePeriod.expirationTime; instance.clientId = gracePeriod.clientId; instance.billingEventOneTime = gracePeriod.billingEventOneTime; - instance.billingEventOneTimeHistoryId = gracePeriod.billingEventOneTimeHistoryId; instance.billingEventRecurring = gracePeriod.billingEventRecurring; - instance.billingEventRecurringHistoryId = gracePeriod.billingEventRecurringHistoryId; return instance; } } diff --git a/core/src/main/java/google/registry/model/domain/GracePeriodBase.java b/core/src/main/java/google/registry/model/domain/GracePeriodBase.java index c90aef084..ed83a23a2 100644 --- a/core/src/main/java/google/registry/model/domain/GracePeriodBase.java +++ b/core/src/main/java/google/registry/model/domain/GracePeriodBase.java @@ -14,14 +14,14 @@ package google.registry.model.domain; -import com.googlecode.objectify.Key; import com.googlecode.objectify.annotation.Embed; import com.googlecode.objectify.annotation.Ignore; import google.registry.model.ImmutableObject; import google.registry.model.ModelUtils; import google.registry.model.billing.BillingEvent; -import google.registry.model.billing.BillingEvent.OneTime; import google.registry.model.domain.rgp.GracePeriodStatus; +import google.registry.persistence.BillingVKey.BillingEventVKey; +import google.registry.persistence.BillingVKey.BillingRecurrenceVKey; import google.registry.persistence.VKey; import java.lang.reflect.Field; import java.util.LinkedHashMap; @@ -68,24 +68,16 @@ public class GracePeriodBase extends ImmutableObject { * billingEventRecurring}) or for redemption grace periods (since deletes have no cost). */ // NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections. - @Column(name = "billing_event_id") - VKey billingEventOneTime = null; - - @Ignore - @Column(name = "billing_event_history_id") - Long billingEventOneTimeHistoryId; + @Access(AccessType.FIELD) + BillingEventVKey billingEventOneTime = null; /** * The recurring billing event corresponding to the action that triggered this grace period, if * applicable - i.e. if the action was an autorenew - or null in all other cases. */ // NB: Would @IgnoreSave(IfNull.class), but not allowed for @Embed collections. - @Column(name = "billing_recurrence_id") - VKey billingEventRecurring = null; - - @Ignore - @Column(name = "billing_recurrence_history_id") - Long billingEventRecurringHistoryId; + @Access(AccessType.FIELD) + BillingRecurrenceVKey billingEventRecurring = null; public long getGracePeriodId() { return gracePeriodId; @@ -123,8 +115,7 @@ public class GracePeriodBase extends ImmutableObject { * period is not AUTO_RENEW. */ public VKey getOneTimeBillingEvent() { - restoreOfyKeys(); - return billingEventOneTime; + return billingEventOneTime == null ? null : billingEventOneTime.createVKey(); } /** @@ -132,18 +123,7 @@ public class GracePeriodBase extends ImmutableObject { * period is AUTO_RENEW. */ public VKey getRecurringBillingEvent() { - restoreOfyKeys(); - return billingEventRecurring; - } - - /** - * Restores history ids for composite VKeys after a load from datastore. - * - *

For use by DomainContent.load() ONLY. - */ - protected void restoreHistoryIds() { - billingEventOneTimeHistoryId = DomainBase.getHistoryId(billingEventOneTime); - billingEventRecurringHistoryId = DomainBase.getHistoryId(billingEventRecurring); + return billingEventRecurring == null ? null : billingEventRecurring.createVKey(); } /** @@ -152,7 +132,6 @@ public class GracePeriodBase extends ImmutableObject { */ @Override protected Map getSignificantFields() { - restoreOfyKeys(); // Can't use streams or ImmutableMap because we can have null values. Map result = new LinkedHashMap(); for (Map.Entry entry : ModelUtils.getFieldValues(this).entrySet()) { @@ -162,33 +141,4 @@ public class GracePeriodBase extends ImmutableObject { } return result; } - - /** - * Restores Ofy keys in the billing events. - * - *

This must be called by all methods that access the one time or recurring billing event keys. - * When the billing event keys are loaded from SQL, they are loaded as asymmetric keys because the - * database columns that we load them from do not contain all of the information necessary to - * reconsitute the Ofy side of the key. In other cases, we restore the Ofy key during the - * hibernate {@link javax.persistence.PostLoad} method from the other fields of the object, but we - * have been unable to make this work with hibernate's internal persistence model in this case - * because the {@link GracePeriod}'s hash code is evaluated prior to these calls, and would be - * invalidated by changing the fields. - */ - private final synchronized void restoreOfyKeys() { - if (billingEventOneTime != null && !billingEventOneTime.maybeGetOfyKey().isPresent()) { - billingEventOneTime = - DomainBase.restoreOfyFrom( - Key.create(DomainBase.class, domainRepoId), - billingEventOneTime, - billingEventOneTimeHistoryId); - } - if (billingEventRecurring != null && !billingEventRecurring.maybeGetOfyKey().isPresent()) { - billingEventRecurring = - DomainBase.restoreOfyFrom( - Key.create(DomainBase.class, domainRepoId), - billingEventRecurring, - billingEventRecurringHistoryId); - } - } } diff --git a/core/src/main/java/google/registry/model/domain/token/AllocationToken.java b/core/src/main/java/google/registry/model/domain/token/AllocationToken.java index 50c07f68a..c3816ae1c 100644 --- a/core/src/main/java/google/registry/model/domain/token/AllocationToken.java +++ b/core/src/main/java/google/registry/model/domain/token/AllocationToken.java @@ -111,9 +111,9 @@ public class AllocationToken extends BackupGroupRoot implements Buildable, Datas @Nullable @Index @AttributeOverrides({ - @AttributeOverride(name = "domainRepoId", column = @Column(name = "redemption_domain_repo_id")), + @AttributeOverride(name = "repoId", column = @Column(name = "redemption_domain_repo_id")), @AttributeOverride( - name = "domainHistoryId", + name = "historyRevisionId", column = @Column(name = "redemption_domain_history_id")) }) DomainHistoryVKey redemptionHistoryEntry; @@ -192,8 +192,9 @@ public class AllocationToken extends BackupGroupRoot implements Buildable, Datas return token; } - public Optional> getRedemptionHistoryEntry() { - return Optional.ofNullable(redemptionHistoryEntry); + public Optional> getRedemptionHistoryEntry() { + return Optional.ofNullable( + redemptionHistoryEntry == null ? null : redemptionHistoryEntry.createDomainHistoryVKey()); } public boolean isRedeemed() { @@ -291,9 +292,10 @@ public class AllocationToken extends BackupGroupRoot implements Buildable, Datas return this; } - public Builder setRedemptionHistoryEntry(DomainHistoryVKey redemptionHistoryEntry) { + public Builder setRedemptionHistoryEntry(VKey redemptionHistoryEntry) { + checkArgumentNotNull(redemptionHistoryEntry, "Redemption history entry must not be null"); getInstance().redemptionHistoryEntry = - checkArgumentNotNull(redemptionHistoryEntry, "Redemption history entry must not be null"); + DomainHistoryVKey.create(redemptionHistoryEntry.getOfyKey()); return this; } diff --git a/core/src/main/java/google/registry/model/ofy/ObjectifyService.java b/core/src/main/java/google/registry/model/ofy/ObjectifyService.java index 3f9fab7d9..b189a3fec 100644 --- a/core/src/main/java/google/registry/model/ofy/ObjectifyService.java +++ b/core/src/main/java/google/registry/model/ofy/ObjectifyService.java @@ -42,8 +42,8 @@ import google.registry.model.translators.CidrAddressBlockTranslatorFactory; import google.registry.model.translators.CommitLogRevisionsTranslatorFactory; import google.registry.model.translators.CreateAutoTimestampTranslatorFactory; import google.registry.model.translators.CurrencyUnitTranslatorFactory; -import google.registry.model.translators.DomainHistoryVKeyTranslatorFactory; import google.registry.model.translators.DurationTranslatorFactory; +import google.registry.model.translators.EppHistoryVKeyTranslatorFactory; import google.registry.model.translators.InetAddressTranslatorFactory; import google.registry.model.translators.ReadableInstantUtcTranslatorFactory; import google.registry.model.translators.UpdateAutoTimestampTranslatorFactory; @@ -128,7 +128,7 @@ public class ObjectifyService { new CreateAutoTimestampTranslatorFactory(), new CurrencyUnitTranslatorFactory(), new DurationTranslatorFactory(), - new DomainHistoryVKeyTranslatorFactory(), + new EppHistoryVKeyTranslatorFactory(), new InetAddressTranslatorFactory(), new MoneyStringTranslatorFactory(), new ReadableInstantUtcTranslatorFactory(), diff --git a/core/src/main/java/google/registry/model/translators/DomainHistoryVKeyTranslatorFactory.java b/core/src/main/java/google/registry/model/translators/DomainHistoryVKeyTranslatorFactory.java deleted file mode 100644 index 3f1e4ef49..000000000 --- a/core/src/main/java/google/registry/model/translators/DomainHistoryVKeyTranslatorFactory.java +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2020 The Nomulus Authors. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package google.registry.model.translators; - -import com.google.appengine.api.datastore.Key; -import google.registry.persistence.DomainHistoryVKey; -import javax.annotation.Nullable; - -/** Translator factory for {@link DomainHistoryVKey}. */ -public class DomainHistoryVKeyTranslatorFactory - extends AbstractSimpleTranslatorFactory { - - public DomainHistoryVKeyTranslatorFactory() { - super(DomainHistoryVKey.class); - } - - @Override - SimpleTranslator createTranslator() { - return new SimpleTranslator() { - - @Nullable - @Override - public DomainHistoryVKey loadValue(@Nullable Key datastoreValue) { - return datastoreValue == null - ? null - : DomainHistoryVKey.create(com.googlecode.objectify.Key.create(datastoreValue)); - } - - @Nullable - @Override - public Key saveValue(@Nullable DomainHistoryVKey pojoValue) { - return pojoValue == null ? null : pojoValue.getOfyKey().getRaw(); - } - }; - } -} diff --git a/core/src/main/java/google/registry/model/translators/EppHistoryVKeyTranslatorFactory.java b/core/src/main/java/google/registry/model/translators/EppHistoryVKeyTranslatorFactory.java new file mode 100644 index 000000000..5e8030bf1 --- /dev/null +++ b/core/src/main/java/google/registry/model/translators/EppHistoryVKeyTranslatorFactory.java @@ -0,0 +1,110 @@ +// Copyright 2020 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.model.translators; + +import static com.google.common.collect.ImmutableMap.toImmutableMap; +import static java.util.function.Function.identity; + +import com.google.appengine.api.datastore.Key; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import google.registry.persistence.BillingVKey.BillingEventVKey; +import google.registry.persistence.BillingVKey.BillingRecurrenceVKey; +import google.registry.persistence.DomainHistoryVKey; +import google.registry.persistence.EppHistoryVKey; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import javax.annotation.Nullable; + +/** Translator factory for {@link EppHistoryVKey}. */ +public class EppHistoryVKeyTranslatorFactory + extends AbstractSimpleTranslatorFactory { + + public EppHistoryVKeyTranslatorFactory() { + super(EppHistoryVKey.class); + } + + // This map is used when we need to convert the raw Datastore key to its VKey instance. We have + // one dedicated VKey class, e.g. DomainHistoryVKey, for each such kind of entity, and we need + // a way to map the raw Datastore key to its VKey class. So, we use the kind path as the key of + // the map, and the kind path is created by concatenating all the kind strings in a raw Datastore + // key, e.g. the map key for ContactPollMessageVKey is "ContactResource/HistoryEntry/PollMessage". + @VisibleForTesting + static final ImmutableMap> kindPathToVKeyClass = + ImmutableSet.of(DomainHistoryVKey.class, BillingEventVKey.class, BillingRecurrenceVKey.class) + .stream() + .collect(toImmutableMap(EppHistoryVKeyTranslatorFactory::getKindPath, identity())); + + /** + * Gets the kind path string for the given {@link Class}. + * + *

This method calls the getKindPath method on an instance of the given {@link Class} to get + * the kind path string. + */ + private static String getKindPath(Class clazz) { + try { + Constructor constructor = clazz.getDeclaredConstructor(); + constructor.setAccessible(true); + Object instance = constructor.newInstance(); + Method getKindPathMethod = EppHistoryVKey.class.getDeclaredMethod("getKindPath"); + getKindPathMethod.setAccessible(true); + return (String) getKindPathMethod.invoke(instance); + } catch (Throwable t) { + throw new IllegalStateException(t); + } + } + + @Override + SimpleTranslator createTranslator() { + return new SimpleTranslator() { + + @Nullable + @Override + public EppHistoryVKey loadValue(@Nullable Key datastoreValue) { + if (datastoreValue == null) { + return null; + } else { + com.googlecode.objectify.Key ofyKey = + com.googlecode.objectify.Key.create(datastoreValue); + String kindPath = EppHistoryVKey.createKindPath(ofyKey); + if (kindPathToVKeyClass.containsKey(kindPath)) { + Class vKeyClass = kindPathToVKeyClass.get(kindPath); + try { + Method createVKeyMethod = + vKeyClass.getDeclaredMethod("create", com.googlecode.objectify.Key.class); + return (EppHistoryVKey) createVKeyMethod.invoke(null, ofyKey); + } catch (NoSuchMethodException e) { + throw new IllegalStateException( + "Missing static method create(com.googlecode.objectify.Key) on " + vKeyClass); + } catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalStateException("Error invoking createVKey on " + vKeyClass, e); + } + } else { + throw new IllegalStateException( + "Missing EppHistoryVKey implementation for kind path: " + kindPath); + } + } + } + + @Nullable + @Override + public Key saveValue(@Nullable EppHistoryVKey pojoValue) { + return pojoValue == null ? null : pojoValue.createOfyKey().getRaw(); + } + }; + } +} diff --git a/core/src/main/java/google/registry/persistence/BillingVKey.java b/core/src/main/java/google/registry/persistence/BillingVKey.java new file mode 100644 index 000000000..7393bb495 --- /dev/null +++ b/core/src/main/java/google/registry/persistence/BillingVKey.java @@ -0,0 +1,134 @@ +// Copyright 2020 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.persistence; + + +import com.googlecode.objectify.Key; +import google.registry.model.billing.BillingEvent; +import google.registry.model.billing.BillingEvent.OneTime; +import google.registry.model.billing.BillingEvent.Recurring; +import google.registry.model.domain.DomainBase; +import google.registry.model.reporting.HistoryEntry; +import javax.annotation.Nullable; +import javax.persistence.AttributeOverride; +import javax.persistence.AttributeOverrides; +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.MappedSuperclass; + +/** Base class for {@link BillingEvent}'s {@link VKey}. */ +@MappedSuperclass +public abstract class BillingVKey extends EppHistoryVKey { + Long billingId; + + // Hibernate requires a default constructor. + BillingVKey() {} + + BillingVKey(String repoId, long historyRevisionId, long billingId) { + super(repoId, historyRevisionId); + this.billingId = billingId; + } + + Key createHistoryEntryKey() { + return Key.create(Key.create(DomainBase.class, repoId), HistoryEntry.class, historyRevisionId); + } + + @Override + public Object createSqlKey() { + return billingId; + } + + /** VKey class for {@link BillingEvent.OneTime} that belongs to a {@link DomainBase} entity. */ + @Embeddable + @AttributeOverrides({ + @AttributeOverride(name = "repoId", column = @Column(name = "billing_event_domain_repo_id")), + @AttributeOverride( + name = "historyRevisionId", + column = @Column(name = "billing_event_history_id")), + @AttributeOverride(name = "billingId", column = @Column(name = "billing_event_id")) + }) + public static class BillingEventVKey extends BillingVKey { + + // Hibernate requires this default constructor + private BillingEventVKey() {} + + private BillingEventVKey(String repoId, long historyRevisionId, long billingEventId) { + super(repoId, historyRevisionId, billingEventId); + } + + @Override + public Key createOfyKey() { + return Key.create(createHistoryEntryKey(), BillingEvent.OneTime.class, billingId); + } + + /** Creates a {@link BillingEventVKey} instance from the given {@link Key} instance. */ + public static BillingEventVKey create(@Nullable Key ofyKey) { + if (ofyKey == null) { + return null; + } + long billingEventId = ofyKey.getId(); + long historyRevisionId = ofyKey.getParent().getId(); + String repoId = ofyKey.getParent().getParent().getName(); + return new BillingEventVKey(repoId, historyRevisionId, billingEventId); + } + + /** Creates a {@link BillingEventVKey} instance from the given {@link VKey} instance. */ + public static BillingEventVKey create(@Nullable VKey vKey) { + return vKey == null ? null : create(vKey.getOfyKey()); + } + } + + /** VKey class for {@link BillingEvent.Recurring} that belongs to a {@link DomainBase} entity. */ + @Embeddable + @AttributeOverrides({ + @AttributeOverride( + name = "repoId", + column = @Column(name = "billing_recurrence_domain_repo_id")), + @AttributeOverride( + name = "historyRevisionId", + column = @Column(name = "billing_recurrence_history_id")), + @AttributeOverride(name = "billingId", column = @Column(name = "billing_recurrence_id")) + }) + public static class BillingRecurrenceVKey extends BillingVKey { + + // Hibernate requires this default constructor + private BillingRecurrenceVKey() {} + + private BillingRecurrenceVKey(String repoId, long historyRevisionId, long billingEventId) { + super(repoId, historyRevisionId, billingEventId); + } + + @Override + public Key createOfyKey() { + return Key.create(createHistoryEntryKey(), BillingEvent.Recurring.class, billingId); + } + + /** Creates a {@link BillingRecurrenceVKey} instance from the given {@link Key} instance. */ + public static BillingRecurrenceVKey create(@Nullable Key ofyKey) { + if (ofyKey == null) { + return null; + } + long billingEventId = ofyKey.getId(); + long historyRevisionId = ofyKey.getParent().getId(); + String repoId = ofyKey.getParent().getParent().getName(); + return new BillingRecurrenceVKey(repoId, historyRevisionId, billingEventId); + } + + /** Creates a {@link BillingRecurrenceVKey} instance from the given {@link VKey} instance. */ + public static BillingRecurrenceVKey create(@Nullable VKey vKey) { + return vKey == null ? null : create(vKey.getOfyKey()); + } + } +} diff --git a/core/src/main/java/google/registry/persistence/DomainHistoryVKey.java b/core/src/main/java/google/registry/persistence/DomainHistoryVKey.java index 32b5d7718..2f266d961 100644 --- a/core/src/main/java/google/registry/persistence/DomainHistoryVKey.java +++ b/core/src/main/java/google/registry/persistence/DomainHistoryVKey.java @@ -18,45 +18,44 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; import com.googlecode.objectify.Key; import google.registry.model.domain.DomainBase; +import google.registry.model.domain.DomainHistory; import google.registry.model.domain.DomainHistory.DomainHistoryId; import google.registry.model.reporting.HistoryEntry; import javax.persistence.Embeddable; -import javax.persistence.PostLoad; /** {@link VKey} for {@link HistoryEntry} which parent is {@link DomainBase}. */ @Embeddable -public class DomainHistoryVKey extends VKey { - - private String domainRepoId; - - private Long domainHistoryId; +public class DomainHistoryVKey extends EppHistoryVKey { // Hibernate requires a default constructor private DomainHistoryVKey() {} - private DomainHistoryVKey(String domainRepoId, long domainHistoryId) { - initWith(domainRepoId, domainHistoryId); + private DomainHistoryVKey(String repoId, long historyRevisionId) { + super(repoId, historyRevisionId); } - @PostLoad - void postLoad() { - initWith(domainRepoId, domainHistoryId); + @Override + public Object createSqlKey() { + return new DomainHistoryId(repoId, historyRevisionId); } - private void initWith(String domainRepoId, long domainHistoryId) { - this.kind = HistoryEntry.class; - this.ofyKey = - Key.create(Key.create(DomainBase.class, domainRepoId), HistoryEntry.class, domainHistoryId); - this.sqlKey = new DomainHistoryId(domainRepoId, domainHistoryId); - this.domainRepoId = domainRepoId; - this.domainHistoryId = domainHistoryId; + @Override + public Key createOfyKey() { + return Key.create(Key.create(DomainBase.class, repoId), HistoryEntry.class, historyRevisionId); } /** Creates {@link DomainHistoryVKey} from the given {@link Key} instance. */ - public static DomainHistoryVKey create(Key ofyKey) { + public static DomainHistoryVKey create(Key ofyKey) { checkArgumentNotNull(ofyKey, "ofyKey must be specified"); - String domainRepoId = ofyKey.getParent().getName(); - long domainHistoryId = ofyKey.getId(); - return new DomainHistoryVKey(domainRepoId, domainHistoryId); + String repoId = ofyKey.getParent().getName(); + long historyRevisionId = ofyKey.getId(); + return new DomainHistoryVKey(repoId, historyRevisionId); + } + + public VKey createDomainHistoryVKey() { + return VKey.create( + DomainHistory.class, + createSqlKey(), + Key.create(Key.create(DomainBase.class, repoId), DomainHistory.class, historyRevisionId)); } } diff --git a/core/src/main/java/google/registry/persistence/EppHistoryVKey.java b/core/src/main/java/google/registry/persistence/EppHistoryVKey.java new file mode 100644 index 000000000..c2cc17e83 --- /dev/null +++ b/core/src/main/java/google/registry/persistence/EppHistoryVKey.java @@ -0,0 +1,107 @@ +// Copyright 2020 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.persistence; + +import com.google.common.base.Joiner; +import com.googlecode.objectify.Key; +import google.registry.model.EppResource; +import google.registry.model.ImmutableObject; +import google.registry.model.reporting.HistoryEntry; +import google.registry.util.TypeUtils.TypeInstantiator; +import java.io.Serializable; +import javax.annotation.Nullable; +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.MappedSuperclass; + +/** + * Base class for {@link VKey} which ofyKey has a {@link HistoryEntry} key as its parent and a key + * for EPP resource as its grandparent. + * + *

For such a {@link VKey}, we need to provide two type parameters to indicate the type of {@link + * VKey} itself and the type of EPP resource respectively. + * + * @param type of the {@link VKey} + * @param type of the EPP resource that the key belongs to + */ +@MappedSuperclass +@Access(AccessType.FIELD) +public abstract class EppHistoryVKey extends ImmutableObject + implements Serializable { + + private static final long serialVersionUID = -3906580677709539818L; + + String repoId; + + Long historyRevisionId; + + // Hibernate requires a default constructor. + EppHistoryVKey() {} + + EppHistoryVKey(String repoId, long historyRevisionId) { + this.repoId = repoId; + this.historyRevisionId = historyRevisionId; + } + + /** + * Returns the kind path for the ofyKey in this instance. + * + *

This method is only used reflectively by {@link EppHistoryVKeyTranslatorFactory} to get the + * kind path for a given {@link EppHistoryVKey} instance so it is marked as a private method. + * + * @see #createKindPath(Key) + */ + @SuppressWarnings("unused") + private String getKindPath() { + String eppKind = Key.getKind(new TypeInstantiator(getClass()) {}.getExactType()); + String keyKind = Key.getKind(new TypeInstantiator(getClass()) {}.getExactType()); + if (keyKind.equals(Key.getKind(HistoryEntry.class))) { + return createKindPath(eppKind, keyKind); + } else { + return createKindPath(eppKind, Key.getKind(HistoryEntry.class), keyKind); + } + } + + /** + * Creates the kind path for the given ofyKey}. + * + *

The kind path is a string including all kind names(delimited by slash) of a hierarchical + * {@link Key}, e.g., the kind path for BillingEvent.OneTime is "DomainBase/HistoryEntry/OneTime". + */ + @Nullable + public static String createKindPath(@Nullable Key ofyKey) { + if (ofyKey == null) { + return null; + } else if (ofyKey.getParent() == null) { + return ofyKey.getKind(); + } else { + return createKindPath(createKindPath(ofyKey.getParent()), ofyKey.getKind()); + } + } + + private static String createKindPath(String... kinds) { + return Joiner.on("/").join(kinds); + } + + /** Creates a {@link VKey} from this instance. */ + public VKey createVKey() { + Class vKeyType = new TypeInstantiator(getClass()) {}.getExactType(); + return VKey.create(vKeyType, createSqlKey(), createOfyKey()); + } + + public abstract Object createSqlKey(); + + public abstract Key createOfyKey(); +} diff --git a/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java b/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java index fd26ea708..d65d8977e 100644 --- a/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java +++ b/core/src/test/java/google/registry/flows/domain/DomainCheckFlowTest.java @@ -71,7 +71,6 @@ import google.registry.model.registry.Registry; import google.registry.model.registry.Registry.TldState; import google.registry.model.registry.label.ReservedList; import google.registry.model.reporting.HistoryEntry; -import google.registry.persistence.DomainHistoryVKey; import org.joda.money.CurrencyUnit; import org.joda.money.Money; import org.joda.time.DateTime; @@ -169,7 +168,7 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase field.getName() + "." + subfield) .distinct() diff --git a/core/src/test/java/google/registry/model/domain/DomainBaseSqlTest.java b/core/src/test/java/google/registry/model/domain/DomainBaseSqlTest.java index 522ad3f5e..c9e214b59 100644 --- a/core/src/test/java/google/registry/model/domain/DomainBaseSqlTest.java +++ b/core/src/test/java/google/registry/model/domain/DomainBaseSqlTest.java @@ -633,14 +633,13 @@ public class DomainBaseSqlTest { "4-COM", END_OF_TIME, "registrar1", - createLegacyVKey( - BillingEvent.OneTime.class, oneTimeBillingEvent.getId())), + oneTimeBillingEvent.createVKey()), GracePeriod.createForRecurring( GracePeriodStatus.AUTO_RENEW, "4-COM", END_OF_TIME, "registrar1", - createLegacyVKey(BillingEvent.Recurring.class, billEvent.getId()))); + billEvent.createVKey())); jpaTm().insert(contact); jpaTm().insert(contact2); diff --git a/core/src/test/java/google/registry/model/domain/DomainBaseTest.java b/core/src/test/java/google/registry/model/domain/DomainBaseTest.java index d64c9934e..09a6ae5cc 100644 --- a/core/src/test/java/google/registry/model/domain/DomainBaseTest.java +++ b/core/src/test/java/google/registry/model/domain/DomainBaseTest.java @@ -875,16 +875,13 @@ public class DomainBaseTest extends EntityTestCase { ImmutableSet historyIds = domain.getGracePeriods().stream() .map( - gp -> - new BillEventInfo( - gp.getRecurringBillingEvent(), gp.billingEventRecurringHistoryId, - gp.getOneTimeBillingEvent(), gp.billingEventOneTimeHistoryId)) + gp -> new BillEventInfo(gp.getRecurringBillingEvent(), gp.getOneTimeBillingEvent())) .collect(toImmutableSet()); assertThat(historyIds) .isEqualTo( ImmutableSet.of( - new BillEventInfo(null, null, oneTimeBillKey, historyEntryKey.getId()), - new BillEventInfo(recurringBillKey, historyEntryKey.getId(), null, null))); + new BillEventInfo(null, oneTimeBillKey), + new BillEventInfo(recurringBillKey, null))); } static class BillEventInfo extends ImmutableObject { @@ -895,13 +892,9 @@ public class DomainBaseTest extends EntityTestCase { BillEventInfo( VKey billingEventRecurring, - Long billingEventRecurringHistoryId, - VKey billingEventOneTime, - Long billingEventOneTimeHistoryId) { + VKey billingEventOneTime) { this.billingEventRecurring = billingEventRecurring; - this.billingEventRecurringHistoryId = billingEventRecurringHistoryId; this.billingEventOneTime = billingEventOneTime; - this.billingEventOneTimeHistoryId = billingEventOneTimeHistoryId; } } } diff --git a/core/src/test/java/google/registry/model/domain/GracePeriodTest.java b/core/src/test/java/google/registry/model/domain/GracePeriodTest.java index 13dffc2be..7904682b7 100644 --- a/core/src/test/java/google/registry/model/domain/GracePeriodTest.java +++ b/core/src/test/java/google/registry/model/domain/GracePeriodTest.java @@ -63,11 +63,11 @@ public class GracePeriodTest { recurringKey = VKey.create( Recurring.class, - 12345, + 12345L, Key.create( Key.create(Key.create(DomainBase.class, "1-TEST"), HistoryEntry.class, 343L), Recurring.class, - 12345)); + 12345L)); } @Test @@ -80,8 +80,6 @@ public class GracePeriodTest { assertThat(gracePeriod.getClientId()).isEqualTo("TheRegistrar"); assertThat(gracePeriod.getExpirationTime()).isEqualTo(now.plusDays(1)); assertThat(gracePeriod.hasBillingEvent()).isTrue(); - assertThat(gracePeriod.billingEventOneTimeHistoryId).isEqualTo(12345L); - assertThat(gracePeriod.billingEventRecurringHistoryId).isNull(); } @Test @@ -96,8 +94,6 @@ public class GracePeriodTest { assertThat(gracePeriod.getClientId()).isEqualTo("TheRegistrar"); assertThat(gracePeriod.getExpirationTime()).isEqualTo(now.plusDays(1)); assertThat(gracePeriod.hasBillingEvent()).isTrue(); - assertThat(gracePeriod.billingEventOneTimeHistoryId).isNull(); - assertThat(gracePeriod.billingEventRecurringHistoryId).isEqualTo(343L); } @Test diff --git a/core/src/test/java/google/registry/model/domain/token/AllocationTokenTest.java b/core/src/test/java/google/registry/model/domain/token/AllocationTokenTest.java index 95761dfb2..4581780d1 100644 --- a/core/src/test/java/google/registry/model/domain/token/AllocationTokenTest.java +++ b/core/src/test/java/google/registry/model/domain/token/AllocationTokenTest.java @@ -40,7 +40,6 @@ import google.registry.model.domain.DomainBase; import google.registry.model.domain.token.AllocationToken.TokenStatus; import google.registry.model.domain.token.AllocationToken.TokenType; import google.registry.model.reporting.HistoryEntry; -import google.registry.persistence.DomainHistoryVKey; import google.registry.persistence.VKey; import org.joda.time.DateTime; import org.junit.jupiter.api.BeforeEach; @@ -86,7 +85,7 @@ public class AllocationTokenTest extends EntityTestCase { persistResource( new AllocationToken.Builder() .setToken("abc123Single") - .setRedemptionHistoryEntry(DomainHistoryVKey.create(historyEntryKey)) + .setRedemptionHistoryEntry(HistoryEntry.createVKey(historyEntryKey)) .setDomainName("example.foo") .setCreationTimeForTest(DateTime.parse("2010-11-12T05:00:00Z")) .setTokenType(SINGLE_USE) @@ -125,7 +124,7 @@ public class AllocationTokenTest extends EntityTestCase { new AllocationToken.Builder() .setToken("abc123") .setTokenType(SINGLE_USE) - .setRedemptionHistoryEntry(DomainHistoryVKey.create(historyEntryKey)) + .setRedemptionHistoryEntry(HistoryEntry.createVKey(historyEntryKey)) .setDomainName("blahdomain.foo") .setCreationTimeForTest(DateTime.parse("2010-11-12T05:00:00Z")) .build()), @@ -231,7 +230,7 @@ public class AllocationTokenTest extends EntityTestCase { new AllocationToken.Builder() .setToken("foobar") .setTokenType(TokenType.UNLIMITED_USE) - .setRedemptionHistoryEntry(DomainHistoryVKey.create(historyEntryKey)); + .setRedemptionHistoryEntry(HistoryEntry.createVKey(historyEntryKey)); IllegalArgumentException thrown = assertThrows(IllegalArgumentException.class, builder::build); assertThat(thrown) .hasMessageThat() diff --git a/core/src/test/java/google/registry/model/translators/EppHistoryVKeyTranslatorFactoryTest.java b/core/src/test/java/google/registry/model/translators/EppHistoryVKeyTranslatorFactoryTest.java new file mode 100644 index 000000000..fc6a371cd --- /dev/null +++ b/core/src/test/java/google/registry/model/translators/EppHistoryVKeyTranslatorFactoryTest.java @@ -0,0 +1,36 @@ +// Copyright 2020 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.model.translators; + +import static google.registry.model.translators.EppHistoryVKeyTranslatorFactory.kindPathToVKeyClass; +import static org.junit.jupiter.api.Assertions.fail; + +import org.junit.jupiter.api.Test; + +/** Unit test for {@link EppHistoryVKeyTranslatorFactory}. */ +class EppHistoryVKeyTranslatorFactoryTest { + + @Test + void assertAllVKeyClassesHavingCreateFromOfyKeyMethod() { + kindPathToVKeyClass.forEach( + (kindPath, vKeyClass) -> { + try { + vKeyClass.getDeclaredMethod("create", com.googlecode.objectify.Key.class); + } catch (NoSuchMethodException e) { + fail("Missing static method create(com.googlecode.objectify.Key) on " + vKeyClass, e); + } + }); + } +} diff --git a/core/src/test/java/google/registry/persistence/BillingVKeyTest.java b/core/src/test/java/google/registry/persistence/BillingVKeyTest.java new file mode 100644 index 000000000..488c16dba --- /dev/null +++ b/core/src/test/java/google/registry/persistence/BillingVKeyTest.java @@ -0,0 +1,116 @@ +// Copyright 2020 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package google.registry.persistence; + +import static com.google.common.truth.Truth.assertThat; +import static google.registry.model.common.EntityGroupRoot.getCrossTldKey; +import static google.registry.persistence.transaction.TransactionManagerFactory.tm; + +import com.googlecode.objectify.Key; +import com.googlecode.objectify.annotation.Entity; +import com.googlecode.objectify.annotation.Id; +import com.googlecode.objectify.annotation.Parent; +import google.registry.model.ImmutableObject; +import google.registry.model.billing.BillingEvent; +import google.registry.model.common.EntityGroupRoot; +import google.registry.model.domain.DomainBase; +import google.registry.model.reporting.HistoryEntry; +import google.registry.persistence.BillingVKey.BillingEventVKey; +import google.registry.persistence.BillingVKey.BillingRecurrenceVKey; +import google.registry.schema.replay.EntityTest.EntityForTesting; +import google.registry.testing.AppEngineExtension; +import google.registry.testing.DualDatabaseTest; +import google.registry.testing.TestOfyAndSql; +import javax.persistence.Transient; +import org.junit.jupiter.api.extension.RegisterExtension; + +/** Unit test for {@link BillingVKey}. */ +@DualDatabaseTest +class BillingVKeyTest { + @RegisterExtension + final AppEngineExtension appEngine = + AppEngineExtension.builder() + .withDatastoreAndCloudSql() + .withOfyTestEntities(BillingVKeyTestEntity.class) + .withJpaUnitTestEntities(BillingVKeyTestEntity.class) + .build(); + + @TestOfyAndSql + void testRestoreSymmetricVKey() { + Key domainHistoryKey = + Key.create(Key.create(DomainBase.class, "domainRepoId"), HistoryEntry.class, 10L); + + Key oneTimeOfyKey = + Key.create(domainHistoryKey, BillingEvent.OneTime.class, 100L); + VKey oneTimeVKey = + VKey.create(BillingEvent.OneTime.class, 100L, oneTimeOfyKey); + + Key recurringOfyKey = + Key.create(domainHistoryKey, BillingEvent.Recurring.class, 200L); + VKey recurringVKey = + VKey.create(BillingEvent.Recurring.class, 200L, recurringOfyKey); + + BillingVKeyTestEntity original = new BillingVKeyTestEntity(oneTimeVKey, recurringVKey); + tm().transact(() -> tm().insert(original)); + BillingVKeyTestEntity persisted = tm().transact(() -> tm().load(original.createVKey())); + + assertThat(persisted).isEqualTo(original); + assertThat(persisted.getBillingEventVKey()).isEqualTo(oneTimeVKey); + assertThat(persisted.getBillingRecurrenceVKey()).isEqualTo(recurringVKey); + } + + @TestOfyAndSql + void testHandleNullVKeyCorrectly() { + BillingVKeyTestEntity original = new BillingVKeyTestEntity(null, null); + tm().transact(() -> tm().insert(original)); + BillingVKeyTestEntity persisted = tm().transact(() -> tm().load(original.createVKey())); + + assertThat(persisted).isEqualTo(original); + } + + @EntityForTesting + @Entity + @javax.persistence.Entity + private static class BillingVKeyTestEntity extends ImmutableObject { + @Transient @Parent Key parent = getCrossTldKey(); + + @Id @javax.persistence.Id String id = "id"; + + BillingEventVKey billingEventVKey; + + BillingRecurrenceVKey billingRecurrenceVKey; + + BillingVKeyTestEntity() {} + + BillingVKeyTestEntity( + VKey onetime, VKey recurring) { + this.billingEventVKey = BillingEventVKey.create(onetime); + this.billingRecurrenceVKey = BillingRecurrenceVKey.create(recurring); + } + + VKey getBillingEventVKey() { + return billingEventVKey.createVKey(); + } + + VKey getBillingRecurrenceVKey() { + return billingRecurrenceVKey.createVKey(); + } + + VKey createVKey() { + return VKey.create( + BillingVKeyTestEntity.class, id, Key.create(parent, BillingVKeyTestEntity.class, id)); + } + } +} diff --git a/core/src/test/java/google/registry/persistence/DomainHistoryVKeyTest.java b/core/src/test/java/google/registry/persistence/DomainHistoryVKeyTest.java index 8c7b26fdf..76254a688 100644 --- a/core/src/test/java/google/registry/persistence/DomainHistoryVKeyTest.java +++ b/core/src/test/java/google/registry/persistence/DomainHistoryVKeyTest.java @@ -56,12 +56,17 @@ class DomainHistoryVKeyTest { TestEntity persisted = tm().transact(() -> tm().load(original.createVKey())); assertThat(persisted).isEqualTo(original); // Double check that the persisted.domainHistoryVKey is a symmetric VKey - assertThat(persisted.domainHistoryVKey.getKind()).isEqualTo(HistoryEntry.class); - assertThat(persisted.domainHistoryVKey.getOfyKey()) + assertThat(persisted.domainHistoryVKey.createOfyKey()) .isEqualTo( Key.create(Key.create(DomainBase.class, "domainRepoId"), HistoryEntry.class, 10L)); - assertThat(persisted.domainHistoryVKey.getSqlKey()) + assertThat(persisted.domainHistoryVKey.createSqlKey()) .isEqualTo(new DomainHistoryId("domainRepoId", 10L)); + assertThat(persisted.domainHistoryVKey.createVKey()) + .isEqualTo( + VKey.create( + HistoryEntry.class, + new DomainHistoryId("domainRepoId", 10L), + Key.create(Key.create(DomainBase.class, "domainRepoId"), HistoryEntry.class, 10L))); } @TestOfyAndSql @@ -69,9 +74,12 @@ class DomainHistoryVKeyTest { Key ofyKey = Key.create(Key.create(DomainBase.class, "domainRepoId"), HistoryEntry.class, 10L); DomainHistoryVKey domainHistoryVKey = DomainHistoryVKey.create(ofyKey); - assertThat(domainHistoryVKey.getKind()).isEqualTo(HistoryEntry.class); - assertThat(domainHistoryVKey.getOfyKey()).isEqualTo(ofyKey); - assertThat(domainHistoryVKey.getSqlKey()).isEqualTo(new DomainHistoryId("domainRepoId", 10L)); + assertThat(domainHistoryVKey.createOfyKey()).isEqualTo(ofyKey); + assertThat(domainHistoryVKey.createSqlKey()) + .isEqualTo(new DomainHistoryId("domainRepoId", 10L)); + assertThat(domainHistoryVKey.createVKey()) + .isEqualTo( + VKey.create(HistoryEntry.class, new DomainHistoryId("domainRepoId", 10L), ofyKey)); } @EntityForTesting diff --git a/core/src/test/java/google/registry/tools/DeleteAllocationTokensCommandTest.java b/core/src/test/java/google/registry/tools/DeleteAllocationTokensCommandTest.java index 9f28c0a2a..889753a70 100644 --- a/core/src/test/java/google/registry/tools/DeleteAllocationTokensCommandTest.java +++ b/core/src/test/java/google/registry/tools/DeleteAllocationTokensCommandTest.java @@ -27,7 +27,6 @@ import google.registry.model.domain.DomainBase; import google.registry.model.domain.token.AllocationToken; import google.registry.model.domain.token.AllocationToken.TokenType; import google.registry.model.reporting.HistoryEntry; -import google.registry.persistence.DomainHistoryVKey; import java.util.Collection; import javax.annotation.Nullable; import org.junit.jupiter.api.BeforeEach; @@ -173,7 +172,7 @@ class DeleteAllocationTokensCommandTest extends CommandTestCase historyEntryKey = Key.create(Key.create(domain), HistoryEntry.class, 1051L); - builder.setRedemptionHistoryEntry(DomainHistoryVKey.create(historyEntryKey)); + builder.setRedemptionHistoryEntry(HistoryEntry.createVKey(historyEntryKey)); } return persistResource(builder.build()); } diff --git a/core/src/test/java/google/registry/tools/GenerateAllocationTokensCommandTest.java b/core/src/test/java/google/registry/tools/GenerateAllocationTokensCommandTest.java index 2d217c0c4..37af7d9d4 100644 --- a/core/src/test/java/google/registry/tools/GenerateAllocationTokensCommandTest.java +++ b/core/src/test/java/google/registry/tools/GenerateAllocationTokensCommandTest.java @@ -39,7 +39,8 @@ import com.google.common.collect.Iterables; import com.google.common.io.Files; import google.registry.model.domain.token.AllocationToken; import google.registry.model.domain.token.AllocationToken.TokenStatus; -import google.registry.persistence.DomainHistoryVKey; +import google.registry.model.reporting.HistoryEntry; +import google.registry.persistence.VKey; import google.registry.testing.DeterministicStringGenerator; import google.registry.testing.DeterministicStringGenerator.Rule; import google.registry.testing.FakeClock; @@ -313,7 +314,7 @@ class GenerateAllocationTokensCommandTest extends CommandTestCase redemptionHistoryEntry, @Nullable String domainName) { AllocationToken.Builder builder = new AllocationToken.Builder().setToken(token).setTokenType(SINGLE_USE); diff --git a/core/src/test/java/google/registry/tools/GetAllocationTokenCommandTest.java b/core/src/test/java/google/registry/tools/GetAllocationTokenCommandTest.java index 6dac92593..515339c4a 100644 --- a/core/src/test/java/google/registry/tools/GetAllocationTokenCommandTest.java +++ b/core/src/test/java/google/registry/tools/GetAllocationTokenCommandTest.java @@ -28,7 +28,7 @@ import com.google.common.collect.ImmutableList; import com.googlecode.objectify.Key; import google.registry.model.domain.DomainBase; import google.registry.model.domain.token.AllocationToken; -import google.registry.persistence.DomainHistoryVKey; +import google.registry.model.reporting.HistoryEntry; import org.joda.time.DateTime; import org.junit.jupiter.api.Test; @@ -85,7 +85,7 @@ class GetAllocationTokenCommandTest extends CommandTestCase billingEventOneTime; - google.registry.persistence.VKey billingEventRecurring; + google.registry.persistence.BillingVKey$BillingEventVKey billingEventOneTime; + google.registry.persistence.BillingVKey$BillingRecurrenceVKey billingEventRecurring; java.lang.Long gracePeriodId; java.lang.String clientId; org.joda.time.DateTime expirationTime; @@ -888,10 +888,17 @@ enum google.registry.model.transfer.TransferStatus { SERVER_APPROVED; SERVER_CANCELLED; } -class google.registry.persistence.DomainHistoryVKey { - com.googlecode.objectify.Key ofyKey; - java.lang.Class kind; - java.lang.Long domainHistoryId; - java.lang.Object sqlKey; - java.lang.String domainRepoId; +class google.registry.persistence.BillingVKey$BillingEventVKey { + java.lang.Long billingId; + java.lang.Long historyRevisionId; + java.lang.String repoId; +} +class google.registry.persistence.BillingVKey$BillingRecurrenceVKey { + java.lang.Long billingId; + java.lang.Long historyRevisionId; + java.lang.String repoId; +} +class google.registry.persistence.DomainHistoryVKey { + java.lang.Long historyRevisionId; + java.lang.String repoId; } diff --git a/db/src/main/resources/sql/er_diagram/brief_er_diagram.html b/db/src/main/resources/sql/er_diagram/brief_er_diagram.html index 52dd59ba8..6015cbdd8 100644 --- a/db/src/main/resources/sql/er_diagram/brief_er_diagram.html +++ b/db/src/main/resources/sql/er_diagram/brief_er_diagram.html @@ -261,11 +261,11 @@ td.section { generated on - 2020-12-05 00:29:03.934355 + 2020-12-16 16:26:55.279224 last flyway file - V81__drop_spec11_fkeys.sql + V82__add_columns_to_restore_symmetric_billing_vkey.sql @@ -284,7 +284,7 @@ td.section { generated on - 2020-12-05 00:29:03.934355 + 2020-12-16 16:26:55.279224 diff --git a/db/src/main/resources/sql/er_diagram/full_er_diagram.html b/db/src/main/resources/sql/er_diagram/full_er_diagram.html index 11d616f0d..93a85397f 100644 --- a/db/src/main/resources/sql/er_diagram/full_er_diagram.html +++ b/db/src/main/resources/sql/er_diagram/full_er_diagram.html @@ -261,19 +261,19 @@ td.section { generated on - 2020-12-05 00:29:01.929048 + 2020-12-16 16:26:53.180789 last flyway file - V81__drop_spec11_fkeys.sql + V82__add_columns_to_restore_symmetric_billing_vkey.sql

 

 

- + SchemaCrawler_Diagram - + generated by @@ -284,5375 +284,5407 @@ td.section { generated on - 2020-12-05 00:29:01.929048 + 2020-12-16 16:26:53.180789 allocationtoken_a08ccbef - - + + public.AllocationToken - - + + [table] - + token - + - + text not null - + update_timestamp - + - + timestamptz - + allowed_registrar_ids - + - + _text - + allowed_tlds - + - + _text - + creation_time - + - + timestamptz not null - + discount_fraction - + - + float8(17, 17) not null - + discount_premiums - + - + bool not null - + discount_years - + - + int4 not null - + domain_name - + - + text - + redemption_domain_repo_id - + - + text - + token_status_transitions - + - + "hstore" - + token_type - + - + text - + redemption_domain_history_id - + - + int8 - + billingevent_a57d1815 - - + + public.BillingEvent - - + + [table] - + billing_event_id - + - + int8 not null - + registrar_id - + - + text not null - + domain_history_revision_id - + - + int8 not null - + domain_repo_id - + - + text not null - + event_time - + - + timestamptz not null - + flags - + - + _text - + reason - + - + text not null - + domain_name - + - + text not null - + allocation_token - + - + text - + billing_time - + - + timestamptz - + cancellation_matching_billing_recurrence_id - + - + int8 - + cost_amount - + - + numeric(19, 2) - + cost_currency - + - + text - + period_years - + - + int4 - + synthetic_creation_time - + - + timestamptz - + billingevent_a57d1815:w->allocationtoken_a08ccbef:e - - - - - - - - + + + + + + + + fk_billing_event_allocation_token billingrecurrence_5fa2cb01 - - + + public.BillingRecurrence - - + + [table] - + billing_recurrence_id - + - + int8 not null - + registrar_id - + - + text not null - + domain_history_revision_id - + - + int8 not null - + domain_repo_id - + - + text not null - + event_time - + - + timestamptz not null - + flags - + - + _text - + reason - + - + text not null - + domain_name - + - + text not null - + recurrence_end_time - + - + timestamptz - + recurrence_time_of_year - + - + text - + billingevent_a57d1815:w->billingrecurrence_5fa2cb01:e - - - - - - - - + + + + + + + + fk_billing_event_cancellation_matching_billing_recurrence_id domainhistory_a54cc226 - - + + public.DomainHistory - - + + [table] - + history_revision_id - + - + int8 not null - + history_by_superuser - + - + bool not null - + history_registrar_id - + - + text - + history_modification_time - + - + timestamptz not null - + history_reason - + - + text - + history_requested_by_registrar - + - + bool - + history_client_transaction_id - + - + text - + history_server_transaction_id - + - + text - + history_type - + - + text not null - + history_xml_bytes - + - + bytea - + admin_contact - + - + text - + auth_info_repo_id - + - + text - + auth_info_value - + - + text - + billing_recurrence_id - + - + int8 - + autorenew_poll_message_id - + - + int8 - + billing_contact - + - + text - + deletion_poll_message_id - + - + int8 - + domain_name - + - + text - + idn_table_name - + - + text - + last_transfer_time - + - + timestamptz - + launch_notice_accepted_time - + - + timestamptz - + launch_notice_expiration_time - + - + timestamptz - + launch_notice_tcn_id - + - + text - + launch_notice_validator_id - + - + text - + registrant_contact - + - + text - + registration_expiration_time - + - + timestamptz - + smd_id - + - + text - + subordinate_hosts - + - + _text - + tech_contact - + - + text - + tld - + - + text - + transfer_billing_cancellation_id - + - + int8 - + transfer_billing_recurrence_id - + - + int8 - + transfer_autorenew_poll_message_id - + - + int8 - + transfer_billing_event_id - + - + int8 - + transfer_renew_period_unit - + - + text - + transfer_renew_period_value - + - + int4 - + transfer_registration_expiration_time - + - + timestamptz - + transfer_gaining_poll_message_id - + - + int8 - + transfer_losing_poll_message_id - + - + int8 - + transfer_client_txn_id - + - + text - + transfer_server_txn_id - + - + text - + transfer_gaining_registrar_id - + - + text - + transfer_losing_registrar_id - + - + text - + transfer_pending_expiration_time - + - + timestamptz - + transfer_request_time - + - + timestamptz - + transfer_status - + - + text - + creation_registrar_id - + - + text - + creation_time - + - + timestamptz - + current_sponsor_registrar_id - + - + text - + deletion_time - + - + timestamptz - + last_epp_update_registrar_id - + - + text - + last_epp_update_time - + - + timestamptz - + statuses - + - + _text - + update_timestamp - + - + timestamptz - + domain_repo_id - + - + text not null - + autorenew_end_time - + - + timestamptz - + history_other_registrar_id - + - + text - + history_period_unit - + - + text - + history_period_value - + - + int4 - + billing_recurrence_history_id - + - + int8 - + autorenew_poll_message_history_id - + - + int8 - + deletion_poll_message_history_id - + - + int8 - + transfer_billing_recurrence_history_id - + - + int8 - + transfer_autorenew_poll_message_history_id - + - + int8 - + transfer_billing_event_history_id - + - + int8 - + billingevent_a57d1815:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fk_billing_event_domain_history billingevent_a57d1815:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fk_billing_event_domain_history registrar_6e1503e3 - - + + public.Registrar - - + + [table] - + registrar_id - + - + text not null - + allowed_tlds - + - + _text - + billing_account_map - + - + "hstore" - + billing_identifier - + - + int8 - + block_premium_names - + - + bool not null - + client_certificate - + - + text - + client_certificate_hash - + - + text - + contacts_require_syncing - + - + bool not null - + creation_time - + - + timestamptz - + drive_folder_id - + - + text - + email_address - + - + text - + failover_client_certificate - + - + text - + failover_client_certificate_hash - + - + text - + fax_number - + - + text - + iana_identifier - + - + int8 - + icann_referral_email - + - + text - + i18n_address_city - + - + text - + i18n_address_country_code - + - + text - + i18n_address_state - + - + text - + i18n_address_street_line1 - + - + text - + i18n_address_street_line2 - + - + text - + i18n_address_street_line3 - + - + text - + i18n_address_zip - + - + text - + ip_address_allow_list - + - + _text - + last_certificate_update_time - + - + timestamptz - + last_update_time - + - + timestamptz - + localized_address_city - + - + text - + localized_address_country_code - + - + text - + localized_address_state - + - + text - + localized_address_street_line1 - + - + text - + localized_address_street_line2 - + - + text - + localized_address_street_line3 - + - + text - + localized_address_zip - + - + text - + password_hash - + - + text - + phone_number - + - + text - + phone_passcode - + - + text - + po_number - + - + text - + rdap_base_urls - + - + _text - + registrar_name - + - + text not null - + registry_lock_allowed - + - + bool not null - + password_salt - + - + text - + state - + - + text - + type - + - + text not null - + url - + - + text - + whois_server - + - + text - + billingevent_a57d1815:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_billing_event_registrar_id billingcancellation_6eedf614 - - + + public.BillingCancellation - - + + [table] - + billing_cancellation_id - + - + int8 not null - + registrar_id - + - + text not null - + domain_history_revision_id - + - + int8 not null - + domain_repo_id - + - + text not null - + event_time - + - + timestamptz not null - + flags - + - + _text - + reason - + - + text not null - + domain_name - + - + text not null - + billing_time - + - + timestamptz - + billing_event_id - + - + int8 - + billing_recurrence_id - + - + int8 - + billingcancellation_6eedf614:w->billingevent_a57d1815:e - - - - - - - - + + + + + + + + fk_billing_cancellation_billing_event_id billingcancellation_6eedf614:w->billingrecurrence_5fa2cb01:e - - - - - - - - + + + + + + + + fk_billing_cancellation_billing_recurrence_id billingcancellation_6eedf614:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fk_billing_cancellation_domain_history billingcancellation_6eedf614:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fk_billing_cancellation_domain_history billingcancellation_6eedf614:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_billing_cancellation_registrar_id domain_6c51cffa - - + + public.Domain - - + + [table] - + repo_id - + - + text not null - + creation_registrar_id - + - + text not null - + creation_time - + - + timestamptz not null - + current_sponsor_registrar_id - + - + text not null - + deletion_time - + - + timestamptz - + last_epp_update_registrar_id - + - + text - + last_epp_update_time - + - + timestamptz - + statuses - + - + _text - + auth_info_repo_id - + - + text - + auth_info_value - + - + text - + domain_name - + - + text - + idn_table_name - + - + text - + last_transfer_time - + - + timestamptz - + launch_notice_accepted_time - + - + timestamptz - + launch_notice_expiration_time - + - + timestamptz - + launch_notice_tcn_id - + - + text - + launch_notice_validator_id - + - + text - + registration_expiration_time - + - + timestamptz - + smd_id - + - + text - + subordinate_hosts - + - + _text - + tld - + - + text - + admin_contact - + - + text - + billing_contact - + - + text - + registrant_contact - + - + text - + tech_contact - + - + text - + transfer_gaining_poll_message_id - + - + int8 - + transfer_losing_poll_message_id - + - + int8 - + transfer_billing_cancellation_id - + - + int8 - + transfer_billing_event_id - + - + int8 - + transfer_billing_recurrence_id - + - + int8 - + transfer_autorenew_poll_message_id - + - + int8 - + transfer_renew_period_unit - + - + text - + transfer_renew_period_value - + - + int4 - + transfer_client_txn_id - + - + text - + transfer_server_txn_id - + - + text - + transfer_registration_expiration_time - + - + timestamptz - + transfer_gaining_registrar_id - + - + text - + transfer_losing_registrar_id - + - + text - + transfer_pending_expiration_time - + - + timestamptz - + transfer_request_time - + - + timestamptz - + transfer_status - + - + text - + update_timestamp - + - + timestamptz - + billing_recurrence_id - + - + int8 - + autorenew_poll_message_id - + - + int8 - + deletion_poll_message_id - + - + int8 - + autorenew_end_time - + - + timestamptz - + billing_recurrence_history_id - + - + int8 - + autorenew_poll_message_history_id - + - + int8 - + deletion_poll_message_history_id - + - + int8 - + transfer_billing_recurrence_history_id - + - + int8 - + transfer_autorenew_poll_message_history_id - + - + int8 - + transfer_billing_event_history_id - + - + int8 - + domain_6c51cffa:w->billingevent_a57d1815:e - - - - - - - - + + + + + + + + fk_domain_transfer_billing_event_id domain_6c51cffa:w->billingcancellation_6eedf614:e - - - - - - - - + + + + + + + + fk_domain_transfer_billing_cancellation_id domain_6c51cffa:w->billingrecurrence_5fa2cb01:e - - - - - - - - + + + + + + + + fk_domain_billing_recurrence_id domain_6c51cffa:w->billingrecurrence_5fa2cb01:e - - - - - - - - + + + + + + + + fk_domain_transfer_billing_recurrence_id contact_8de8cb16 - - + + public.Contact - - + + [table] - + repo_id - + - + text not null - + creation_registrar_id - + - + text not null - + creation_time - + - + timestamptz not null - + current_sponsor_registrar_id - + - + text not null - + deletion_time - + - + timestamptz - + last_epp_update_registrar_id - + - + text - + last_epp_update_time - + - + timestamptz - + statuses - + - + _text - + auth_info_repo_id - + - + text - + auth_info_value - + - + text - + contact_id - + - + text - + disclose_types_addr - + - + _text - + disclose_show_email - + - + bool - + disclose_show_fax - + - + bool - + disclose_mode_flag - + - + bool - + disclose_types_name - + - + _text - + disclose_types_org - + - + _text - + disclose_show_voice - + - + bool - + email - + - + text - + fax_phone_extension - + - + text - + fax_phone_number - + - + text - + addr_i18n_city - + - + text - + addr_i18n_country_code - + - + text - + addr_i18n_state - + - + text - + addr_i18n_street_line1 - + - + text - + addr_i18n_street_line2 - + - + text - + addr_i18n_street_line3 - + - + text - + addr_i18n_zip - + - + text - + addr_i18n_name - + - + text - + addr_i18n_org - + - + text - + addr_i18n_type - + - + text - + last_transfer_time - + - + timestamptz - + addr_local_city - + - + text - + addr_local_country_code - + - + text - + addr_local_state - + - + text - + addr_local_street_line1 - + - + text - + addr_local_street_line2 - + - + text - + addr_local_street_line3 - + - + text - + addr_local_zip - + - + text - + addr_local_name - + - + text - + addr_local_org - + - + text - + addr_local_type - + - + text - + search_name - + - + text - + voice_phone_extension - + - + text - + voice_phone_number - + - + text - + transfer_gaining_poll_message_id - + - + int8 - + transfer_losing_poll_message_id - + - + int8 - + transfer_client_txn_id - + - + text - + transfer_server_txn_id - + - + text - + transfer_gaining_registrar_id - + - + text - + transfer_losing_registrar_id - + - + text - + transfer_pending_expiration_time - + - + timestamptz - + transfer_request_time - + - + timestamptz - + transfer_status - + - + text - + update_timestamp - + - + timestamptz - + domain_6c51cffa:w->contact_8de8cb16:e - - - - - - - - + + + + + + + + fk_domain_admin_contact domain_6c51cffa:w->contact_8de8cb16:e - - - - - - - - + + + + + + + + fk_domain_billing_contact domain_6c51cffa:w->contact_8de8cb16:e - - - - - - - - + + + + + + + + fk_domain_registrant_contact domain_6c51cffa:w->contact_8de8cb16:e - - - - - - - - + + + + + + + + fk_domain_tech_contact domain_6c51cffa:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk2jc69qyg2tv9hhnmif6oa1cx1 domain_6c51cffa:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk2u3srsfbei272093m3b3xwj23 domain_6c51cffa:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fkjc0r9r5y1lfbt4gpbqw4wsuvq domain_6c51cffa:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_domain_transfer_gaining_registrar_id domain_6c51cffa:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_domain_transfer_losing_registrar_id tld_f1fa57e2 - - + + public.Tld - - + + [table] - + tld_name - + - + text not null - + add_grace_period_length - + - + interval not null - + allowed_fully_qualified_host_names - + - + _text - + allowed_registrant_contact_ids - + - + _text - + anchor_tenant_add_grace_period_length - + - + interval not null - + auto_renew_grace_period_length - + - + interval not null - + automatic_transfer_length - + - + interval not null - + claims_period_end - + - + timestamptz not null - + create_billing_cost_amount - + - + numeric(19, 2) - + create_billing_cost_currency - + - + text - + creation_time - + - + timestamptz not null - + currency - + - + text not null - + dns_paused - + - + bool not null - + dns_writers - + - + _text not null - + drive_folder_id - + - + text - + eap_fee_schedule - + - + "hstore" not null - + escrow_enabled - + - + bool not null - + invoicing_enabled - + - + bool not null - + lordn_username - + - + text - + num_dns_publish_locks - + - + int4 not null - + pending_delete_length - + - + interval not null - + premium_list_name - + - + text - + pricing_engine_class_name - + - + text - + redemption_grace_period_length - + - + interval not null - + registry_lock_or_unlock_cost_amount - + - + numeric(19, 2) - + registry_lock_or_unlock_cost_currency - + - + text - + renew_billing_cost_transitions - + - + "hstore" not null - + renew_grace_period_length - + - + interval not null - + reserved_list_names - + - + _text - + restore_billing_cost_amount - + - + numeric(19, 2) - + restore_billing_cost_currency - + - + text - + roid_suffix - + - + text - + server_status_change_billing_cost_amount - + - + numeric(19, 2) - + server_status_change_billing_cost_currency - + - + text - + tld_state_transitions - + - + "hstore" not null - + tld_type - + - + text not null - + tld_unicode - + - + text not null - + transfer_grace_period_length - + - + interval not null - + domain_6c51cffa:w->tld_f1fa57e2:e - - - - - - - - + + + + + + + + fk_domain_tld graceperiod_cd3b2e8f - - + + public.GracePeriod - - + + [table] - + grace_period_id - + - + int8 not null - + billing_event_id - + - + int8 - + billing_recurrence_id - + - + int8 - + registrar_id - + - + text not null - + domain_repo_id - + - + text not null - + expiration_time - + - + timestamptz not null - + type - + - + text not null - + billing_event_history_id - + - + int8 - + billing_recurrence_history_id - + - + int8 - + + billing_event_domain_repo_id + + + + + text + + + billing_recurrence_domain_repo_id + + + + + text + + graceperiod_cd3b2e8f:w->billingevent_a57d1815:e - - - - - - - - + + + + + + + + fk_grace_period_billing_event_id graceperiod_cd3b2e8f:w->domain_6c51cffa:e - - - - - - - - + + + + + + + + fk_grace_period_domain_repo_id graceperiod_cd3b2e8f:w->billingrecurrence_5fa2cb01:e - - - - - - - - + + + + + + + + fk_grace_period_billing_recurrence_id graceperiod_cd3b2e8f:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_grace_period_registrar_id billingrecurrence_5fa2cb01:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fk_billing_recurrence_domain_history billingrecurrence_5fa2cb01:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fk_billing_recurrence_domain_history billingrecurrence_5fa2cb01:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_billing_recurrence_registrar_id claimsentry_105da9f1 - - + + public.ClaimsEntry - - + + [table] - + revision_id - + - + int8 not null - + claim_key - + - + text not null - + domain_label - + - + text not null - + claimslist_3d49bc2b - - + + public.ClaimsList - - + + [table] - + revision_id - + - + bigserial not null - + - + auto-incremented - + creation_timestamp - + - + timestamptz not null - + tmdb_generation_time - + - + timestamptz not null - + claimsentry_105da9f1:w->claimslist_3d49bc2b:e - - - - - - - - + + + + + + + + fk6sc6at5hedffc0nhdcab6ivuq contact_8de8cb16:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk1sfyj7o7954prbn1exk7lpnoe contact_8de8cb16:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk93c185fx7chn68uv7nl6uv2s0 contact_8de8cb16:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fkmb7tdiv85863134w1wogtxrb2 contact_8de8cb16:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_contact_transfer_gaining_registrar_id contact_8de8cb16:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_contact_transfer_losing_registrar_id contacthistory_d2964f8a - - + + public.ContactHistory - - + + [table] - + history_revision_id - + - + int8 not null - + history_by_superuser - + - + bool not null - + history_registrar_id - + - + text - + history_modification_time - + - + timestamptz not null - + history_reason - + - + text - + history_requested_by_registrar - + - + bool - + history_client_transaction_id - + - + text - + history_server_transaction_id - + - + text - + history_type - + - + text not null - + history_xml_bytes - + - + bytea - + auth_info_repo_id - + - + text - + auth_info_value - + - + text - + contact_id - + - + text - + disclose_types_addr - + - + _text - + disclose_show_email - + - + bool - + disclose_show_fax - + - + bool - + disclose_mode_flag - + - + bool - + disclose_types_name - + - + _text - + disclose_types_org - + - + _text - + disclose_show_voice - + - + bool - + email - + - + text - + fax_phone_extension - + - + text - + fax_phone_number - + - + text - + addr_i18n_city - + - + text - + addr_i18n_country_code - + - + text - + addr_i18n_state - + - + text - + addr_i18n_street_line1 - + - + text - + addr_i18n_street_line2 - + - + text - + addr_i18n_street_line3 - + - + text - + addr_i18n_zip - + - + text - + addr_i18n_name - + - + text - + addr_i18n_org - + - + text - + addr_i18n_type - + - + text - + last_transfer_time - + - + timestamptz - + addr_local_city - + - + text - + addr_local_country_code - + - + text - + addr_local_state - + - + text - + addr_local_street_line1 - + - + text - + addr_local_street_line2 - + - + text - + addr_local_street_line3 - + - + text - + addr_local_zip - + - + text - + addr_local_name - + - + text - + addr_local_org - + - + text - + addr_local_type - + - + text - + search_name - + - + text - + transfer_gaining_poll_message_id - + - + int8 - + transfer_losing_poll_message_id - + - + int8 - + transfer_client_txn_id - + - + text - + transfer_server_txn_id - + - + text - + transfer_gaining_registrar_id - + - + text - + transfer_losing_registrar_id - + - + text - + transfer_pending_expiration_time - + - + timestamptz - + transfer_request_time - + - + timestamptz - + transfer_status - + - + text - + voice_phone_extension - + - + text - + voice_phone_number - + - + text - + creation_registrar_id - + - + text - + creation_time - + - + timestamptz - + current_sponsor_registrar_id - + - + text - + deletion_time - + - + timestamptz - + last_epp_update_registrar_id - + - + text - + last_epp_update_time - + - + timestamptz - + statuses - + - + _text - + contact_repo_id - + - + text not null - + update_timestamp - + - + timestamptz - + contacthistory_d2964f8a:w->contact_8de8cb16:e - - - - - - - - + + + + + + + + fk_contact_history_contact_repo_id contacthistory_d2964f8a:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_contact_history_registrar_id pollmessage_614a523e - - + + public.PollMessage - - + + [table] - + type - + - + text not null - + poll_message_id - + - + int8 not null - + registrar_id - + - + text not null - + contact_repo_id - + - + text - + contact_history_revision_id - + - + int8 - + domain_repo_id - + - + text - + domain_history_revision_id - + - + int8 - + event_time - + - + timestamptz not null - + host_repo_id - + - + text - + host_history_revision_id - + - + int8 - + message - + - + text - + transfer_response_contact_id - + - + text - + transfer_response_domain_expiration_time - + - + timestamptz - + transfer_response_domain_name - + - + text - + pending_action_response_action_result - + - + bool - + pending_action_response_name_or_id - + - + text - + pending_action_response_processed_date - + - + timestamptz - + pending_action_response_client_txn_id - + - + text - + pending_action_response_server_txn_id - + - + text - + transfer_response_gaining_registrar_id - + - + text - + transfer_response_losing_registrar_id - + - + text - + transfer_response_pending_transfer_expiration_time - + - + timestamptz - + transfer_response_transfer_request_time - + - + timestamptz - + transfer_response_transfer_status - + - + text - + autorenew_end_time - + - + timestamptz - + autorenew_domain_name - + - + text - + pollmessage_614a523e:w->domain_6c51cffa:e - - - - - - - - + + + + + + + + fk_poll_message_domain_repo_id pollmessage_614a523e:w->contact_8de8cb16:e - - - - - - - - + + + + + + + + fk_poll_message_contact_repo_id pollmessage_614a523e:w->contacthistory_d2964f8a:e - - - - - - - - + + + + + + + + fk_poll_message_contact_history pollmessage_614a523e:w->contacthistory_d2964f8a:e - - - - - - - - + + + + + + + + fk_poll_message_contact_history pollmessage_614a523e:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fk_poll_message_domain_history pollmessage_614a523e:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fk_poll_message_domain_history host_f21b78de - - + + public.Host - - + + [table] - + repo_id - + - + text not null - + creation_registrar_id - + - + text - + creation_time - + - + timestamptz - + current_sponsor_registrar_id - + - + text - + deletion_time - + - + timestamptz - + last_epp_update_registrar_id - + - + text - + last_epp_update_time - + - + timestamptz - + statuses - + - + _text - + host_name - + - + text - + last_superordinate_change - + - + timestamptz - + last_transfer_time - + - + timestamptz - + superordinate_domain - + - + text - + inet_addresses - + - + _text - + update_timestamp - + - + timestamptz - + pollmessage_614a523e:w->host_f21b78de:e - - - - - - - - + + + + + + + + fk_poll_message_host_repo_id hosthistory_56210c2 - - + + public.HostHistory - - + + [table] - + history_revision_id - + - + int8 not null - + history_by_superuser - + - + bool not null - + history_registrar_id - + - + text not null - + history_modification_time - + - + timestamptz not null - + history_reason - + - + text - + history_requested_by_registrar - + - + bool - + history_client_transaction_id - + - + text - + history_server_transaction_id - + - + text - + history_type - + - + text not null - + history_xml_bytes - + - + bytea - + host_name - + - + text - + inet_addresses - + - + _text - + last_superordinate_change - + - + timestamptz - + last_transfer_time - + - + timestamptz - + superordinate_domain - + - + text - + creation_registrar_id - + - + text - + creation_time - + - + timestamptz - + current_sponsor_registrar_id - + - + text - + deletion_time - + - + timestamptz - + last_epp_update_registrar_id - + - + text - + last_epp_update_time - + - + timestamptz - + statuses - + - + _text - + host_repo_id - + - + text not null - + update_timestamp - + - + timestamptz - + pollmessage_614a523e:w->hosthistory_56210c2:e - - - - - - - - + + + + + + + + fk_poll_message_host_history pollmessage_614a523e:w->hosthistory_56210c2:e - - - - - - - - + + + + + + + + fk_poll_message_host_history pollmessage_614a523e:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_poll_message_registrar_id pollmessage_614a523e:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_poll_message_transfer_response_gaining_registrar_id pollmessage_614a523e:w->registrar_6e1503e3:e - - - - - - - + + + + + + + fk_poll_message_transfer_response_losing_registrar_id cursor_6af40e8c - - + + public."Cursor" - - + + [table] - + "scope" - + - + text not null - + type - + - + text not null - + cursor_time - + - + timestamptz not null - + last_update_time - + - + timestamptz not null - + delegationsignerdata_e542a872 - - + + public.DelegationSignerData - - + + [table] - + domain_repo_id - + - + text not null - + key_tag - + - + int4 not null - + algorithm - + - + int4 not null - + digest - + - + bytea not null - + digest_type - + - + int4 not null - + delegationsignerdata_e542a872:w->domain_6c51cffa:e - - - - - - - - + + + + + + + + fktr24j9v14ph2mfuw2gsmt12kq domainhistory_a54cc226:w->domain_6c51cffa:e - - - - - - - - + + + + + + + + fk_domain_history_domain_repo_id domainhistory_a54cc226:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_domain_history_registrar_id domainhost_1ea127c2 - - + + public.DomainHost - - + + [table] - + domain_repo_id - + - + text not null - + host_repo_id - + - + text - + domainhost_1ea127c2:w->domain_6c51cffa:e - - - - - - - - + + + + + + + + fkfmi7bdink53swivs390m2btxg domainhost_1ea127c2:w->host_f21b78de:e - - - - - - - - + + + + + + + + fk_domainhost_host_valid host_f21b78de:w->domain_6c51cffa:e - - - - - - - - + + + + + + + + fk_host_superordinate_domain host_f21b78de:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_host_creation_registrar_id host_f21b78de:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_host_current_sponsor_registrar_id host_f21b78de:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk_host_last_epp_update_registrar_id domaindsdatahistory_995b060d - - + + public.DomainDsDataHistory - - + + [table] - + ds_data_history_revision_id - + - + int8 not null - + algorithm - + - + int4 not null - + digest - + - + bytea not null - + digest_type - + - + int4 not null - + domain_history_revision_id - + - + int8 not null - + key_tag - + - + int4 not null - + domain_repo_id - + - + text - + domaindsdatahistory_995b060d:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fko4ilgyyfnvppbpuivus565i0j domaindsdatahistory_995b060d:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fko4ilgyyfnvppbpuivus565i0j domainhistoryhost_9f3f23ee - - + + public.DomainHistoryHost - - + + [table] - + domain_history_history_revision_id - + - + int8 not null - + host_repo_id - + - + text - + domain_history_domain_repo_id - + - + text not null - + domainhistoryhost_9f3f23ee:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fka9woh3hu8gx5x0vly6bai327n domainhistoryhost_9f3f23ee:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fka9woh3hu8gx5x0vly6bai327n domaintransactionrecord_6e77ff61 - - + + public.DomainTransactionRecord - - + + [table] - + id - + - + bigserial not null - + - + auto-incremented - + report_amount - + - + int4 not null - + report_field - + - + text not null - + reporting_time - + - + timestamptz not null - + tld - + - + text not null - + domain_repo_id - + - + text - + history_revision_id - + - + int8 - + domaintransactionrecord_6e77ff61:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fkcjqe54u72kha71vkibvxhjye7 domaintransactionrecord_6e77ff61:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fkcjqe54u72kha71vkibvxhjye7 domaintransactionrecord_6e77ff61:w->tld_f1fa57e2:e - - - - - - - - + + + + + + + + fk_domain_transaction_record_tld graceperiodhistory_40ccc1f1 - - + + public.GracePeriodHistory - - + + [table] - + grace_period_history_revision_id - + - + int8 not null - + billing_event_id - + - + int8 - + billing_event_history_id - + - + int8 - + billing_recurrence_id - + - + int8 - + billing_recurrence_history_id - + - + int8 - + registrar_id - + - + text not null - + domain_repo_id - + - + text not null - + expiration_time - + - + timestamptz not null - + type - + - + text not null - + domain_history_revision_id - + - + int8 - + grace_period_id - + - + int8 not null - + + billing_event_domain_repo_id + + + + + text + + + billing_recurrence_domain_repo_id + + + + + text + + graceperiodhistory_40ccc1f1:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fk7w3cx8d55q8bln80e716tr7b8 graceperiodhistory_40ccc1f1:w->domainhistory_a54cc226:e - - - - - - - - + + + + + + + + fk7w3cx8d55q8bln80e716tr7b8 hosthistory_56210c2:w->host_f21b78de:e - - - - - - - - + + + + + + + + fk_hosthistory_host hosthistory_56210c2:w->registrar_6e1503e3:e - - - - - - - - + + + + + + + + fk3d09knnmxrt6iniwnp8j2ykga kmssecret_f3b28857 - - + + public.KmsSecret - - + + [table] - + revision_id - + - + int8 not null - + creation_time - + - + timestamptz not null - + encrypted_value - + - + text not null - + crypto_key_version_name - + - + text not null - + secret_name - + - + text not null - + lock_f21d4861 - - + + public.Lock - - + + [table] - + resource_name - + - + text not null - + tld - + - + text not null - + acquired_time - + - + timestamptz not null - + expiration_time - + - + timestamptz not null - + request_log_id - + - + text not null - + premiumentry_b0060b91 - - + + public.PremiumEntry - - + + [table] - + revision_id - + - + int8 not null - + price - + - + numeric(19, 2) not null - + domain_label - + - + text not null - + premiumlist_7c3ea68b - - + + public.PremiumList - - + + [table] - + revision_id - + - + bigserial not null - + - + auto-incremented - + creation_timestamp - + - + timestamptz - + name - + - + text not null - + bloom_filter - + - + bytea not null - + currency - + - + text not null - + premiumentry_b0060b91:w->premiumlist_7c3ea68b:e - - - - - - - - + + + + + + + + fko0gw90lpo1tuee56l0nb6y6g5 rderevision_83396864 - - + + public.RdeRevision - - + + [table] - + tld - + - + text not null - + mode - + - + text not null - + "date" - + - + date not null - + update_timestamp - + - + timestamptz - + revision - + - + int4 not null - + registrarpoc_ab47054d @@ -5780,536 +5812,536 @@ td.section { registrarpoc_ab47054d:w->registrar_6e1503e3:e - + - - - - + + + + fk_registrar_poc_registrar_id registrylock_ac88663e - - + + public.RegistryLock - - + + [table] - + revision_id - + - + bigserial not null - + - + auto-incremented - + lock_completion_timestamp - + - + timestamptz - + lock_request_timestamp - + - + timestamptz not null - + domain_name - + - + text not null - + is_superuser - + - + bool not null - + registrar_id - + - + text not null - + registrar_poc_id - + - + text - + repo_id - + - + text not null - + verification_code - + - + text not null - + unlock_request_timestamp - + - + timestamptz - + unlock_completion_timestamp - + - + timestamptz - + last_update_timestamp - + - + timestamptz - + relock_revision_id - + - + int8 - + relock_duration - + - + interval - + registrylock_ac88663e:w->registrylock_ac88663e:e - - - - - - - - + + + + + + + + fk2lhcwpxlnqijr96irylrh1707 reservedentry_1a7b8520 - - + + public.ReservedEntry - - + + [table] - + revision_id - + - + int8 not null - + comment - + - + text - + reservation_type - + - + int4 not null - + domain_label - + - + text not null - + reservedlist_b97c3f1c - - + + public.ReservedList - - + + [table] - + revision_id - + - + bigserial not null - + - + auto-incremented - + creation_timestamp - + - + timestamptz not null - + name - + - + text not null - + should_publish - + - + bool not null - + reservedentry_1a7b8520:w->reservedlist_b97c3f1c:e - - - - - - - - + + + + + + + + fkgq03rk0bt1hb915dnyvd3vnfc serversecret_6cc90f09 - - + + public.ServerSecret - - + + [table] - + secret - + - + uuid not null - + signedmarkrevocationentry_99c39721 - - + + public.SignedMarkRevocationEntry - - + + [table] - + revision_id - + - + int8 not null - + revocation_time - + - + timestamptz not null - + smd_id - + - + text not null - + signedmarkrevocationlist_c5d968fb - - + + public.SignedMarkRevocationList - - + + [table] - + revision_id - + - + bigserial not null - + - + auto-incremented - + creation_time - + - + timestamptz - + signedmarkrevocationentry_99c39721:w->signedmarkrevocationlist_c5d968fb:e - - - - - - - - + + + + + + + + fk5ivlhvs3121yx2li5tqh54u4 spec11threatmatch_a61228a6 - - + + public.Spec11ThreatMatch - - + + [table] - + id - + - + bigserial not null - + - + auto-incremented - + check_date - + - + date not null - + domain_name - + - + text not null - + domain_repo_id - + - + text not null - + registrar_id - + - + text not null - + threat_types - + - + _text not null - + tld - + - + text not null - + sqlreplaycheckpoint_342081b3 - - + + public.SqlReplayCheckpoint - - + + [table] - + revision_id - + - + int8 not null - + last_replay_time - + - + timestamptz not null - + tmchcrl_d282355 - - + + public.TmchCrl - - + + [table] - + certificate_revocations - + - + text not null - + update_timestamp - + - + timestamptz not null - + url - + - + text not null - + transaction_d50389d4 - - + + public.Transaction - - + + [table] - + id - + - + bigserial not null - + - + auto-incremented - + contents - + - + bytea - + @@ -10106,6 +10138,16 @@ td.section { billing_recurrence_history_id int8 +
+ + billing_event_domain_repo_id + text +
+
+ + billing_recurrence_domain_repo_id + text +
@@ -10270,6 +10312,16 @@ td.section { grace_period_id int8 not null +
+ + billing_event_domain_repo_id + text +
+
+ + billing_recurrence_domain_repo_id + text +
diff --git a/db/src/main/resources/sql/flyway.txt b/db/src/main/resources/sql/flyway.txt index 5cda2afd2..3bc5cc50f 100644 --- a/db/src/main/resources/sql/flyway.txt +++ b/db/src/main/resources/sql/flyway.txt @@ -79,3 +79,4 @@ V78__add_history_id_for_redemption_history_entry.sql V79__drop_foreign_keys_on_pollmessage.sql V80__defer_bill_event_key.sql V81__drop_spec11_fkeys.sql +V82__add_columns_to_restore_symmetric_billing_vkey.sql diff --git a/db/src/main/resources/sql/flyway/V82__add_columns_to_restore_symmetric_billing_vkey.sql b/db/src/main/resources/sql/flyway/V82__add_columns_to_restore_symmetric_billing_vkey.sql new file mode 100644 index 000000000..beae3b647 --- /dev/null +++ b/db/src/main/resources/sql/flyway/V82__add_columns_to_restore_symmetric_billing_vkey.sql @@ -0,0 +1,22 @@ +-- Copyright 2020 The Nomulus Authors. All Rights Reserved. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. + +alter table "GracePeriod" + add column if not exists "billing_event_domain_repo_id" text; +alter table "GracePeriod" + add column if not exists "billing_recurrence_domain_repo_id" text; +alter table "GracePeriodHistory" + add column if not exists "billing_event_domain_repo_id" text; +alter table "GracePeriodHistory" + add column if not exists "billing_recurrence_domain_repo_id" text; diff --git a/db/src/main/resources/sql/schema/db-schema.sql.generated b/db/src/main/resources/sql/schema/db-schema.sql.generated index 20400cbd5..7b2fbaaae 100644 --- a/db/src/main/resources/sql/schema/db-schema.sql.generated +++ b/db/src/main/resources/sql/schema/db-schema.sql.generated @@ -398,8 +398,10 @@ grace_period_id int8 not null, billing_event_id int8, billing_event_history_id int8, + billing_event_domain_repo_id text, billing_recurrence_id int8, billing_recurrence_history_id int8, + billing_recurrence_domain_repo_id text, registrar_id text not null, domain_repo_id text not null, expiration_time timestamptz not null, @@ -411,8 +413,10 @@ grace_period_history_revision_id int8 not null, billing_event_id int8, billing_event_history_id int8, + billing_event_domain_repo_id text, billing_recurrence_id int8, billing_recurrence_history_id int8, + billing_recurrence_domain_repo_id text, registrar_id text not null, domain_repo_id text not null, expiration_time timestamptz not null, diff --git a/db/src/main/resources/sql/schema/nomulus.golden.sql b/db/src/main/resources/sql/schema/nomulus.golden.sql index c1e9039d0..26afb03dd 100644 --- a/db/src/main/resources/sql/schema/nomulus.golden.sql +++ b/db/src/main/resources/sql/schema/nomulus.golden.sql @@ -533,7 +533,9 @@ CREATE TABLE public."GracePeriod" ( expiration_time timestamp with time zone NOT NULL, type text NOT NULL, billing_event_history_id bigint, - billing_recurrence_history_id bigint + billing_recurrence_history_id bigint, + billing_event_domain_repo_id text, + billing_recurrence_domain_repo_id text ); @@ -552,7 +554,9 @@ CREATE TABLE public."GracePeriodHistory" ( expiration_time timestamp with time zone NOT NULL, type text NOT NULL, domain_history_revision_id bigint, - grace_period_id bigint NOT NULL + grace_period_id bigint NOT NULL, + billing_event_domain_repo_id text, + billing_recurrence_domain_repo_id text );