This PR is proposition for more convenient way to pass collections into queries. I added ability to expand collections by introducing new format of parameter operator: #{param...}. When parsing query, format #{params...} is resolved as ForEachSqlNode.

In other words existing operator #{param} is always translated to single param ?, but #{param...} expands collections to list of parameters, for example to ?, ?, ?.

This should cover these cases:

  1. No need to use <script> and <foreach> tags when using annotations This can be simplified:
  @Select({
    "<script>select * from users ",
    "where id in <foreach item=\"item\" collection=\"ids\" open=\"(\" separator=\",\" close=\")\">#{item}</foreach> ",
    "order by id</script>"})

to:

  @Select("select * from users where id in (#{ids...}) order by id")
  1. This works also in xml mappers:
  <select id="getUsers" resultType="org.apache.ibatis.submitted.expand_collection_param.model.User">
    select * from users where id != #{id} and role in
    <foreach item='item' index='index' collection='roles' open='(' separator=',' close=')'>
      #{item}
    </foreach>
    order by id
  </select>

vs:

  <select id="getUsers" resultType="org.apache.ibatis.submitted.expand_collection_param.model.User">
      select * from users
      where id != #{id} and role in (#{roles...})
      order by id
  </select>
  1. This will also reduce code when using providers:
  @SelectProvider(type = StatementProvider.class, method = "getUsers")
  public String getUsers(@Param("roles") List<UserRole> roles) {
    SQL sql = new SQL().SELECT("*").FROM("users");
    if (!roles.isEmpty()) {
      sql.WHERE("role in (#{roles...})");
    }
    sql.ORDER_BY("id");
    return sql.toString();
  }

What do you think?