1+ /*
2+ * Copyright 2004-2010 the Seasar Foundation and the Others.
3+ *
4+ * Licensed under the Apache License, Version 2.0 (the "License");
5+ * you may not use this file except in compliance with the License.
6+ * You may obtain a copy of the License at
7+ *
8+ * http://www.apache.org/licenses/LICENSE-2.0
9+ *
10+ * Unless required by applicable law or agreed to in writing, software
11+ * distributed under the License is distributed on an "AS IS" BASIS,
12+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13+ * either express or implied. See the License for the specific language
14+ * governing permissions and limitations under the License.
15+ */
16+ package org .seasar .doma .jdbc .builder ;
17+
18+ import java .util .function .Supplier ;
19+ import java .util .Map ;
20+ import java .util .HashMap ;
21+ import java .util .List ;
22+
23+ import org .seasar .doma .DomaNullPointerException ;
24+ import org .seasar .doma .jdbc .JdbcException ;
25+ import org .seasar .doma .jdbc .Sql ;
26+ import org .seasar .doma .jdbc .SqlLogType ;
27+ import org .seasar .doma .jdbc .command .BatchModifyCommand ;
28+ import org .seasar .doma .jdbc .query .SqlBatchModifyQuery ;
29+ import org .seasar .doma .message .Message ;
30+
31+ /**
32+ * バッチ更新で利用される、SQL文を組み立てるクラスです。
33+ *
34+ * @author bakenezumi
35+ * @since 2.14.0
36+ */
37+ public abstract class BatchBuilder {
38+
39+ final BatchBuildingHelper helper ;
40+
41+ final SqlBatchModifyQuery query ;
42+
43+ final ParamIndex paramIndex ;
44+
45+ final Map <Integer , String > paramNameMap ;
46+
47+ BatchBuilder (SqlBatchModifyQuery query ) {
48+ this .helper = new BatchBuildingHelper ();
49+ this .query = query ;
50+ this .paramIndex = new ParamIndex ();
51+ paramNameMap = new HashMap <>();
52+ }
53+
54+ BatchBuilder (BatchBuildingHelper builder , SqlBatchModifyQuery query ,
55+ ParamIndex paramIndex , Map <Integer , String > paramNameMap ) {
56+ this .helper = builder ;
57+ this .query = query ;
58+ this .paramIndex = paramIndex ;
59+ this .paramNameMap = paramNameMap ;
60+ }
61+
62+ static BatchBuilder newInstance (SqlBatchModifyQuery query ) {
63+ if (query == null ) {
64+ throw new DomaNullPointerException ("query" );
65+ }
66+ if (query .getClassName () == null ) {
67+ query .setCallerClassName (BatchBuilder .class .getName ());
68+ }
69+ return new InitialBatchBuilder (query );
70+ }
71+
72+ /**
73+ * SQLの断片を追加します。
74+ *
75+ * @param sql
76+ * SQLの断片
77+ * @return このインスタンス
78+ * @throws DomaNullPointerException
79+ * 引数が {@code null} の場合
80+ */
81+ public abstract BatchBuilder sql (String sql );
82+
83+ /**
84+ * 最後に追加したSQLもしくはパラメータを削除します。
85+ *
86+ * @return このインスタンス
87+ */
88+ public abstract BatchBuilder removeLast ();
89+
90+ /**
91+ * パラメータを追加します。
92+ * <p>
93+ * パラメータの型には、基本型とドメインクラスを指定できます。
94+ *
95+ * @param <P>
96+ * パラメータの型
97+ * @param paramClass
98+ * パラメータの要素のクラス
99+ * @param param
100+ * パラメータ
101+ * @return このインスタンス
102+ * @throws DomaNullPointerException
103+ * {@code paramClass} が {@code null} の場合
104+ */
105+ public <P > BatchBuilder param (Class <P > paramClass , P param ) {
106+ if (paramClass == null ) {
107+ throw new DomaNullPointerException ("paramClass" );
108+ }
109+ return appendParam (paramClass , param , false );
110+ }
111+
112+ /**
113+ * リテラルとしてパラメータを追加します。
114+ * <p>
115+ * パラメータの型には、基本型とドメインクラスを指定できます。
116+ *
117+ * @param <P>
118+ * パラメータの型
119+ * @param paramClass
120+ * パラメータのクラス
121+ * @param param
122+ * パラメータ
123+ * @return このインスタンス
124+ * @throws DomaNullPointerException
125+ * {@code paramClass} が {@code null} の場合
126+ */
127+ public <P > BatchBuilder literal (Class <P > paramClass , P param ) {
128+ if (paramClass == null ) {
129+ throw new DomaNullPointerException ("paramClass" );
130+ }
131+ return appendParam (paramClass , param , true );
132+ }
133+
134+ abstract <P > BatchBuilder appendParam (Class <P > paramClass , P param , boolean literal );
135+
136+ BatchBuilder fixSql () {
137+ return new FixedBatchBuilder (helper , query , paramNameMap );
138+ }
139+
140+ private void prepare () {
141+ query .clearParameters ();
142+ for (BatchParam p : helper .getParams ()) {
143+ query .addParameter (p .name , p .paramClass , p .params );
144+ }
145+ query .setSqlNode (helper .getSqlNode ());
146+ query .prepare ();
147+ }
148+
149+ int [] execute (Supplier <BatchModifyCommand > commandFactory ) {
150+ if (query .getMethodName () == null ) {
151+ query .setCallerMethodName ("execute" );
152+ }
153+ prepare ();
154+ BatchModifyCommand command = commandFactory .get ();
155+ int [] result = command .execute ();
156+ query .complete ();
157+ return result ;
158+ }
159+
160+ List <? extends Sql <?>> getSqls () {
161+ if (query .getMethodName () == null ) {
162+ query .setCallerMethodName ("getSqls" );
163+ }
164+ prepare ();
165+ return query .getSqls ();
166+ }
167+
168+ private static class InitialBatchBuilder extends BatchBuilder {
169+
170+ private InitialBatchBuilder (SqlBatchModifyQuery query ) {
171+ super (query );
172+ }
173+
174+ private InitialBatchBuilder (BatchBuildingHelper builder , SqlBatchModifyQuery query ,
175+ ParamIndex paramIndex , Map <Integer , String > paramNameMap ) {
176+ super (builder , query , paramIndex , paramNameMap );
177+ }
178+
179+ @ Override
180+ public BatchBuilder sql (String sql ) {
181+ if (sql == null ) {
182+ throw new DomaNullPointerException ("sql" );
183+ }
184+ helper .appendSqlWithLineSeparator (sql );
185+ return new SubsequentBatchBuilder (helper , query , paramIndex , paramNameMap );
186+ }
187+
188+ @ Override
189+ public BatchBuilder removeLast () {
190+ helper .removeLast ();
191+ return new SubsequentBatchBuilder (helper , query , paramIndex , paramNameMap );
192+ }
193+
194+ @ Override
195+ <P > BatchBuilder appendParam (Class <P > paramClass , P param , boolean literal ) {
196+ BatchParam <P > batchParam = new BatchParam <>(paramClass , paramIndex , literal );
197+ batchParam .add (param );
198+ helper .appendParam (batchParam );
199+ paramNameMap .put (paramIndex .getValue (), batchParam .name );
200+ paramIndex .increment ();
201+ return new SubsequentBatchBuilder (helper , query , paramIndex , paramNameMap );
202+ }
203+
204+ }
205+
206+ private static class SubsequentBatchBuilder extends InitialBatchBuilder {
207+
208+ SubsequentBatchBuilder (BatchBuildingHelper builder ,
209+ SqlBatchModifyQuery query , ParamIndex paramIndex ,
210+ Map <Integer , String > paramNameMap ) {
211+ super (builder , query , paramIndex , paramNameMap );
212+ }
213+
214+ @ Override
215+ public BatchBuilder sql (String sql ) {
216+ if (sql == null ) {
217+ throw new DomaNullPointerException ("sql" );
218+ }
219+ super .helper .appendSql (sql );
220+ return this ;
221+ }
222+ }
223+
224+ private static class FixedBatchBuilder extends BatchBuilder {
225+
226+ private FixedBatchBuilder (BatchBuildingHelper builder , SqlBatchModifyQuery query , Map <Integer , String > paramNameMap ) {
227+ super (builder , query , new ParamIndex (), paramNameMap );
228+ }
229+
230+ @ Override
231+ public BatchBuilder sql (String sql ) {
232+ return this ;
233+ }
234+
235+ @ Override
236+ public BatchBuilder removeLast () {
237+ return this ;
238+ }
239+
240+ @ Override
241+ <P extends Object > BatchBuilder appendParam (Class <P > paramClass , P param , boolean literal ) {
242+ final String paramName = paramNameMap .get (paramIndex .getValue ());
243+ if (paramName == null ) {
244+ throw new JdbcException (Message .DOMA2231 );
245+ }
246+ final BatchParam <?> batchParam = helper .getParam (paramName );
247+
248+ if (literal != batchParam .literal ) {
249+ throw new JdbcException (Message .DOMA2230 );
250+ }
251+ if (paramClass != batchParam .paramClass ) {
252+ // BatchParamの初期値が型:Object、値:nullの場合に限り型を上書き
253+ if (batchParam .paramClass == Object .class ) {
254+ final BatchParam <P > newBatchParam = new BatchParam <P >(batchParam , paramClass );
255+ newBatchParam .add (param );
256+ helper .modifyParam (newBatchParam );
257+ } else if (param == null && paramClass == Object .class ) {
258+ // 型違いは型:Object、値:nullの場合のみ許可
259+ batchParam .add (null );
260+ } else {
261+ throw new JdbcException (Message .DOMA2229 );
262+ }
263+ } else {
264+ // paramClass == batchParam.paramClass であるため下記キャストは常に安全
265+ @ SuppressWarnings ("unchecked" )
266+ final BatchParam <P > castedBatchParam = (BatchParam <P >) batchParam ;
267+ castedBatchParam .add (param );
268+ }
269+ paramIndex .increment ();
270+ return this ;
271+ }
272+
273+ }
274+
275+ }
0 commit comments