All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.ebeaninternal.server.deploy.DeployParser Maven / Gradle / Ivy

There is a newer version: 15.8.0
Show newest version
package io.ebeaninternal.server.deploy;

import java.util.Set;

/**
 * Converts logical property names to database columns.
 */
public abstract class DeployParser {

  /**
   * used to identify sql literal.
   */
  private static final char SINGLE_QUOTE = '\'';

  /**
   * used to identify query named parameters.
   */
  private static final char COLON = ':';

  /**
   * Used to determine when a column name terminates.
   */
  private static final char UNDERSCORE = '_';

  private static final char OPEN_SQUARE_BRACKET = '[';
  private static final char CLOSE_SQUARE_BRACKET = ']';
  private static final char DOUBLE_QUOTE = '\"';
  private static final char BACK_QUOTE = '`';

  /**
   * Used to determine when a column name terminates.
   */
  private static final char PERIOD = '.';

  private static final char OPEN_BRACKET = '(';

  boolean encrypted;
  private String source;
  private StringBuilder sb;
  private int sourceLength;
  private int pos;
  String priorWord;
  String word;
  private char wordTerminator;
  private StringBuilder wordBuffer;

  protected abstract String convertWord();

  public abstract String deployWord(String expression);

  /**
   * Return the join includes.
   */
  public abstract Set includes();

  public void setEncrypted(boolean encrypted) {
    this.encrypted = encrypted;
  }

  /**
   * Fast path parse() which first checks that the source is a bean property.
   */
  public String property(String expression) {
    String deployWord = deployWord(expression);
    if (deployWord != null) {
      return deployWord;
    }
    // fallback to use parse()
    return parse(expression);
  }

  public String parse(String expression) {
    if (expression == null) {
      return null;
    }
    pos = -1;
    this.source = expression;
    this.sourceLength = expression.length();
    this.sb = new StringBuilder(expression.length() + 20);
    while (nextWord()) {
      if (skipWordConvert()) {
        sb.append(word);
        priorWord = word;
      } else {
        String deployWord = convertWord();
        sb.append(deployWord);
        priorWord = deployWord;
      }
      if (pos < sourceLength) {
        if (wordTerminator != OPEN_BRACKET) {
          sb.append(wordTerminator);
        }
        if (wordTerminator == SINGLE_QUOTE) {
          readLiteral();
        }
      }
    }
    return sb.toString();
  }

  boolean skipWordConvert() {
    return false;
  }

  private boolean nextWord() {
    if (!findWordStart()) {
      return false;
    }
    wordBuffer = new StringBuilder();
    wordBuffer.append(source.charAt(pos));
    while (++pos < sourceLength) {
      char ch = source.charAt(pos);
      if (isWordPart(ch)) {
        wordBuffer.append(ch);
      } else {
        wordTerminator = ch;
        break;
      }
    }
    word = wordBuffer.toString();
    return true;
  }

  private boolean findWordStart() {
    while (++pos < sourceLength) {
      char ch = source.charAt(pos);
      if (ch == SINGLE_QUOTE) {
        // read a literal value and just
        // append to string builder
        sb.append(ch);
        readLiteral();
      } else if (ch == COLON) {
        // read a named parameter
        // just append to string builder
        sb.append(ch);
        readNamedParameter();
      } else if (isWordStart(ch)) {
        // its the start of a word that could
        // be translated
        return true;
      } else {
        sb.append(ch);
      }
    }
    return false;
  }

  /**
   * Read the rest of a literal value. These do not get translated so are just
   * read and appended to the string builder.
   */
  private void readLiteral() {
    while (++pos < sourceLength) {
      char ch = source.charAt(pos);
      sb.append(ch);
      if (ch == SINGLE_QUOTE) {
        break;
      }
    }
  }

  /**
   * Read a named parameter. These are not translated. They will be replaced
   * by positioned parameters later.
   */
  private void readNamedParameter() {
    while (++pos < sourceLength) {
      char ch = source.charAt(pos);
      sb.append(ch);
      if (Character.isWhitespace(ch)) {
        break;
      } else if (ch == ',') {
        break;
      }
    }
  }

  /**
   * return true if the char is a letter, digit or underscore.
   */
  private boolean isWordPart(char ch) {
    if (ch == OPEN_BRACKET) {
      // include in the 'word' such that "count(" formula doesn't clash with property "count"
      wordBuffer.append(ch);
      return false;
    }
    return Character.isLetterOrDigit(ch) || ch == UNDERSCORE || ch == PERIOD || ch == DOUBLE_QUOTE || ch == CLOSE_SQUARE_BRACKET || ch == BACK_QUOTE;
  }

  private boolean isWordStart(char ch) {
    return Character.isLetter(ch) || ch == UNDERSCORE || ch == DOUBLE_QUOTE || ch == OPEN_SQUARE_BRACKET || ch == BACK_QUOTE;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy