sql name for table columns

9 posts / 0 new
Last post
atao
Offline
Joined: 10/15/2008
sql name for table columns

Vincent,

When a sql reserved keyword is used as attribute name, there is no means to specify a different column name from the model.

I don't know if it's on purpose, but at least it'b fine that GenerateSqlName checks this and replace such name by something like property name + "_" + property type

Regards

Pierre

 

 

vvandens
Offline
Joined: 05/29/2008
sql name for table columns

Hi Pierre,

You are right. The pattern you suggest might generate very long names. Something like just appending an "_" at the end of the currently generated name might do the trick (I think hibernate does something similar when generating aliases in SQL queries).

Best regards,

Vincent

atao
Offline
Joined: 10/15/2008
sql name for table columns

[quote]

The pattern you suggest might generate very long names

[/quote]

 

I use here a copy of GenerateSqlName which works with the short name of the property type. IMO the column name length is acceptable. But your way is also fine.

 

 

atao
Offline
Joined: 10/15/2008
sql name for table columns

Vincent,

 

This point is still there in jspresso 3.

 

Have you made up your mind about it?

 

Regards

Pierre

vvandens
Offline
Joined: 05/29/2008
sql name for table columns

Pierre,

Have you made up your mind about it?

Well, not really. Actually, I think I forgot about it Wink. I'm getting old... The problem I would like to avoid is forcing a complete schema update for a framework version upgrade. Of course, it's transparent for HSQLDB but for other concrete databases, it would be really painful.

A solution might be to act only on forbidden (reserved) column names by maintaining a list of them somewhere. The column names are actually generated by the GenerateSqlName utility class that is injected in the template by the EntityGenerator class. So this strategy class should be the good place to maintain this list in. And we could even make this injection customizable by a property on the entity generator so that a user could add missing reserved words without waiting for an update of the framework classes. It would keep the existing schemas unmodified, keep the column names short and readable by acting only when actually needed. In the "reserved keyword" cases, I would still implement a "_" at the end of the column.

What do you think of it ? I've opened a feature request in the tracker for it so that it helps my memory...

Vincent

atao
Offline
Joined: 10/15/2008
sql name for table columns

Vincent,

[quote]

Actually, I think I forgot about it Wink. I'm getting old...

[/quote]

You aren't alone...

[quote]

A solution might be to act only on forbidden (reserved) column names by maintaining a list of them somewhere. The column names are actually generated by the GenerateSqlName utility class that is injected in the template by the EntityGenerator class. So this strategy class should be the good place to maintain this list in. And we could even make this injection customizable by a property on the entity generator so that a user could add missing reserved words without waiting for an update of the framework classes.

[/quote]

It's the solution I have applied here. With also some versatility on the conversion from camel style...

See modified GenerateSqlName below. The use of functors is may be a little overmuch, but the changes to be made in a derived class of EntityGenetor are then clearly delimited.

[quote]

I would still implement a "_" at the end of the column.

[/quote]

You're the boss!

In fact, you can get the choice. With the code below, if a second argument is provided from the template, then it is appended after a "_". But if none, i.e. as in the current template, then, only the "_" is appended.

Regards

Pierre

==================================

package org.jspresso.framework.util.freemarker;

import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import freemarker.template.SimpleScalar;
import freemarker.template.TemplateMethodModel;
import freemarker.template.TemplateModel;
import freemarker.template.TemplateModelException;

/**
 * Infers a SQL column name from a property name.
 */
public class GenerateSqlName implements TemplateMethodModel {

  /**
   * Any modification of the provided word before checking,
   * e.g. from camel style to upper case and underscore separated.
   */
  public interface Formatter {
      String run(String name);
  }

  /**
   * Provide upper case reserved key words.
   */
  public interface KeyWordProvider {
      List<String> run();
  }

  private final static String          WORD_SEP                  = "_";   
 
  private final static KeyWordProvider DEFAULT_KEY_WORD_PROVIDER =
    new KeyWordProvider() {
      public List<String> run() {
          return Arrays.asList(
            new String[]{"BEGIN", "END", "GROUP", "FUNCTION", "ACTION",
                        "ARRAY", "DATE", "DATA", "DAY", "MONTH", "YEAR"});
      }
    };

  private final static Formatter       DEFAULT_FORMATTER         =
    new Formatter() {
      public String run(String name) {
          StringBuffer result = new StringBuffer();
          for (int i = 0; i < name.length(); i++) {
            if (i > 0 && Character.isLowerCase(name.charAt(i - 1))
                && Character.isUpperCase(name.charAt(i))) {
                result.append(WORD_SEP);
            }
            result.append(Character.toUpperCase(name.charAt(i)));
          }
          return result.toString();
      }
    };
 
  private Set<String> reservedKeyWords = new HashSet<String>(DEFAULT_KEY_WORD_PROVIDER.run());
  private Formatter   formatter        = DEFAULT_FORMATTER;
   
  /**
   * Infer a SQL column name from a property name.
   * By default:
   * - use camel parser to separate words with "_"
   * - check for sql reserved key words
   *
   * {@inheritDoc}
   */
  @SuppressWarnings("unchecked")
  public TemplateModel exec(List arguments) throws TemplateModelException {
     
      String sqlColumnName = formatter.run(arguments.get(0).toString());
      if (isReserved(sqlColumnName))
      {
          sqlColumnName += WORD_SEP;
          if (arguments.size()>1 && arguments.get(1) != null)
          {
              sqlColumnName += formatter.run(arguments.get(1).toString());
          }
      }
      try {
        return new SimpleScalar(sqlColumnName);
      } catch (Exception ex) {
        throw new TemplateModelException("Could not infer SQL column name.", ex);
      }
  }
 
  private boolean isReserved(String name) {
      return reservedKeyWords.contains(name.toUpperCase());
  }
 
  public void setKeyWordProvider(KeyWordProvider provider) {
      KeyWordProvider currentProvider = provider == null ? DEFAULT_KEY_WORD_PROVIDER : provider;
      reservedKeyWords = new HashSet<String>(currentProvider.run());
  }

  public void setAdditionalKeyWordProvider(KeyWordProvider provider) {
      if (provider == null) return;
     
      reservedKeyWords.addAll(provider.run());
  }
 
  public void setFormatter(Formatter formatter) {
      this.formatter = (formatter == null) ? DEFAULT_FORMATTER : formatter;
  }
 
}

 

vvandens
Offline
Joined: 05/29/2008
sql name for table columns

Pierre,
Nice code ! Under which license ? ;-)

Vincent

atao
Offline
Joined: 10/15/2008
sql name for table columns

:-D  jspresso's indeed!

vvandens
Offline
Joined: 05/29/2008
sql name for table columns

Great!

So it's in the snapshot repo now.

Thanks.