mybatis / mybatis-3

MyBatis SQL mapper framework for Java
http://mybatis.github.io/mybatis-3/
Apache License 2.0
19.6k stars 12.77k forks source link

Support for pluggable scripting engines in expression evaluation #32

Open guy-rouillier opened 11 years ago

guy-rouillier commented 11 years ago

This issue is a continuation of http://code.google.com/p/mybatis/issues/detail?id=583. That issue addressed scripting engines in SQL statement construction, and left expression evaluation for a later time. This issue addresses expression evaluation. This issue was also recently discussed on the MyBatis User mailing list in a thread with subject "Expression evaluation".

To be clear, we are talking about #{} and ${} expressions. The former are parameters, while the latter can be used anywhere.

guy-rouillier commented 11 years ago

I'd like to kick off the discussion by addressing various use cases, so we can all come to a consensus on the scope of what we are trying to achieve. The particular use case that started me looking is to incorporate program-defined enums. In MyBatis 3, OGNL expressions can refer to enums like so:

<if test="myParam.contains(@com.company.MyEnum@VALUE1) == false">

where myParam is an EnumSet. I'd like to be able to use use references to enums in various parts of a SQL statement:

select 
    x,
    y,
    @com.company.MyEnum@VALUE1.toInt()
from
    table1
where 
    z = @com.company.MyEnum@VALUE2.toInt()

insert into table1
   values
   (
   #{x},
   #{y},
   @com.company.MyEnum@VALUE1.toInt()
   }

Currently, in my mapper.xml file, I use hard-coded integers in the places indicated, what I refer to as magic numbers. Using enums is better because if named correctly, they are more descriptive and help the reader better understand intent.

Frank has implemented one approach for using enum values in mapper.xml files here: https://github.com/mybatis/velocity-scripting/commit/9c2fb55193dff3dbe578f10fcb9dfa1dbcc0e88d. That approach requires a wrapper and a #set each time an enum value is needed in a SQL statement. But the various scripting languages already have a mechanism for accessing enum values in the classpath, so we should be able to use that approach without wrappers or #set.

guy-rouillier commented 11 years ago

Ha! On a whim, I tried the above expression in ${} braces, and it actually works with the 3.1.1. code (and hence I assume the 3.2.x code.) Here is a working example:

<select id="selectAllAccounts" resultMap="AccountMap">
     SELECT 
            id, 
        name,
        ${@org.sample.beans.AccountTypeEnum@RESELLER.toInt()} as account_type_id 
    FROM 
        account
    WHERE
       -- ${} works, #{} does not
        account_type_id = ${@org.sample.beans.AccountTypeEnum@RETAIL.toInt()}
</select>

So, for my immediate needs, looks like the current implementation does what I need. But we should keep this issue open and implement a full expression handler in the selected scripting language.