Class Definer

java.lang.Object
org.reldb.wrapd.sqldb.Definer

public class Definer
extends java.lang.Object

Mechanism for defining Query, Update and valueOf classes.

This is the main class you'll use to interact with Wrapd, at least to start with.

This class turns SQL query definitions into Java methods, like having an assistant who writes code for you.

Use it like this:

 public class Definitions extends Definer {

     public Definitions(Database database, String codeDirectory, String packageSpec) {
         super(database, codeDirectory, packageSpec);
     }

     void generate() throws Throwable {
         // Delete everything in the target directory.
         purgeTarget();

         // Generate definition for table ABC.
         defineTable("$$ABC");

         // Generate definition for a query called JoinABCXYZWhere.
         defineQuery("JoinABCXYZWhere",
           "SELECT * FROM $$ABC, $$XYZ WHERE x = a AND x > {lower} AND x < {higher}", 2, 5);

         // Generate a definition for a query called ValueOfXYZz that returns the value of the first
         // column of the first row of the result. (If there isn't one, the returned Option type is empty.)
         defineValueOf("ValueOfXYZz",
           "SELECT z FROM $$XYZ WHERE x = {xValue}", 33);

         // Emit the above definitions in a single class called DatabaseAbstractionLayer, with
         // methods for each definition above.
         emitDatabaseAbstractionLayer("DatabaseAbstractionLayer");
     }

     // Run the above queries; generate code to run them again via Java methods.
     public static void main(String[] args) throws Throwable {
         var database = new Database(...);
         var codeDirectory = "../path/to/code/in/project";
         var codePackage = "pkg.code.the";
         var sqlDefinitions = new Definitions(database, codeDirectory, codePackage);
         sqlDefinitions.generate();
         System.out.println("OK: Queries are ready.");
     }
 }
 
Then take a look in the "../path/to/code/in/project" directory to see what it's generated. In particular, in this example you'll want to look at DatabaseAbstractionLayer.java. You'll see that it contains method definitions corresponding to the generated queries.
  • Nested Class Summary

    Nested Classes
    Modifier and Type Class Description
    static class  Definer.DefineQueryResult
    The result of Query generation.
    static class  Definer.DefineValueOfResult
    The result of ValueOf generation.
  • Constructor Summary

    Constructors
    Constructor Description
    Definer​(Database database, java.lang.String codeDirectory, java.lang.String packageSpec)
    Create a Definer, given a Database, the directory where generated class definitions will be stored, and their package.
  • Method Summary

    Modifier and Type Method Description
    void define​(java.lang.String yamlFileName)
    Given the filespec of a YAML query definition file, run it to define queries.
    Definer.DefineQueryResult defineQuery​(java.lang.String queryName, java.lang.String sqlText, java.lang.Object... args)
    Define a Tuple type, and a Query class with query methods.
    Definer.DefineQueryResult defineQueryForTable​(java.lang.String queryName, java.lang.String tableName, java.lang.String sqlText, java.lang.Object... args)
    Define a Tuple type, and a Query class with query methods.
    Definer.DefineQueryResult defineTable​(java.lang.String tableName)
    Define a Tuple type, and Query class that has an insert(...) and an update(...) for the specified table.
    Definer.DefineQueryResult defineTable​(java.lang.String tableName, java.lang.String whereClause, java.lang.Object... args)
    Define a Tuple type, and a Query class with insert(...) and update(...) methods for the specified table.
    java.util.Collection<SQLTypeGenerator.Method> defineUpdate​(java.lang.String queryName, java.lang.String sqlText, java.lang.Object... args)
    Define an Update class with update(...) methods.
    Definer.DefineValueOfResult defineValueOf​(java.lang.String queryName, java.lang.String sqlText, java.lang.Object... args)
    Define a ValueOf class with methods that return the first column of the first row.
    void emitDatabaseAbstractionLayer​(java.lang.String newClassName)
    Create a new class that provides to invoke all the methods defined using this Definer.
    java.util.Map<java.lang.String,​java.util.Collection<SQLTypeGenerator.Method>> getMethods()
    Get all the classes and their methods defined by using this Definer.
    void purgeTarget()
    Prior to generating new code, purge everything in the package-specified subdirectory of the code directory.

    Methods inherited from class java.lang.Object

    clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
  • Constructor Details

    • Definer

      public Definer​(Database database, java.lang.String codeDirectory, java.lang.String packageSpec)
      Create a Definer, given a Database, the directory where generated class definitions will be stored, and their package.
      Parameters:
      database - Database
      codeDirectory - Directory for generated class definitions.
      packageSpec - The package, in dotted notation, to which the Tuple belongs.
  • Method Details

    • getMethods

      public java.util.Map<java.lang.String,​java.util.Collection<SQLTypeGenerator.Method>> getMethods()
      Get all the classes and their methods defined by using this Definer.
      Returns:
      Collection of method definitions for each defined class.
    • emitDatabaseAbstractionLayer

      public void emitDatabaseAbstractionLayer​(java.lang.String newClassName)
      Create a new class that provides to invoke all the methods defined using this Definer. Note that generated methods will always have (at least) a lower-case first character, in keeping with Java convention. That means query names with an upper-case first character, e.g., ClearABC, will emit a method called clearABC.
      Parameters:
      newClassName - Name of the generated database abstraction layer class definition.
    • purgeTarget

      public void purgeTarget()
      Prior to generating new code, purge everything in the package-specified subdirectory of the code directory. This avoids possible build errors that may result from the build pipeline attempting to compile outdated code. It's an optional operation in case the target contains content that needs to be kept, though arguably it shouldn't be used that way.
    • defineQueryForTable

      public Definer.DefineQueryResult defineQueryForTable​(java.lang.String queryName, java.lang.String tableName, java.lang.String sqlText, java.lang.Object... args) throws java.lang.Throwable
      Define a Tuple type, and a Query class with query methods.
      Parameters:
      queryName - Name of query. Should be unique.
      tableName - Name of table the generated Tuple maps to. Null if not mapped to a table. If not null, the Tuple type will have an insert(...) and an update(...) for the specified table.
      sqlText - SQL query text. Parameters may be specified as ? or {name}. If {name} is used, it will appear as a corresponding Java method name. If ? is used, it will be named pn, where n is a unique number in the given definition. Use getSQLText() after generate() to obtain final SQL query text with all {name} converted to ? for subsequent evaluation.
      args - Arguments that specify parameter type(s) and allow query to succeed.
      Returns:
      Result of generation.
      Throws:
      java.lang.Throwable - Error.
    • defineQuery

      public Definer.DefineQueryResult defineQuery​(java.lang.String queryName, java.lang.String sqlText, java.lang.Object... args) throws java.lang.Throwable
      Define a Tuple type, and a Query class with query methods.
      Parameters:
      queryName - Name of query. Should be unique.
      sqlText - SQL query text. Parameters may be specified as ? or {name}. If {name} is used, it will appear as a corresponding Java method name. If ? is used, it will be named pn, where n is a unique number in the given definition. Use getSQLText() after generate() to obtain final SQL query text with all {name} converted to ? for subsequent evaluation.
      args - Arguments that specify parameter type(s) and allow query to succeed.
      Returns:
      Result of generation.
      Throws:
      java.lang.Throwable - Error.
    • defineUpdate

      public java.util.Collection<SQLTypeGenerator.Method> defineUpdate​(java.lang.String queryName, java.lang.String sqlText, java.lang.Object... args) throws java.lang.Throwable
      Define an Update class with update(...) methods. WARNING: This will test the query by running it. Hope you're not doing this on a production database!
      Parameters:
      queryName - Name of update query. Should be unique.
      sqlText - SQL query text. Parameters may be specified as ? or {name}. If {name} is used, it will appear as a corresponding Java method name. If ? is used, it will be named pn, where n is a unique number in the given definition. Use getSQLText() after generate() to obtain final SQL query text with all {name} converted to ? for subsequent evaluation.
      args - Arguments that specify parameter type(s) and allow update query to succeed.
      Returns:
      Result of generation.
      Throws:
      java.lang.Throwable - Error.
    • defineTable

      public Definer.DefineQueryResult defineTable​(java.lang.String tableName, java.lang.String whereClause, java.lang.Object... args) throws java.lang.Throwable
      Define a Tuple type, and a Query class with insert(...) and update(...) methods for the specified table. The Query is SELECT * FROM tableName WHERE whereClause.
      Parameters:
      tableName - Name of the table, optionally including $$. Note that the generated class will have the same name as the table without $$ and with the first character converted to upper case. E.g., a table name of $$blah will be represented by a class named Blah.
      whereClause - The WHERE clause without the 'WHERE' keyword. Parameters may be specified as ? or {name}. If {name} is used, it will appear as a corresponding Java method name. If ? is used, it will be named pn, where n is a unique number in the given definition. Use getSQLText() after generate() to obtain final SQL query text with all {name} converted to ? for subsequent evaluation.
      args - Arguments that specify parameter type(s) and allow query to succeed.
      Returns:
      Result of generation.
      Throws:
      java.lang.Throwable - Error.
    • defineTable

      public Definer.DefineQueryResult defineTable​(java.lang.String tableName) throws java.lang.Throwable
      Define a Tuple type, and Query class that has an insert(...) and an update(...) for the specified table. The Query is SELECT * FROM tableName.
      Parameters:
      tableName - Name of the table, optionally including $$.
      Returns:
      Result of generation.
      Throws:
      java.lang.Throwable - Error.
    • defineValueOf

      public Definer.DefineValueOfResult defineValueOf​(java.lang.String queryName, java.lang.String sqlText, java.lang.Object... args) throws java.lang.Throwable
      Define a ValueOf class with methods that return the first column of the first row.
      Parameters:
      queryName - Name of valueOf query. Should be unique.
      sqlText - SQL query text. Parameters may be specified as ? or {name}. If {name} is used, it will appear as a corresponding Java method name. If ? is used, it will be named pn, where n is a unique number in the given definition. Use getSQLText() after generate() to obtain final SQL query text with all {name} converted to ? for subsequent evaluation. For optimum performance, should have one and only one column and return one row.
      args - Arguments that specify parameter type(s) and allow query to succeed.
      Returns:
      Result of generation.
      Throws:
      java.lang.Throwable - Error.
    • define

      public void define​(java.lang.String yamlFileName) throws java.lang.Throwable

      Given the filespec of a YAML query definition file, run it to define queries.

      The file actually specifies a series of method invocations of methods defined in the Definer class.

      An example YAML query definition file -- which might be called testqueries.yaml -- looks like this:

           defineTable:
              $$abc:
      
              $$xyz:
                  - x = {xvalue}
                  - [22]
      
           defineQueryForTable:
               SelectABCWhere2:
                   - $$abc
                   - SELECT *
                       FROM $$abc
                       WHERE a = {aVal}
                   - [22]
      
           defineQuery:
               JoinABCXYZ2:
                   - SELECT * FROM $$abc, $$xyz WHERE x = a
      
               JoinABCXYZWhere2:
                   - SELECT *
                       FROM $$abc, $$xyz
                       WHERE x = a
                       AND x > {lower}
                       AND x < {higher}
                   - [2, 5]
      
           defineUpdate:
               ClearABC2:
                   - DELETE FROM $$abc
      
               ClearXYZ2:
                   - DELETE FROM $$xyz
      
               ClearABCWhere2:
                   - DELETE FROM $$abc WHERE a = {aValue}
                   - [3]
      
           defineValueOf:
               ValueOfABCb2:
                   - SELECT b FROM $$abc
      
               ValueOfXYZz2:
                   - SELECT z FROM $$xyz WHERE x = {xValue}
                   - [33]
           

      The file is defined as a set of keys, where each key is the name of a Definer method. E.g., defineQueryForTable, defineQuery, defineUpdate, defineValueOf, etc. The define method may be specified here to include other YAML query definition files within a YAML query definition file.

      Within each key, query names are defined. E.g, JoinABCXYZ2 and JoinABCXYZWhere2 are defineQuery queries.

      Each query name specifies an array, where the first element must be the SQL text associated with the query name. E.g., the query named by JoinABCXYZWhere2 is:

      SELECT * FROM $$abc, $$xyz WHERE x = a AND x > {lower} AND x < {higher}

      If the query defines parameters, test arguments must be provided. Then they are the second array element, which is itself an array. For the above query, the test argument array is [2, 5]. Since the arguments are positional corresponding to the appearance of the parameter names, 2 will be the value passed to lower and 5 will be the value passed to higher.

      Parameters:
      yamlFileName - YAML query definition file.
      Throws:
      java.lang.Throwable - Error.