Add naming strategy (#256)

* Add naming strategy

* Add test for formatting in GenerateSqlSchemaCommandTest

* "domain" -> "Domain"

* Call site literals

* checkstyle

* varchar -> text

* Fix external messaging capitalization typo
This commit is contained in:
gbrodman 2019-09-09 14:27:52 -04:00 committed by GitHub
parent c5e4e862bd
commit b35026b30d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 95 additions and 6 deletions

View file

@ -89,7 +89,7 @@ import org.joda.time.Interval;
@ReportedOn @ReportedOn
@Entity @Entity
@javax.persistence.Entity @javax.persistence.Entity
@javax.persistence.Table(name = "domain") @javax.persistence.Table(name = "Domain")
@ExternalMessagingName("domain") @ExternalMessagingName("domain")
public class DomainBase extends EppResource public class DomainBase extends EppResource
implements ForeignKeyedEppResource, ResourceWithTransferData { implements ForeignKeyedEppResource, ResourceWithTransferData {

View file

@ -47,6 +47,9 @@ public class EntityManagerFactoryProvider {
// SessionFactory is created. Setting it to 'none' to turn off the feature. // SessionFactory is created. Setting it to 'none' to turn off the feature.
properties.put(Environment.HBM2DDL_AUTO, "none"); properties.put(Environment.HBM2DDL_AUTO, "none");
properties.put(
Environment.PHYSICAL_NAMING_STRATEGY, NomulusNamingStrategy.class.getCanonicalName());
properties.put(Environment.ISOLATION, getHibernateConnectionIsolation()); properties.put(Environment.ISOLATION, getHibernateConnectionIsolation());
properties.put(Environment.SHOW_SQL, getHibernateLogSqlQueries()); properties.put(Environment.SHOW_SQL, getHibernateLogSqlQueries());
properties.put(HIKARI_CONNECTION_TIMEOUT, getHibernateHikariConnectionTimeout()); properties.put(HIKARI_CONNECTION_TIMEOUT, getHibernateHikariConnectionTimeout());

View file

@ -0,0 +1,77 @@
// 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.persistence;
import com.google.common.base.CaseFormat;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
/**
* Nomulus naming strategy for Hibernate ORM.
*
* <p>This class applies the following naming strategies to protect readability of SQL statements:
*
* <ul>
* <li>Table names are quoted UpperCamelCases.
* <li>Column names are in lower_underscore format.
* </ul>
*
* These strategies ensure that both types of names are readable on case-insensitive platforms, and
* are easily distinguishable from each other.
*
* <p>The use of quoted names may introduce portability problems with hand-crafted SQL queries,
* e.g., between postgresql (which only accepts double-quotes) and MySQL(which only accepts
* back-quotes). This gives us incentives for adopting SQL query builders such as JOOQ for reporting
* etc.
*/
public class NomulusNamingStrategy implements PhysicalNamingStrategy {
@Override
public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return name;
}
@Override
public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return name;
}
@Override
public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) {
if (name.isQuoted()) {
return name;
}
return jdbcEnvironment.getIdentifierHelper().toIdentifier(name.getText(), /* quoted= */ true);
}
@Override
public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment jdbcEnvironment) {
return name;
}
@Override
public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment jdbcEnvironment) {
if (name.isQuoted()) {
return name;
}
// Convert the lowerCamelCase field name into the snake_case column name
return jdbcEnvironment
.getIdentifierHelper()
.toIdentifier(
CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, name.getText()),
/* quoted= */ false);
}
}

View file

@ -27,6 +27,7 @@ import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.model.eppcommon.Trid; import google.registry.model.eppcommon.Trid;
import google.registry.model.transfer.BaseTransferObject; import google.registry.model.transfer.BaseTransferObject;
import google.registry.model.transfer.TransferData; import google.registry.model.transfer.TransferData;
import google.registry.persistence.NomulusNamingStrategy;
import google.registry.schema.tld.PremiumList; import google.registry.schema.tld.PremiumList;
import google.registry.schema.tmch.ClaimsList; import google.registry.schema.tmch.ClaimsList;
import java.io.IOException; import java.io.IOException;
@ -38,6 +39,7 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.hibernate.boot.MetadataSources; import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.PostgreSQL95Dialect; import org.hibernate.dialect.PostgreSQL95Dialect;
import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaExport;
import org.hibernate.tool.schema.TargetType; import org.hibernate.tool.schema.TargetType;
@ -150,6 +152,8 @@ public class GenerateSqlSchemaCommand implements Command {
settings.put("hibernate.connection.password", "domain-registry"); settings.put("hibernate.connection.password", "domain-registry");
settings.put("hibernate.hbm2ddl.auto", "none"); settings.put("hibernate.hbm2ddl.auto", "none");
settings.put("show_sql", "true"); settings.put("show_sql", "true");
settings.put(
Environment.PHYSICAL_NAMING_STRATEGY, NomulusNamingStrategy.class.getCanonicalName());
MetadataSources metadata = MetadataSources metadata =
new MetadataSources(new StandardServiceRegistryBuilder().applySettings(settings).build()); new MetadataSources(new StandardServiceRegistryBuilder().applySettings(settings).build());

View file

@ -11,12 +11,13 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package google.registry.tools; package google.registry.tools;
// import static org.mockito.Mockito.mock;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.io.Files;
import java.io.File; import java.io.File;
import org.junit.Before; import org.junit.Before;
import org.junit.ClassRule; import org.junit.ClassRule;
@ -57,10 +58,14 @@ public class GenerateSqlSchemaCommandTest extends CommandTestCase<GenerateSqlSch
"--db_host=" + containerHostName, "--db_host=" + containerHostName,
"--db_port=" + containerPort); "--db_port=" + containerPort);
// We're just interested in verifying that there is a schema file generated, we don't do any // We don't verify the exact contents of the result SQL file because that would be too brittle,
// checks on the contents, this would make the test too brittle and serves no real purpose. // but we check to make sure that a couple parts of it are named as we expect them to be
// TODO: try running the schema against the test database. // TODO: try running the schema against the test database.
assertThat(new File(tmp.getRoot(), "schema.sql").exists()).isTrue(); File sqlFile = new File(tmp.getRoot(), "schema.sql");
assertThat(sqlFile.exists()).isTrue();
String fileContent = Files.asCharSource(sqlFile, UTF_8).read();
assertThat(fileContent).contains("create table \"Domain\" (");
assertThat(fileContent).contains("repo_id text not null,");
} }
@Test @Test