Class VariablePrefix

java.lang.Object
no.sikt.graphitron.generators.codebuilding.VariablePrefix

public class VariablePrefix extends Object
This class handles the naming conventions for internal variables. When generating code, we need to name parameters and variables. The different names may come from different namespaces. A namespace in this context is a set of strings, meaning a collection that has no duplicates. A namespace can for example be the set of fields that a GraphQL type has, as there can not be two fields with the same name. Therefore, using the names of the fields as variables is safe, as they will never collide with each other. Another example is the set of internal helper variables in Graphitron-generated code, as these must also be unique and are predetermined by a single source, the developers. When variables hail from different namespaces, however, they inevitably risk colliding in the generated code without proper countermeasures.

An example of a collision may be an input field (it will become a method parameter) which has the same name as a jOOQ table. In the query Graphitron may create an alias for this table, while also having a method parameter that inherits the name of the input field. Such code may result in uncompilable code at best or produce incorrect query results at worst.

The risk of collisions would be even higher for instance if the DB/GraphQL-domain was code-related. To prevent such issues we use variable prefixes for all variables in the generated code. These make it impossible to accidentally or intentionally produce naming collisions, given that the prefixes are not substrings of each other.

Here is a more rigorous explanation and proof for why this is needed:
Assume two variable names N and M (which are based on user-defined configuration beyond our control or other factors such as DB-schema). These two variables exist in their corresponding namespaces with their own prefixes P and Q where P ≠ Q and where there exists no string S such that P = S + Q or Q = S + P.

Let us take a look at the possibilities:
1. No prefixes are applied. Here, a conflict immediately emerges in the case N = M. As such, this solution is unacceptable.

2. Prefixes are applied to only one namespace, P. This means that the resulting variable X in the code will be X = P + N.
One can easily engineer a problem case by assuming that M consists of two substrings concatenated such that M = P + N.
Since prefixes in the name space Q are not applied (are empty), we get that the generated variable Y will be Y = M = P + N = X, and so we have another collision. Thus, this solution is also unacceptable.

3. Prefixes are applied for all namespaces. This time the generated variables will be X = P + N and Y = Q + M.
Let us disprove that there exist a case where X = Y. If X = Y, then P + N = Q + M. We have three possibilities:
* N = M results in P + N = Q + N and P = Q which is a contradiction with our premise P ≠ Q. So we have that N ≠ M.
* The next possibility is that the prefixes have the same length |P| = |Q|.
For this to be true and for the strings to still be equal, every character in P must match the one at the same index in Q, thus resulting in P = Q, contradicting P ≠ Q.
* Lastly, for |P| ≠ |Q| one of them must be shorter, so let us use |P| < |Q|. This would be equivalent for |Q| < |P|. Since P + N = Q + M, Q must use P as a prefix.
This means that Q = P + S where S is a non-empty string. This contradicts our second premise that there must not exist a string S such that P = S + Q or Q = S + P.
With this solution there can not exist a case where X = Y and variable naming collisions are impossible.

  • Field Details

  • Constructor Details

    • VariablePrefix

      public VariablePrefix()
  • Method Details

    • internalPrefix

      public static String internalPrefix(String name)
      Returns:
      This name formatted as an internal variable to avoid namespace collisions.
    • inputPrefix

      public static String inputPrefix(String name)
      Returns:
      This name formatted as an input variable to avoid namespace collisions.
    • resolverKeyPrefix

      public static String resolverKeyPrefix(String name)
      Returns:
      This name formatted as a resolver key variable to avoid namespace collisions.
    • aliasPrefix

      public static String aliasPrefix(String name)
      Returns:
      This name formatted as an alias variable to avoid namespace collisions.
    • contextFieldPrefix

      public static String contextFieldPrefix(String name)
      Returns:
      This name formatted as a context variable to avoid namespace collisions.
    • mapperInputPrefix

      public static String mapperInputPrefix(String name)
      Returns:
      This name formatted as a mapper input variable to avoid namespace collisions.
    • mapperOutputPrefix

      public static String mapperOutputPrefix(String name)
      Returns:
      This name formatted as a mapper output variable to avoid namespace collisions.