[MySQL] snake_case table and column names (#4860)

* [MySQL] Add identifierNamingConvention option

Possible values are "original" to not transform original names and
"snake_case".

* [MySQL] Add option tests

* [MySQL] Update doc

* [MySQL] Add original name to comment
This commit is contained in:
Yuriy Belenko 2019-12-26 12:05:36 +05:00 committed by William Cheng
parent a8bc3360fd
commit ad4b9c711b
5 changed files with 139 additions and 8 deletions

View File

@ -7,3 +7,4 @@ sidebar_label: mysql-schema
| ------ | ----------- | ------ | ------- |
|defaultDatabaseName|Default database name for all MySQL queries| ||
|jsonDataTypeEnabled|Use special JSON MySQL data type for complex model properties. Requires MySQL version 5.7.8. Generates TEXT data type when disabled| |true|
|identifierNamingConvention|Naming convention of MySQL identifiers(table names and column names). This is not related to database name which is defined by defaultDatabaseName option|<dl><dt>**original**</dt><dd>Do not transform original names</dd><dt>**snake_case**</dt><dd>Use snake_case names</dd><dl>|original|

View File

@ -24,12 +24,15 @@ import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static org.openapitools.codegen.utils.StringUtils.underscore;
public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig {
private static final Logger LOGGER = LoggerFactory.getLogger(MysqlSchemaCodegen.class);
public static final String CODEGEN_VENDOR_EXTENSION_KEY = "x-mysqlSchema";
public static final String DEFAULT_DATABASE_NAME = "defaultDatabaseName";
public static final String JSON_DATA_TYPE_ENABLED = "jsonDataTypeEnabled";
public static final String IDENTIFIER_NAMING_CONVENTION = "identifierNamingConvention";
public static final Integer ENUM_MAX_ELEMENTS = 65535;
public static final Integer IDENTIFIER_MAX_LENGTH = 64;
@ -53,6 +56,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
protected String tableNamePrefix = "tbl_", tableNameSuffix = "";
protected String columnNamePrefix = "col_", columnNameSuffix = "";
protected Boolean jsonDataTypeEnabled = true;
protected String identifierNamingConvention = "original";
public MysqlSchemaCodegen() {
super();
@ -158,6 +162,16 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
cliOptions.clear();
addOption(DEFAULT_DATABASE_NAME, "Default database name for all MySQL queries", defaultDatabaseName);
addSwitch(JSON_DATA_TYPE_ENABLED, "Use special JSON MySQL data type for complex model properties. Requires MySQL version 5.7.8. Generates TEXT data type when disabled", jsonDataTypeEnabled);
// we used to snake_case table/column names, let's add this option
CliOption identifierNamingOpt = new CliOption(IDENTIFIER_NAMING_CONVENTION,
"Naming convention of MySQL identifiers(table names and column names). This is not related to database name which is defined by " + DEFAULT_DATABASE_NAME + " option");
identifierNamingOpt.addEnum("original", "Do not transform original names")
.addEnum("snake_case", "Use snake_case names")
.setDefault("original");
cliOptions.add(identifierNamingOpt);
}
@Override
@ -195,6 +209,10 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
additionalProperties.put(JSON_DATA_TYPE_ENABLED, getJsonDataTypeEnabled());
}
if (additionalProperties.containsKey(IDENTIFIER_NAMING_CONVENTION)) {
this.setIdentifierNamingConvention((String) additionalProperties.get(IDENTIFIER_NAMING_CONVENTION));
}
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("mysql_schema.mustache", "", "mysql_schema.sql"));
}
@ -208,11 +226,18 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> mo = (Map<String, Object>) _mo;
CodegenModel model = (CodegenModel) mo.get("model");
String modelName = model.getName();
String tableName = this.toTableName(modelName);
String modelDescription = model.getDescription();
Map<String, Object> modelVendorExtensions = model.getVendorExtensions();
Map<String, Object> mysqlSchema = new HashMap<String, Object>();
Map<String, Object> tableDefinition = new HashMap<String, Object>();
if (this.getIdentifierNamingConvention().equals("snake_case") && !modelName.equals(tableName)) {
// add original name in table comment
String commentExtra = "Original model name - " + modelName + ".";
modelDescription = (modelDescription == null || modelDescription.isEmpty()) ? commentExtra : modelDescription + ". " + commentExtra;
}
if (modelVendorExtensions.containsKey(CODEGEN_VENDOR_EXTENSION_KEY)) {
// user already specified schema values
LOGGER.info("Found vendor extension in '" + modelName + "' model, autogeneration skipped");
@ -220,7 +245,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
} else {
modelVendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("tableDefinition", tableDefinition);
tableDefinition.put("tblName", toTableName(modelName));
tableDefinition.put("tblName", tableName);
tableDefinition.put("tblComment", modelDescription);
}
}
@ -271,6 +296,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> columnDefinition = new HashMap<String, Object>();
ArrayList columnDataTypeArguments = new ArrayList();
String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String dataType = property.getDataType();
String dataFormat = property.getDataFormat();
String description = property.getDescription();
@ -290,9 +316,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return;
}
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName));
columnDefinition.put("colName", colName);
if (Boolean.TRUE.equals(isEnum)) {
Map<String, Object> allowableValues = property.getAllowableValues();
@ -352,6 +384,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> columnDefinition = new HashMap<String, Object>();
ArrayList columnDataTypeArguments = new ArrayList();
String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String dataType = property.getDataType();
String dataFormat = property.getDataFormat();
String description = property.getDescription();
@ -370,9 +403,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return;
}
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName));
columnDefinition.put("colName", colName);
if (Boolean.TRUE.equals(isEnum)) {
Map<String, Object> allowableValues = property.getAllowableValues();
@ -431,6 +470,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> columnDefinition = new HashMap<String, Object>();
ArrayList columnDataTypeArguments = new ArrayList();
String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String description = property.getDescription();
String defaultValue = property.getDefaultValue();
Boolean required = property.getRequired();
@ -441,9 +481,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return;
}
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName));
columnDefinition.put("colName", colName);
columnDefinition.put("colDataType", "TINYINT");
columnDefinition.put("colDataTypeArguments", columnDataTypeArguments);
columnDataTypeArguments.add(toCodegenMysqlDataTypeArgument(1, false));
@ -477,6 +523,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> columnDefinition = new HashMap<String, Object>();
ArrayList columnDataTypeArguments = new ArrayList();
String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String dataType = property.getDataType();
String dataFormat = property.getDataFormat();
String description = property.getDescription();
@ -492,9 +539,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return;
}
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName));
columnDefinition.put("colName", colName);
if (Boolean.TRUE.equals(isEnum)) {
Map<String, Object> allowableValues = property.getAllowableValues();
@ -548,6 +601,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> mysqlSchema = new HashMap<String, Object>();
Map<String, Object> columnDefinition = new HashMap<String, Object>();
String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String dataType = property.getDataType();
Boolean required = property.getRequired();
String description = property.getDescription();
@ -559,9 +613,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return;
}
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName));
columnDefinition.put("colName", colName);
columnDefinition.put("colDataType", dataType);
if (Boolean.TRUE.equals(required)) {
@ -592,6 +652,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> mysqlSchema = new HashMap<String, Object>();
Map<String, Object> columnDefinition = new HashMap<String, Object>();
String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
String dataType = property.getDataType();
Boolean required = property.getRequired();
String description = property.getDescription();
@ -603,9 +664,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return;
}
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName));
columnDefinition.put("colName", colName);
columnDefinition.put("colDataType", dataType);
if (Boolean.FALSE.equals(getJsonDataTypeEnabled())) {
columnDefinition.put("colDataType", "TEXT");
@ -640,6 +707,7 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
Map<String, Object> mysqlSchema = new HashMap<String, Object>();
Map<String, Object> columnDefinition = new HashMap<String, Object>();
String baseName = property.getBaseName();
String colName = this.toColumnName(baseName);
Boolean required = property.getRequired();
String description = property.getDescription();
String defaultValue = property.getDefaultValue();
@ -650,9 +718,15 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return;
}
if (this.getIdentifierNamingConvention().equals("snake_case") && !baseName.equals(colName)) {
// add original name in column comment
String commentExtra = "Original param name - " + baseName + ".";
description = (description == null || description.isEmpty()) ? commentExtra : description + ". " + commentExtra;
}
vendorExtensions.put(CODEGEN_VENDOR_EXTENSION_KEY, mysqlSchema);
mysqlSchema.put("columnDefinition", columnDefinition);
columnDefinition.put("colName", toColumnName(baseName));
columnDefinition.put("colName", colName);
columnDefinition.put("colDataType", "TEXT");
if (Boolean.TRUE.equals(required)) {
@ -897,6 +971,9 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
*/
public String toTableName(String name) {
String identifier = toMysqlIdentifier(name, tableNamePrefix, tableNameSuffix);
if (identifierNamingConvention.equals("snake_case")) {
identifier = underscore(identifier);
}
if (identifier.length() > IDENTIFIER_MAX_LENGTH) {
LOGGER.warn("Table name cannot exceed 64 chars. Name '" + name + "' will be truncated");
identifier = identifier.substring(0, IDENTIFIER_MAX_LENGTH);
@ -913,6 +990,9 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
*/
public String toColumnName(String name) {
String identifier = toMysqlIdentifier(name, columnNamePrefix, columnNameSuffix);
if (identifierNamingConvention.equals("snake_case")) {
identifier = underscore(identifier);
}
if (identifier.length() > IDENTIFIER_MAX_LENGTH) {
LOGGER.warn("Column name cannot exceed 64 chars. Name '" + name + "' will be truncated");
identifier = identifier.substring(0, IDENTIFIER_MAX_LENGTH);
@ -1054,4 +1134,30 @@ public class MysqlSchemaCodegen extends DefaultCodegen implements CodegenConfig
return this.jsonDataTypeEnabled;
}
/**
* Sets identifier naming convention for table names and column names.
* This is not related to database name which is defined by defaultDatabaseName option.
*
* @param naming identifier naming convention (original|snake_case)
*/
public void setIdentifierNamingConvention(String naming) {
switch (naming) {
case "original":
case "snake_case":
this.identifierNamingConvention = naming;
break;
default:
LOGGER.warn("\"" + (String) naming + "\" is invalid \"identifierNamingConvention\" argument. Current \"" + (String) this.identifierNamingConvention + "\" used instead.");
}
}
/**
* Returns identifier naming convention for table names and column names.
*
* @return identifier naming convention
*/
public String getIdentifierNamingConvention() {
return this.identifierNamingConvention;
}
}

View File

@ -274,4 +274,24 @@ public class MysqlSchemaCodegenTest {
Assert.assertFalse(codegen.getJsonDataTypeEnabled());
}
@Test
public void testSetIdentifierNamingConvention() {
final MysqlSchemaCodegen codegen = new MysqlSchemaCodegen();
Assert.assertSame("original", codegen.getIdentifierNamingConvention());
codegen.setIdentifierNamingConvention("invalidValue");
Assert.assertSame("original", codegen.getIdentifierNamingConvention());
codegen.setIdentifierNamingConvention("snake_case");
Assert.assertSame("snake_case", codegen.getIdentifierNamingConvention());
codegen.setIdentifierNamingConvention("anotherInvalid");
Assert.assertSame("snake_case", codegen.getIdentifierNamingConvention());
}
@Test
public void testGetIdentifierNamingConvention() {
final MysqlSchemaCodegen codegen = new MysqlSchemaCodegen();
Assert.assertSame("original", codegen.getIdentifierNamingConvention());
codegen.setIdentifierNamingConvention("snake_case");
Assert.assertSame("snake_case", codegen.getIdentifierNamingConvention());
}
}

View File

@ -45,6 +45,8 @@ public class MysqlSchemaOptionsTest extends AbstractOptionsTest {
times = 1;
clientCodegen.setJsonDataTypeEnabled(Boolean.valueOf(MysqlSchemaOptionsProvider.JSON_DATA_TYPE_ENABLED_VALUE));
times = 1;
clientCodegen.setIdentifierNamingConvention(MysqlSchemaOptionsProvider.IDENTIFIER_NAMING_CONVENTION_VALUE);
times = 1;
}};
}
}

View File

@ -24,6 +24,7 @@ import java.util.Map;
public class MysqlSchemaOptionsProvider implements OptionsProvider {
public static final String DEFAULT_DATABASE_NAME_VALUE = "database_name";
public static final String JSON_DATA_TYPE_ENABLED_VALUE = "false";
public static final String IDENTIFIER_NAMING_CONVENTION_VALUE = "snake_case";
@Override
public String getLanguage() {
@ -35,6 +36,7 @@ public class MysqlSchemaOptionsProvider implements OptionsProvider {
ImmutableMap.Builder<String, String> builder = new ImmutableMap.Builder<String, String>();
return builder.put(MysqlSchemaCodegen.DEFAULT_DATABASE_NAME, DEFAULT_DATABASE_NAME_VALUE)
.put(MysqlSchemaCodegen.JSON_DATA_TYPE_ENABLED, JSON_DATA_TYPE_ENABLED_VALUE)
.put(MysqlSchemaCodegen.IDENTIFIER_NAMING_CONVENTION, IDENTIFIER_NAMING_CONVENTION_VALUE)
.build();
}