Showing posts with label jooq. Show all posts
Showing posts with label jooq. Show all posts

Thursday, October 3, 2013

minuteproject 4 propel motivations

Propel is based on some forward engineering technics that creates your Php Object Domain and ORM classes for your based on a file describing your model.

Propel ORM also offers reverse-engineering facilities to generate this input file.
Minuteproject meanwhile creates a track for propel. Why? What are the motivations?

Minuteproject 4 propel track will be delivered in version 0.8.5.

Polyglot generator


Minuteproject was essentially generating java framework oriented artifact but the php tracks with propel and soon doctrine offers another perspective.
Whatever your language and your framework, minuteproject can offer you reverse-engineering facilities.


Get Php knowledge

Testing with php was quite easy and interesting.

Propel specifics

As mentionned previously Propel offers reverse-engineering solution.

Interesting points

Their solutions is interesting because for each database Propel support the tool issue database query-specific-data-dictionnary lookup. It is the same philosophy that JOOQ framework with JOOQ meta is following.

Minuteproject 4 propel advantages

Propel reverse-engineering solution propose raw reverse-engineering, while minuteproject offers you the possibility to make a reverse-analysis before.

Enrichment

All the enrichment facilities are available for Propel track. Which means that you can have smart reverse-engineering aspects:
  • Alias for tables (DB table naming convention can differ from you Php classes conventions)
    • In schema.xml 'name' is filled by DB name and phpName by your given name.
  • Alias for columns same principle as above
  • Apply alias (column or view) globally by conventions or individually
    • Ex tables starting with T_ such as T_USER can get User in php.
    • Ex field ending with FK (ex PRODUCT_FK) have the variable $product.
  • Granularity select only tables or views you need
    • No need to reverse-engineer all the entities

Multiple artifacts

Minuteproject 4 propel generate other artifacts such as
  • runtime-conf.xml
  • build.properties
  • command line scripts
  • setup.php

Updatable code

Generator tools are often see as generate once and no more...
It is not the case of minuteproject!

The code that you generate is updatable! 
If you do not like it change it! 
If it misses something add it!

Next time you generate YOUR ALTERATIONS WILL BE KEPT!


This is call updatable code feature. And all the minuteproject 4 propel templates have this feature!


Which means that if you do not like what  you have in the schema.xml node you can change them. If your model changes add couples of db object (table/view), change cardinality between objects, the next time you generate, new object and relationship will be added BUT your modification (ex table phpName) will be kept!

Thursday, September 5, 2013

piping generators with minuteproject

There are couple of really interesting generators working based on some input file and execution principles.
It is easy to understand and tooling-oriented. Input 2 Tool gives Result Code.

Minuteproject principle is the same

When working with generators dealing with RDBMS persistence (Rev-Eng or Fwd-Eng), minuteproject can generate initial input for those generators.

This strategy is called generator piping.

Each generator has its own particularities and kind of DSL.
The goal is then to degrade as less as possible the 'other-generator' input in order to keep the added value as high as possible.


Minuteproject is particularily interested by the following OS generators:
  • Liferay Service Builder
  • JOOQ
  • Benerator
  • Roo (input script instructions)
  • RoR (input script instructions)
  • Propel

Tooling to deal with other generators available in minuteproject
  • Plugin
    • write a mp plugin (java bean match target technology specifics)
    • this plugin is available at template level to query target-generator-centric info.
  • Parametrization
    • offer track customization
    • a classical parameter could be the version of the target generator
  • Updatable code feature
    • tune your output without losing your altertions over consecutive generations
  • Enrichment
    • Conventions
      • Some configuration can be tedious because quite verbose, fortunately minuteproject can pin common caracteristics via conventions
    • Aliasing
      • provides indirection level to have DB names look like DB names and Java name matching Java conventions
The main difficulty is to know what is the input for field type (is it an SQL, UML, Java, own DSL type) that has to be treated at plugin level.

Saturday, February 25, 2012

Productivity by example: Liferay with JOOQ

This article shows how to use jOOQ for the Liferay data model.
Minuteproject generates jOOQ artifacts for Liferay.
The main interest of using minuteproject to generate jOOQ artefacts are 
  • Liferay database does not have any foreign key, but minuteproject is able to detect relationship based on patterns.
  •  Some DB naming convention might need to be adapted at Java level
    • DB tables ending with '_' will have underscore stripped
    • Column name ending with '_id' corresponding to PK or FK will have this particule stripped when not coliding with other variable
  • Code is updatable, meaning that you can change part of it or entirely and consecutive generation will keep your alterations
For more information about the enrichment made on top of Liferay by minuteproject check another post targeting Liferay with JPA2.
Here the reverse-engineering targets jOOQ framework and the configuration mentions jOOQ track reference

Configuration
mp-config-LIFERAY-JOOQ.xml
<!DOCTYPE root>
<generator-config>
 <configuration>
  <conventions>
   <target-convention type="enable-updatable-code-feature" />
  </conventions>
  <model name="liferay" version="1.0" package-root="net.sf.mp.demo">
   <data-model>
    <driver name="mysql" version="5.1.16" groupId="mysql"
     artifactId="mysql-connector-java"></driver>
    <dataSource>
     <driverClassName>org.gjt.mm.mysql.Driver</driverClassName>
     <url>jdbc:mysql://127.0.0.1:3306/lportal</url>
     <username>root</username>
     <password>mysql</password>
    </dataSource>
    <schema>lportal</schema>
    <primaryKeyPolicy oneGlobal="true">
     <primaryKeyPolicyPattern name="none"></primaryKeyPolicyPattern>
    </primaryKeyPolicy>
   </data-model>
   <business-model>
    <generation-condition>
     <condition type="exclude" startsWith="QUARTZ"></condition>
    </generation-condition>
    <enrichment>
     <conventions>
      <entity-naming-convention type="apply-strip-table-name-suffix"
       pattern-to-strip="_" />
      <!-- manipulate the structure and entities BEFORE manipulating the 
       entities -->
      <foreign-key-convention
       type="autodetect-foreign-key-based-on-similarity-and-map"
       column-ending="id" column-starting="" />
      <column-naming-convention type="apply-strip-column-name-suffix"
       pattern-to-strip="ID" />
      <reference-naming-convention
       type="apply-referenced-alias-when-no-ambiguity" is-to-plurialize="true" />
     </conventions>
    </enrichment>
   </business-model>
  </model>
  <targets>
   <target refname="JOOQ" name="JOOQ" fileName="mp-template-config-JOOQ.xml"
    outputdir-root="../../dev/JOOQ/liferay" templatedir-root="../../template/framework/jooq">
    <property name="jooq-version" value="2.0.4"></property>
   </target>
   <target refname="LIB" fileName="mp-template-config-bsla-LIB-features.xml"
    templatedir-root="../../template/framework/bsla">
   </target>
  </targets>
 </configuration>
</generator-config>
Execution
Install Liferay mysql 6.0.6 running
Download minuteproject
Drop this config in /mywork/config
And execute model-generation.(sh/cmd) mp-config-LIFERAY-JOOQ.xml

Result 
Artifacts
The resulting artefacts are
  • A maven project with following dependencies
    • jOOQ
    • jUnit
    •  mysql drive
  • jOOQ artifacts
    • factory, keys, tables, records...
  • unit test
The artifacts are generated in /dev/JOOQ/liferay
If you build there will be a compilation error in jOOQ artifacts:
Table 'expandotable' has a field call 'table' that collides with a Jooq method. 
But just by altering the code to remove the compilation error and flaging to take into account this modification:
In ExpandotableRecord 
  • Change getTable into getTable_ 
  • Exclude code from been overwritten: line 24 //MP-MANAGED-UPDATABLE-BEGINNING-ENABLE
 //MP-MANAGED-UPDATABLE-BEGINNING-ENABLE @jooq-record-pk-liferay@
 /**
  * An uncommented item
  * 
  * PRIMARY KEY
  */
    public void setTable(java.lang.Long value) {
        setValue(net.sf.mp.demo.liferay.tables.Expandotable.__EXPANDOTABLE.TABLE, value);
    }
 /**
  * An uncommented item
  * 
  * PRIMARY KEY
  */
    public java.lang.Long getTable_() {
        return getValue(net.sf.mp.demo.liferay.tables.Expandotable.__EXPANDOTABLE.TABLE);
    }
 //MP-MANAGED-UPDATABLE-ENDING

Remark: Future version will handle this issue but it is interesting to see how the code can be customized without losing the productivity of consecutive generations.

Eventually run: mvn clean package
  • A set of unittest are executed:
    • The default unit test consist to retrieve the first row of each entity.
  • A JOOQ package is released
Code
The code can be downloaded from minuteproject googlecode here.

Sample
Active record:
Providing the Foreign key gives the ability to provide jOOQ records with some methods
One to many
//todo
Testing

/**
 * This class is generated by minuteproject 4 jOOQ
 */
package net.sf.mp.demo.liferay.tables;

import net.sf.mp.demo.liferay.tables.records.UserRecord;
import net.sf.mp.demo.liferay.Liferay;
import net.sf.mp.demo.liferay.Keys;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import net.sf.mp.demo.liferay.LiferayFactory;
import static net.sf.mp.demo.liferay.tables.User.__USER;

import org.jooq.Record;
import org.jooq.Result;
import org.junit.Test;

//MP-MANAGED-ADDED-AREA-BEGINNING @import@
import static net.sf.mp.demo.liferay.tables.Company.__COMPANY;
import static net.sf.mp.demo.liferay.tables.Account.__ACCOUNT;
//MP-MANAGED-ADDED-AREA-ENDING @import@

//MP-MANAGED-ADDED-AREA-BEGINNING @class-annotation@
//MP-MANAGED-ADDED-AREA-ENDING @class-annotation@
@javax.annotation.Generated(value = { "http://www.jooq.org", "2.0.4" }, comments = "This class is generated by minuteproject 4 jOOQ")
public class TestUser {

 @Test
 public void testUser() {
  Connection conn = null;
  String userName = "root";
  String password = "mysql";
  String url = "jdbc:mysql://127.0.0.1:3306/lportal";

  try {
   Class.forName("org.gjt.mm.mysql.Driver").newInstance();
   conn = DriverManager.getConnection(url, userName, password);
   LiferayFactory create = new LiferayFactory(conn);

   // MP-MANAGED-UPDATABLE-BEGINNING-ENABLE
   // @jooq-unittest-testUser-liferay@
   // write your own tests, just set DISABLE to ENABLE in the comment
   // above
   // future generation will not erase your code ;)
   Result<Record> result = create
     .select(__USER.FIRSTNAME, __USER.LASTNAME, __COMPANY.WEB, __ACCOUNT.NAME)
     .from(__USER).join(__COMPANY)
     .on(__USER.COMPANY.equal(__COMPANY.COMPANY))
     .join(__ACCOUNT)
     .on(__COMPANY.ACCOUNT.equal(__ACCOUNT.ACCOUNT))
     .where(__COMPANY.WEB.like("%ray.com"))
     .orderBy(__USER.LASTNAME.asc().nullsFirst()).limit(10)
     .fetch();
   for (Record r : result) {
    String firstname = r.getValue(__USER.FIRSTNAME);
    String lastname = r.getValue(__USER.LASTNAME);
    String web = r.getValue(__COMPANY.WEB);
    String accountname = r.getValue(__ACCOUNT.NAME);

    System.out.println(" firstname : " + firstname + " lastname : "
      + lastname + " web : " + web + " accountname : "
      + accountname);
   }
   // MP-MANAGED-UPDATABLE-ENDING

  } catch (Exception e) {
   e.printStackTrace();
  } finally {
   if (conn != null) {
    try {
     conn.close();
    } catch (SQLException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }
 }

 // MP-MANAGED-ADDED-AREA-BEGINNING @implementation@
 // MP-MANAGED-ADDED-AREA-ENDING @implementation@

}
Giving at execution
 firstname :  lastname :  web : liferay.com accountname : Liferay
 firstname : Joe lastname : Bloggs web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 1 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 10 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 2 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 3 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 4 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 5 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 6 web : liferay.com accountname : Liferay
 firstname : Test lastname : DLC 7 web : liferay.com accountname : Liferay
JOOQ quick review
//todo
  • Typesafe query speeds up the development process
  • No ORM 
  • Focus on CRUD and complexe query 
  • No configuration loading meaning fast to test