Code Monkey home page Code Monkey logo

velocity-scripting's Introduction

MyBatis Velocity Support

Build Status Coverage Status Maven central Sonatype Nexus (Snapshots) License

mybatis-velocity

Mybatis Velocity Scripting Support.

Requirements

  • master(2.1.x) : MyBatis 3.5+, Velocity 2.1+ and Java 8+
  • 2.0.x : MyBatis 3.4+, Velocity 2.0 and Java 7+

Essentials

velocity-scripting's People

Contributors

dependabot-preview[bot] avatar dependabot[bot] avatar emacarron avatar harawata avatar hazendaz avatar hboutemy avatar kazuki43zoo avatar mnesarco avatar renovate[bot] avatar simonetripodi avatar wakuflair avatar zaherhammoud avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

velocity-scripting's Issues

#set inside #repeat does not work correctly

Mapper:

<update id="velocity-nested-set" lang="velocity">
    #repeat( $_parameter.list $level1)
        #set( $foo = $level1)
        @{foo}
    #end
</update>

Test:

@Test
public void velocityTestNestedSet() throws SQLException, IOException {
    expect(connection.getAutoCommit()).andStubReturn(false);
    expect(connection.prepareStatement("\n" +
            "                    ?\n" +
            "                    ?\n" +
            "            ")).andReturn(statement);
    statement.setInt(1, 1);
    statement.addBatch();
    statement.setInt(2, 2);
    statement.addBatch();
    expect(statement.executeBatch()).andStubReturn(new int[]{2});
    statement.close();
    connection.setAutoCommit(true);
    connection.rollback();
    connection.close();

    replay();

    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(
            Resources.getResourceAsStream("configuration.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, connection);
    List<Integer> param = Arrays.asList(1,2);
    sqlSession.insert("velocity-nested-set", param);
    sqlSession.flushStatements();
    sqlSession.close();

}

Exception:

java.lang.AssertionError: 
  Unexpected method call setInt(1, 2):
    setInt(1, 1): expected: 1, actual: 0
    addBatch(): expected: 2, actual: 0
    setInt(2, 2): expected: 1, actual: 0
    close(): expected: 1, actual: 0
    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:29)
    at org.easymock.internal.ObjectMethodsFilter.invoke(ObjectMethodsFilter.java:56)
    at com.sun.proxy.$Proxy7.setInt(Unknown Source)
    at org.apache.ibatis.type.IntegerTypeHandler.setNonNullParameter(IntegerTypeHandler.java:28)
    at org.apache.ibatis.type.IntegerTypeHandler.setNonNullParameter(IntegerTypeHandler.java:23)
    at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:46)
    at org.apache.ibatis.type.UnknownTypeHandler.setNonNullParameter(UnknownTypeHandler.java:42)
    at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:46)
    at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:77)
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:77)
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:58)
    at org.apache.ibatis.executor.BatchExecutor.doUpdate(BatchExecutor.java:68)
    at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:100)
    at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:75)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:148)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:137)

#where() directive always prefixes "WHERE"

If we use the #where() directive, a "WHERE" is always prepended at the beginning, even though no condition met.

It's because of the "VelocityWhitespaceGobbling".

Example:

select * from foo

where()

end

output: select * from foo WHERE

Add support for adding attributes to the Velocity context

The MyBatis Velocity plugin does not allow to put attributes in the Velocity context to be used during the query transformation phase. This feature is very important for existing projects that have code to support SQL and literal parameters transformation.

The idea is to introduce an optional property file where custom attributes can be defined and injected into the Velocity context at run time. The same property file can be used to override the default properties defined in the "velocity.properties" file.

Reference to outer parameter in nested repeat does not work

Mapper:

<update id="velocity-nested-ref" lang="velocity">
    #repeat( $_parameter.list $level1)
    #repeat( $level1 $level2)
    @{level1}
    #end
    #end
</update>

Test:

@Test
public void velocityTestNestedRef() throws SQLException, IOException {
    expect(connection.getAutoCommit()).andStubReturn(false);
    expect(connection.prepareStatement("\n" +
            "                        ?\n" +
            "                ?\n" +
            "                                ?\n" +
            "                ?\n" +
            "                    ")).andReturn(statement);

    replay();

    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(
            Resources.getResourceAsStream("configuration.xml"));
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, connection);
    List<List<Integer>> param = Arrays.asList(Arrays.asList(10,11),Arrays.asList(20, 21));
    sqlSession.insert("velocity-nested-ref", param);
    sqlSession.flushStatements();
    sqlSession.close();

}

Exception:

org.apache.ibatis.exceptions.PersistenceException: 
### Error updating database.  Cause: org.apache.ibatis.binding.BindingException: Parameter 'level1' not found. Available parameters are [list]
### The error may involve defaultParameterMap
### The error occurred while setting parameters
### SQL: ?                 ?                                 ?                 ?
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'level1' not found. Available parameters are [list]
    at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:150)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.insert(DefaultSqlSession.java:137)
    at com.luxoft.mybatis.splitter.UpdateSplitterPluginTest.velocityTestNestedRef(UpdateSplitterPluginTest.java:154)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
    at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:107)
    at org.unitils.UnitilsJUnit4TestClassRunner$TestListenerInvokingMethodRoadie.runTestMethod(UnitilsJUnit4TestClassRunner.java:174)
    at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:88)
    at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96)
    at org.unitils.UnitilsJUnit4TestClassRunner$TestListenerInvokingMethodRoadie.runBeforesThenTestThenAfters(UnitilsJUnit4TestClassRunner.java:156)
    at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86)
    at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
    at org.unitils.UnitilsJUnit4TestClassRunner.invokeTestMethod(UnitilsJUnit4TestClassRunner.java:95)
    at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:61)
    at org.unitils.UnitilsJUnit4TestClassRunner.access$000(UnitilsJUnit4TestClassRunner.java:44)
    at org.unitils.UnitilsJUnit4TestClassRunner$1.run(UnitilsJUnit4TestClassRunner.java:62)
    at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33)
    at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45)
    at org.unitils.UnitilsJUnit4TestClassRunner.run(UnitilsJUnit4TestClassRunner.java:68)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:76)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:195)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:63)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
Caused by: org.apache.ibatis.binding.BindingException: Parameter 'level1' not found. Available parameters are [list]
    at org.apache.ibatis.session.defaults.DefaultSqlSession$StrictMap.get(DefaultSqlSession.java:257)
    at org.apache.ibatis.reflection.wrapper.MapWrapper.get(MapWrapper.java:41)
    at org.apache.ibatis.reflection.MetaObject.getValue(MetaObject.java:113)
    at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:72)
    at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:77)
    at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:58)
    at org.apache.ibatis.executor.BatchExecutor.doUpdate(BatchExecutor.java:68)
    at org.apache.ibatis.executor.BaseExecutor.update(BaseExecutor.java:100)
    at org.apache.ibatis.executor.CachingExecutor.update(CachingExecutor.java:75)
    at org.apache.ibatis.session.defaults.DefaultSqlSession.update(DefaultSqlSession.java:148)
    ... 30 more

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/ci.yaml
  • actions/checkout v4
  • actions/setup-java v4
.github/workflows/codeql.yml
  • actions/checkout v4
  • github/codeql-action v3
  • github/codeql-action v3
  • github/codeql-action v3
.github/workflows/coveralls.yaml
  • actions/checkout v4
  • actions/setup-java v4
.github/workflows/site.yaml
  • actions/checkout v4
  • actions/setup-java v4
  • JamesIves/github-pages-deploy-action v4.6.0
.github/workflows/sonar.yaml
  • actions/checkout v4
  • actions/setup-java v4
.github/workflows/sonatype.yaml
  • actions/checkout v4
  • actions/setup-java v4
maven
pom.xml
  • org.mybatis:mybatis-parent 43
  • org.mybatis:mybatis 3.5.16
  • org.apache.velocity:velocity-engine-core 2.3
  • org.apache.commons:commons-text 1.12.0
  • org.junit.jupiter:junit-jupiter-engine 5.10.2
  • org.hsqldb:hsqldb 2.7.2
  • org.slf4j:slf4j-simple 2.0.13
maven-wrapper
.mvn/wrapper/maven-wrapper.properties
  • maven 3.9.6
  • maven-wrapper 3.2.0

  • Check this box to trigger a request for Renovate to run again on this repository

Support #in directive to render an sql IN clause with more than 1000 items

Currently mybatis-scripting supports the #repeat directive which iterates through the first 1000 items in a collection and ignores the rest. Most of the time the #repeat directive will be used to render an IN clause and it is not convenient to partially render a collection. Some of the databases such as Oracle have a limit of 1000 items in their IN clause. One way to get around this limitation is to use an OR clause inside the IN .
For example: "WHERE ( (id IN (1,2,....1000)) OR (id IN (1001,1002 ......2000))) ".

I am proposing to add a block #in(Collection $item columnName) directive to mybatis-scripting to handle any collection size. If the collection size is greater than a 1000 , then items will be grouped by 1000 and OR'ed together. It can be used as follow :

SELECT \* FROM MyTable WHERE #in(_param.ids $id "id") @{id} #end

Please note that we do not have to pass the "IN" , "(" , ")" and ","

A dengrous bug with InDirective.

here is a example.

select * from user
#where() 
    #in( $_parameter.ids $id "userid" ) 
    @{id} 
   #end
#end

it will excute the sql "select * from user" while $_parameter.ids is empty.

the bug causes by this code.

String content = buffer.toString().trim();
    if (!"".equals(content)) {
      writer.append(this.open);
      writer.append(content);
      writer.append(this.close);
    }
    clean(context, o, collector, savedItemKey);
    return true;

to fix the bug,we should do this

String content = buffer.toString().trim();
if (!"".equals(content)) {
    writer.append(this.open);
    writer.append(content);
    writer.append(this.close);
}else{
     writer.append(this.open);
      writer.append(this.open);
      writer.append(this.column);
      writer.append(" NOT IN ");
      writer.append(this.open);
      writer.append(" NULL ");
      writer.append(this.close);
      writer.append(this.close);
      writer.append(this.close);
}
clean(context, o, collector, savedItemKey);
return true;

so ti will excute "select * from user where userid not in (null)"
"userid not in (null)" always return false even though the user table have one line which userid have value.

this bug is hidden dangers while the sql is a update or delete operation.

Discontinue use of deprecated properties on 2.0.x

The mybatis-velocity 2.0 used deprecated properties as follow:

[main] WARN org.apache.velocity.deprecation - configuration key 'class.resource.loader.class' has been deprecated in favor of 'resource.loader.class.class'
[main] WARN org.apache.velocity.deprecation - configuration key 'resource.loader' has been deprecated in favor of 'resource.loaders'
[main] WARN org.apache.velocity.deprecation - configuration key 'userdirective' has been deprecated in favor of 'runtime.custom_directives'
[main] WARN org.apache.velocity.deprecation - configuration key 'userdirective' has been deprecated in favor of 'runtime.custom_directives'
[main] WARN org.apache.velocity.deprecation - configuration key 'userdirective' has been deprecated in favor of 'runtime.custom_directives'
[main] WARN org.apache.velocity.deprecation - configuration key 'userdirective' has been deprecated in favor of 'runtime.custom_directives'

Support template file

In current version, template file(vm file) does not support.

For example:

  • CityMapper-findByState.vm
select
  id, name, state, country
from
  city
where
  state = @{state}
  • Mapper
@Select("#parse('/mappers/CityMapper-findByState.vm')")
City findByState(@Param("state") String state);

In above case, @{state} cannot translate to JDBC bind variable (?).

We will consider to support a template file(.vm) like as mybatis-freemarker and mybatis-thymeleaf.

Eclipse Oxygen requires AspectJ to run JUnit tests

I just upgraded to Eclipse Oxygen. I had been running velocity-scripting successfully under Neon. When I imported the project to Neon and tried to run a unit test in VelocityLanguageTest, I kept getting initialization errors, which were simply reported as FilterRequest errors. Here's a bug report about FilterRequest hiding the actual problem:

junit-team/junit4#1277

Using the suggested workaround of running JUnit against the file instead of a single test, I discovered that the stack trace was claiming ClassNotFound on AspectJ. So, I added an AspectJ dependency in pom.xml, and that fixed the issue.

I do have AspectJ in Eclipse, but that does not help.

Boundary issue with the RepeatDirective

The RepeatDirective takes the first 1000 items from the collection and ignores the remaining. It is appending the separator after the last item and before the closing character.
For example :

repeat($_parameter.ids $id ',' 'id IN (' ')')

    @{id}
  #end

Will generate
column IN (1,.......,1000,)

The `userdirective` change to the deprecated property key

I've deprecated the userdirective for specifying user defined custom directive because it can be replaced the runtime.custom_directives provided by Velocity 2.1. The userdirective can be use, however it become the deprecated property key since 2.1.0. If you are updating to 2.1+, please change to use the velocity-settings.runtime.custom_directives or runtime.custom_directives instead of it.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.