From 961f58978ca7602ae59afa122bee7e94b15eec54 Mon Sep 17 00:00:00 2001 From: Kazuki Shimizu Date: Mon, 4 Nov 2019 22:32:48 +0900 Subject: [PATCH] Support dynamic indexed access on mb:p tag Fixes gh-41 --- src/main/asciidoc/user-guide.adoc | 21 +++++ .../processor/MyBatisParamTagProcessor.java | 11 +++ .../AnnotationDrivenMapperTest.java | 94 ++++++++++++++++++- .../integrationtest/mapper/PersonMapper.java | 7 ++ .../PersonMapper/insertByBulkWithIndexed.sql | 22 +++++ .../insertMailsByBulkWithIndexed.sql | 26 +++++ 6 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 src/test/resources/sql/PersonMapper/insertByBulkWithIndexed.sql create mode 100644 src/test/resources/sql/PersonMapper/insertMailsByBulkWithIndexed.sql diff --git a/src/main/asciidoc/user-guide.adoc b/src/main/asciidoc/user-guide.adoc index 83d805e..7ea0214 100644 --- a/src/main/asciidoc/user-guide.adoc +++ b/src/main/asciidoc/user-guide.adoc @@ -576,6 +576,27 @@ SELECT * FROM names /*[/]*/ ORDER BY id ---- + +Since 1.0.2, We support the indexed access using an iteration status object as follow: + +[source,sql] +.Use indexed access using an iteration status object +---- +SELECT * FROM names + WHERE 1 = 1 + /*[# th:if="${not #lists.isEmpty(ids)}"]*/ + AND id IN ( + /*[# th:each="id : ${ids}"]*/ + /*[# mb:p="ids[${idStat.index}]"]*/ 1 /*[/]*/ -- <1> + /*[(${idStat.last} ? '' : ',')]*/ + /*[/]*/ + ) + /*[/]*/ + ORDER BY id +---- + +<1> Access to a iterable object using indexed + ==== About more advanced usage of `th:each` , please see <>. diff --git a/src/main/java/org/mybatis/scripting/thymeleaf/processor/MyBatisParamTagProcessor.java b/src/main/java/org/mybatis/scripting/thymeleaf/processor/MyBatisParamTagProcessor.java index 14921df..716011e 100644 --- a/src/main/java/org/mybatis/scripting/thymeleaf/processor/MyBatisParamTagProcessor.java +++ b/src/main/java/org/mybatis/scripting/thymeleaf/processor/MyBatisParamTagProcessor.java @@ -65,6 +65,10 @@ public MyBatisParamTagProcessor(final TemplateMode templateMode, final String pr @Override protected void doProcess(ITemplateContext context, IProcessableElementTag tag, AttributeName attributeName, String attributeValue, IElementTagStructureHandler structureHandler) { + if (attributeValue.contains("${")) { + attributeValue = getExpressionEvaluatedText(context, tag, attributeName, attributeValue); + } + Pair parameterAndOptionPair = Pair.parse(attributeValue, ','); String parameterPath = parameterAndOptionPair.left; String options = parameterAndOptionPair.right; @@ -111,6 +115,13 @@ private Object getExpressionEvaluatedValue(ITemplateContext context, IProcessabl return expression.execute(context, this.expressionExecutionContext); } + private String getExpressionEvaluatedText(ITemplateContext context, IProcessableElementTag tag, + AttributeName attributeName, String parameterValue) { + IStandardExpression expression = EngineEventUtils.computeAttributeExpression(context, tag, attributeName, + "|" + parameterValue + "|"); + return expression.execute(context, this.expressionExecutionContext).toString(); + } + private boolean isCollectionOrArray(Object value) { return value != null && (Collection.class.isAssignableFrom(value.getClass()) || value.getClass().isArray()); } diff --git a/src/test/java/org/mybatis/scripting/thymeleaf/integrationtest/AnnotationDrivenMapperTest.java b/src/test/java/org/mybatis/scripting/thymeleaf/integrationtest/AnnotationDrivenMapperTest.java index cb7a97b..fa7843e 100644 --- a/src/test/java/org/mybatis/scripting/thymeleaf/integrationtest/AnnotationDrivenMapperTest.java +++ b/src/test/java/org/mybatis/scripting/thymeleaf/integrationtest/AnnotationDrivenMapperTest.java @@ -383,11 +383,11 @@ void testBulkInsertAndSelect() { persons.add(person); } - int maxMailId = Optional.ofNullable(mapper.getMaxMailId()).filter(x -> x != 0).orElse(-1); - mapper.insertByBulk(persons); mapper.insertMailsByBulk(persons); + int maxMailId = Optional.ofNullable(mapper.getMaxMailId()).filter(x -> x != 0).orElse(-1) - 4; + // Select List loadedPersons = mapper.selectPersons(persons.get(0).getId(), persons.get(1).getId()); Assertions.assertEquals(2, loadedPersons.size()); @@ -478,4 +478,94 @@ void testBulkInsertAndSelect() { } } + @Test + void testBulkInsertWithIndexedAndSelect() { + + try (SqlSession sqlSession = sqlSessionFactory.openSession()) { + PersonMapper mapper = sqlSession.getMapper(PersonMapper.class); + // Insert + List persons = new ArrayList<>(); + { + Person person = new Person(); + person.setName("MyBatis 1"); + List mails = new ArrayList<>(); + person.setMails(mails); + { + Mail mail = new Mail(); + mail.setAddress("mybatis1.main@test.com"); + mails.add(mail); + } + { + Mail mail = new Mail(); + mail.setAddress("mybatis1.sub@test.com"); + mails.add(mail); + } + persons.add(person); + } + { + Person person = new Person(); + person.setName("MyBatis 2"); + List mails = new ArrayList<>(); + person.setMails(mails); + { + Mail mail = new Mail(); + mail.setAddress("mybatis2.main@test.com"); + mails.add(mail); + } + { + Mail mail = new Mail(); + mail.setAddress("mybatis2.sub@test.com"); + mails.add(mail); + } + persons.add(person); + } + + mapper.insertByBulkWithIndexed(persons); + mapper.insertMailsByBulkWithIndexed(persons); + + int maxMailId = Optional.ofNullable(mapper.getMaxMailId()).filter(x -> x != 0).orElse(-1) - 4; + + // Select + List loadedPersons = mapper.selectPersons(persons.get(0).getId(), persons.get(1).getId()); + Assertions.assertEquals(2, loadedPersons.size()); + { + Person person = loadedPersons.get(0); + Assertions.assertEquals(persons.get(0).getId(), person.getId()); + Assertions.assertEquals("MyBatis 1", person.getName()); + List mails = person.getMails(); + Assertions.assertEquals(2, mails.size()); + { + Mail mail = mails.get(0); + Assertions.assertEquals(maxMailId + 1, mail.getId()); + Assertions.assertEquals(persons.get(0).getId(), mail.getPersonId()); + Assertions.assertEquals("mybatis1.main@test.com", mail.getAddress()); + } + { + Mail mail = mails.get(1); + Assertions.assertEquals(maxMailId + 2, mail.getId()); + Assertions.assertEquals(persons.get(0).getId(), mail.getPersonId()); + Assertions.assertEquals("mybatis1.sub@test.com", mail.getAddress()); + } + } + { + Person person = loadedPersons.get(1); + Assertions.assertEquals(persons.get(1).getId(), person.getId()); + Assertions.assertEquals("MyBatis 2", person.getName()); + List mails = person.getMails(); + Assertions.assertEquals(2, mails.size()); + { + Mail mail = mails.get(0); + Assertions.assertEquals(maxMailId + 3, mail.getId()); + Assertions.assertEquals(persons.get(1).getId(), mail.getPersonId()); + Assertions.assertEquals("mybatis2.main@test.com", mail.getAddress()); + } + { + Mail mail = mails.get(1); + Assertions.assertEquals(maxMailId + 4, mail.getId()); + Assertions.assertEquals(persons.get(1).getId(), mail.getPersonId()); + Assertions.assertEquals("mybatis2.sub@test.com", mail.getAddress()); + } + } + } + } } diff --git a/src/test/java/org/mybatis/scripting/thymeleaf/integrationtest/mapper/PersonMapper.java b/src/test/java/org/mybatis/scripting/thymeleaf/integrationtest/mapper/PersonMapper.java index 0eccab6..1f778a7 100644 --- a/src/test/java/org/mybatis/scripting/thymeleaf/integrationtest/mapper/PersonMapper.java +++ b/src/test/java/org/mybatis/scripting/thymeleaf/integrationtest/mapper/PersonMapper.java @@ -28,9 +28,16 @@ public interface PersonMapper { @Insert("sql/PersonMapper/insertByBulk.sql") void insertByBulk(List persons); + @Options(useGeneratedKeys = true, keyProperty = "id") + @Insert("sql/PersonMapper/insertByBulkWithIndexed.sql") + void insertByBulkWithIndexed(List persons); + @Insert("sql/PersonMapper/insertMailsByBulk.sql") void insertMailsByBulk(List persons); + @Insert("sql/PersonMapper/insertMailsByBulkWithIndexed.sql") + void insertMailsByBulkWithIndexed(List persons); + @Select("SELECT MAX(id) FROM person_mails") Integer getMaxMailId(); diff --git a/src/test/resources/sql/PersonMapper/insertByBulkWithIndexed.sql b/src/test/resources/sql/PersonMapper/insertByBulkWithIndexed.sql new file mode 100644 index 0000000..fea15f1 --- /dev/null +++ b/src/test/resources/sql/PersonMapper/insertByBulkWithIndexed.sql @@ -0,0 +1,22 @@ +-- +-- Copyright 2018-2019 the original author or authors. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +INSERT INTO persons (name) VALUES +/*[# th:each="person : ${list}"]*/ + ( + /*[# mb:p="list[${personStat.index}].name"]*/ 'Taro Yamada' /*[/]*/ + )/*[(${personStat.last} ? '' : ',')]*/ +/*[/]*/ diff --git a/src/test/resources/sql/PersonMapper/insertMailsByBulkWithIndexed.sql b/src/test/resources/sql/PersonMapper/insertMailsByBulkWithIndexed.sql new file mode 100644 index 0000000..7fabc8e --- /dev/null +++ b/src/test/resources/sql/PersonMapper/insertMailsByBulkWithIndexed.sql @@ -0,0 +1,26 @@ +-- +-- Copyright 2018-2019 the original author or authors. +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- + +INSERT INTO person_mails (person_id, address) VALUES +/*[# th:each="person : ${list}"]*/ + /*[# th:each="mail : ${person.mails}"]*/ + ( + /*[# mb:p="list[${personStat.index}].id"]*/ 1 /*[/]*/, + /*[# mb:p="list[${personStat.index}].mails[${mailStat.index}].address"]*/ 'taro.yamada@test.com' /*[/]*/ + )/*[(${personStat.last and mailStat.last} ? '' : ',')]*/ + /*[/]*/ +/*[/]*/ +