Add Cloud SQL schema for premium lists (#254)

* Re-add other schema classes

* Add Cloud SQL schema for premium lists

This won't work quite yet, pending a solution for the type translator issue
(which will be needed for the currency field, and potentially others).
This commit is contained in:
Ben McIlwain 2019-09-06 11:25:34 -04:00 committed by GitHub
parent 725df06d2b
commit c55e3422c2
7 changed files with 192 additions and 14 deletions

View file

@ -0,0 +1,102 @@
// Copyright 2019 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.schema.tld;
import static com.google.common.base.Preconditions.checkState;
import java.math.BigDecimal;
import java.time.ZonedDateTime;
import java.util.Map;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapKeyColumn;
import javax.persistence.Table;
import org.joda.money.CurrencyUnit;
/**
* A list of premium prices for domain names.
*
* <p>Note that the primary key of this entity is {@link #revisionId}, which is auto-generated by
* the database. So, if a retry of insertion happens after the previous attempt unexpectedly
* succeeds, we will end up with having two exact same premium lists that differ only by revisionId.
* This is fine though, because we only use the list with the highest revisionId.
*/
@Entity
@Table(name = "PremiumList")
public class PremiumList {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "revision_id")
private Long revisionId;
@Column(name = "creation_timestamp", nullable = false)
private ZonedDateTime creationTimestamp;
@Column(name = "currency", nullable = false)
private CurrencyUnit currency;
@ElementCollection
@CollectionTable(
name = "PremiumEntry",
joinColumns = @JoinColumn(name = "revision_id", referencedColumnName = "revision_id"))
@MapKeyColumn(name = "domain_label")
@Column(name = "price", nullable = false)
private Map<String, BigDecimal> labelsToPrices;
private PremiumList(
ZonedDateTime creationTimestamp,
CurrencyUnit currency,
Map<String, BigDecimal> labelsToPrices) {
this.creationTimestamp = creationTimestamp;
this.currency = currency;
this.labelsToPrices = labelsToPrices;
}
// Hibernate requires this default constructor.
private PremiumList() {}
// TODO(mcilwain): Change creationTimestamp to Joda DateTime.
/** Constructs a {@link PremiumList} object. */
public static PremiumList create(
ZonedDateTime creationTimestamp,
CurrencyUnit currency,
Map<String, BigDecimal> labelsToPrices) {
return new PremiumList(creationTimestamp, currency, labelsToPrices);
}
/** Returns the ID of this revision, or throws if null. */
public Long getRevisionId() {
checkState(
revisionId != null, "revisionId is null because it is not persisted in the database");
return revisionId;
}
/** Returns the creation time of this revision of the premium list. */
public ZonedDateTime getCreationTimestamp() {
return creationTimestamp;
}
/** Returns a {@link Map} of domain labels to prices. */
public Map<String, BigDecimal> getLabelsToPrices() {
return labelsToPrices;
}
}

View file

@ -19,6 +19,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import google.registry.model.domain.DesignatedContact;
import google.registry.model.domain.DomainBase;
import google.registry.model.domain.GracePeriod;
@ -26,6 +27,8 @@ import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.Trid;
import google.registry.model.transfer.BaseTransferObject;
import google.registry.model.transfer.TransferData;
import google.registry.schema.tld.PremiumList;
import google.registry.schema.tmch.ClaimsList;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
@ -49,6 +52,21 @@ import org.testcontainers.containers.PostgreSQLContainer;
@Parameters(separators = " =", commandDescription = "Generate PostgreSQL schema.")
public class GenerateSqlSchemaCommand implements Command {
// TODO(mmuller): These should be read from persistence.xml so we don't need to maintain two
// separate lists of all SQL table classes.
private static final ImmutableSet<Class> SQL_TABLE_CLASSES =
ImmutableSet.of(
BaseTransferObject.class,
ClaimsList.class,
DelegationSignerData.class,
DesignatedContact.class,
DomainBase.class,
GracePeriod.class,
Period.class,
PremiumList.class,
TransferData.class,
Trid.class);
@VisibleForTesting
public static final String DB_OPTIONS_CLASH =
"Database host and port may not be specified along with the option to start a "
@ -109,8 +127,7 @@ public class GenerateSqlSchemaCommand implements Command {
+ " -d postgres:9.6.12\n\n"
+ "Copy the container id output from the command, then run:\n\n"
+ " docker inspect <container-id> | grep IPAddress\n\n"
+ "To obtain the value for --db-host.\n"
);
+ "To obtain the value for --db-host.\n");
// TODO(mmuller): need exit(1), see above.
return;
}
@ -134,14 +151,7 @@ public class GenerateSqlSchemaCommand implements Command {
MetadataSources metadata =
new MetadataSources(new StandardServiceRegistryBuilder().applySettings(settings).build());
metadata.addAnnotatedClass(BaseTransferObject.class);
metadata.addAnnotatedClass(DelegationSignerData.class);
metadata.addAnnotatedClass(DesignatedContact.class);
metadata.addAnnotatedClass(DomainBase.class);
metadata.addAnnotatedClass(GracePeriod.class);
metadata.addAnnotatedClass(Period.class);
metadata.addAnnotatedClass(TransferData.class);
metadata.addAnnotatedClass(Trid.class);
SQL_TABLE_CLASSES.forEach(metadata::addAnnotatedClass);
SchemaExport schemaExport = new SchemaExport();
schemaExport.setHaltOnError(true);
schemaExport.setFormat(true);

View file

@ -22,6 +22,7 @@
<class>google.registry.model.domain.DomainBase</class>
<class>google.registry.schema.tmch.ClaimsList</class>
<class>google.registry.model.transfer.BaseTransferObject</class>
<class>google.registry.schema.tld.PremiumList</class>
<class>google.registry.model.domain.secdns.DelegationSignerData</class>
<class>google.registry.model.domain.DesignatedContact</class>
<class>google.registry.model.domain.DomainBase</class>

View file

@ -27,7 +27,6 @@ import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.testcontainers.containers.PostgreSQLContainer;
/** Unit tests for {@link google.registry.tools.GenerateSqlSchemaCommand}. */
@RunWith(JUnit4.class)
public class GenerateSqlSchemaCommandTest extends CommandTestCase<GenerateSqlSchemaCommand> {
@ -77,8 +76,7 @@ public class GenerateSqlSchemaCommandTest extends CommandTestCase<GenerateSqlSch
@Test
public void testDockerPostgresql() throws Exception {
runCommand(
"--start_postgresql",
"--out_file=" + tmp.getRoot() + File.separatorChar + "schema.sql");
"--start_postgresql", "--out_file=" + tmp.getRoot() + File.separatorChar + "schema.sql");
assertThat(new File(tmp.getRoot(), "schema.sql").exists()).isTrue();
}
}

View file

@ -116,7 +116,9 @@ public class RegistrarConsoleScreenshotTest extends WebDriverTestCase {
@Test
public void settingsContactItem_asAdmin() throws Throwable {
server.setIsAdmin(true);
driver.get(server.getUrl("/registrar?clientId=NewRegistrar#contact-settings/janedoe@theregistrar.com"));
driver.get(
server.getUrl(
"/registrar?clientId=NewRegistrar#contact-settings/janedoe@theregistrar.com"));
Thread.sleep(1000);
driver.waitForElement(By.tagName("h1"));
driver.diffPage("page");